51#include "sim/system.hh" 52 53using namespace std; 54using namespace TheISA; 55 56void 57SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) 58{ 59 if (DTRACE(SyscallBase)) { 60 int index = 0; 61 IntReg arg[6] M5_VAR_USED; 62 63 // we can't just put the calls to getSyscallArg() in the 64 // DPRINTF arg list, because C++ doesn't guarantee their order 65 for (int i = 0; i < 6; ++i) 66 arg[i] = process->getSyscallArg(tc, index); 67 68 // Linux supports up to six system call arguments through registers 69 // so we want to print all six. Check to the relevant man page to 70 // verify how many are actually used by a given system call. 71 DPRINTF_SYSCALL(Base, 72 "%s called w/arguments %d, %d, %d, %d, %d, %d\n", 73 name, arg[0], arg[1], arg[2], arg[3], arg[4], 74 arg[5]); 75 } 76 77 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); 78 79 if (retval.needsRetry()) { 80 DPRINTF_SYSCALL(Base, "%s needs retry\n", name); 81 } else { 82 DPRINTF_SYSCALL(Base, "%s returns %d\n", name, 83 retval.encodedValue()); 84 } 85 86 if (!(flags & SyscallDesc::SuppressReturnValue) && !retval.needsRetry()) 87 process->setSyscallReturn(tc, retval); 88} 89 90 91SyscallReturn 92unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 93 ThreadContext *tc) 94{ 95 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 96 97 return 1; 98} 99 100 101SyscallReturn 102ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 103 ThreadContext *tc) 104{ 105 int index = 0; 106 const char *extra_text = ""; 107 108 if (desc->warnOnce()) { 109 if (desc->warned) 110 return 0; 111 112 desc->warned = true; 113 extra_text = "\n (further warnings will be suppressed)"; 114 } 115 116 warn("ignoring syscall %s(%d, ...)%s", desc->name, 117 process->getSyscallArg(tc, index), extra_text); 118 119 return 0; 120} 121 122 123SyscallReturn 124exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 125 ThreadContext *tc) 126{ 127 if (process->system->numRunningContexts() == 1) { 128 // Last running context... exit simulator 129 int index = 0; 130 exitSimLoop("target called exit()", 131 process->getSyscallArg(tc, index) & 0xff); 132 } else { 133 // other running threads... just halt this one 134 tc->halt(); 135 } 136 137 return 1; 138} 139 140 141SyscallReturn 142exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 143 ThreadContext *tc) 144{ 145 // halt all threads belonging to this process 146 for (auto i: process->contextIds) { 147 process->system->getThreadContext(i)->halt(); 148 } 149 150 if (!process->system->numRunningContexts()) { 151 // all threads belonged to this process... exit simulator 152 int index = 0; 153 exitSimLoop("target called exit()", 154 process->getSyscallArg(tc, index) & 0xff); 155 } 156 157 return 1; 158} 159 160 161SyscallReturn 162getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 163{ 164 return (int)PageBytes; 165} 166 167 168SyscallReturn 169brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 170{ 171 // change brk addr to first arg 172 int index = 0; 173 Addr new_brk = p->getSyscallArg(tc, index); 174 175 // in Linux at least, brk(0) returns the current break value 176 // (note that the syscall and the glibc function have different behavior) 177 if (new_brk == 0) 178 return p->brk_point; 179 180 if (new_brk > p->brk_point) { 181 // might need to allocate some new pages 182 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 183 PageBytes); !gen.done(); gen.next()) { 184 if (!p->pTable->translate(gen.addr())) 185 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 186 187 // if the address is already there, zero it out 188 else { 189 uint8_t zero = 0; 190 SETranslatingPortProxy &tp = tc->getMemProxy(); 191 192 // split non-page aligned accesses 193 Addr next_page = roundUp(gen.addr(), PageBytes); 194 uint32_t size_needed = next_page - gen.addr(); 195 tp.memsetBlob(gen.addr(), zero, size_needed); 196 if (gen.addr() + PageBytes > next_page && 197 next_page < new_brk && 198 p->pTable->translate(next_page)) 199 { 200 size_needed = PageBytes - size_needed; 201 tp.memsetBlob(next_page, zero, size_needed); 202 } 203 } 204 } 205 } 206 207 p->brk_point = new_brk; 208 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 209 p->brk_point); 210 return p->brk_point; 211} 212 213 214SyscallReturn 215closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 216{ 217 int index = 0; 218 int tgt_fd = p->getSyscallArg(tc, index); 219 220 int sim_fd = p->getSimFD(tgt_fd); 221 if (sim_fd < 0) 222 return -EBADF; 223 224 int status = 0; 225 if (sim_fd > 2) 226 status = close(sim_fd); 227 if (status >= 0) 228 p->resetFDEntry(tgt_fd); 229 return status; 230} 231 232 233SyscallReturn 234readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 235{ 236 int index = 0; 237 int tgt_fd = p->getSyscallArg(tc, index); 238 Addr bufPtr = p->getSyscallArg(tc, index); 239 int nbytes = p->getSyscallArg(tc, index); 240 BufferArg bufArg(bufPtr, nbytes); 241 242 int sim_fd = p->getSimFD(tgt_fd); 243 if (sim_fd < 0) 244 return -EBADF; 245 246 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 247 248 if (bytes_read > 0) 249 bufArg.copyOut(tc->getMemProxy()); 250 251 return bytes_read; 252} 253 254SyscallReturn 255writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 256{ 257 int index = 0; 258 int tgt_fd = p->getSyscallArg(tc, index); 259 Addr bufPtr = p->getSyscallArg(tc, index); 260 int nbytes = p->getSyscallArg(tc, index); 261 BufferArg bufArg(bufPtr, nbytes); 262 263 int sim_fd = p->getSimFD(tgt_fd); 264 if (sim_fd < 0) 265 return -EBADF; 266 267 bufArg.copyIn(tc->getMemProxy()); 268 269 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 270 271 fsync(sim_fd); 272 273 return bytes_written; 274} 275 276 277SyscallReturn 278lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 279{ 280 int index = 0; 281 int tgt_fd = p->getSyscallArg(tc, index); 282 uint64_t offs = p->getSyscallArg(tc, index); 283 int whence = p->getSyscallArg(tc, index); 284 285 int sim_fd = p->getSimFD(tgt_fd); 286 if (sim_fd < 0) 287 return -EBADF; 288 289 off_t result = lseek(sim_fd, offs, whence); 290 291 return (result == (off_t)-1) ? -errno : result; 292} 293 294 295SyscallReturn 296_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 297{ 298 int index = 0; 299 int tgt_fd = p->getSyscallArg(tc, index); 300 uint64_t offset_high = p->getSyscallArg(tc, index); 301 uint32_t offset_low = p->getSyscallArg(tc, index); 302 Addr result_ptr = p->getSyscallArg(tc, index); 303 int whence = p->getSyscallArg(tc, index); 304 305 int sim_fd = p->getSimFD(tgt_fd); 306 if (sim_fd < 0) 307 return -EBADF; 308 309 uint64_t offset = (offset_high << 32) | offset_low; 310 311 uint64_t result = lseek(sim_fd, offset, whence); 312 result = TheISA::htog(result); 313 314 if (result == (off_t)-1) 315 return -errno; 316 // Assuming that the size of loff_t is 64 bits on the target platform 317 BufferArg result_buf(result_ptr, sizeof(result)); 318 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 319 result_buf.copyOut(tc->getMemProxy()); 320 return 0; 321} 322 323 324SyscallReturn 325munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 326{ 327 // With mmap more fully implemented, it might be worthwhile to bite 328 // the bullet and implement munmap. Should allow us to reuse simulated 329 // memory. 330 return 0; 331} 332 333 334const char *hostname = "m5.eecs.umich.edu"; 335 336SyscallReturn 337gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 338{ 339 int index = 0; 340 Addr bufPtr = p->getSyscallArg(tc, index); 341 int name_len = p->getSyscallArg(tc, index); 342 BufferArg name(bufPtr, name_len); 343 344 strncpy((char *)name.bufferPtr(), hostname, name_len); 345 346 name.copyOut(tc->getMemProxy()); 347 348 return 0; 349} 350 351SyscallReturn 352getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 353{ 354 int result = 0; 355 int index = 0; 356 Addr bufPtr = p->getSyscallArg(tc, index); 357 unsigned long size = p->getSyscallArg(tc, index); 358 BufferArg buf(bufPtr, size); 359 360 // Is current working directory defined? 361 string cwd = p->getcwd(); 362 if (!cwd.empty()) { 363 if (cwd.length() >= size) { 364 // Buffer too small 365 return -ERANGE; 366 } 367 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 368 result = cwd.length(); 369 } else { 370 if (getcwd((char *)buf.bufferPtr(), size) != NULL) { 371 result = strlen((char *)buf.bufferPtr()); 372 } else { 373 result = -1; 374 } 375 } 376 377 buf.copyOut(tc->getMemProxy()); 378 379 return (result == -1) ? -errno : result; 380} 381 382/// Target open() handler. 383SyscallReturn 384readlinkFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 385 ThreadContext *tc) 386{ 387 return readlinkFunc(desc, callnum, process, tc, 0); 388} 389 390SyscallReturn 391readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 392 int index) 393{ 394 string path; 395 396 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 397 return -EFAULT; 398 399 // Adjust path for current working directory 400 path = p->fullPath(path); 401 402 Addr bufPtr = p->getSyscallArg(tc, index); 403 size_t bufsiz = p->getSyscallArg(tc, index); 404 405 BufferArg buf(bufPtr, bufsiz); 406 407 int result = -1; 408 if (path != "/proc/self/exe") { 409 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 410 } else { 411 // Emulate readlink() called on '/proc/self/exe' should return the 412 // absolute path of the binary running in the simulated system (the 413 // LiveProcess' executable). It is possible that using this path in 414 // the simulated system will result in unexpected behavior if: 415 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 416 // called binary calls readlink(). 417 // 2) The host's full path to the running benchmark changes from one 418 // simulation to another. This can result in different simulated 419 // performance since the simulated system will process the binary 420 // path differently, even if the binary itself does not change. 421 422 // Get the absolute canonical path to the running application 423 char real_path[PATH_MAX]; 424 char *check_real_path = realpath(p->progName(), real_path); 425 if (!check_real_path) { 426 fatal("readlink('/proc/self/exe') unable to resolve path to " 427 "executable: %s", p->progName()); 428 } 429 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 430 size_t real_path_len = strlen(real_path); 431 if (real_path_len > bufsiz) { 432 // readlink will truncate the contents of the 433 // path to ensure it is no more than bufsiz 434 result = bufsiz; 435 } else { 436 result = real_path_len; 437 } 438 439 // Issue a warning about potential unexpected results 440 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 441 "results in various settings.\n Returning '%s'\n", 442 (char*)buf.bufferPtr()); 443 } 444 445 buf.copyOut(tc->getMemProxy()); 446 447 return (result == -1) ? -errno : result; 448} 449 450SyscallReturn 451unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 452{ 453 return unlinkHelper(desc, num, p, tc, 0); 454} 455 456SyscallReturn 457unlinkHelper(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 458 int index) 459{ 460 string path; 461 462 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 463 return -EFAULT; 464 465 // Adjust path for current working directory 466 path = p->fullPath(path); 467 468 int result = unlink(path.c_str()); 469 return (result == -1) ? -errno : result; 470} 471 472 473SyscallReturn 474mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 475{ 476 string path; 477 478 int index = 0; 479 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 480 return -EFAULT; 481 482 // Adjust path for current working directory 483 path = p->fullPath(path); 484 485 mode_t mode = p->getSyscallArg(tc, index); 486 487 int result = mkdir(path.c_str(), mode); 488 return (result == -1) ? -errno : result; 489} 490 491SyscallReturn 492renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 493{ 494 string old_name; 495 496 int index = 0; 497 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 498 return -EFAULT; 499 500 string new_name; 501 502 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 503 return -EFAULT; 504 505 // Adjust path for current working directory 506 old_name = p->fullPath(old_name); 507 new_name = p->fullPath(new_name); 508 509 int64_t result = rename(old_name.c_str(), new_name.c_str()); 510 return (result == -1) ? -errno : result; 511} 512 513SyscallReturn 514truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 515{ 516 string path; 517 518 int index = 0; 519 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 520 return -EFAULT; 521 522 off_t length = p->getSyscallArg(tc, index); 523 524 // Adjust path for current working directory 525 path = p->fullPath(path); 526 527 int result = truncate(path.c_str(), length); 528 return (result == -1) ? -errno : result; 529} 530 531SyscallReturn 532ftruncateFunc(SyscallDesc *desc, int num, 533 LiveProcess *process, ThreadContext *tc) 534{ 535 int index = 0; 536 int tgt_fd = process->getSyscallArg(tc, index); 537 off_t length = process->getSyscallArg(tc, index); 538 539 int sim_fd = process->getSimFD(tgt_fd); 540 if (sim_fd < 0) 541 return -EBADF; 542 543 int result = ftruncate(sim_fd, length); 544 return (result == -1) ? -errno : result; 545} 546 547SyscallReturn 548truncate64Func(SyscallDesc *desc, int num, 549 LiveProcess *process, ThreadContext *tc) 550{ 551 int index = 0; 552 string path; 553 554 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 555 return -EFAULT; 556 557 int64_t length = process->getSyscallArg(tc, index, 64); 558 559 // Adjust path for current working directory 560 path = process->fullPath(path); 561 562#if NO_STAT64 563 int result = truncate(path.c_str(), length); 564#else 565 int result = truncate64(path.c_str(), length); 566#endif 567 return (result == -1) ? -errno : result; 568} 569 570SyscallReturn 571ftruncate64Func(SyscallDesc *desc, int num, 572 LiveProcess *process, ThreadContext *tc) 573{ 574 int index = 0; 575 int tgt_fd = process->getSyscallArg(tc, index); 576 int64_t length = process->getSyscallArg(tc, index, 64); 577 578 int sim_fd = process->getSimFD(tgt_fd); 579 if (sim_fd < 0) 580 return -EBADF; 581 582#if NO_STAT64 583 int result = ftruncate(sim_fd, length); 584#else 585 int result = ftruncate64(sim_fd, length); 586#endif 587 return (result == -1) ? -errno : result; 588} 589 590SyscallReturn 591umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 592{ 593 // Letting the simulated program change the simulator's umask seems like 594 // a bad idea. Compromise by just returning the current umask but not 595 // changing anything. 596 mode_t oldMask = umask(0); 597 umask(oldMask); 598 return (int)oldMask; 599} 600 601SyscallReturn 602chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 603{ 604 string path; 605 606 int index = 0; 607 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 608 return -EFAULT; 609 610 /* XXX endianess */ 611 uint32_t owner = p->getSyscallArg(tc, index); 612 uid_t hostOwner = owner; 613 uint32_t group = p->getSyscallArg(tc, index); 614 gid_t hostGroup = group; 615 616 // Adjust path for current working directory 617 path = p->fullPath(path); 618 619 int result = chown(path.c_str(), hostOwner, hostGroup); 620 return (result == -1) ? -errno : result; 621} 622 623SyscallReturn 624fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 625{ 626 int index = 0; 627 int tgt_fd = process->getSyscallArg(tc, index); 628 629 int sim_fd = process->getSimFD(tgt_fd); 630 if (sim_fd < 0) 631 return -EBADF; 632 633 /* XXX endianess */ 634 uint32_t owner = process->getSyscallArg(tc, index); 635 uid_t hostOwner = owner; 636 uint32_t group = process->getSyscallArg(tc, index); 637 gid_t hostGroup = group; 638 639 int result = fchown(sim_fd, hostOwner, hostGroup); 640 return (result == -1) ? -errno : result; 641} 642 643 644SyscallReturn 645dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 646{ 647 int index = 0; 648 int tgt_fd = process->getSyscallArg(tc, index); 649 650 int sim_fd = process->getSimFD(tgt_fd); 651 if (sim_fd < 0) 652 return -EBADF; 653 654 FDEntry *fde = process->getFDEntry(tgt_fd); 655 656 int result = dup(sim_fd); 657 return (result == -1) ? -errno : 658 process->allocFD(result, fde->filename, fde->flags, fde->mode, false); 659} 660 661 662SyscallReturn 663fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, 664 ThreadContext *tc) 665{ 666 int index = 0; 667 int tgt_fd = process->getSyscallArg(tc, index); 668 669 int sim_fd = process->getSimFD(tgt_fd); 670 if (sim_fd < 0) 671 return -EBADF; 672 673 int cmd = process->getSyscallArg(tc, index); 674 switch (cmd) { 675 case 0: // F_DUPFD 676 // if we really wanted to support this, we'd need to do it 677 // in the target fd space. 678 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", tgt_fd); 679 return -EMFILE; 680 681 case 1: // F_GETFD (get close-on-exec flag) 682 case 2: // F_SETFD (set close-on-exec flag) 683 return 0; 684 685 case 3: // F_GETFL (get file flags) 686 case 4: // F_SETFL (set file flags) 687 // not sure if this is totally valid, but we'll pass it through 688 // to the underlying OS 689 warn("fcntl(%d, %d) passed through to host\n", tgt_fd, cmd); 690 return fcntl(sim_fd, cmd); 691 // return 0; 692 693 case 7: // F_GETLK (get lock) 694 case 8: // F_SETLK (set lock) 695 case 9: // F_SETLKW (set lock and wait) 696 // don't mess with file locking... just act like it's OK 697 warn("File lock call (fcntl(%d, %d)) ignored.\n", tgt_fd, cmd); 698 return 0; 699 700 default: 701 warn("Unknown fcntl command %d\n", cmd); 702 return 0; 703 } 704} 705 706SyscallReturn 707fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, 708 ThreadContext *tc) 709{ 710 int index = 0; 711 int tgt_fd = process->getSyscallArg(tc, index); 712 713 int sim_fd = process->getSimFD(tgt_fd); 714 if (sim_fd < 0) 715 return -EBADF; 716 717 int cmd = process->getSyscallArg(tc, index); 718 switch (cmd) { 719 case 33: //F_GETLK64 720 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 721 return -EMFILE; 722 723 case 34: // F_SETLK64 724 case 35: // F_SETLKW64 725 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 726 tgt_fd); 727 return -EMFILE; 728 729 default: 730 // not sure if this is totally valid, but we'll pass it through 731 // to the underlying OS 732 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 733 return fcntl(sim_fd, cmd); 734 // return 0; 735 } 736} 737 738SyscallReturn 739pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 740 ThreadContext *tc) 741{ 742 int fds[2], sim_fds[2]; 743 int pipe_retval = pipe(fds); 744 745 if (pipe_retval < 0) { 746 // error 747 return pipe_retval; 748 } 749 750 sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true); 751 sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); 752 753 process->setReadPipeSource(sim_fds[0], sim_fds[1]); 754 // Alpha Linux convention for pipe() is that fd[0] is returned as 755 // the return value of the function, and fd[1] is returned in r20. 756 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 757 return sim_fds[0]; 758} 759 760 761SyscallReturn 762getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 763 ThreadContext *tc) 764{ 765 // Make up a PID. There's no interprocess communication in 766 // fake_syscall mode, so there's no way for a process to know it's 767 // not getting a unique value. 768 769 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 770 return process->pid(); 771} 772 773 774SyscallReturn 775getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 776 ThreadContext *tc) 777{ 778 // Make up a UID and EUID... it shouldn't matter, and we want the 779 // simulation to be deterministic. 780 781 // EUID goes in r20. 782 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 783 return process->uid(); // UID 784} 785 786 787SyscallReturn 788getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 789 ThreadContext *tc) 790{ 791 // Get current group ID. EGID goes in r20. 792 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 793 return process->gid(); 794} 795 796 797SyscallReturn 798setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 799 ThreadContext *tc) 800{ 801 // can't fathom why a benchmark would call this. 802 int index = 0; 803 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 804 return 0; 805} 806 807SyscallReturn 808getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 809 ThreadContext *tc) 810{ 811 // Make up a PID. There's no interprocess communication in 812 // fake_syscall mode, so there's no way for a process to know it's 813 // not getting a unique value. 814 815 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID 816 return process->pid(); 817} 818 819SyscallReturn 820getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 821 ThreadContext *tc) 822{ 823 return process->ppid(); 824} 825 826SyscallReturn 827getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 828 ThreadContext *tc) 829{ 830 return process->uid(); // UID 831} 832 833SyscallReturn 834geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 835 ThreadContext *tc) 836{ 837 return process->euid(); // UID 838} 839 840SyscallReturn 841getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 842 ThreadContext *tc) 843{ 844 return process->gid(); 845} 846 847SyscallReturn 848getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 849 ThreadContext *tc) 850{ 851 return process->egid(); 852} 853 854 855SyscallReturn 856cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 857 ThreadContext *tc) 858{ 859 int index = 0; 860 IntReg flags = process->getSyscallArg(tc, index); 861 IntReg newStack = process->getSyscallArg(tc, index); 862 863 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 864 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 865 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 866 867 868 if (flags != 0x10f00) { 869 warn("This sys_clone implementation assumes flags " 870 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 871 "(0x10f00), and may not work correctly with given flags " 872 "0x%llx\n", flags); 873 } 874 875 ThreadContext* ctc; // child thread context 876 if ( ( ctc = process->findFreeContext() ) != NULL ) { 877 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 878 879 ctc->clearArchRegs(); 880 881 // Arch-specific cloning code 882 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 883 // Cloning the misc. regs for these archs is enough 884 TheISA::copyMiscRegs(tc, ctc); 885 #elif THE_ISA == SPARC_ISA 886 TheISA::copyRegs(tc, ctc); 887 888 // TODO: Explain what this code actually does :-) 889 ctc->setIntReg(NumIntArchRegs + 6, 0); 890 ctc->setIntReg(NumIntArchRegs + 4, 0); 891 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 892 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 893 ctc->setMiscReg(MISCREG_CWP, 0); 894 ctc->setIntReg(NumIntArchRegs + 7, 0); 895 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 896 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 897 898 for (int y = 8; y < 32; y++) 899 ctc->setIntReg(y, tc->readIntReg(y)); 900 #elif THE_ISA == ARM_ISA 901 TheISA::copyRegs(tc, ctc); 902 #else 903 fatal("sys_clone is not implemented for this ISA\n"); 904 #endif 905 906 // Set up stack register 907 ctc->setIntReg(TheISA::StackPointerReg, newStack); 908 909 // Set up syscall return values in parent and child 910 ctc->setIntReg(ReturnValueReg, 0); // return value, child 911 912 // Alpha needs SyscallSuccessReg=0 in child 913 #if THE_ISA == ALPHA_ISA 914 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 915 #endif 916 917 // In SPARC/Linux, clone returns 0 on pseudo-return register if 918 // parent, non-zero if child 919 #if THE_ISA == SPARC_ISA 920 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 921 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 922 #endif 923 924 ctc->pcState(tc->nextInstAddr()); 925 926 ctc->activate(); 927 928 // Should return nonzero child TID in parent's syscall return register, 929 // but for our pthread library any non-zero value will work 930 return 1; 931 } else { 932 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 933 return 0; 934 } 935} 936 937SyscallReturn 938fallocateFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 939 ThreadContext *tc) 940{ 941 int index = 0; 942 int tgt_fd = process->getSyscallArg(tc, index); 943 int mode = process->getSyscallArg(tc, index); 944 off_t offset = process->getSyscallArg(tc, index); 945 off_t len = process->getSyscallArg(tc, index); 946 947 int sim_fd = process->getSimFD(tgt_fd); 948 if (sim_fd < 0) 949 return -EBADF; 950 951 int result = fallocate(sim_fd, mode, offset, len); 952 if (result < 0) 953 return -errno; 954 955 return 0; 956} 957 958SyscallReturn 959accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc, 960 int index) 961{ 962 string path; 963 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 964 return -EFAULT; 965 966 // Adjust path for current working directory 967 path = p->fullPath(path); 968 969 mode_t mode = p->getSyscallArg(tc, index); 970 971 int result = access(path.c_str(), mode); 972 return (result == -1) ? -errno : result; 973} 974 975SyscallReturn 976accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc) 977{ 978 return accessFunc(desc, callnum, p, tc, 0); 979} 980
| 52#include "sim/system.hh" 53 54using namespace std; 55using namespace TheISA; 56 57void 58SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) 59{ 60 if (DTRACE(SyscallBase)) { 61 int index = 0; 62 IntReg arg[6] M5_VAR_USED; 63 64 // we can't just put the calls to getSyscallArg() in the 65 // DPRINTF arg list, because C++ doesn't guarantee their order 66 for (int i = 0; i < 6; ++i) 67 arg[i] = process->getSyscallArg(tc, index); 68 69 // Linux supports up to six system call arguments through registers 70 // so we want to print all six. Check to the relevant man page to 71 // verify how many are actually used by a given system call. 72 DPRINTF_SYSCALL(Base, 73 "%s called w/arguments %d, %d, %d, %d, %d, %d\n", 74 name, arg[0], arg[1], arg[2], arg[3], arg[4], 75 arg[5]); 76 } 77 78 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); 79 80 if (retval.needsRetry()) { 81 DPRINTF_SYSCALL(Base, "%s needs retry\n", name); 82 } else { 83 DPRINTF_SYSCALL(Base, "%s returns %d\n", name, 84 retval.encodedValue()); 85 } 86 87 if (!(flags & SyscallDesc::SuppressReturnValue) && !retval.needsRetry()) 88 process->setSyscallReturn(tc, retval); 89} 90 91 92SyscallReturn 93unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 94 ThreadContext *tc) 95{ 96 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 97 98 return 1; 99} 100 101 102SyscallReturn 103ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 104 ThreadContext *tc) 105{ 106 int index = 0; 107 const char *extra_text = ""; 108 109 if (desc->warnOnce()) { 110 if (desc->warned) 111 return 0; 112 113 desc->warned = true; 114 extra_text = "\n (further warnings will be suppressed)"; 115 } 116 117 warn("ignoring syscall %s(%d, ...)%s", desc->name, 118 process->getSyscallArg(tc, index), extra_text); 119 120 return 0; 121} 122 123 124SyscallReturn 125exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 126 ThreadContext *tc) 127{ 128 if (process->system->numRunningContexts() == 1) { 129 // Last running context... exit simulator 130 int index = 0; 131 exitSimLoop("target called exit()", 132 process->getSyscallArg(tc, index) & 0xff); 133 } else { 134 // other running threads... just halt this one 135 tc->halt(); 136 } 137 138 return 1; 139} 140 141 142SyscallReturn 143exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 144 ThreadContext *tc) 145{ 146 // halt all threads belonging to this process 147 for (auto i: process->contextIds) { 148 process->system->getThreadContext(i)->halt(); 149 } 150 151 if (!process->system->numRunningContexts()) { 152 // all threads belonged to this process... exit simulator 153 int index = 0; 154 exitSimLoop("target called exit()", 155 process->getSyscallArg(tc, index) & 0xff); 156 } 157 158 return 1; 159} 160 161 162SyscallReturn 163getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 164{ 165 return (int)PageBytes; 166} 167 168 169SyscallReturn 170brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 171{ 172 // change brk addr to first arg 173 int index = 0; 174 Addr new_brk = p->getSyscallArg(tc, index); 175 176 // in Linux at least, brk(0) returns the current break value 177 // (note that the syscall and the glibc function have different behavior) 178 if (new_brk == 0) 179 return p->brk_point; 180 181 if (new_brk > p->brk_point) { 182 // might need to allocate some new pages 183 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 184 PageBytes); !gen.done(); gen.next()) { 185 if (!p->pTable->translate(gen.addr())) 186 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 187 188 // if the address is already there, zero it out 189 else { 190 uint8_t zero = 0; 191 SETranslatingPortProxy &tp = tc->getMemProxy(); 192 193 // split non-page aligned accesses 194 Addr next_page = roundUp(gen.addr(), PageBytes); 195 uint32_t size_needed = next_page - gen.addr(); 196 tp.memsetBlob(gen.addr(), zero, size_needed); 197 if (gen.addr() + PageBytes > next_page && 198 next_page < new_brk && 199 p->pTable->translate(next_page)) 200 { 201 size_needed = PageBytes - size_needed; 202 tp.memsetBlob(next_page, zero, size_needed); 203 } 204 } 205 } 206 } 207 208 p->brk_point = new_brk; 209 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 210 p->brk_point); 211 return p->brk_point; 212} 213 214 215SyscallReturn 216closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 217{ 218 int index = 0; 219 int tgt_fd = p->getSyscallArg(tc, index); 220 221 int sim_fd = p->getSimFD(tgt_fd); 222 if (sim_fd < 0) 223 return -EBADF; 224 225 int status = 0; 226 if (sim_fd > 2) 227 status = close(sim_fd); 228 if (status >= 0) 229 p->resetFDEntry(tgt_fd); 230 return status; 231} 232 233 234SyscallReturn 235readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 236{ 237 int index = 0; 238 int tgt_fd = p->getSyscallArg(tc, index); 239 Addr bufPtr = p->getSyscallArg(tc, index); 240 int nbytes = p->getSyscallArg(tc, index); 241 BufferArg bufArg(bufPtr, nbytes); 242 243 int sim_fd = p->getSimFD(tgt_fd); 244 if (sim_fd < 0) 245 return -EBADF; 246 247 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 248 249 if (bytes_read > 0) 250 bufArg.copyOut(tc->getMemProxy()); 251 252 return bytes_read; 253} 254 255SyscallReturn 256writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 257{ 258 int index = 0; 259 int tgt_fd = p->getSyscallArg(tc, index); 260 Addr bufPtr = p->getSyscallArg(tc, index); 261 int nbytes = p->getSyscallArg(tc, index); 262 BufferArg bufArg(bufPtr, nbytes); 263 264 int sim_fd = p->getSimFD(tgt_fd); 265 if (sim_fd < 0) 266 return -EBADF; 267 268 bufArg.copyIn(tc->getMemProxy()); 269 270 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 271 272 fsync(sim_fd); 273 274 return bytes_written; 275} 276 277 278SyscallReturn 279lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 280{ 281 int index = 0; 282 int tgt_fd = p->getSyscallArg(tc, index); 283 uint64_t offs = p->getSyscallArg(tc, index); 284 int whence = p->getSyscallArg(tc, index); 285 286 int sim_fd = p->getSimFD(tgt_fd); 287 if (sim_fd < 0) 288 return -EBADF; 289 290 off_t result = lseek(sim_fd, offs, whence); 291 292 return (result == (off_t)-1) ? -errno : result; 293} 294 295 296SyscallReturn 297_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 298{ 299 int index = 0; 300 int tgt_fd = p->getSyscallArg(tc, index); 301 uint64_t offset_high = p->getSyscallArg(tc, index); 302 uint32_t offset_low = p->getSyscallArg(tc, index); 303 Addr result_ptr = p->getSyscallArg(tc, index); 304 int whence = p->getSyscallArg(tc, index); 305 306 int sim_fd = p->getSimFD(tgt_fd); 307 if (sim_fd < 0) 308 return -EBADF; 309 310 uint64_t offset = (offset_high << 32) | offset_low; 311 312 uint64_t result = lseek(sim_fd, offset, whence); 313 result = TheISA::htog(result); 314 315 if (result == (off_t)-1) 316 return -errno; 317 // Assuming that the size of loff_t is 64 bits on the target platform 318 BufferArg result_buf(result_ptr, sizeof(result)); 319 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 320 result_buf.copyOut(tc->getMemProxy()); 321 return 0; 322} 323 324 325SyscallReturn 326munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 327{ 328 // With mmap more fully implemented, it might be worthwhile to bite 329 // the bullet and implement munmap. Should allow us to reuse simulated 330 // memory. 331 return 0; 332} 333 334 335const char *hostname = "m5.eecs.umich.edu"; 336 337SyscallReturn 338gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 339{ 340 int index = 0; 341 Addr bufPtr = p->getSyscallArg(tc, index); 342 int name_len = p->getSyscallArg(tc, index); 343 BufferArg name(bufPtr, name_len); 344 345 strncpy((char *)name.bufferPtr(), hostname, name_len); 346 347 name.copyOut(tc->getMemProxy()); 348 349 return 0; 350} 351 352SyscallReturn 353getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 354{ 355 int result = 0; 356 int index = 0; 357 Addr bufPtr = p->getSyscallArg(tc, index); 358 unsigned long size = p->getSyscallArg(tc, index); 359 BufferArg buf(bufPtr, size); 360 361 // Is current working directory defined? 362 string cwd = p->getcwd(); 363 if (!cwd.empty()) { 364 if (cwd.length() >= size) { 365 // Buffer too small 366 return -ERANGE; 367 } 368 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 369 result = cwd.length(); 370 } else { 371 if (getcwd((char *)buf.bufferPtr(), size) != NULL) { 372 result = strlen((char *)buf.bufferPtr()); 373 } else { 374 result = -1; 375 } 376 } 377 378 buf.copyOut(tc->getMemProxy()); 379 380 return (result == -1) ? -errno : result; 381} 382 383/// Target open() handler. 384SyscallReturn 385readlinkFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 386 ThreadContext *tc) 387{ 388 return readlinkFunc(desc, callnum, process, tc, 0); 389} 390 391SyscallReturn 392readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 393 int index) 394{ 395 string path; 396 397 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 398 return -EFAULT; 399 400 // Adjust path for current working directory 401 path = p->fullPath(path); 402 403 Addr bufPtr = p->getSyscallArg(tc, index); 404 size_t bufsiz = p->getSyscallArg(tc, index); 405 406 BufferArg buf(bufPtr, bufsiz); 407 408 int result = -1; 409 if (path != "/proc/self/exe") { 410 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 411 } else { 412 // Emulate readlink() called on '/proc/self/exe' should return the 413 // absolute path of the binary running in the simulated system (the 414 // LiveProcess' executable). It is possible that using this path in 415 // the simulated system will result in unexpected behavior if: 416 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 417 // called binary calls readlink(). 418 // 2) The host's full path to the running benchmark changes from one 419 // simulation to another. This can result in different simulated 420 // performance since the simulated system will process the binary 421 // path differently, even if the binary itself does not change. 422 423 // Get the absolute canonical path to the running application 424 char real_path[PATH_MAX]; 425 char *check_real_path = realpath(p->progName(), real_path); 426 if (!check_real_path) { 427 fatal("readlink('/proc/self/exe') unable to resolve path to " 428 "executable: %s", p->progName()); 429 } 430 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 431 size_t real_path_len = strlen(real_path); 432 if (real_path_len > bufsiz) { 433 // readlink will truncate the contents of the 434 // path to ensure it is no more than bufsiz 435 result = bufsiz; 436 } else { 437 result = real_path_len; 438 } 439 440 // Issue a warning about potential unexpected results 441 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 442 "results in various settings.\n Returning '%s'\n", 443 (char*)buf.bufferPtr()); 444 } 445 446 buf.copyOut(tc->getMemProxy()); 447 448 return (result == -1) ? -errno : result; 449} 450 451SyscallReturn 452unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 453{ 454 return unlinkHelper(desc, num, p, tc, 0); 455} 456 457SyscallReturn 458unlinkHelper(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 459 int index) 460{ 461 string path; 462 463 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 464 return -EFAULT; 465 466 // Adjust path for current working directory 467 path = p->fullPath(path); 468 469 int result = unlink(path.c_str()); 470 return (result == -1) ? -errno : result; 471} 472 473 474SyscallReturn 475mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 476{ 477 string path; 478 479 int index = 0; 480 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 481 return -EFAULT; 482 483 // Adjust path for current working directory 484 path = p->fullPath(path); 485 486 mode_t mode = p->getSyscallArg(tc, index); 487 488 int result = mkdir(path.c_str(), mode); 489 return (result == -1) ? -errno : result; 490} 491 492SyscallReturn 493renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 494{ 495 string old_name; 496 497 int index = 0; 498 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 499 return -EFAULT; 500 501 string new_name; 502 503 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 504 return -EFAULT; 505 506 // Adjust path for current working directory 507 old_name = p->fullPath(old_name); 508 new_name = p->fullPath(new_name); 509 510 int64_t result = rename(old_name.c_str(), new_name.c_str()); 511 return (result == -1) ? -errno : result; 512} 513 514SyscallReturn 515truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 516{ 517 string path; 518 519 int index = 0; 520 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 521 return -EFAULT; 522 523 off_t length = p->getSyscallArg(tc, index); 524 525 // Adjust path for current working directory 526 path = p->fullPath(path); 527 528 int result = truncate(path.c_str(), length); 529 return (result == -1) ? -errno : result; 530} 531 532SyscallReturn 533ftruncateFunc(SyscallDesc *desc, int num, 534 LiveProcess *process, ThreadContext *tc) 535{ 536 int index = 0; 537 int tgt_fd = process->getSyscallArg(tc, index); 538 off_t length = process->getSyscallArg(tc, index); 539 540 int sim_fd = process->getSimFD(tgt_fd); 541 if (sim_fd < 0) 542 return -EBADF; 543 544 int result = ftruncate(sim_fd, length); 545 return (result == -1) ? -errno : result; 546} 547 548SyscallReturn 549truncate64Func(SyscallDesc *desc, int num, 550 LiveProcess *process, ThreadContext *tc) 551{ 552 int index = 0; 553 string path; 554 555 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 556 return -EFAULT; 557 558 int64_t length = process->getSyscallArg(tc, index, 64); 559 560 // Adjust path for current working directory 561 path = process->fullPath(path); 562 563#if NO_STAT64 564 int result = truncate(path.c_str(), length); 565#else 566 int result = truncate64(path.c_str(), length); 567#endif 568 return (result == -1) ? -errno : result; 569} 570 571SyscallReturn 572ftruncate64Func(SyscallDesc *desc, int num, 573 LiveProcess *process, ThreadContext *tc) 574{ 575 int index = 0; 576 int tgt_fd = process->getSyscallArg(tc, index); 577 int64_t length = process->getSyscallArg(tc, index, 64); 578 579 int sim_fd = process->getSimFD(tgt_fd); 580 if (sim_fd < 0) 581 return -EBADF; 582 583#if NO_STAT64 584 int result = ftruncate(sim_fd, length); 585#else 586 int result = ftruncate64(sim_fd, length); 587#endif 588 return (result == -1) ? -errno : result; 589} 590 591SyscallReturn 592umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 593{ 594 // Letting the simulated program change the simulator's umask seems like 595 // a bad idea. Compromise by just returning the current umask but not 596 // changing anything. 597 mode_t oldMask = umask(0); 598 umask(oldMask); 599 return (int)oldMask; 600} 601 602SyscallReturn 603chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 604{ 605 string path; 606 607 int index = 0; 608 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 609 return -EFAULT; 610 611 /* XXX endianess */ 612 uint32_t owner = p->getSyscallArg(tc, index); 613 uid_t hostOwner = owner; 614 uint32_t group = p->getSyscallArg(tc, index); 615 gid_t hostGroup = group; 616 617 // Adjust path for current working directory 618 path = p->fullPath(path); 619 620 int result = chown(path.c_str(), hostOwner, hostGroup); 621 return (result == -1) ? -errno : result; 622} 623 624SyscallReturn 625fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 626{ 627 int index = 0; 628 int tgt_fd = process->getSyscallArg(tc, index); 629 630 int sim_fd = process->getSimFD(tgt_fd); 631 if (sim_fd < 0) 632 return -EBADF; 633 634 /* XXX endianess */ 635 uint32_t owner = process->getSyscallArg(tc, index); 636 uid_t hostOwner = owner; 637 uint32_t group = process->getSyscallArg(tc, index); 638 gid_t hostGroup = group; 639 640 int result = fchown(sim_fd, hostOwner, hostGroup); 641 return (result == -1) ? -errno : result; 642} 643 644 645SyscallReturn 646dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 647{ 648 int index = 0; 649 int tgt_fd = process->getSyscallArg(tc, index); 650 651 int sim_fd = process->getSimFD(tgt_fd); 652 if (sim_fd < 0) 653 return -EBADF; 654 655 FDEntry *fde = process->getFDEntry(tgt_fd); 656 657 int result = dup(sim_fd); 658 return (result == -1) ? -errno : 659 process->allocFD(result, fde->filename, fde->flags, fde->mode, false); 660} 661 662 663SyscallReturn 664fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, 665 ThreadContext *tc) 666{ 667 int index = 0; 668 int tgt_fd = process->getSyscallArg(tc, index); 669 670 int sim_fd = process->getSimFD(tgt_fd); 671 if (sim_fd < 0) 672 return -EBADF; 673 674 int cmd = process->getSyscallArg(tc, index); 675 switch (cmd) { 676 case 0: // F_DUPFD 677 // if we really wanted to support this, we'd need to do it 678 // in the target fd space. 679 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", tgt_fd); 680 return -EMFILE; 681 682 case 1: // F_GETFD (get close-on-exec flag) 683 case 2: // F_SETFD (set close-on-exec flag) 684 return 0; 685 686 case 3: // F_GETFL (get file flags) 687 case 4: // F_SETFL (set file flags) 688 // not sure if this is totally valid, but we'll pass it through 689 // to the underlying OS 690 warn("fcntl(%d, %d) passed through to host\n", tgt_fd, cmd); 691 return fcntl(sim_fd, cmd); 692 // return 0; 693 694 case 7: // F_GETLK (get lock) 695 case 8: // F_SETLK (set lock) 696 case 9: // F_SETLKW (set lock and wait) 697 // don't mess with file locking... just act like it's OK 698 warn("File lock call (fcntl(%d, %d)) ignored.\n", tgt_fd, cmd); 699 return 0; 700 701 default: 702 warn("Unknown fcntl command %d\n", cmd); 703 return 0; 704 } 705} 706 707SyscallReturn 708fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, 709 ThreadContext *tc) 710{ 711 int index = 0; 712 int tgt_fd = process->getSyscallArg(tc, index); 713 714 int sim_fd = process->getSimFD(tgt_fd); 715 if (sim_fd < 0) 716 return -EBADF; 717 718 int cmd = process->getSyscallArg(tc, index); 719 switch (cmd) { 720 case 33: //F_GETLK64 721 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 722 return -EMFILE; 723 724 case 34: // F_SETLK64 725 case 35: // F_SETLKW64 726 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 727 tgt_fd); 728 return -EMFILE; 729 730 default: 731 // not sure if this is totally valid, but we'll pass it through 732 // to the underlying OS 733 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 734 return fcntl(sim_fd, cmd); 735 // return 0; 736 } 737} 738 739SyscallReturn 740pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 741 ThreadContext *tc) 742{ 743 int fds[2], sim_fds[2]; 744 int pipe_retval = pipe(fds); 745 746 if (pipe_retval < 0) { 747 // error 748 return pipe_retval; 749 } 750 751 sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true); 752 sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); 753 754 process->setReadPipeSource(sim_fds[0], sim_fds[1]); 755 // Alpha Linux convention for pipe() is that fd[0] is returned as 756 // the return value of the function, and fd[1] is returned in r20. 757 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 758 return sim_fds[0]; 759} 760 761 762SyscallReturn 763getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 764 ThreadContext *tc) 765{ 766 // Make up a PID. There's no interprocess communication in 767 // fake_syscall mode, so there's no way for a process to know it's 768 // not getting a unique value. 769 770 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 771 return process->pid(); 772} 773 774 775SyscallReturn 776getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 777 ThreadContext *tc) 778{ 779 // Make up a UID and EUID... it shouldn't matter, and we want the 780 // simulation to be deterministic. 781 782 // EUID goes in r20. 783 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 784 return process->uid(); // UID 785} 786 787 788SyscallReturn 789getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 790 ThreadContext *tc) 791{ 792 // Get current group ID. EGID goes in r20. 793 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 794 return process->gid(); 795} 796 797 798SyscallReturn 799setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 800 ThreadContext *tc) 801{ 802 // can't fathom why a benchmark would call this. 803 int index = 0; 804 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 805 return 0; 806} 807 808SyscallReturn 809getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 810 ThreadContext *tc) 811{ 812 // Make up a PID. There's no interprocess communication in 813 // fake_syscall mode, so there's no way for a process to know it's 814 // not getting a unique value. 815 816 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID 817 return process->pid(); 818} 819 820SyscallReturn 821getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 822 ThreadContext *tc) 823{ 824 return process->ppid(); 825} 826 827SyscallReturn 828getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 829 ThreadContext *tc) 830{ 831 return process->uid(); // UID 832} 833 834SyscallReturn 835geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 836 ThreadContext *tc) 837{ 838 return process->euid(); // UID 839} 840 841SyscallReturn 842getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 843 ThreadContext *tc) 844{ 845 return process->gid(); 846} 847 848SyscallReturn 849getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 850 ThreadContext *tc) 851{ 852 return process->egid(); 853} 854 855 856SyscallReturn 857cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 858 ThreadContext *tc) 859{ 860 int index = 0; 861 IntReg flags = process->getSyscallArg(tc, index); 862 IntReg newStack = process->getSyscallArg(tc, index); 863 864 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 865 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 866 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 867 868 869 if (flags != 0x10f00) { 870 warn("This sys_clone implementation assumes flags " 871 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 872 "(0x10f00), and may not work correctly with given flags " 873 "0x%llx\n", flags); 874 } 875 876 ThreadContext* ctc; // child thread context 877 if ( ( ctc = process->findFreeContext() ) != NULL ) { 878 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 879 880 ctc->clearArchRegs(); 881 882 // Arch-specific cloning code 883 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 884 // Cloning the misc. regs for these archs is enough 885 TheISA::copyMiscRegs(tc, ctc); 886 #elif THE_ISA == SPARC_ISA 887 TheISA::copyRegs(tc, ctc); 888 889 // TODO: Explain what this code actually does :-) 890 ctc->setIntReg(NumIntArchRegs + 6, 0); 891 ctc->setIntReg(NumIntArchRegs + 4, 0); 892 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 893 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 894 ctc->setMiscReg(MISCREG_CWP, 0); 895 ctc->setIntReg(NumIntArchRegs + 7, 0); 896 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 897 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 898 899 for (int y = 8; y < 32; y++) 900 ctc->setIntReg(y, tc->readIntReg(y)); 901 #elif THE_ISA == ARM_ISA 902 TheISA::copyRegs(tc, ctc); 903 #else 904 fatal("sys_clone is not implemented for this ISA\n"); 905 #endif 906 907 // Set up stack register 908 ctc->setIntReg(TheISA::StackPointerReg, newStack); 909 910 // Set up syscall return values in parent and child 911 ctc->setIntReg(ReturnValueReg, 0); // return value, child 912 913 // Alpha needs SyscallSuccessReg=0 in child 914 #if THE_ISA == ALPHA_ISA 915 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 916 #endif 917 918 // In SPARC/Linux, clone returns 0 on pseudo-return register if 919 // parent, non-zero if child 920 #if THE_ISA == SPARC_ISA 921 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 922 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 923 #endif 924 925 ctc->pcState(tc->nextInstAddr()); 926 927 ctc->activate(); 928 929 // Should return nonzero child TID in parent's syscall return register, 930 // but for our pthread library any non-zero value will work 931 return 1; 932 } else { 933 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 934 return 0; 935 } 936} 937 938SyscallReturn 939fallocateFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 940 ThreadContext *tc) 941{ 942 int index = 0; 943 int tgt_fd = process->getSyscallArg(tc, index); 944 int mode = process->getSyscallArg(tc, index); 945 off_t offset = process->getSyscallArg(tc, index); 946 off_t len = process->getSyscallArg(tc, index); 947 948 int sim_fd = process->getSimFD(tgt_fd); 949 if (sim_fd < 0) 950 return -EBADF; 951 952 int result = fallocate(sim_fd, mode, offset, len); 953 if (result < 0) 954 return -errno; 955 956 return 0; 957} 958 959SyscallReturn 960accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc, 961 int index) 962{ 963 string path; 964 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 965 return -EFAULT; 966 967 // Adjust path for current working directory 968 path = p->fullPath(path); 969 970 mode_t mode = p->getSyscallArg(tc, index); 971 972 int result = access(path.c_str(), mode); 973 return (result == -1) ? -errno : result; 974} 975 976SyscallReturn 977accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc) 978{ 979 return accessFunc(desc, callnum, p, tc, 0); 980} 981
|