syscall_emul.cc revision 11906:4b99c1bb3b72
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Steve Reinhardt 29 * Ali Saidi 30 */ 31 32#include "sim/syscall_emul.hh" 33 34#include <fcntl.h> 35#include <unistd.h> 36 37#include <iostream> 38#include <string> 39 40#include "arch/utility.hh" 41#include "base/chunk_generator.hh" 42#include "base/trace.hh" 43#include "config/the_isa.hh" 44#include "cpu/thread_context.hh" 45#include "mem/page_table.hh" 46#include "sim/process.hh" 47#include "sim/sim_exit.hh" 48#include "sim/syscall_debug_macros.hh" 49#include "sim/syscall_desc.hh" 50#include "sim/system.hh" 51 52using namespace std; 53using namespace TheISA; 54 55SyscallReturn 56unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 57 ThreadContext *tc) 58{ 59 fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum); 60 61 return 1; 62} 63 64 65SyscallReturn 66ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 67 ThreadContext *tc) 68{ 69 if (desc->needWarning()) { 70 warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ? 71 "\n (further warnings will be suppressed)" : ""); 72 } 73 74 return 0; 75} 76 77static void 78exitFutexWake(ThreadContext *tc, uint64_t uaddr) 79{ 80 std::map<uint64_t, std::list<ThreadContext *> * > 81 &futex_map = tc->getSystemPtr()->futexMap; 82 83 int wokenUp = 0; 84 std::list<ThreadContext *> * tcWaitList; 85 if (futex_map.count(uaddr)) { 86 tcWaitList = futex_map.find(uaddr)->second; 87 if (tcWaitList->size() > 0) { 88 tcWaitList->front()->activate(); 89 tcWaitList->pop_front(); 90 wokenUp++; 91 } 92 if (tcWaitList->empty()) { 93 futex_map.erase(uaddr); 94 delete tcWaitList; 95 } 96 } 97 DPRINTF(SyscallVerbose, "exit: FUTEX_WAKE, activated %d waiting " 98 "thread contexts\n", wokenUp); 99} 100 101SyscallReturn 102exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 103{ 104 if (p->system->numRunningContexts() == 1 && !p->childClearTID) { 105 // Last running free-parent context; exit simulator. 106 int index = 0; 107 exitSimLoop("target called exit()", 108 p->getSyscallArg(tc, index) & 0xff); 109 } else { 110 if (p->childClearTID) 111 exitFutexWake(tc, p->childClearTID); 112 tc->halt(); 113 } 114 115 return 1; 116} 117 118 119SyscallReturn 120exitGroupFunc(SyscallDesc *desc, int callnum, Process *process, 121 ThreadContext *tc) 122{ 123 // halt all threads belonging to this process 124 for (auto i: process->contextIds) { 125 process->system->getThreadContext(i)->halt(); 126 } 127 128 if (!process->system->numRunningContexts()) { 129 // all threads belonged to this process... exit simulator 130 int index = 0; 131 exitSimLoop("target called exit()", 132 process->getSyscallArg(tc, index) & 0xff); 133 } 134 135 return 1; 136} 137 138 139SyscallReturn 140getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 141{ 142 return (int)PageBytes; 143} 144 145 146SyscallReturn 147brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 148{ 149 // change brk addr to first arg 150 int index = 0; 151 Addr new_brk = p->getSyscallArg(tc, index); 152 153 std::shared_ptr<MemState> mem_state = p->memState; 154 Addr brk_point = mem_state->getBrkPoint(); 155 156 // in Linux at least, brk(0) returns the current break value 157 // (note that the syscall and the glibc function have different behavior) 158 if (new_brk == 0) 159 return brk_point; 160 161 if (new_brk > brk_point) { 162 // might need to allocate some new pages 163 for (ChunkGenerator gen(brk_point, 164 new_brk - brk_point, 165 PageBytes); !gen.done(); gen.next()) { 166 if (!p->pTable->translate(gen.addr())) 167 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 168 169 // if the address is already there, zero it out 170 else { 171 uint8_t zero = 0; 172 SETranslatingPortProxy &tp = tc->getMemProxy(); 173 174 // split non-page aligned accesses 175 Addr next_page = roundUp(gen.addr(), PageBytes); 176 uint32_t size_needed = next_page - gen.addr(); 177 tp.memsetBlob(gen.addr(), zero, size_needed); 178 if (gen.addr() + PageBytes > next_page && 179 next_page < new_brk && 180 p->pTable->translate(next_page)) { 181 size_needed = PageBytes - size_needed; 182 tp.memsetBlob(next_page, zero, size_needed); 183 } 184 } 185 } 186 } 187 188 mem_state->setBrkPoint(new_brk); 189 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 190 mem_state->getBrkPoint()); 191 return mem_state->getBrkPoint(); 192} 193 194SyscallReturn 195setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process, 196 ThreadContext *tc) 197{ 198 int index = 0; 199 uint64_t tidPtr = process->getSyscallArg(tc, index); 200 201 process->childClearTID = tidPtr; 202 return process->pid(); 203} 204 205SyscallReturn 206closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 207{ 208 int index = 0; 209 int tgt_fd = p->getSyscallArg(tc, index); 210 211 return p->fds->closeFDEntry(tgt_fd); 212} 213 214 215SyscallReturn 216readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 217{ 218 int index = 0; 219 int tgt_fd = p->getSyscallArg(tc, index); 220 Addr buf_ptr = p->getSyscallArg(tc, index); 221 int nbytes = p->getSyscallArg(tc, index); 222 223 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 224 if (!hbfdp) 225 return -EBADF; 226 int sim_fd = hbfdp->getSimFD(); 227 228 BufferArg bufArg(buf_ptr, nbytes); 229 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 230 231 if (bytes_read > 0) 232 bufArg.copyOut(tc->getMemProxy()); 233 234 return bytes_read; 235} 236 237SyscallReturn 238writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 239{ 240 int index = 0; 241 int tgt_fd = p->getSyscallArg(tc, index); 242 Addr buf_ptr = p->getSyscallArg(tc, index); 243 int nbytes = p->getSyscallArg(tc, index); 244 245 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 246 if (!hbfdp) 247 return -EBADF; 248 int sim_fd = hbfdp->getSimFD(); 249 250 BufferArg bufArg(buf_ptr, nbytes); 251 bufArg.copyIn(tc->getMemProxy()); 252 253 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 254 255 fsync(sim_fd); 256 257 return bytes_written; 258} 259 260 261SyscallReturn 262lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 263{ 264 int index = 0; 265 int tgt_fd = p->getSyscallArg(tc, index); 266 uint64_t offs = p->getSyscallArg(tc, index); 267 int whence = p->getSyscallArg(tc, index); 268 269 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 270 if (!ffdp) 271 return -EBADF; 272 int sim_fd = ffdp->getSimFD(); 273 274 off_t result = lseek(sim_fd, offs, whence); 275 276 return (result == (off_t)-1) ? -errno : result; 277} 278 279 280SyscallReturn 281_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 282{ 283 int index = 0; 284 int tgt_fd = p->getSyscallArg(tc, index); 285 uint64_t offset_high = p->getSyscallArg(tc, index); 286 uint32_t offset_low = p->getSyscallArg(tc, index); 287 Addr result_ptr = 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 uint64_t offset = (offset_high << 32) | offset_low; 296 297 uint64_t result = lseek(sim_fd, offset, whence); 298 result = TheISA::htog(result); 299 300 if (result == (off_t)-1) 301 return -errno; 302 // Assuming that the size of loff_t is 64 bits on the target platform 303 BufferArg result_buf(result_ptr, sizeof(result)); 304 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 305 result_buf.copyOut(tc->getMemProxy()); 306 return 0; 307} 308 309 310SyscallReturn 311munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 312{ 313 // With mmap more fully implemented, it might be worthwhile to bite 314 // the bullet and implement munmap. Should allow us to reuse simulated 315 // memory. 316 return 0; 317} 318 319 320const char *hostname = "m5.eecs.umich.edu"; 321 322SyscallReturn 323gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 324{ 325 int index = 0; 326 Addr buf_ptr = p->getSyscallArg(tc, index); 327 int name_len = p->getSyscallArg(tc, index); 328 BufferArg name(buf_ptr, name_len); 329 330 strncpy((char *)name.bufferPtr(), hostname, name_len); 331 332 name.copyOut(tc->getMemProxy()); 333 334 return 0; 335} 336 337SyscallReturn 338getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 339{ 340 int result = 0; 341 int index = 0; 342 Addr buf_ptr = p->getSyscallArg(tc, index); 343 unsigned long size = p->getSyscallArg(tc, index); 344 BufferArg buf(buf_ptr, size); 345 346 // Is current working directory defined? 347 string cwd = p->getcwd(); 348 if (!cwd.empty()) { 349 if (cwd.length() >= size) { 350 // Buffer too small 351 return -ERANGE; 352 } 353 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 354 result = cwd.length(); 355 } else { 356 if (getcwd((char *)buf.bufferPtr(), size)) { 357 result = strlen((char *)buf.bufferPtr()); 358 } else { 359 result = -1; 360 } 361 } 362 363 buf.copyOut(tc->getMemProxy()); 364 365 return (result == -1) ? -errno : result; 366} 367 368/// Target open() handler. 369SyscallReturn 370readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 371 ThreadContext *tc) 372{ 373 return readlinkFunc(desc, callnum, process, tc, 0); 374} 375 376SyscallReturn 377readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 378 int index) 379{ 380 string path; 381 382 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 383 return -EFAULT; 384 385 // Adjust path for current working directory 386 path = p->fullPath(path); 387 388 Addr buf_ptr = p->getSyscallArg(tc, index); 389 size_t bufsiz = p->getSyscallArg(tc, index); 390 391 BufferArg buf(buf_ptr, bufsiz); 392 393 int result = -1; 394 if (path != "/proc/self/exe") { 395 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 396 } else { 397 // Emulate readlink() called on '/proc/self/exe' should return the 398 // absolute path of the binary running in the simulated system (the 399 // Process' executable). It is possible that using this path in 400 // the simulated system will result in unexpected behavior if: 401 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 402 // called binary calls readlink(). 403 // 2) The host's full path to the running benchmark changes from one 404 // simulation to another. This can result in different simulated 405 // performance since the simulated system will process the binary 406 // path differently, even if the binary itself does not change. 407 408 // Get the absolute canonical path to the running application 409 char real_path[PATH_MAX]; 410 char *check_real_path = realpath(p->progName(), real_path); 411 if (!check_real_path) { 412 fatal("readlink('/proc/self/exe') unable to resolve path to " 413 "executable: %s", p->progName()); 414 } 415 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 416 size_t real_path_len = strlen(real_path); 417 if (real_path_len > bufsiz) { 418 // readlink will truncate the contents of the 419 // path to ensure it is no more than bufsiz 420 result = bufsiz; 421 } else { 422 result = real_path_len; 423 } 424 425 // Issue a warning about potential unexpected results 426 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 427 "results in various settings.\n Returning '%s'\n", 428 (char*)buf.bufferPtr()); 429 } 430 431 buf.copyOut(tc->getMemProxy()); 432 433 return (result == -1) ? -errno : result; 434} 435 436SyscallReturn 437unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 438{ 439 return unlinkHelper(desc, num, p, tc, 0); 440} 441 442SyscallReturn 443unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 444 int index) 445{ 446 string path; 447 448 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 449 return -EFAULT; 450 451 // Adjust path for current working directory 452 path = p->fullPath(path); 453 454 int result = unlink(path.c_str()); 455 return (result == -1) ? -errno : result; 456} 457 458 459SyscallReturn 460mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 461{ 462 string path; 463 464 int index = 0; 465 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 466 return -EFAULT; 467 468 // Adjust path for current working directory 469 path = p->fullPath(path); 470 471 mode_t mode = p->getSyscallArg(tc, index); 472 473 int result = mkdir(path.c_str(), mode); 474 return (result == -1) ? -errno : result; 475} 476 477SyscallReturn 478renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 479{ 480 string old_name; 481 482 int index = 0; 483 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 484 return -EFAULT; 485 486 string new_name; 487 488 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 489 return -EFAULT; 490 491 // Adjust path for current working directory 492 old_name = p->fullPath(old_name); 493 new_name = p->fullPath(new_name); 494 495 int64_t result = rename(old_name.c_str(), new_name.c_str()); 496 return (result == -1) ? -errno : result; 497} 498 499SyscallReturn 500truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 501{ 502 string path; 503 504 int index = 0; 505 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 506 return -EFAULT; 507 508 off_t length = p->getSyscallArg(tc, index); 509 510 // Adjust path for current working directory 511 path = p->fullPath(path); 512 513 int result = truncate(path.c_str(), length); 514 return (result == -1) ? -errno : result; 515} 516 517SyscallReturn 518ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 519{ 520 int index = 0; 521 int tgt_fd = p->getSyscallArg(tc, index); 522 off_t length = p->getSyscallArg(tc, index); 523 524 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 525 if (!ffdp) 526 return -EBADF; 527 int sim_fd = ffdp->getSimFD(); 528 529 int result = ftruncate(sim_fd, length); 530 return (result == -1) ? -errno : result; 531} 532 533SyscallReturn 534truncate64Func(SyscallDesc *desc, int num, 535 Process *process, ThreadContext *tc) 536{ 537 int index = 0; 538 string path; 539 540 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 541 return -EFAULT; 542 543 int64_t length = process->getSyscallArg(tc, index, 64); 544 545 // Adjust path for current working directory 546 path = process->fullPath(path); 547 548#if NO_STAT64 549 int result = truncate(path.c_str(), length); 550#else 551 int result = truncate64(path.c_str(), length); 552#endif 553 return (result == -1) ? -errno : result; 554} 555 556SyscallReturn 557ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 558{ 559 int index = 0; 560 int tgt_fd = p->getSyscallArg(tc, index); 561 int64_t length = p->getSyscallArg(tc, index, 64); 562 563 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 564 if (!ffdp) 565 return -EBADF; 566 int sim_fd = ffdp->getSimFD(); 567 568#if NO_STAT64 569 int result = ftruncate(sim_fd, length); 570#else 571 int result = ftruncate64(sim_fd, length); 572#endif 573 return (result == -1) ? -errno : result; 574} 575 576SyscallReturn 577umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 578{ 579 // Letting the simulated program change the simulator's umask seems like 580 // a bad idea. Compromise by just returning the current umask but not 581 // changing anything. 582 mode_t oldMask = umask(0); 583 umask(oldMask); 584 return (int)oldMask; 585} 586 587SyscallReturn 588chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 589{ 590 string path; 591 592 int index = 0; 593 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 594 return -EFAULT; 595 596 /* XXX endianess */ 597 uint32_t owner = p->getSyscallArg(tc, index); 598 uid_t hostOwner = owner; 599 uint32_t group = p->getSyscallArg(tc, index); 600 gid_t hostGroup = group; 601 602 // Adjust path for current working directory 603 path = p->fullPath(path); 604 605 int result = chown(path.c_str(), hostOwner, hostGroup); 606 return (result == -1) ? -errno : result; 607} 608 609SyscallReturn 610fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 611{ 612 int index = 0; 613 int tgt_fd = p->getSyscallArg(tc, index); 614 615 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 616 if (!ffdp) 617 return -EBADF; 618 int sim_fd = ffdp->getSimFD(); 619 620 /* XXX endianess */ 621 uint32_t owner = p->getSyscallArg(tc, index); 622 uid_t hostOwner = owner; 623 uint32_t group = p->getSyscallArg(tc, index); 624 gid_t hostGroup = group; 625 626 int result = fchown(sim_fd, hostOwner, hostGroup); 627 return (result == -1) ? -errno : result; 628} 629 630 631/** 632 * TODO: there's a bit more involved here since file descriptors created with 633 * dup are supposed to share a file description. So, there is a problem with 634 * maintaining fields like file offset or flags since an update to such a 635 * field won't be reflected in the metadata for the fd entries that we 636 * maintain to hold metadata for checkpoint restoration. 637 */ 638SyscallReturn 639dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 640{ 641 int index = 0; 642 int tgt_fd = p->getSyscallArg(tc, index); 643 644 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 645 if (!old_hbfdp) 646 return -EBADF; 647 int sim_fd = old_hbfdp->getSimFD(); 648 649 int result = dup(sim_fd); 650 int local_errno = errno; 651 652 std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone(); 653 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep); 654 new_hbfdp->setSimFD(result); 655 656 return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); 657} 658 659SyscallReturn 660fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 661{ 662 int arg; 663 int index = 0; 664 int tgt_fd = p->getSyscallArg(tc, index); 665 int cmd = p->getSyscallArg(tc, index); 666 667 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 668 if (!hbfdp) 669 return -EBADF; 670 int sim_fd = hbfdp->getSimFD(); 671 672 int coe = hbfdp->getCOE(); 673 674 switch (cmd) { 675 case F_GETFD: 676 return coe & FD_CLOEXEC; 677 678 case F_SETFD: { 679 arg = p->getSyscallArg(tc, index); 680 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 681 return 0; 682 } 683 684 // Rely on the host to maintain the file status flags for this file 685 // description rather than maintain it ourselves. Admittedly, this 686 // is suboptimal (and possibly error prone), but it is difficult to 687 // maintain the flags by tracking them across the different descriptors 688 // (that refer to this file description) caused by clone, dup, and 689 // subsequent fcntls. 690 case F_GETFL: 691 case F_SETFL: { 692 arg = p->getSyscallArg(tc, index); 693 int rv = fcntl(sim_fd, cmd, arg); 694 return (rv == -1) ? -errno : rv; 695 } 696 697 default: 698 warn("fcntl: unsupported command %d\n", cmd); 699 return 0; 700 } 701} 702 703SyscallReturn 704fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 705{ 706 int index = 0; 707 int tgt_fd = p->getSyscallArg(tc, index); 708 709 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 710 if (!hbfdp) 711 return -EBADF; 712 int sim_fd = hbfdp->getSimFD(); 713 714 int cmd = p->getSyscallArg(tc, index); 715 switch (cmd) { 716 case 33: //F_GETLK64 717 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 718 return -EMFILE; 719 720 case 34: // F_SETLK64 721 case 35: // F_SETLKW64 722 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 723 tgt_fd); 724 return -EMFILE; 725 726 default: 727 // not sure if this is totally valid, but we'll pass it through 728 // to the underlying OS 729 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 730 return fcntl(sim_fd, cmd); 731 } 732} 733 734SyscallReturn 735pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 736 ThreadContext *tc) 737{ 738 int sim_fds[2], tgt_fds[2]; 739 740 int pipe_retval = pipe(sim_fds); 741 if (pipe_retval < 0) 742 return pipe_retval; 743 744 auto rend = PipeFDEntry::EndType::read; 745 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 746 747 auto wend = PipeFDEntry::EndType::write; 748 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 749 750 tgt_fds[0] = process->fds->allocFD(rpfd); 751 tgt_fds[1] = process->fds->allocFD(wpfd); 752 753 /** 754 * Now patch the read object to record the target file descriptor chosen 755 * as the write end of the pipe. 756 */ 757 rpfd->setPipeReadSource(tgt_fds[1]); 758 759 /** 760 * Alpha Linux convention for pipe() is that fd[0] is returned as 761 * the return value of the function, and fd[1] is returned in r20. 762 */ 763 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 764 return sim_fds[0]; 765} 766 767SyscallReturn 768setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 769 ThreadContext *tc) 770{ 771 int index = 0; 772 int pid = process->getSyscallArg(tc, index); 773 int pgid = process->getSyscallArg(tc, index); 774 775 if (pgid < 0) 776 return -EINVAL; 777 778 if (pid == 0) { 779 process->setpgid(process->pid()); 780 return 0; 781 } 782 783 Process *matched_ph = NULL; 784 System *sysh = tc->getSystemPtr(); 785 786 // Retrieves process pointer from active/suspended thread contexts. 787 for (int i = 0; i < sysh->numContexts(); i++) { 788 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 789 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 790 Process *walk_ph = (Process*)temp_h; 791 792 if (walk_ph && walk_ph->pid() == process->pid()) 793 matched_ph = walk_ph; 794 } 795 } 796 797 assert(matched_ph != NULL); 798 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 799 800 return 0; 801} 802 803SyscallReturn 804getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 805 ThreadContext *tc) 806{ 807 // Make up a PID. There's no interprocess communication in 808 // fake_syscall mode, so there's no way for a process to know it's 809 // not getting a unique value. 810 811 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 812 return process->pid(); 813} 814 815 816SyscallReturn 817getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 818 ThreadContext *tc) 819{ 820 // Make up a UID and EUID... it shouldn't matter, and we want the 821 // simulation to be deterministic. 822 823 // EUID goes in r20. 824 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 825 return process->uid(); // UID 826} 827 828 829SyscallReturn 830getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 831 ThreadContext *tc) 832{ 833 // Get current group ID. EGID goes in r20. 834 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 835 return process->gid(); 836} 837 838 839SyscallReturn 840setuidFunc(SyscallDesc *desc, int callnum, Process *process, 841 ThreadContext *tc) 842{ 843 // can't fathom why a benchmark would call this. 844 int index = 0; 845 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 846 return 0; 847} 848 849SyscallReturn 850getpidFunc(SyscallDesc *desc, int callnum, Process *process, 851 ThreadContext *tc) 852{ 853 return process->tgid(); 854} 855 856SyscallReturn 857gettidFunc(SyscallDesc *desc, int callnum, Process *process, 858 ThreadContext *tc) 859{ 860 return process->pid(); 861} 862 863SyscallReturn 864getppidFunc(SyscallDesc *desc, int callnum, Process *process, 865 ThreadContext *tc) 866{ 867 return process->ppid(); 868} 869 870SyscallReturn 871getuidFunc(SyscallDesc *desc, int callnum, Process *process, 872 ThreadContext *tc) 873{ 874 return process->uid(); // UID 875} 876 877SyscallReturn 878geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 879 ThreadContext *tc) 880{ 881 return process->euid(); // UID 882} 883 884SyscallReturn 885getgidFunc(SyscallDesc *desc, int callnum, Process *process, 886 ThreadContext *tc) 887{ 888 return process->gid(); 889} 890 891SyscallReturn 892getegidFunc(SyscallDesc *desc, int callnum, Process *process, 893 ThreadContext *tc) 894{ 895 return process->egid(); 896} 897 898SyscallReturn 899fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 900{ 901#if NO_FALLOCATE 902 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 903#else 904 int index = 0; 905 int tgt_fd = p->getSyscallArg(tc, index); 906 int mode = p->getSyscallArg(tc, index); 907 off_t offset = p->getSyscallArg(tc, index); 908 off_t len = p->getSyscallArg(tc, index); 909 910 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 911 if (!ffdp) 912 return -EBADF; 913 int sim_fd = ffdp->getSimFD(); 914 915 int result = fallocate(sim_fd, mode, offset, len); 916 if (result < 0) 917 return -errno; 918#endif 919 return 0; 920} 921 922SyscallReturn 923accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 924 int index) 925{ 926 string path; 927 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 928 return -EFAULT; 929 930 // Adjust path for current working directory 931 path = p->fullPath(path); 932 933 mode_t mode = p->getSyscallArg(tc, index); 934 935 int result = access(path.c_str(), mode); 936 return (result == -1) ? -errno : result; 937} 938 939SyscallReturn 940accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 941{ 942 return accessFunc(desc, callnum, p, tc, 0); 943} 944 945