192 return status; 193} 194 195SyscallReturn 196exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 197{ 198 return exitImpl(desc, callnum, p, tc, false); 199} 200 201SyscallReturn 202exitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 203{ 204 return exitImpl(desc, callnum, p, tc, true); 205} 206 207SyscallReturn 208getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 209{ 210 return (int)PageBytes; 211} 212 213 214SyscallReturn 215brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 216{ 217 // change brk addr to first arg 218 int index = 0; 219 Addr new_brk = p->getSyscallArg(tc, index); 220 221 std::shared_ptr<MemState> mem_state = p->memState; 222 Addr brk_point = mem_state->getBrkPoint(); 223 224 // in Linux at least, brk(0) returns the current break value 225 // (note that the syscall and the glibc function have different behavior) 226 if (new_brk == 0) 227 return brk_point; 228 229 if (new_brk > brk_point) { 230 // might need to allocate some new pages 231 for (ChunkGenerator gen(brk_point, 232 new_brk - brk_point, 233 PageBytes); !gen.done(); gen.next()) { 234 if (!p->pTable->translate(gen.addr())) 235 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 236 237 // if the address is already there, zero it out 238 else { 239 uint8_t zero = 0; 240 SETranslatingPortProxy &tp = tc->getMemProxy(); 241 242 // split non-page aligned accesses 243 Addr next_page = roundUp(gen.addr(), PageBytes); 244 uint32_t size_needed = next_page - gen.addr(); 245 tp.memsetBlob(gen.addr(), zero, size_needed); 246 if (gen.addr() + PageBytes > next_page && 247 next_page < new_brk && 248 p->pTable->translate(next_page)) { 249 size_needed = PageBytes - size_needed; 250 tp.memsetBlob(next_page, zero, size_needed); 251 } 252 } 253 } 254 } 255 256 mem_state->setBrkPoint(new_brk); 257 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 258 mem_state->getBrkPoint()); 259 return mem_state->getBrkPoint(); 260} 261 262SyscallReturn 263setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process, 264 ThreadContext *tc) 265{ 266 int index = 0; 267 uint64_t tidPtr = process->getSyscallArg(tc, index); 268 269 process->childClearTID = tidPtr; 270 return process->pid(); 271} 272 273SyscallReturn 274closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 275{ 276 int index = 0; 277 int tgt_fd = p->getSyscallArg(tc, index); 278 279 return p->fds->closeFDEntry(tgt_fd); 280} 281 282SyscallReturn 283lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 284{ 285 int index = 0; 286 int tgt_fd = p->getSyscallArg(tc, index); 287 uint64_t offs = p->getSyscallArg(tc, index); 288 int whence = p->getSyscallArg(tc, index); 289 290 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 291 if (!ffdp) 292 return -EBADF; 293 int sim_fd = ffdp->getSimFD(); 294 295 off_t result = lseek(sim_fd, offs, whence); 296 297 return (result == (off_t)-1) ? -errno : result; 298} 299 300 301SyscallReturn 302_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 303{ 304 int index = 0; 305 int tgt_fd = p->getSyscallArg(tc, index); 306 uint64_t offset_high = p->getSyscallArg(tc, index); 307 uint32_t offset_low = p->getSyscallArg(tc, index); 308 Addr result_ptr = p->getSyscallArg(tc, index); 309 int whence = p->getSyscallArg(tc, index); 310 311 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 312 if (!ffdp) 313 return -EBADF; 314 int sim_fd = ffdp->getSimFD(); 315 316 uint64_t offset = (offset_high << 32) | offset_low; 317 318 uint64_t result = lseek(sim_fd, offset, whence); 319 result = TheISA::htog(result); 320 321 if (result == (off_t)-1) 322 return -errno; 323 // Assuming that the size of loff_t is 64 bits on the target platform 324 BufferArg result_buf(result_ptr, sizeof(result)); 325 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 326 result_buf.copyOut(tc->getMemProxy()); 327 return 0; 328} 329 330 331SyscallReturn 332munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 333{ 334 // With mmap more fully implemented, it might be worthwhile to bite 335 // the bullet and implement munmap. Should allow us to reuse simulated 336 // memory. 337 return 0; 338} 339 340 341const char *hostname = "m5.eecs.umich.edu"; 342 343SyscallReturn 344gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 345{ 346 int index = 0; 347 Addr buf_ptr = p->getSyscallArg(tc, index); 348 int name_len = p->getSyscallArg(tc, index); 349 BufferArg name(buf_ptr, name_len); 350 351 strncpy((char *)name.bufferPtr(), hostname, name_len); 352 353 name.copyOut(tc->getMemProxy()); 354 355 return 0; 356} 357 358SyscallReturn 359getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 360{ 361 int result = 0; 362 int index = 0; 363 Addr buf_ptr = p->getSyscallArg(tc, index); 364 unsigned long size = p->getSyscallArg(tc, index); 365 BufferArg buf(buf_ptr, size); 366 367 // Is current working directory defined? 368 string cwd = p->getcwd(); 369 if (!cwd.empty()) { 370 if (cwd.length() >= size) { 371 // Buffer too small 372 return -ERANGE; 373 } 374 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 375 result = cwd.length(); 376 } else { 377 if (getcwd((char *)buf.bufferPtr(), size)) { 378 result = strlen((char *)buf.bufferPtr()); 379 } else { 380 result = -1; 381 } 382 } 383 384 buf.copyOut(tc->getMemProxy()); 385 386 return (result == -1) ? -errno : result; 387} 388 389SyscallReturn 390readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 391 ThreadContext *tc) 392{ 393 return readlinkFunc(desc, callnum, process, tc, 0); 394} 395 396SyscallReturn 397readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 398 int index) 399{ 400 string path; 401 402 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 403 return -EFAULT; 404 405 // Adjust path for current working directory 406 path = p->fullPath(path); 407 408 Addr buf_ptr = p->getSyscallArg(tc, index); 409 size_t bufsiz = p->getSyscallArg(tc, index); 410 411 BufferArg buf(buf_ptr, bufsiz); 412 413 int result = -1; 414 if (path != "/proc/self/exe") { 415 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 416 } else { 417 // Emulate readlink() called on '/proc/self/exe' should return the 418 // absolute path of the binary running in the simulated system (the 419 // Process' executable). It is possible that using this path in 420 // the simulated system will result in unexpected behavior if: 421 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 422 // called binary calls readlink(). 423 // 2) The host's full path to the running benchmark changes from one 424 // simulation to another. This can result in different simulated 425 // performance since the simulated system will process the binary 426 // path differently, even if the binary itself does not change. 427 428 // Get the absolute canonical path to the running application 429 char real_path[PATH_MAX]; 430 char *check_real_path = realpath(p->progName(), real_path); 431 if (!check_real_path) { 432 fatal("readlink('/proc/self/exe') unable to resolve path to " 433 "executable: %s", p->progName()); 434 } 435 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 436 size_t real_path_len = strlen(real_path); 437 if (real_path_len > bufsiz) { 438 // readlink will truncate the contents of the 439 // path to ensure it is no more than bufsiz 440 result = bufsiz; 441 } else { 442 result = real_path_len; 443 } 444 445 // Issue a warning about potential unexpected results 446 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 447 "results in various settings.\n Returning '%s'\n", 448 (char*)buf.bufferPtr()); 449 } 450 451 buf.copyOut(tc->getMemProxy()); 452 453 return (result == -1) ? -errno : result; 454} 455 456SyscallReturn 457unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 458{ 459 return unlinkHelper(desc, num, p, tc, 0); 460} 461 462SyscallReturn 463unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 464 int index) 465{ 466 string path; 467 468 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 469 return -EFAULT; 470 471 path = p->fullPath(path); 472 473 int result = unlink(path.c_str()); 474 return (result == -1) ? -errno : result; 475} 476 477SyscallReturn 478linkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 479{ 480 string path; 481 string new_path; 482 483 int index = 0; 484 auto &virt_mem = tc->getMemProxy(); 485 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 486 return -EFAULT; 487 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 488 return -EFAULT; 489 490 path = p->fullPath(path); 491 new_path = p->fullPath(new_path); 492 493 int result = link(path.c_str(), new_path.c_str()); 494 return (result == -1) ? -errno : result; 495} 496 497SyscallReturn 498symlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 499{ 500 string path; 501 string new_path; 502 503 int index = 0; 504 auto &virt_mem = tc->getMemProxy(); 505 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 506 return -EFAULT; 507 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 508 return -EFAULT; 509 510 path = p->fullPath(path); 511 new_path = p->fullPath(new_path); 512 513 int result = symlink(path.c_str(), new_path.c_str()); 514 return (result == -1) ? -errno : result; 515} 516 517SyscallReturn 518mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 519{ 520 string path; 521 522 int index = 0; 523 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 524 return -EFAULT; 525 526 // Adjust path for current working directory 527 path = p->fullPath(path); 528 529 mode_t mode = p->getSyscallArg(tc, index); 530 531 int result = mkdir(path.c_str(), mode); 532 return (result == -1) ? -errno : result; 533} 534 535SyscallReturn 536renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 537{ 538 string old_name; 539 540 int index = 0; 541 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 542 return -EFAULT; 543 544 string new_name; 545 546 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 547 return -EFAULT; 548 549 // Adjust path for current working directory 550 old_name = p->fullPath(old_name); 551 new_name = p->fullPath(new_name); 552 553 int64_t result = rename(old_name.c_str(), new_name.c_str()); 554 return (result == -1) ? -errno : result; 555} 556 557SyscallReturn 558truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 559{ 560 string path; 561 562 int index = 0; 563 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 564 return -EFAULT; 565 566 off_t length = p->getSyscallArg(tc, index); 567 568 // Adjust path for current working directory 569 path = p->fullPath(path); 570 571 int result = truncate(path.c_str(), length); 572 return (result == -1) ? -errno : result; 573} 574 575SyscallReturn 576ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 577{ 578 int index = 0; 579 int tgt_fd = p->getSyscallArg(tc, index); 580 off_t length = p->getSyscallArg(tc, index); 581 582 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 583 if (!ffdp) 584 return -EBADF; 585 int sim_fd = ffdp->getSimFD(); 586 587 int result = ftruncate(sim_fd, length); 588 return (result == -1) ? -errno : result; 589} 590 591SyscallReturn 592truncate64Func(SyscallDesc *desc, int num, 593 Process *process, ThreadContext *tc) 594{ 595 int index = 0; 596 string path; 597 598 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 599 return -EFAULT; 600 601 int64_t length = process->getSyscallArg(tc, index, 64); 602 603 // Adjust path for current working directory 604 path = process->fullPath(path); 605 606#if NO_STAT64 607 int result = truncate(path.c_str(), length); 608#else 609 int result = truncate64(path.c_str(), length); 610#endif 611 return (result == -1) ? -errno : result; 612} 613 614SyscallReturn 615ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 616{ 617 int index = 0; 618 int tgt_fd = p->getSyscallArg(tc, index); 619 int64_t length = p->getSyscallArg(tc, index, 64); 620 621 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 622 if (!ffdp) 623 return -EBADF; 624 int sim_fd = ffdp->getSimFD(); 625 626#if NO_STAT64 627 int result = ftruncate(sim_fd, length); 628#else 629 int result = ftruncate64(sim_fd, length); 630#endif 631 return (result == -1) ? -errno : result; 632} 633 634SyscallReturn 635umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 636{ 637 // Letting the simulated program change the simulator's umask seems like 638 // a bad idea. Compromise by just returning the current umask but not 639 // changing anything. 640 mode_t oldMask = umask(0); 641 umask(oldMask); 642 return (int)oldMask; 643} 644 645SyscallReturn 646chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 647{ 648 string path; 649 650 int index = 0; 651 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 652 return -EFAULT; 653 654 /* XXX endianess */ 655 uint32_t owner = p->getSyscallArg(tc, index); 656 uid_t hostOwner = owner; 657 uint32_t group = p->getSyscallArg(tc, index); 658 gid_t hostGroup = group; 659 660 // Adjust path for current working directory 661 path = p->fullPath(path); 662 663 int result = chown(path.c_str(), hostOwner, hostGroup); 664 return (result == -1) ? -errno : result; 665} 666 667SyscallReturn 668fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 669{ 670 int index = 0; 671 int tgt_fd = p->getSyscallArg(tc, index); 672 673 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 674 if (!ffdp) 675 return -EBADF; 676 int sim_fd = ffdp->getSimFD(); 677 678 /* XXX endianess */ 679 uint32_t owner = p->getSyscallArg(tc, index); 680 uid_t hostOwner = owner; 681 uint32_t group = p->getSyscallArg(tc, index); 682 gid_t hostGroup = group; 683 684 int result = fchown(sim_fd, hostOwner, hostGroup); 685 return (result == -1) ? -errno : result; 686} 687 688/** 689 * FIXME: The file description is not shared among file descriptors created 690 * with dup. Really, it's difficult to maintain fields like file offset or 691 * flags since an update to such a field won't be reflected in the metadata 692 * for the fd entries that we maintain for checkpoint restoration. 693 */ 694SyscallReturn 695dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 696{ 697 int index = 0; 698 int tgt_fd = p->getSyscallArg(tc, index); 699 700 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 701 if (!old_hbfdp) 702 return -EBADF; 703 int sim_fd = old_hbfdp->getSimFD(); 704 705 int result = dup(sim_fd); 706 if (result == -1) 707 return -errno; 708 709 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 710 new_hbfdp->setSimFD(result); 711 new_hbfdp->setCOE(false); 712 return p->fds->allocFD(new_hbfdp); 713} 714 715SyscallReturn 716dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 717{ 718 int index = 0; 719 720 int old_tgt_fd = p->getSyscallArg(tc, index); 721 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 722 if (!old_hbp) 723 return -EBADF; 724 int old_sim_fd = old_hbp->getSimFD(); 725 726 /** 727 * We need a valid host file descriptor number to be able to pass into 728 * the second parameter for dup2 (newfd), but we don't know what the 729 * viable numbers are; we execute the open call to retrieve one. 730 */ 731 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 732 if (res_fd == -1) 733 return -errno; 734 735 int new_tgt_fd = p->getSyscallArg(tc, index); 736 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 737 if (new_hbp) 738 p->fds->closeFDEntry(new_tgt_fd); 739 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 740 new_hbp->setSimFD(res_fd); 741 new_hbp->setCOE(false); 742 743 return p->fds->allocFD(new_hbp); 744} 745 746SyscallReturn 747fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 748{ 749 int arg; 750 int index = 0; 751 int tgt_fd = p->getSyscallArg(tc, index); 752 int cmd = p->getSyscallArg(tc, index); 753 754 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 755 if (!hbfdp) 756 return -EBADF; 757 int sim_fd = hbfdp->getSimFD(); 758 759 int coe = hbfdp->getCOE(); 760 761 switch (cmd) { 762 case F_GETFD: 763 return coe & FD_CLOEXEC; 764 765 case F_SETFD: { 766 arg = p->getSyscallArg(tc, index); 767 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 768 return 0; 769 } 770 771 // Rely on the host to maintain the file status flags for this file 772 // description rather than maintain it ourselves. Admittedly, this 773 // is suboptimal (and possibly error prone), but it is difficult to 774 // maintain the flags by tracking them across the different descriptors 775 // (that refer to this file description) caused by clone, dup, and 776 // subsequent fcntls. 777 case F_GETFL: 778 case F_SETFL: { 779 arg = p->getSyscallArg(tc, index); 780 int rv = fcntl(sim_fd, cmd, arg); 781 return (rv == -1) ? -errno : rv; 782 } 783 784 default: 785 warn("fcntl: unsupported command %d\n", cmd); 786 return 0; 787 } 788} 789 790SyscallReturn 791fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 792{ 793 int index = 0; 794 int tgt_fd = p->getSyscallArg(tc, index); 795 796 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 797 if (!hbfdp) 798 return -EBADF; 799 int sim_fd = hbfdp->getSimFD(); 800 801 int cmd = p->getSyscallArg(tc, index); 802 switch (cmd) { 803 case 33: //F_GETLK64 804 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 805 return -EMFILE; 806 807 case 34: // F_SETLK64 808 case 35: // F_SETLKW64 809 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 810 tgt_fd); 811 return -EMFILE; 812 813 default: 814 // not sure if this is totally valid, but we'll pass it through 815 // to the underlying OS 816 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 817 return fcntl(sim_fd, cmd); 818 } 819} 820 821SyscallReturn 822pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 823 bool pseudoPipe) 824{ 825 Addr tgt_addr = 0; 826 if (!pseudoPipe) { 827 int index = 0; 828 tgt_addr = p->getSyscallArg(tc, index); 829 } 830 831 int sim_fds[2], tgt_fds[2]; 832 833 int pipe_retval = pipe(sim_fds); 834 if (pipe_retval == -1) 835 return -errno; 836 837 auto rend = PipeFDEntry::EndType::read; 838 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 839 tgt_fds[0] = p->fds->allocFD(rpfd); 840 841 auto wend = PipeFDEntry::EndType::write; 842 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 843 tgt_fds[1] = p->fds->allocFD(wpfd); 844 845 /** 846 * Now patch the read object to record the target file descriptor chosen 847 * as the write end of the pipe. 848 */ 849 rpfd->setPipeReadSource(tgt_fds[1]); 850 851 /** 852 * Alpha Linux convention for pipe() is that fd[0] is returned as 853 * the return value of the function, and fd[1] is returned in r20. 854 */ 855 if (pseudoPipe) { 856 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 857 return tgt_fds[0]; 858 } 859 860 /** 861 * Copy the target file descriptors into buffer space and then copy 862 * the buffer space back into the target address space. 863 */ 864 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 865 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 866 buf_ptr[0] = tgt_fds[0]; 867 buf_ptr[1] = tgt_fds[1]; 868 tgt_handle.copyOut(tc->getMemProxy()); 869 return 0; 870} 871 872SyscallReturn 873pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 874 ThreadContext *tc) 875{ 876 return pipeImpl(desc, callnum, process, tc, true); 877} 878 879SyscallReturn 880pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 881{ 882 return pipeImpl(desc, callnum, process, tc, false); 883} 884 885SyscallReturn 886setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 887 ThreadContext *tc) 888{ 889 int index = 0; 890 int pid = process->getSyscallArg(tc, index); 891 int pgid = process->getSyscallArg(tc, index); 892 893 if (pgid < 0) 894 return -EINVAL; 895 896 if (pid == 0) { 897 process->setpgid(process->pid()); 898 return 0; 899 } 900 901 Process *matched_ph = nullptr; 902 System *sysh = tc->getSystemPtr(); 903 904 // Retrieves process pointer from active/suspended thread contexts. 905 for (int i = 0; i < sysh->numContexts(); i++) { 906 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 907 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 908 Process *walk_ph = (Process*)temp_h; 909 910 if (walk_ph && walk_ph->pid() == process->pid()) 911 matched_ph = walk_ph; 912 } 913 } 914 915 assert(matched_ph); 916 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 917 918 return 0; 919} 920 921SyscallReturn 922getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 923 ThreadContext *tc) 924{ 925 // Make up a PID. There's no interprocess communication in 926 // fake_syscall mode, so there's no way for a process to know it's 927 // not getting a unique value. 928 929 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 930 return process->pid(); 931} 932 933 934SyscallReturn 935getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 936 ThreadContext *tc) 937{ 938 // Make up a UID and EUID... it shouldn't matter, and we want the 939 // simulation to be deterministic. 940 941 // EUID goes in r20. 942 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 943 return process->uid(); // UID 944} 945 946 947SyscallReturn 948getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 949 ThreadContext *tc) 950{ 951 // Get current group ID. EGID goes in r20. 952 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 953 return process->gid(); 954} 955 956 957SyscallReturn 958setuidFunc(SyscallDesc *desc, int callnum, Process *process, 959 ThreadContext *tc) 960{ 961 // can't fathom why a benchmark would call this. 962 int index = 0; 963 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 964 return 0; 965} 966 967SyscallReturn 968getpidFunc(SyscallDesc *desc, int callnum, Process *process, 969 ThreadContext *tc) 970{ 971 return process->tgid(); 972} 973 974SyscallReturn 975gettidFunc(SyscallDesc *desc, int callnum, Process *process, 976 ThreadContext *tc) 977{ 978 return process->pid(); 979} 980 981SyscallReturn 982getppidFunc(SyscallDesc *desc, int callnum, Process *process, 983 ThreadContext *tc) 984{ 985 return process->ppid(); 986} 987 988SyscallReturn 989getuidFunc(SyscallDesc *desc, int callnum, Process *process, 990 ThreadContext *tc) 991{ 992 return process->uid(); // UID 993} 994 995SyscallReturn 996geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 997 ThreadContext *tc) 998{ 999 return process->euid(); // UID 1000} 1001 1002SyscallReturn 1003getgidFunc(SyscallDesc *desc, int callnum, Process *process, 1004 ThreadContext *tc) 1005{ 1006 return process->gid(); 1007} 1008 1009SyscallReturn 1010getegidFunc(SyscallDesc *desc, int callnum, Process *process, 1011 ThreadContext *tc) 1012{ 1013 return process->egid(); 1014} 1015 1016SyscallReturn 1017fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1018{ 1019#if NO_FALLOCATE 1020 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 1021#else 1022 int index = 0; 1023 int tgt_fd = p->getSyscallArg(tc, index); 1024 int mode = p->getSyscallArg(tc, index); 1025 off_t offset = p->getSyscallArg(tc, index); 1026 off_t len = p->getSyscallArg(tc, index); 1027 1028 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1029 if (!ffdp) 1030 return -EBADF; 1031 int sim_fd = ffdp->getSimFD(); 1032 1033 int result = fallocate(sim_fd, mode, offset, len); 1034 if (result < 0) 1035 return -errno; 1036#endif 1037 return 0; 1038} 1039 1040SyscallReturn 1041accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 1042 int index) 1043{ 1044 string path; 1045 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1046 return -EFAULT; 1047 1048 // Adjust path for current working directory 1049 path = p->fullPath(path); 1050 1051 mode_t mode = p->getSyscallArg(tc, index); 1052 1053 int result = access(path.c_str(), mode); 1054 return (result == -1) ? -errno : result; 1055} 1056 1057SyscallReturn 1058accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1059{ 1060 return accessFunc(desc, callnum, p, tc, 0); 1061} 1062 1063SyscallReturn 1064mknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1065{ 1066 int index = 0; 1067 std::string path; 1068 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1069 return -EFAULT; 1070 1071 path = p->fullPath(path); 1072 mode_t mode = p->getSyscallArg(tc, index); 1073 dev_t dev = p->getSyscallArg(tc, index); 1074 1075 auto result = mknod(path.c_str(), mode, dev); 1076 return (result == -1) ? -errno : result; 1077} 1078 1079SyscallReturn 1080chdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1081{ 1082 int index = 0; 1083 std::string path; 1084 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1085 return -EFAULT; 1086 1087 path = p->fullPath(path); 1088 1089 auto result = chdir(path.c_str()); 1090 return (result == -1) ? -errno : result; 1091} 1092 1093SyscallReturn 1094rmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1095{ 1096 int index = 0; 1097 std::string path; 1098 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1099 return -EFAULT; 1100 1101 path = p->fullPath(path); 1102 1103 auto result = rmdir(path.c_str()); 1104 return (result == -1) ? -errno : result; 1105} 1106 1107#if defined(SYS_getdents) || defined(SYS_getdents64) 1108template<typename DE, int SYS_NUM> 1109static SyscallReturn 1110getdentsImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1111{ 1112 int index = 0; 1113 int tgt_fd = p->getSyscallArg(tc, index); 1114 Addr buf_ptr = p->getSyscallArg(tc, index); 1115 unsigned count = p->getSyscallArg(tc, index); 1116 1117 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1118 if (!hbfdp) 1119 return -EBADF; 1120 int sim_fd = hbfdp->getSimFD(); 1121 1122 BufferArg buf_arg(buf_ptr, count); 1123 auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count); 1124 1125 if (status == -1) 1126 return -errno; 1127 1128 unsigned traversed = 0; 1129 while (traversed < status) { 1130 DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed); 1131 1132 auto host_reclen = buffer->d_reclen; 1133 1134 /** 1135 * Convert the byte ordering from the host to the target before 1136 * passing the data back into the target's address space to preserve 1137 * endianness. 1138 */ 1139 buffer->d_ino = htog(buffer->d_ino); 1140 buffer->d_off = htog(buffer->d_off); 1141 buffer->d_reclen = htog(buffer->d_reclen); 1142 1143 traversed += host_reclen; 1144 } 1145 1146 buf_arg.copyOut(tc->getMemProxy()); 1147 return status; 1148} 1149#endif 1150 1151#if defined(SYS_getdents) 1152SyscallReturn 1153getdentsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1154{ 1155 typedef struct linux_dirent { 1156 unsigned long d_ino; 1157 unsigned long d_off; 1158 unsigned short d_reclen; 1159 char dname[]; 1160 } LinDent; 1161 1162 return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, p, tc); 1163} 1164#endif 1165 1166#if defined(SYS_getdents64) 1167SyscallReturn 1168getdents64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1169{ 1170 typedef struct linux_dirent64 { 1171 ino64_t d_ino; 1172 off64_t d_off; 1173 unsigned short d_reclen; 1174 char dname[]; 1175 } LinDent64; 1176 1177 return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, p, tc); 1178} 1179#endif 1180 1181SyscallReturn 1182shutdownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1183{ 1184 int index = 0; 1185 int tgt_fd = p->getSyscallArg(tc, index); 1186 int how = p->getSyscallArg(tc, index); 1187 1188 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1189 if (!sfdp) 1190 return -EBADF; 1191 int sim_fd = sfdp->getSimFD(); 1192 1193 int retval = shutdown(sim_fd, how); 1194 1195 return (retval == -1) ? -errno : retval; 1196} 1197 1198SyscallReturn 1199bindFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1200{ 1201 int index = 0; 1202 int tgt_fd = p->getSyscallArg(tc, index); 1203 Addr buf_ptr = p->getSyscallArg(tc, index); 1204 int addrlen = p->getSyscallArg(tc, index); 1205 1206 BufferArg bufSock(buf_ptr, addrlen); 1207 bufSock.copyIn(tc->getMemProxy()); 1208 1209 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1210 if (!sfdp) 1211 return -EBADF; 1212 int sim_fd = sfdp->getSimFD(); 1213 1214 int status = ::bind(sim_fd, 1215 (struct sockaddr *)bufSock.bufferPtr(), 1216 addrlen); 1217 1218 return (status == -1) ? -errno : status; 1219} 1220 1221SyscallReturn 1222listenFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1223{ 1224 int index = 0; 1225 int tgt_fd = p->getSyscallArg(tc, index); 1226 int backlog = p->getSyscallArg(tc, index); 1227 1228 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1229 if (!sfdp) 1230 return -EBADF; 1231 int sim_fd = sfdp->getSimFD(); 1232 1233 int status = listen(sim_fd, backlog); 1234 1235 return (status == -1) ? -errno : status; 1236} 1237 1238SyscallReturn 1239connectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1240{ 1241 int index = 0; 1242 int tgt_fd = p->getSyscallArg(tc, index); 1243 Addr buf_ptr = p->getSyscallArg(tc, index); 1244 int addrlen = p->getSyscallArg(tc, index); 1245 1246 BufferArg addr(buf_ptr, addrlen); 1247 addr.copyIn(tc->getMemProxy()); 1248 1249 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1250 if (!sfdp) 1251 return -EBADF; 1252 int sim_fd = sfdp->getSimFD(); 1253 1254 int status = connect(sim_fd, 1255 (struct sockaddr *)addr.bufferPtr(), 1256 (socklen_t)addrlen); 1257 1258 return (status == -1) ? -errno : status; 1259} 1260 1261SyscallReturn 1262recvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1263{ 1264 int index = 0; 1265 int tgt_fd = p->getSyscallArg(tc, index); 1266 Addr bufrPtr = p->getSyscallArg(tc, index); 1267 size_t bufrLen = p->getSyscallArg(tc, index); 1268 int flags = p->getSyscallArg(tc, index); 1269 Addr addrPtr = p->getSyscallArg(tc, index); 1270 Addr addrlenPtr = p->getSyscallArg(tc, index); 1271 1272 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1273 if (!sfdp) 1274 return -EBADF; 1275 int sim_fd = sfdp->getSimFD(); 1276 1277 // Reserve buffer space. 1278 BufferArg bufrBuf(bufrPtr, bufrLen); 1279 1280 // Get address length. 1281 socklen_t addrLen = 0; 1282 if (addrlenPtr != 0) { 1283 // Read address length parameter. 1284 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1285 addrlenBuf.copyIn(tc->getMemProxy()); 1286 addrLen = *((socklen_t *)addrlenBuf.bufferPtr()); 1287 } 1288 1289 struct sockaddr sa, *sap = NULL; 1290 if (addrLen != 0) { 1291 BufferArg addrBuf(addrPtr, addrLen); 1292 addrBuf.copyIn(tc->getMemProxy()); 1293 memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(), 1294 sizeof(struct sockaddr)); 1295 sap = &sa; 1296 } 1297 1298 ssize_t recvd_size = recvfrom(sim_fd, 1299 (void *)bufrBuf.bufferPtr(), 1300 bufrLen, flags, sap, (socklen_t *)&addrLen); 1301 1302 if (recvd_size == -1) 1303 return -errno; 1304 1305 // Pass the received data out. 1306 bufrBuf.copyOut(tc->getMemProxy()); 1307 1308 // Copy address to addrPtr and pass it on. 1309 if (sap != NULL) { 1310 BufferArg addrBuf(addrPtr, addrLen); 1311 memcpy(addrBuf.bufferPtr(), sap, sizeof(sa)); 1312 addrBuf.copyOut(tc->getMemProxy()); 1313 } 1314 1315 // Copy len to addrlenPtr and pass it on. 1316 if (addrLen != 0) { 1317 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1318 *(socklen_t *)addrlenBuf.bufferPtr() = addrLen; 1319 addrlenBuf.copyOut(tc->getMemProxy()); 1320 } 1321 1322 return recvd_size; 1323} 1324 1325SyscallReturn 1326sendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1327{ 1328 int index = 0; 1329 int tgt_fd = p->getSyscallArg(tc, index); 1330 Addr bufrPtr = p->getSyscallArg(tc, index); 1331 size_t bufrLen = p->getSyscallArg(tc, index); 1332 int flags = p->getSyscallArg(tc, index); 1333 Addr addrPtr = p->getSyscallArg(tc, index); 1334 socklen_t addrLen = p->getSyscallArg(tc, index); 1335 1336 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1337 if (!sfdp) 1338 return -EBADF; 1339 int sim_fd = sfdp->getSimFD(); 1340 1341 // Reserve buffer space. 1342 BufferArg bufrBuf(bufrPtr, bufrLen); 1343 bufrBuf.copyIn(tc->getMemProxy()); 1344 1345 struct sockaddr sa, *sap = nullptr; 1346 memset(&sa, 0, sizeof(sockaddr)); 1347 if (addrLen != 0) { 1348 BufferArg addrBuf(addrPtr, addrLen); 1349 addrBuf.copyIn(tc->getMemProxy()); 1350 memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen); 1351 sap = &sa; 1352 } 1353 1354 ssize_t sent_size = sendto(sim_fd, 1355 (void *)bufrBuf.bufferPtr(), 1356 bufrLen, flags, sap, (socklen_t)addrLen); 1357 1358 return (sent_size == -1) ? -errno : sent_size; 1359} 1360 1361SyscallReturn 1362recvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1363{ 1364 int index = 0; 1365 int tgt_fd = p->getSyscallArg(tc, index); 1366 Addr msgPtr = p->getSyscallArg(tc, index); 1367 int flags = p->getSyscallArg(tc, index); 1368 1369 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1370 if (!sfdp) 1371 return -EBADF; 1372 int sim_fd = sfdp->getSimFD(); 1373 1374 /** 1375 * struct msghdr { 1376 * void *msg_name; // optional address 1377 * socklen_t msg_namelen; // size of address 1378 * struct iovec *msg_iov; // iovec array 1379 * size_t msg_iovlen; // number entries in msg_iov 1380 * i // entries correspond to buffer 1381 * void *msg_control; // ancillary data 1382 * size_t msg_controllen; // ancillary data buffer len 1383 * int msg_flags; // flags on received message 1384 * }; 1385 * 1386 * struct iovec { 1387 * void *iov_base; // starting address 1388 * size_t iov_len; // number of bytes to transfer 1389 * }; 1390 */ 1391 1392 /** 1393 * The plan with this system call is to replace all of the pointers in the 1394 * structure and the substructure with BufferArg class pointers. We will 1395 * copy every field from the structures into our BufferArg classes. 1396 */ 1397 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1398 msgBuf.copyIn(tc->getMemProxy()); 1399 struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr(); 1400 1401 /** 1402 * We will use these address place holders to retain the pointers which 1403 * we are going to replace with our own buffers in our simulator address 1404 * space. 1405 */ 1406 Addr msg_name_phold = 0; 1407 Addr msg_iov_phold = 0; 1408 Addr iovec_base_phold[msgHdr->msg_iovlen]; 1409 Addr msg_control_phold = 0; 1410 1411 /** 1412 * Record msg_name pointer then replace with buffer pointer. 1413 */ 1414 BufferArg *nameBuf = NULL; 1415 if (msgHdr->msg_name) { 1416 /*1*/msg_name_phold = (Addr)msgHdr->msg_name; 1417 /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen); 1418 /*3*/nameBuf->copyIn(tc->getMemProxy()); 1419 /*4*/msgHdr->msg_name = nameBuf->bufferPtr(); 1420 } 1421 1422 /** 1423 * Record msg_iov pointer then replace with buffer pointer. Also, setup 1424 * an array of buffer pointers for the iovec structs record and replace 1425 * their pointers with buffer pointers. 1426 */ 1427 BufferArg *iovBuf = NULL; 1428 BufferArg *iovecBuf[msgHdr->msg_iovlen]; 1429 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1430 iovec_base_phold[i] = 0; 1431 iovecBuf[i] = NULL; 1432 } 1433 1434 if (msgHdr->msg_iov) { 1435 /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov; 1436 /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen * 1437 sizeof(struct iovec)); 1438 /*3*/iovBuf->copyIn(tc->getMemProxy()); 1439 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1440 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1441 /*1*/iovec_base_phold[i] = 1442 (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base; 1443 /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i], 1444 ((struct iovec *)iovBuf->bufferPtr())[i].iov_len); 1445 /*3*/iovecBuf[i]->copyIn(tc->getMemProxy()); 1446 /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1447 iovecBuf[i]->bufferPtr(); 1448 } 1449 } 1450 /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr(); 1451 } 1452 1453 /** 1454 * Record msg_control pointer then replace with buffer pointer. 1455 */ 1456 BufferArg *controlBuf = NULL; 1457 if (msgHdr->msg_control) { 1458 /*1*/msg_control_phold = (Addr)msgHdr->msg_control; 1459 /*2*/controlBuf = new BufferArg(msg_control_phold, 1460 CMSG_ALIGN(msgHdr->msg_controllen)); 1461 /*3*/controlBuf->copyIn(tc->getMemProxy()); 1462 /*4*/msgHdr->msg_control = controlBuf->bufferPtr(); 1463 } 1464 1465 ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags); 1466 1467 if (recvd_size < 0) 1468 return -errno; 1469 1470 if (msgHdr->msg_name) { 1471 nameBuf->copyOut(tc->getMemProxy()); 1472 delete(nameBuf); 1473 msgHdr->msg_name = (void *)msg_name_phold; 1474 } 1475 1476 if (msgHdr->msg_iov) { 1477 for (int i = 0; i< msgHdr->msg_iovlen; i++) { 1478 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1479 iovecBuf[i]->copyOut(tc->getMemProxy()); 1480 delete iovecBuf[i]; 1481 ((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1482 (void *)iovec_base_phold[i]; 1483 } 1484 } 1485 iovBuf->copyOut(tc->getMemProxy()); 1486 delete iovBuf; 1487 msgHdr->msg_iov = (struct iovec *)msg_iov_phold; 1488 } 1489 1490 if (msgHdr->msg_control) { 1491 controlBuf->copyOut(tc->getMemProxy()); 1492 delete(controlBuf); 1493 msgHdr->msg_control = (void *)msg_control_phold; 1494 } 1495 1496 msgBuf.copyOut(tc->getMemProxy()); 1497 1498 return recvd_size; 1499} 1500 1501SyscallReturn 1502sendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1503{ 1504 int index = 0; 1505 int tgt_fd = p->getSyscallArg(tc, index); 1506 Addr msgPtr = p->getSyscallArg(tc, index); 1507 int flags = p->getSyscallArg(tc, index); 1508 1509 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1510 if (!sfdp) 1511 return -EBADF; 1512 int sim_fd = sfdp->getSimFD(); 1513 1514 /** 1515 * Reserve buffer space. 1516 */ 1517 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1518 msgBuf.copyIn(tc->getMemProxy()); 1519 struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr()); 1520 1521 /** 1522 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling 1523 * recvmsg without a buffer. 1524 */ 1525 struct iovec *iovPtr = msgHdr.msg_iov; 1526 BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen); 1527 iovBuf.copyIn(tc->getMemProxy()); 1528 struct iovec *iov = (struct iovec *)iovBuf.bufferPtr(); 1529 msgHdr.msg_iov = iov; 1530 1531 /** 1532 * Cannot instantiate buffers till inside the loop. 1533 * Create array to hold buffer addresses, to be used during copyIn of 1534 * send data. 1535 */ 1536 BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen 1537 * sizeof(BufferArg *)); 1538 1539 /** 1540 * Iterate through the iovec structures: 1541 * Get the base buffer addreses, reserve iov_len amount of space for each. 1542 * Put the buf address into the bufferArray for later retrieval. 1543 */ 1544 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1545 Addr basePtr = (Addr) iov[iovIndex].iov_base; 1546 bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len); 1547 bufferArray[iovIndex]->copyIn(tc->getMemProxy()); 1548 iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr(); 1549 } 1550 1551 ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags); 1552 int local_errno = errno; 1553 1554 /** 1555 * Free dynamically allocated memory. 1556 */ 1557 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1558 BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex]; 1559 delete(baseBuf); 1560 } 1561 1562 /** 1563 * Malloced above. 1564 */ 1565 free(bufferArray); 1566 1567 return (sent_size < 0) ? -local_errno : sent_size; 1568} 1569 1570SyscallReturn 1571getsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1572{ 1573 // union of all possible return value types from getsockopt 1574 union val { 1575 int i_val; 1576 long l_val; 1577 struct linger linger_val; 1578 struct timeval timeval_val; 1579 } val; 1580 1581 int index = 0; 1582 int tgt_fd = p->getSyscallArg(tc, index); 1583 int level = p->getSyscallArg(tc, index); 1584 int optname = p->getSyscallArg(tc, index); 1585 Addr valPtr = p->getSyscallArg(tc, index); 1586 Addr lenPtr = p->getSyscallArg(tc, index); 1587 1588 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1589 if (!sfdp) 1590 return -EBADF; 1591 int sim_fd = sfdp->getSimFD(); 1592 1593 socklen_t len = sizeof(val); 1594 int status = getsockopt(sim_fd, level, optname, &val, &len); 1595 1596 if (status == -1) 1597 return -errno; 1598 1599 // copy val to valPtr and pass it on 1600 BufferArg valBuf(valPtr, sizeof(val)); 1601 memcpy(valBuf.bufferPtr(), &val, sizeof(val)); 1602 valBuf.copyOut(tc->getMemProxy()); 1603 1604 // copy len to lenPtr and pass it on 1605 BufferArg lenBuf(lenPtr, sizeof(len)); 1606 memcpy(lenBuf.bufferPtr(), &len, sizeof(len)); 1607 lenBuf.copyOut(tc->getMemProxy()); 1608 1609 return status; 1610} 1611 1612SyscallReturn 1613getsocknameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1614{ 1615 int index = 0; 1616 int tgt_fd = p->getSyscallArg(tc, index); 1617 Addr addrPtr = p->getSyscallArg(tc, index); 1618 Addr lenPtr = p->getSyscallArg(tc, index); 1619 1620 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1621 if (!sfdp) 1622 return -EBADF; 1623 int sim_fd = sfdp->getSimFD(); 1624 1625 // lenPtr is an in-out paramenter: 1626 // sending the address length in, conveying the final length out 1627 1628 // Read in the value of len from the passed pointer. 1629 BufferArg lenBuf(lenPtr, sizeof(socklen_t)); 1630 lenBuf.copyIn(tc->getMemProxy()); 1631 socklen_t len = *(socklen_t *)lenBuf.bufferPtr(); 1632 1633 struct sockaddr sa; 1634 int status = getsockname(sim_fd, &sa, &len); 1635 1636 if (status == -1) 1637 return -errno; 1638 1639 // Copy address to addrPtr and pass it on. 1640 BufferArg addrBuf(addrPtr, sizeof(sa)); 1641 memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa)); 1642 addrBuf.copyOut(tc->getMemProxy()); 1643 1644 // Copy len to lenPtr and pass it on. 1645 *(socklen_t *)lenBuf.bufferPtr() = len; 1646 lenBuf.copyOut(tc->getMemProxy()); 1647 1648 return status; 1649} 1650 1651SyscallReturn 1652getpeernameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1653{ 1654 int index = 0; 1655 int tgt_fd = p->getSyscallArg(tc, index); 1656 Addr sockAddrPtr = p->getSyscallArg(tc, index); 1657 Addr addrlenPtr = p->getSyscallArg(tc, index); 1658 1659 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1660 if (!sfdp) 1661 return -EBADF; 1662 int sim_fd = sfdp->getSimFD(); 1663 1664 BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned)); 1665 bufAddrlen.copyIn(tc->getMemProxy()); 1666 BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr()); 1667 1668 int retval = getpeername(sim_fd, 1669 (struct sockaddr *)bufSock.bufferPtr(), 1670 (unsigned *)bufAddrlen.bufferPtr()); 1671 1672 if (retval != -1) { 1673 bufSock.copyOut(tc->getMemProxy()); 1674 bufAddrlen.copyOut(tc->getMemProxy()); 1675 } 1676 1677 return (retval == -1) ? -errno : retval; 1678} 1679 1680SyscallReturn 1681setsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1682{ 1683 int index = 0; 1684 int tgt_fd = p->getSyscallArg(tc, index); 1685 int level = p->getSyscallArg(tc, index); 1686 int optname = p->getSyscallArg(tc, index); 1687 Addr valPtr = p->getSyscallArg(tc, index); 1688 socklen_t len = p->getSyscallArg(tc, index); 1689 1690 BufferArg valBuf(valPtr, len); 1691 valBuf.copyIn(tc->getMemProxy()); 1692 1693 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1694 if (!sfdp) 1695 return -EBADF; 1696 int sim_fd = sfdp->getSimFD(); 1697 1698 int status = setsockopt(sim_fd, level, optname, 1699 (struct sockaddr *)valBuf.bufferPtr(), len); 1700 1701 return (status == -1) ? -errno : status; 1702} 1703
| 215 return status; 216} 217 218SyscallReturn 219exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 220{ 221 return exitImpl(desc, callnum, p, tc, false); 222} 223 224SyscallReturn 225exitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 226{ 227 return exitImpl(desc, callnum, p, tc, true); 228} 229 230SyscallReturn 231getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 232{ 233 return (int)PageBytes; 234} 235 236 237SyscallReturn 238brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 239{ 240 // change brk addr to first arg 241 int index = 0; 242 Addr new_brk = p->getSyscallArg(tc, index); 243 244 std::shared_ptr<MemState> mem_state = p->memState; 245 Addr brk_point = mem_state->getBrkPoint(); 246 247 // in Linux at least, brk(0) returns the current break value 248 // (note that the syscall and the glibc function have different behavior) 249 if (new_brk == 0) 250 return brk_point; 251 252 if (new_brk > brk_point) { 253 // might need to allocate some new pages 254 for (ChunkGenerator gen(brk_point, 255 new_brk - brk_point, 256 PageBytes); !gen.done(); gen.next()) { 257 if (!p->pTable->translate(gen.addr())) 258 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 259 260 // if the address is already there, zero it out 261 else { 262 uint8_t zero = 0; 263 SETranslatingPortProxy &tp = tc->getMemProxy(); 264 265 // split non-page aligned accesses 266 Addr next_page = roundUp(gen.addr(), PageBytes); 267 uint32_t size_needed = next_page - gen.addr(); 268 tp.memsetBlob(gen.addr(), zero, size_needed); 269 if (gen.addr() + PageBytes > next_page && 270 next_page < new_brk && 271 p->pTable->translate(next_page)) { 272 size_needed = PageBytes - size_needed; 273 tp.memsetBlob(next_page, zero, size_needed); 274 } 275 } 276 } 277 } 278 279 mem_state->setBrkPoint(new_brk); 280 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 281 mem_state->getBrkPoint()); 282 return mem_state->getBrkPoint(); 283} 284 285SyscallReturn 286setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process, 287 ThreadContext *tc) 288{ 289 int index = 0; 290 uint64_t tidPtr = process->getSyscallArg(tc, index); 291 292 process->childClearTID = tidPtr; 293 return process->pid(); 294} 295 296SyscallReturn 297closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 298{ 299 int index = 0; 300 int tgt_fd = p->getSyscallArg(tc, index); 301 302 return p->fds->closeFDEntry(tgt_fd); 303} 304 305SyscallReturn 306lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 307{ 308 int index = 0; 309 int tgt_fd = p->getSyscallArg(tc, index); 310 uint64_t offs = p->getSyscallArg(tc, index); 311 int whence = p->getSyscallArg(tc, index); 312 313 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 314 if (!ffdp) 315 return -EBADF; 316 int sim_fd = ffdp->getSimFD(); 317 318 off_t result = lseek(sim_fd, offs, whence); 319 320 return (result == (off_t)-1) ? -errno : result; 321} 322 323 324SyscallReturn 325_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 326{ 327 int index = 0; 328 int tgt_fd = p->getSyscallArg(tc, index); 329 uint64_t offset_high = p->getSyscallArg(tc, index); 330 uint32_t offset_low = p->getSyscallArg(tc, index); 331 Addr result_ptr = p->getSyscallArg(tc, index); 332 int whence = p->getSyscallArg(tc, index); 333 334 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 335 if (!ffdp) 336 return -EBADF; 337 int sim_fd = ffdp->getSimFD(); 338 339 uint64_t offset = (offset_high << 32) | offset_low; 340 341 uint64_t result = lseek(sim_fd, offset, whence); 342 result = TheISA::htog(result); 343 344 if (result == (off_t)-1) 345 return -errno; 346 // Assuming that the size of loff_t is 64 bits on the target platform 347 BufferArg result_buf(result_ptr, sizeof(result)); 348 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 349 result_buf.copyOut(tc->getMemProxy()); 350 return 0; 351} 352 353 354SyscallReturn 355munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 356{ 357 // With mmap more fully implemented, it might be worthwhile to bite 358 // the bullet and implement munmap. Should allow us to reuse simulated 359 // memory. 360 return 0; 361} 362 363 364const char *hostname = "m5.eecs.umich.edu"; 365 366SyscallReturn 367gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 368{ 369 int index = 0; 370 Addr buf_ptr = p->getSyscallArg(tc, index); 371 int name_len = p->getSyscallArg(tc, index); 372 BufferArg name(buf_ptr, name_len); 373 374 strncpy((char *)name.bufferPtr(), hostname, name_len); 375 376 name.copyOut(tc->getMemProxy()); 377 378 return 0; 379} 380 381SyscallReturn 382getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 383{ 384 int result = 0; 385 int index = 0; 386 Addr buf_ptr = p->getSyscallArg(tc, index); 387 unsigned long size = p->getSyscallArg(tc, index); 388 BufferArg buf(buf_ptr, size); 389 390 // Is current working directory defined? 391 string cwd = p->getcwd(); 392 if (!cwd.empty()) { 393 if (cwd.length() >= size) { 394 // Buffer too small 395 return -ERANGE; 396 } 397 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 398 result = cwd.length(); 399 } else { 400 if (getcwd((char *)buf.bufferPtr(), size)) { 401 result = strlen((char *)buf.bufferPtr()); 402 } else { 403 result = -1; 404 } 405 } 406 407 buf.copyOut(tc->getMemProxy()); 408 409 return (result == -1) ? -errno : result; 410} 411 412SyscallReturn 413readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 414 ThreadContext *tc) 415{ 416 return readlinkFunc(desc, callnum, process, tc, 0); 417} 418 419SyscallReturn 420readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 421 int index) 422{ 423 string path; 424 425 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 426 return -EFAULT; 427 428 // Adjust path for current working directory 429 path = p->fullPath(path); 430 431 Addr buf_ptr = p->getSyscallArg(tc, index); 432 size_t bufsiz = p->getSyscallArg(tc, index); 433 434 BufferArg buf(buf_ptr, bufsiz); 435 436 int result = -1; 437 if (path != "/proc/self/exe") { 438 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 439 } else { 440 // Emulate readlink() called on '/proc/self/exe' should return the 441 // absolute path of the binary running in the simulated system (the 442 // Process' executable). It is possible that using this path in 443 // the simulated system will result in unexpected behavior if: 444 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 445 // called binary calls readlink(). 446 // 2) The host's full path to the running benchmark changes from one 447 // simulation to another. This can result in different simulated 448 // performance since the simulated system will process the binary 449 // path differently, even if the binary itself does not change. 450 451 // Get the absolute canonical path to the running application 452 char real_path[PATH_MAX]; 453 char *check_real_path = realpath(p->progName(), real_path); 454 if (!check_real_path) { 455 fatal("readlink('/proc/self/exe') unable to resolve path to " 456 "executable: %s", p->progName()); 457 } 458 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 459 size_t real_path_len = strlen(real_path); 460 if (real_path_len > bufsiz) { 461 // readlink will truncate the contents of the 462 // path to ensure it is no more than bufsiz 463 result = bufsiz; 464 } else { 465 result = real_path_len; 466 } 467 468 // Issue a warning about potential unexpected results 469 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 470 "results in various settings.\n Returning '%s'\n", 471 (char*)buf.bufferPtr()); 472 } 473 474 buf.copyOut(tc->getMemProxy()); 475 476 return (result == -1) ? -errno : result; 477} 478 479SyscallReturn 480unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 481{ 482 return unlinkHelper(desc, num, p, tc, 0); 483} 484 485SyscallReturn 486unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 487 int index) 488{ 489 string path; 490 491 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 492 return -EFAULT; 493 494 path = p->fullPath(path); 495 496 int result = unlink(path.c_str()); 497 return (result == -1) ? -errno : result; 498} 499 500SyscallReturn 501linkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 502{ 503 string path; 504 string new_path; 505 506 int index = 0; 507 auto &virt_mem = tc->getMemProxy(); 508 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 509 return -EFAULT; 510 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 511 return -EFAULT; 512 513 path = p->fullPath(path); 514 new_path = p->fullPath(new_path); 515 516 int result = link(path.c_str(), new_path.c_str()); 517 return (result == -1) ? -errno : result; 518} 519 520SyscallReturn 521symlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 522{ 523 string path; 524 string new_path; 525 526 int index = 0; 527 auto &virt_mem = tc->getMemProxy(); 528 if (!virt_mem.tryReadString(path, p->getSyscallArg(tc, index))) 529 return -EFAULT; 530 if (!virt_mem.tryReadString(new_path, p->getSyscallArg(tc, index))) 531 return -EFAULT; 532 533 path = p->fullPath(path); 534 new_path = p->fullPath(new_path); 535 536 int result = symlink(path.c_str(), new_path.c_str()); 537 return (result == -1) ? -errno : result; 538} 539 540SyscallReturn 541mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 542{ 543 string path; 544 545 int index = 0; 546 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 547 return -EFAULT; 548 549 // Adjust path for current working directory 550 path = p->fullPath(path); 551 552 mode_t mode = p->getSyscallArg(tc, index); 553 554 int result = mkdir(path.c_str(), mode); 555 return (result == -1) ? -errno : result; 556} 557 558SyscallReturn 559renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 560{ 561 string old_name; 562 563 int index = 0; 564 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 565 return -EFAULT; 566 567 string new_name; 568 569 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 570 return -EFAULT; 571 572 // Adjust path for current working directory 573 old_name = p->fullPath(old_name); 574 new_name = p->fullPath(new_name); 575 576 int64_t result = rename(old_name.c_str(), new_name.c_str()); 577 return (result == -1) ? -errno : result; 578} 579 580SyscallReturn 581truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 582{ 583 string path; 584 585 int index = 0; 586 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 587 return -EFAULT; 588 589 off_t length = p->getSyscallArg(tc, index); 590 591 // Adjust path for current working directory 592 path = p->fullPath(path); 593 594 int result = truncate(path.c_str(), length); 595 return (result == -1) ? -errno : result; 596} 597 598SyscallReturn 599ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 600{ 601 int index = 0; 602 int tgt_fd = p->getSyscallArg(tc, index); 603 off_t length = p->getSyscallArg(tc, index); 604 605 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 606 if (!ffdp) 607 return -EBADF; 608 int sim_fd = ffdp->getSimFD(); 609 610 int result = ftruncate(sim_fd, length); 611 return (result == -1) ? -errno : result; 612} 613 614SyscallReturn 615truncate64Func(SyscallDesc *desc, int num, 616 Process *process, ThreadContext *tc) 617{ 618 int index = 0; 619 string path; 620 621 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 622 return -EFAULT; 623 624 int64_t length = process->getSyscallArg(tc, index, 64); 625 626 // Adjust path for current working directory 627 path = process->fullPath(path); 628 629#if NO_STAT64 630 int result = truncate(path.c_str(), length); 631#else 632 int result = truncate64(path.c_str(), length); 633#endif 634 return (result == -1) ? -errno : result; 635} 636 637SyscallReturn 638ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 639{ 640 int index = 0; 641 int tgt_fd = p->getSyscallArg(tc, index); 642 int64_t length = p->getSyscallArg(tc, index, 64); 643 644 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 645 if (!ffdp) 646 return -EBADF; 647 int sim_fd = ffdp->getSimFD(); 648 649#if NO_STAT64 650 int result = ftruncate(sim_fd, length); 651#else 652 int result = ftruncate64(sim_fd, length); 653#endif 654 return (result == -1) ? -errno : result; 655} 656 657SyscallReturn 658umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 659{ 660 // Letting the simulated program change the simulator's umask seems like 661 // a bad idea. Compromise by just returning the current umask but not 662 // changing anything. 663 mode_t oldMask = umask(0); 664 umask(oldMask); 665 return (int)oldMask; 666} 667 668SyscallReturn 669chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 670{ 671 string path; 672 673 int index = 0; 674 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 675 return -EFAULT; 676 677 /* XXX endianess */ 678 uint32_t owner = p->getSyscallArg(tc, index); 679 uid_t hostOwner = owner; 680 uint32_t group = p->getSyscallArg(tc, index); 681 gid_t hostGroup = group; 682 683 // Adjust path for current working directory 684 path = p->fullPath(path); 685 686 int result = chown(path.c_str(), hostOwner, hostGroup); 687 return (result == -1) ? -errno : result; 688} 689 690SyscallReturn 691fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 692{ 693 int index = 0; 694 int tgt_fd = p->getSyscallArg(tc, index); 695 696 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 697 if (!ffdp) 698 return -EBADF; 699 int sim_fd = ffdp->getSimFD(); 700 701 /* XXX endianess */ 702 uint32_t owner = p->getSyscallArg(tc, index); 703 uid_t hostOwner = owner; 704 uint32_t group = p->getSyscallArg(tc, index); 705 gid_t hostGroup = group; 706 707 int result = fchown(sim_fd, hostOwner, hostGroup); 708 return (result == -1) ? -errno : result; 709} 710 711/** 712 * FIXME: The file description is not shared among file descriptors created 713 * with dup. Really, it's difficult to maintain fields like file offset or 714 * flags since an update to such a field won't be reflected in the metadata 715 * for the fd entries that we maintain for checkpoint restoration. 716 */ 717SyscallReturn 718dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 719{ 720 int index = 0; 721 int tgt_fd = p->getSyscallArg(tc, index); 722 723 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 724 if (!old_hbfdp) 725 return -EBADF; 726 int sim_fd = old_hbfdp->getSimFD(); 727 728 int result = dup(sim_fd); 729 if (result == -1) 730 return -errno; 731 732 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 733 new_hbfdp->setSimFD(result); 734 new_hbfdp->setCOE(false); 735 return p->fds->allocFD(new_hbfdp); 736} 737 738SyscallReturn 739dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 740{ 741 int index = 0; 742 743 int old_tgt_fd = p->getSyscallArg(tc, index); 744 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 745 if (!old_hbp) 746 return -EBADF; 747 int old_sim_fd = old_hbp->getSimFD(); 748 749 /** 750 * We need a valid host file descriptor number to be able to pass into 751 * the second parameter for dup2 (newfd), but we don't know what the 752 * viable numbers are; we execute the open call to retrieve one. 753 */ 754 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 755 if (res_fd == -1) 756 return -errno; 757 758 int new_tgt_fd = p->getSyscallArg(tc, index); 759 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 760 if (new_hbp) 761 p->fds->closeFDEntry(new_tgt_fd); 762 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 763 new_hbp->setSimFD(res_fd); 764 new_hbp->setCOE(false); 765 766 return p->fds->allocFD(new_hbp); 767} 768 769SyscallReturn 770fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 771{ 772 int arg; 773 int index = 0; 774 int tgt_fd = p->getSyscallArg(tc, index); 775 int cmd = p->getSyscallArg(tc, index); 776 777 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 778 if (!hbfdp) 779 return -EBADF; 780 int sim_fd = hbfdp->getSimFD(); 781 782 int coe = hbfdp->getCOE(); 783 784 switch (cmd) { 785 case F_GETFD: 786 return coe & FD_CLOEXEC; 787 788 case F_SETFD: { 789 arg = p->getSyscallArg(tc, index); 790 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 791 return 0; 792 } 793 794 // Rely on the host to maintain the file status flags for this file 795 // description rather than maintain it ourselves. Admittedly, this 796 // is suboptimal (and possibly error prone), but it is difficult to 797 // maintain the flags by tracking them across the different descriptors 798 // (that refer to this file description) caused by clone, dup, and 799 // subsequent fcntls. 800 case F_GETFL: 801 case F_SETFL: { 802 arg = p->getSyscallArg(tc, index); 803 int rv = fcntl(sim_fd, cmd, arg); 804 return (rv == -1) ? -errno : rv; 805 } 806 807 default: 808 warn("fcntl: unsupported command %d\n", cmd); 809 return 0; 810 } 811} 812 813SyscallReturn 814fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 815{ 816 int index = 0; 817 int tgt_fd = p->getSyscallArg(tc, index); 818 819 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 820 if (!hbfdp) 821 return -EBADF; 822 int sim_fd = hbfdp->getSimFD(); 823 824 int cmd = p->getSyscallArg(tc, index); 825 switch (cmd) { 826 case 33: //F_GETLK64 827 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 828 return -EMFILE; 829 830 case 34: // F_SETLK64 831 case 35: // F_SETLKW64 832 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 833 tgt_fd); 834 return -EMFILE; 835 836 default: 837 // not sure if this is totally valid, but we'll pass it through 838 // to the underlying OS 839 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 840 return fcntl(sim_fd, cmd); 841 } 842} 843 844SyscallReturn 845pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 846 bool pseudoPipe) 847{ 848 Addr tgt_addr = 0; 849 if (!pseudoPipe) { 850 int index = 0; 851 tgt_addr = p->getSyscallArg(tc, index); 852 } 853 854 int sim_fds[2], tgt_fds[2]; 855 856 int pipe_retval = pipe(sim_fds); 857 if (pipe_retval == -1) 858 return -errno; 859 860 auto rend = PipeFDEntry::EndType::read; 861 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 862 tgt_fds[0] = p->fds->allocFD(rpfd); 863 864 auto wend = PipeFDEntry::EndType::write; 865 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 866 tgt_fds[1] = p->fds->allocFD(wpfd); 867 868 /** 869 * Now patch the read object to record the target file descriptor chosen 870 * as the write end of the pipe. 871 */ 872 rpfd->setPipeReadSource(tgt_fds[1]); 873 874 /** 875 * Alpha Linux convention for pipe() is that fd[0] is returned as 876 * the return value of the function, and fd[1] is returned in r20. 877 */ 878 if (pseudoPipe) { 879 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 880 return tgt_fds[0]; 881 } 882 883 /** 884 * Copy the target file descriptors into buffer space and then copy 885 * the buffer space back into the target address space. 886 */ 887 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 888 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 889 buf_ptr[0] = tgt_fds[0]; 890 buf_ptr[1] = tgt_fds[1]; 891 tgt_handle.copyOut(tc->getMemProxy()); 892 return 0; 893} 894 895SyscallReturn 896pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 897 ThreadContext *tc) 898{ 899 return pipeImpl(desc, callnum, process, tc, true); 900} 901 902SyscallReturn 903pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 904{ 905 return pipeImpl(desc, callnum, process, tc, false); 906} 907 908SyscallReturn 909setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 910 ThreadContext *tc) 911{ 912 int index = 0; 913 int pid = process->getSyscallArg(tc, index); 914 int pgid = process->getSyscallArg(tc, index); 915 916 if (pgid < 0) 917 return -EINVAL; 918 919 if (pid == 0) { 920 process->setpgid(process->pid()); 921 return 0; 922 } 923 924 Process *matched_ph = nullptr; 925 System *sysh = tc->getSystemPtr(); 926 927 // Retrieves process pointer from active/suspended thread contexts. 928 for (int i = 0; i < sysh->numContexts(); i++) { 929 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 930 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 931 Process *walk_ph = (Process*)temp_h; 932 933 if (walk_ph && walk_ph->pid() == process->pid()) 934 matched_ph = walk_ph; 935 } 936 } 937 938 assert(matched_ph); 939 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 940 941 return 0; 942} 943 944SyscallReturn 945getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 946 ThreadContext *tc) 947{ 948 // Make up a PID. There's no interprocess communication in 949 // fake_syscall mode, so there's no way for a process to know it's 950 // not getting a unique value. 951 952 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 953 return process->pid(); 954} 955 956 957SyscallReturn 958getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 959 ThreadContext *tc) 960{ 961 // Make up a UID and EUID... it shouldn't matter, and we want the 962 // simulation to be deterministic. 963 964 // EUID goes in r20. 965 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 966 return process->uid(); // UID 967} 968 969 970SyscallReturn 971getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 972 ThreadContext *tc) 973{ 974 // Get current group ID. EGID goes in r20. 975 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 976 return process->gid(); 977} 978 979 980SyscallReturn 981setuidFunc(SyscallDesc *desc, int callnum, Process *process, 982 ThreadContext *tc) 983{ 984 // can't fathom why a benchmark would call this. 985 int index = 0; 986 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 987 return 0; 988} 989 990SyscallReturn 991getpidFunc(SyscallDesc *desc, int callnum, Process *process, 992 ThreadContext *tc) 993{ 994 return process->tgid(); 995} 996 997SyscallReturn 998gettidFunc(SyscallDesc *desc, int callnum, Process *process, 999 ThreadContext *tc) 1000{ 1001 return process->pid(); 1002} 1003 1004SyscallReturn 1005getppidFunc(SyscallDesc *desc, int callnum, Process *process, 1006 ThreadContext *tc) 1007{ 1008 return process->ppid(); 1009} 1010 1011SyscallReturn 1012getuidFunc(SyscallDesc *desc, int callnum, Process *process, 1013 ThreadContext *tc) 1014{ 1015 return process->uid(); // UID 1016} 1017 1018SyscallReturn 1019geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 1020 ThreadContext *tc) 1021{ 1022 return process->euid(); // UID 1023} 1024 1025SyscallReturn 1026getgidFunc(SyscallDesc *desc, int callnum, Process *process, 1027 ThreadContext *tc) 1028{ 1029 return process->gid(); 1030} 1031 1032SyscallReturn 1033getegidFunc(SyscallDesc *desc, int callnum, Process *process, 1034 ThreadContext *tc) 1035{ 1036 return process->egid(); 1037} 1038 1039SyscallReturn 1040fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1041{ 1042#if NO_FALLOCATE 1043 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 1044#else 1045 int index = 0; 1046 int tgt_fd = p->getSyscallArg(tc, index); 1047 int mode = p->getSyscallArg(tc, index); 1048 off_t offset = p->getSyscallArg(tc, index); 1049 off_t len = p->getSyscallArg(tc, index); 1050 1051 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1052 if (!ffdp) 1053 return -EBADF; 1054 int sim_fd = ffdp->getSimFD(); 1055 1056 int result = fallocate(sim_fd, mode, offset, len); 1057 if (result < 0) 1058 return -errno; 1059#endif 1060 return 0; 1061} 1062 1063SyscallReturn 1064accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 1065 int index) 1066{ 1067 string path; 1068 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1069 return -EFAULT; 1070 1071 // Adjust path for current working directory 1072 path = p->fullPath(path); 1073 1074 mode_t mode = p->getSyscallArg(tc, index); 1075 1076 int result = access(path.c_str(), mode); 1077 return (result == -1) ? -errno : result; 1078} 1079 1080SyscallReturn 1081accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1082{ 1083 return accessFunc(desc, callnum, p, tc, 0); 1084} 1085 1086SyscallReturn 1087mknodFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1088{ 1089 int index = 0; 1090 std::string path; 1091 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1092 return -EFAULT; 1093 1094 path = p->fullPath(path); 1095 mode_t mode = p->getSyscallArg(tc, index); 1096 dev_t dev = p->getSyscallArg(tc, index); 1097 1098 auto result = mknod(path.c_str(), mode, dev); 1099 return (result == -1) ? -errno : result; 1100} 1101 1102SyscallReturn 1103chdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1104{ 1105 int index = 0; 1106 std::string path; 1107 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1108 return -EFAULT; 1109 1110 path = p->fullPath(path); 1111 1112 auto result = chdir(path.c_str()); 1113 return (result == -1) ? -errno : result; 1114} 1115 1116SyscallReturn 1117rmdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1118{ 1119 int index = 0; 1120 std::string path; 1121 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1122 return -EFAULT; 1123 1124 path = p->fullPath(path); 1125 1126 auto result = rmdir(path.c_str()); 1127 return (result == -1) ? -errno : result; 1128} 1129 1130#if defined(SYS_getdents) || defined(SYS_getdents64) 1131template<typename DE, int SYS_NUM> 1132static SyscallReturn 1133getdentsImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1134{ 1135 int index = 0; 1136 int tgt_fd = p->getSyscallArg(tc, index); 1137 Addr buf_ptr = p->getSyscallArg(tc, index); 1138 unsigned count = p->getSyscallArg(tc, index); 1139 1140 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 1141 if (!hbfdp) 1142 return -EBADF; 1143 int sim_fd = hbfdp->getSimFD(); 1144 1145 BufferArg buf_arg(buf_ptr, count); 1146 auto status = syscall(SYS_NUM, sim_fd, buf_arg.bufferPtr(), count); 1147 1148 if (status == -1) 1149 return -errno; 1150 1151 unsigned traversed = 0; 1152 while (traversed < status) { 1153 DE *buffer = (DE*)((Addr)buf_arg.bufferPtr() + traversed); 1154 1155 auto host_reclen = buffer->d_reclen; 1156 1157 /** 1158 * Convert the byte ordering from the host to the target before 1159 * passing the data back into the target's address space to preserve 1160 * endianness. 1161 */ 1162 buffer->d_ino = htog(buffer->d_ino); 1163 buffer->d_off = htog(buffer->d_off); 1164 buffer->d_reclen = htog(buffer->d_reclen); 1165 1166 traversed += host_reclen; 1167 } 1168 1169 buf_arg.copyOut(tc->getMemProxy()); 1170 return status; 1171} 1172#endif 1173 1174#if defined(SYS_getdents) 1175SyscallReturn 1176getdentsFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1177{ 1178 typedef struct linux_dirent { 1179 unsigned long d_ino; 1180 unsigned long d_off; 1181 unsigned short d_reclen; 1182 char dname[]; 1183 } LinDent; 1184 1185 return getdentsImpl<LinDent, SYS_getdents>(desc, callnum, p, tc); 1186} 1187#endif 1188 1189#if defined(SYS_getdents64) 1190SyscallReturn 1191getdents64Func(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1192{ 1193 typedef struct linux_dirent64 { 1194 ino64_t d_ino; 1195 off64_t d_off; 1196 unsigned short d_reclen; 1197 char dname[]; 1198 } LinDent64; 1199 1200 return getdentsImpl<LinDent64, SYS_getdents64>(desc, callnum, p, tc); 1201} 1202#endif 1203 1204SyscallReturn 1205shutdownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1206{ 1207 int index = 0; 1208 int tgt_fd = p->getSyscallArg(tc, index); 1209 int how = p->getSyscallArg(tc, index); 1210 1211 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1212 if (!sfdp) 1213 return -EBADF; 1214 int sim_fd = sfdp->getSimFD(); 1215 1216 int retval = shutdown(sim_fd, how); 1217 1218 return (retval == -1) ? -errno : retval; 1219} 1220 1221SyscallReturn 1222bindFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1223{ 1224 int index = 0; 1225 int tgt_fd = p->getSyscallArg(tc, index); 1226 Addr buf_ptr = p->getSyscallArg(tc, index); 1227 int addrlen = p->getSyscallArg(tc, index); 1228 1229 BufferArg bufSock(buf_ptr, addrlen); 1230 bufSock.copyIn(tc->getMemProxy()); 1231 1232 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1233 if (!sfdp) 1234 return -EBADF; 1235 int sim_fd = sfdp->getSimFD(); 1236 1237 int status = ::bind(sim_fd, 1238 (struct sockaddr *)bufSock.bufferPtr(), 1239 addrlen); 1240 1241 return (status == -1) ? -errno : status; 1242} 1243 1244SyscallReturn 1245listenFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1246{ 1247 int index = 0; 1248 int tgt_fd = p->getSyscallArg(tc, index); 1249 int backlog = p->getSyscallArg(tc, index); 1250 1251 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1252 if (!sfdp) 1253 return -EBADF; 1254 int sim_fd = sfdp->getSimFD(); 1255 1256 int status = listen(sim_fd, backlog); 1257 1258 return (status == -1) ? -errno : status; 1259} 1260 1261SyscallReturn 1262connectFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1263{ 1264 int index = 0; 1265 int tgt_fd = p->getSyscallArg(tc, index); 1266 Addr buf_ptr = p->getSyscallArg(tc, index); 1267 int addrlen = p->getSyscallArg(tc, index); 1268 1269 BufferArg addr(buf_ptr, addrlen); 1270 addr.copyIn(tc->getMemProxy()); 1271 1272 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1273 if (!sfdp) 1274 return -EBADF; 1275 int sim_fd = sfdp->getSimFD(); 1276 1277 int status = connect(sim_fd, 1278 (struct sockaddr *)addr.bufferPtr(), 1279 (socklen_t)addrlen); 1280 1281 return (status == -1) ? -errno : status; 1282} 1283 1284SyscallReturn 1285recvfromFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1286{ 1287 int index = 0; 1288 int tgt_fd = p->getSyscallArg(tc, index); 1289 Addr bufrPtr = p->getSyscallArg(tc, index); 1290 size_t bufrLen = p->getSyscallArg(tc, index); 1291 int flags = p->getSyscallArg(tc, index); 1292 Addr addrPtr = p->getSyscallArg(tc, index); 1293 Addr addrlenPtr = p->getSyscallArg(tc, index); 1294 1295 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1296 if (!sfdp) 1297 return -EBADF; 1298 int sim_fd = sfdp->getSimFD(); 1299 1300 // Reserve buffer space. 1301 BufferArg bufrBuf(bufrPtr, bufrLen); 1302 1303 // Get address length. 1304 socklen_t addrLen = 0; 1305 if (addrlenPtr != 0) { 1306 // Read address length parameter. 1307 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1308 addrlenBuf.copyIn(tc->getMemProxy()); 1309 addrLen = *((socklen_t *)addrlenBuf.bufferPtr()); 1310 } 1311 1312 struct sockaddr sa, *sap = NULL; 1313 if (addrLen != 0) { 1314 BufferArg addrBuf(addrPtr, addrLen); 1315 addrBuf.copyIn(tc->getMemProxy()); 1316 memcpy(&sa, (struct sockaddr *)addrBuf.bufferPtr(), 1317 sizeof(struct sockaddr)); 1318 sap = &sa; 1319 } 1320 1321 ssize_t recvd_size = recvfrom(sim_fd, 1322 (void *)bufrBuf.bufferPtr(), 1323 bufrLen, flags, sap, (socklen_t *)&addrLen); 1324 1325 if (recvd_size == -1) 1326 return -errno; 1327 1328 // Pass the received data out. 1329 bufrBuf.copyOut(tc->getMemProxy()); 1330 1331 // Copy address to addrPtr and pass it on. 1332 if (sap != NULL) { 1333 BufferArg addrBuf(addrPtr, addrLen); 1334 memcpy(addrBuf.bufferPtr(), sap, sizeof(sa)); 1335 addrBuf.copyOut(tc->getMemProxy()); 1336 } 1337 1338 // Copy len to addrlenPtr and pass it on. 1339 if (addrLen != 0) { 1340 BufferArg addrlenBuf(addrlenPtr, sizeof(socklen_t)); 1341 *(socklen_t *)addrlenBuf.bufferPtr() = addrLen; 1342 addrlenBuf.copyOut(tc->getMemProxy()); 1343 } 1344 1345 return recvd_size; 1346} 1347 1348SyscallReturn 1349sendtoFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1350{ 1351 int index = 0; 1352 int tgt_fd = p->getSyscallArg(tc, index); 1353 Addr bufrPtr = p->getSyscallArg(tc, index); 1354 size_t bufrLen = p->getSyscallArg(tc, index); 1355 int flags = p->getSyscallArg(tc, index); 1356 Addr addrPtr = p->getSyscallArg(tc, index); 1357 socklen_t addrLen = p->getSyscallArg(tc, index); 1358 1359 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1360 if (!sfdp) 1361 return -EBADF; 1362 int sim_fd = sfdp->getSimFD(); 1363 1364 // Reserve buffer space. 1365 BufferArg bufrBuf(bufrPtr, bufrLen); 1366 bufrBuf.copyIn(tc->getMemProxy()); 1367 1368 struct sockaddr sa, *sap = nullptr; 1369 memset(&sa, 0, sizeof(sockaddr)); 1370 if (addrLen != 0) { 1371 BufferArg addrBuf(addrPtr, addrLen); 1372 addrBuf.copyIn(tc->getMemProxy()); 1373 memcpy(&sa, (sockaddr*)addrBuf.bufferPtr(), addrLen); 1374 sap = &sa; 1375 } 1376 1377 ssize_t sent_size = sendto(sim_fd, 1378 (void *)bufrBuf.bufferPtr(), 1379 bufrLen, flags, sap, (socklen_t)addrLen); 1380 1381 return (sent_size == -1) ? -errno : sent_size; 1382} 1383 1384SyscallReturn 1385recvmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1386{ 1387 int index = 0; 1388 int tgt_fd = p->getSyscallArg(tc, index); 1389 Addr msgPtr = p->getSyscallArg(tc, index); 1390 int flags = p->getSyscallArg(tc, index); 1391 1392 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1393 if (!sfdp) 1394 return -EBADF; 1395 int sim_fd = sfdp->getSimFD(); 1396 1397 /** 1398 * struct msghdr { 1399 * void *msg_name; // optional address 1400 * socklen_t msg_namelen; // size of address 1401 * struct iovec *msg_iov; // iovec array 1402 * size_t msg_iovlen; // number entries in msg_iov 1403 * i // entries correspond to buffer 1404 * void *msg_control; // ancillary data 1405 * size_t msg_controllen; // ancillary data buffer len 1406 * int msg_flags; // flags on received message 1407 * }; 1408 * 1409 * struct iovec { 1410 * void *iov_base; // starting address 1411 * size_t iov_len; // number of bytes to transfer 1412 * }; 1413 */ 1414 1415 /** 1416 * The plan with this system call is to replace all of the pointers in the 1417 * structure and the substructure with BufferArg class pointers. We will 1418 * copy every field from the structures into our BufferArg classes. 1419 */ 1420 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1421 msgBuf.copyIn(tc->getMemProxy()); 1422 struct msghdr *msgHdr = (struct msghdr *)msgBuf.bufferPtr(); 1423 1424 /** 1425 * We will use these address place holders to retain the pointers which 1426 * we are going to replace with our own buffers in our simulator address 1427 * space. 1428 */ 1429 Addr msg_name_phold = 0; 1430 Addr msg_iov_phold = 0; 1431 Addr iovec_base_phold[msgHdr->msg_iovlen]; 1432 Addr msg_control_phold = 0; 1433 1434 /** 1435 * Record msg_name pointer then replace with buffer pointer. 1436 */ 1437 BufferArg *nameBuf = NULL; 1438 if (msgHdr->msg_name) { 1439 /*1*/msg_name_phold = (Addr)msgHdr->msg_name; 1440 /*2*/nameBuf = new BufferArg(msg_name_phold, msgHdr->msg_namelen); 1441 /*3*/nameBuf->copyIn(tc->getMemProxy()); 1442 /*4*/msgHdr->msg_name = nameBuf->bufferPtr(); 1443 } 1444 1445 /** 1446 * Record msg_iov pointer then replace with buffer pointer. Also, setup 1447 * an array of buffer pointers for the iovec structs record and replace 1448 * their pointers with buffer pointers. 1449 */ 1450 BufferArg *iovBuf = NULL; 1451 BufferArg *iovecBuf[msgHdr->msg_iovlen]; 1452 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1453 iovec_base_phold[i] = 0; 1454 iovecBuf[i] = NULL; 1455 } 1456 1457 if (msgHdr->msg_iov) { 1458 /*1*/msg_iov_phold = (Addr)msgHdr->msg_iov; 1459 /*2*/iovBuf = new BufferArg(msg_iov_phold, msgHdr->msg_iovlen * 1460 sizeof(struct iovec)); 1461 /*3*/iovBuf->copyIn(tc->getMemProxy()); 1462 for (int i = 0; i < msgHdr->msg_iovlen; i++) { 1463 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1464 /*1*/iovec_base_phold[i] = 1465 (Addr)((struct iovec *)iovBuf->bufferPtr())[i].iov_base; 1466 /*2*/iovecBuf[i] = new BufferArg(iovec_base_phold[i], 1467 ((struct iovec *)iovBuf->bufferPtr())[i].iov_len); 1468 /*3*/iovecBuf[i]->copyIn(tc->getMemProxy()); 1469 /*4*/((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1470 iovecBuf[i]->bufferPtr(); 1471 } 1472 } 1473 /*4*/msgHdr->msg_iov = (struct iovec *)iovBuf->bufferPtr(); 1474 } 1475 1476 /** 1477 * Record msg_control pointer then replace with buffer pointer. 1478 */ 1479 BufferArg *controlBuf = NULL; 1480 if (msgHdr->msg_control) { 1481 /*1*/msg_control_phold = (Addr)msgHdr->msg_control; 1482 /*2*/controlBuf = new BufferArg(msg_control_phold, 1483 CMSG_ALIGN(msgHdr->msg_controllen)); 1484 /*3*/controlBuf->copyIn(tc->getMemProxy()); 1485 /*4*/msgHdr->msg_control = controlBuf->bufferPtr(); 1486 } 1487 1488 ssize_t recvd_size = recvmsg(sim_fd, msgHdr, flags); 1489 1490 if (recvd_size < 0) 1491 return -errno; 1492 1493 if (msgHdr->msg_name) { 1494 nameBuf->copyOut(tc->getMemProxy()); 1495 delete(nameBuf); 1496 msgHdr->msg_name = (void *)msg_name_phold; 1497 } 1498 1499 if (msgHdr->msg_iov) { 1500 for (int i = 0; i< msgHdr->msg_iovlen; i++) { 1501 if (((struct iovec *)iovBuf->bufferPtr())[i].iov_base) { 1502 iovecBuf[i]->copyOut(tc->getMemProxy()); 1503 delete iovecBuf[i]; 1504 ((struct iovec *)iovBuf->bufferPtr())[i].iov_base = 1505 (void *)iovec_base_phold[i]; 1506 } 1507 } 1508 iovBuf->copyOut(tc->getMemProxy()); 1509 delete iovBuf; 1510 msgHdr->msg_iov = (struct iovec *)msg_iov_phold; 1511 } 1512 1513 if (msgHdr->msg_control) { 1514 controlBuf->copyOut(tc->getMemProxy()); 1515 delete(controlBuf); 1516 msgHdr->msg_control = (void *)msg_control_phold; 1517 } 1518 1519 msgBuf.copyOut(tc->getMemProxy()); 1520 1521 return recvd_size; 1522} 1523 1524SyscallReturn 1525sendmsgFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1526{ 1527 int index = 0; 1528 int tgt_fd = p->getSyscallArg(tc, index); 1529 Addr msgPtr = p->getSyscallArg(tc, index); 1530 int flags = p->getSyscallArg(tc, index); 1531 1532 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1533 if (!sfdp) 1534 return -EBADF; 1535 int sim_fd = sfdp->getSimFD(); 1536 1537 /** 1538 * Reserve buffer space. 1539 */ 1540 BufferArg msgBuf(msgPtr, sizeof(struct msghdr)); 1541 msgBuf.copyIn(tc->getMemProxy()); 1542 struct msghdr msgHdr = *((struct msghdr *)msgBuf.bufferPtr()); 1543 1544 /** 1545 * Assuming msgHdr.msg_iovlen >= 1, then there is no point calling 1546 * recvmsg without a buffer. 1547 */ 1548 struct iovec *iovPtr = msgHdr.msg_iov; 1549 BufferArg iovBuf((Addr)iovPtr, sizeof(struct iovec) * msgHdr.msg_iovlen); 1550 iovBuf.copyIn(tc->getMemProxy()); 1551 struct iovec *iov = (struct iovec *)iovBuf.bufferPtr(); 1552 msgHdr.msg_iov = iov; 1553 1554 /** 1555 * Cannot instantiate buffers till inside the loop. 1556 * Create array to hold buffer addresses, to be used during copyIn of 1557 * send data. 1558 */ 1559 BufferArg **bufferArray = (BufferArg **)malloc(msgHdr.msg_iovlen 1560 * sizeof(BufferArg *)); 1561 1562 /** 1563 * Iterate through the iovec structures: 1564 * Get the base buffer addreses, reserve iov_len amount of space for each. 1565 * Put the buf address into the bufferArray for later retrieval. 1566 */ 1567 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1568 Addr basePtr = (Addr) iov[iovIndex].iov_base; 1569 bufferArray[iovIndex] = new BufferArg(basePtr, iov[iovIndex].iov_len); 1570 bufferArray[iovIndex]->copyIn(tc->getMemProxy()); 1571 iov[iovIndex].iov_base = bufferArray[iovIndex]->bufferPtr(); 1572 } 1573 1574 ssize_t sent_size = sendmsg(sim_fd, &msgHdr, flags); 1575 int local_errno = errno; 1576 1577 /** 1578 * Free dynamically allocated memory. 1579 */ 1580 for (int iovIndex = 0 ; iovIndex < msgHdr.msg_iovlen; iovIndex++) { 1581 BufferArg *baseBuf = ( BufferArg *)bufferArray[iovIndex]; 1582 delete(baseBuf); 1583 } 1584 1585 /** 1586 * Malloced above. 1587 */ 1588 free(bufferArray); 1589 1590 return (sent_size < 0) ? -local_errno : sent_size; 1591} 1592 1593SyscallReturn 1594getsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1595{ 1596 // union of all possible return value types from getsockopt 1597 union val { 1598 int i_val; 1599 long l_val; 1600 struct linger linger_val; 1601 struct timeval timeval_val; 1602 } val; 1603 1604 int index = 0; 1605 int tgt_fd = p->getSyscallArg(tc, index); 1606 int level = p->getSyscallArg(tc, index); 1607 int optname = p->getSyscallArg(tc, index); 1608 Addr valPtr = p->getSyscallArg(tc, index); 1609 Addr lenPtr = p->getSyscallArg(tc, index); 1610 1611 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1612 if (!sfdp) 1613 return -EBADF; 1614 int sim_fd = sfdp->getSimFD(); 1615 1616 socklen_t len = sizeof(val); 1617 int status = getsockopt(sim_fd, level, optname, &val, &len); 1618 1619 if (status == -1) 1620 return -errno; 1621 1622 // copy val to valPtr and pass it on 1623 BufferArg valBuf(valPtr, sizeof(val)); 1624 memcpy(valBuf.bufferPtr(), &val, sizeof(val)); 1625 valBuf.copyOut(tc->getMemProxy()); 1626 1627 // copy len to lenPtr and pass it on 1628 BufferArg lenBuf(lenPtr, sizeof(len)); 1629 memcpy(lenBuf.bufferPtr(), &len, sizeof(len)); 1630 lenBuf.copyOut(tc->getMemProxy()); 1631 1632 return status; 1633} 1634 1635SyscallReturn 1636getsocknameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1637{ 1638 int index = 0; 1639 int tgt_fd = p->getSyscallArg(tc, index); 1640 Addr addrPtr = p->getSyscallArg(tc, index); 1641 Addr lenPtr = p->getSyscallArg(tc, index); 1642 1643 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1644 if (!sfdp) 1645 return -EBADF; 1646 int sim_fd = sfdp->getSimFD(); 1647 1648 // lenPtr is an in-out paramenter: 1649 // sending the address length in, conveying the final length out 1650 1651 // Read in the value of len from the passed pointer. 1652 BufferArg lenBuf(lenPtr, sizeof(socklen_t)); 1653 lenBuf.copyIn(tc->getMemProxy()); 1654 socklen_t len = *(socklen_t *)lenBuf.bufferPtr(); 1655 1656 struct sockaddr sa; 1657 int status = getsockname(sim_fd, &sa, &len); 1658 1659 if (status == -1) 1660 return -errno; 1661 1662 // Copy address to addrPtr and pass it on. 1663 BufferArg addrBuf(addrPtr, sizeof(sa)); 1664 memcpy(addrBuf.bufferPtr(), &sa, sizeof(sa)); 1665 addrBuf.copyOut(tc->getMemProxy()); 1666 1667 // Copy len to lenPtr and pass it on. 1668 *(socklen_t *)lenBuf.bufferPtr() = len; 1669 lenBuf.copyOut(tc->getMemProxy()); 1670 1671 return status; 1672} 1673 1674SyscallReturn 1675getpeernameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1676{ 1677 int index = 0; 1678 int tgt_fd = p->getSyscallArg(tc, index); 1679 Addr sockAddrPtr = p->getSyscallArg(tc, index); 1680 Addr addrlenPtr = p->getSyscallArg(tc, index); 1681 1682 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1683 if (!sfdp) 1684 return -EBADF; 1685 int sim_fd = sfdp->getSimFD(); 1686 1687 BufferArg bufAddrlen(addrlenPtr, sizeof(unsigned)); 1688 bufAddrlen.copyIn(tc->getMemProxy()); 1689 BufferArg bufSock(sockAddrPtr, *(unsigned *)bufAddrlen.bufferPtr()); 1690 1691 int retval = getpeername(sim_fd, 1692 (struct sockaddr *)bufSock.bufferPtr(), 1693 (unsigned *)bufAddrlen.bufferPtr()); 1694 1695 if (retval != -1) { 1696 bufSock.copyOut(tc->getMemProxy()); 1697 bufAddrlen.copyOut(tc->getMemProxy()); 1698 } 1699 1700 return (retval == -1) ? -errno : retval; 1701} 1702 1703SyscallReturn 1704setsockoptFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 1705{ 1706 int index = 0; 1707 int tgt_fd = p->getSyscallArg(tc, index); 1708 int level = p->getSyscallArg(tc, index); 1709 int optname = p->getSyscallArg(tc, index); 1710 Addr valPtr = p->getSyscallArg(tc, index); 1711 socklen_t len = p->getSyscallArg(tc, index); 1712 1713 BufferArg valBuf(valPtr, len); 1714 valBuf.copyIn(tc->getMemProxy()); 1715 1716 auto sfdp = std::dynamic_pointer_cast<SocketFDEntry>((*p->fds)[tgt_fd]); 1717 if (!sfdp) 1718 return -EBADF; 1719 int sim_fd = sfdp->getSimFD(); 1720 1721 int status = setsockopt(sim_fd, level, optname, 1722 (struct sockaddr *)valBuf.bufferPtr(), len); 1723 1724 return (status == -1) ? -errno : status; 1725} 1726
|