syscall_emul.cc revision 11907:48a3d32da9d8
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 368SyscallReturn 369readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 370 ThreadContext *tc) 371{ 372 return readlinkFunc(desc, callnum, process, tc, 0); 373} 374 375SyscallReturn 376readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 377 int index) 378{ 379 string path; 380 381 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 382 return -EFAULT; 383 384 // Adjust path for current working directory 385 path = p->fullPath(path); 386 387 Addr buf_ptr = p->getSyscallArg(tc, index); 388 size_t bufsiz = p->getSyscallArg(tc, index); 389 390 BufferArg buf(buf_ptr, bufsiz); 391 392 int result = -1; 393 if (path != "/proc/self/exe") { 394 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 395 } else { 396 // Emulate readlink() called on '/proc/self/exe' should return the 397 // absolute path of the binary running in the simulated system (the 398 // Process' executable). It is possible that using this path in 399 // the simulated system will result in unexpected behavior if: 400 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 401 // called binary calls readlink(). 402 // 2) The host's full path to the running benchmark changes from one 403 // simulation to another. This can result in different simulated 404 // performance since the simulated system will process the binary 405 // path differently, even if the binary itself does not change. 406 407 // Get the absolute canonical path to the running application 408 char real_path[PATH_MAX]; 409 char *check_real_path = realpath(p->progName(), real_path); 410 if (!check_real_path) { 411 fatal("readlink('/proc/self/exe') unable to resolve path to " 412 "executable: %s", p->progName()); 413 } 414 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 415 size_t real_path_len = strlen(real_path); 416 if (real_path_len > bufsiz) { 417 // readlink will truncate the contents of the 418 // path to ensure it is no more than bufsiz 419 result = bufsiz; 420 } else { 421 result = real_path_len; 422 } 423 424 // Issue a warning about potential unexpected results 425 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 426 "results in various settings.\n Returning '%s'\n", 427 (char*)buf.bufferPtr()); 428 } 429 430 buf.copyOut(tc->getMemProxy()); 431 432 return (result == -1) ? -errno : result; 433} 434 435SyscallReturn 436unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 437{ 438 return unlinkHelper(desc, num, p, tc, 0); 439} 440 441SyscallReturn 442unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 443 int index) 444{ 445 string path; 446 447 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 448 return -EFAULT; 449 450 // Adjust path for current working directory 451 path = p->fullPath(path); 452 453 int result = unlink(path.c_str()); 454 return (result == -1) ? -errno : result; 455} 456 457 458SyscallReturn 459mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 460{ 461 string path; 462 463 int index = 0; 464 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 465 return -EFAULT; 466 467 // Adjust path for current working directory 468 path = p->fullPath(path); 469 470 mode_t mode = p->getSyscallArg(tc, index); 471 472 int result = mkdir(path.c_str(), mode); 473 return (result == -1) ? -errno : result; 474} 475 476SyscallReturn 477renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 478{ 479 string old_name; 480 481 int index = 0; 482 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 483 return -EFAULT; 484 485 string new_name; 486 487 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 488 return -EFAULT; 489 490 // Adjust path for current working directory 491 old_name = p->fullPath(old_name); 492 new_name = p->fullPath(new_name); 493 494 int64_t result = rename(old_name.c_str(), new_name.c_str()); 495 return (result == -1) ? -errno : result; 496} 497 498SyscallReturn 499truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 500{ 501 string path; 502 503 int index = 0; 504 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 505 return -EFAULT; 506 507 off_t length = p->getSyscallArg(tc, index); 508 509 // Adjust path for current working directory 510 path = p->fullPath(path); 511 512 int result = truncate(path.c_str(), length); 513 return (result == -1) ? -errno : result; 514} 515 516SyscallReturn 517ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 518{ 519 int index = 0; 520 int tgt_fd = p->getSyscallArg(tc, index); 521 off_t length = p->getSyscallArg(tc, index); 522 523 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 524 if (!ffdp) 525 return -EBADF; 526 int sim_fd = ffdp->getSimFD(); 527 528 int result = ftruncate(sim_fd, length); 529 return (result == -1) ? -errno : result; 530} 531 532SyscallReturn 533truncate64Func(SyscallDesc *desc, int num, 534 Process *process, ThreadContext *tc) 535{ 536 int index = 0; 537 string path; 538 539 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 540 return -EFAULT; 541 542 int64_t length = process->getSyscallArg(tc, index, 64); 543 544 // Adjust path for current working directory 545 path = process->fullPath(path); 546 547#if NO_STAT64 548 int result = truncate(path.c_str(), length); 549#else 550 int result = truncate64(path.c_str(), length); 551#endif 552 return (result == -1) ? -errno : result; 553} 554 555SyscallReturn 556ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 557{ 558 int index = 0; 559 int tgt_fd = p->getSyscallArg(tc, index); 560 int64_t length = p->getSyscallArg(tc, index, 64); 561 562 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 563 if (!ffdp) 564 return -EBADF; 565 int sim_fd = ffdp->getSimFD(); 566 567#if NO_STAT64 568 int result = ftruncate(sim_fd, length); 569#else 570 int result = ftruncate64(sim_fd, length); 571#endif 572 return (result == -1) ? -errno : result; 573} 574 575SyscallReturn 576umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 577{ 578 // Letting the simulated program change the simulator's umask seems like 579 // a bad idea. Compromise by just returning the current umask but not 580 // changing anything. 581 mode_t oldMask = umask(0); 582 umask(oldMask); 583 return (int)oldMask; 584} 585 586SyscallReturn 587chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 588{ 589 string path; 590 591 int index = 0; 592 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 593 return -EFAULT; 594 595 /* XXX endianess */ 596 uint32_t owner = p->getSyscallArg(tc, index); 597 uid_t hostOwner = owner; 598 uint32_t group = p->getSyscallArg(tc, index); 599 gid_t hostGroup = group; 600 601 // Adjust path for current working directory 602 path = p->fullPath(path); 603 604 int result = chown(path.c_str(), hostOwner, hostGroup); 605 return (result == -1) ? -errno : result; 606} 607 608SyscallReturn 609fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 610{ 611 int index = 0; 612 int tgt_fd = p->getSyscallArg(tc, index); 613 614 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 615 if (!ffdp) 616 return -EBADF; 617 int sim_fd = ffdp->getSimFD(); 618 619 /* XXX endianess */ 620 uint32_t owner = p->getSyscallArg(tc, index); 621 uid_t hostOwner = owner; 622 uint32_t group = p->getSyscallArg(tc, index); 623 gid_t hostGroup = group; 624 625 int result = fchown(sim_fd, hostOwner, hostGroup); 626 return (result == -1) ? -errno : result; 627} 628 629 630/** 631 * TODO: there's a bit more involved here since file descriptors created with 632 * dup are supposed to share a file description. So, there is a problem with 633 * maintaining fields like file offset or flags since an update to such a 634 * field won't be reflected in the metadata for the fd entries that we 635 * maintain to hold metadata for checkpoint restoration. 636 */ 637SyscallReturn 638dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 639{ 640 int index = 0; 641 int tgt_fd = p->getSyscallArg(tc, index); 642 643 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 644 if (!old_hbfdp) 645 return -EBADF; 646 int sim_fd = old_hbfdp->getSimFD(); 647 648 int result = dup(sim_fd); 649 int local_errno = errno; 650 651 std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone(); 652 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep); 653 new_hbfdp->setSimFD(result); 654 655 return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); 656} 657 658SyscallReturn 659fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 660{ 661 int arg; 662 int index = 0; 663 int tgt_fd = p->getSyscallArg(tc, index); 664 int cmd = p->getSyscallArg(tc, index); 665 666 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 667 if (!hbfdp) 668 return -EBADF; 669 int sim_fd = hbfdp->getSimFD(); 670 671 int coe = hbfdp->getCOE(); 672 673 switch (cmd) { 674 case F_GETFD: 675 return coe & FD_CLOEXEC; 676 677 case F_SETFD: { 678 arg = p->getSyscallArg(tc, index); 679 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 680 return 0; 681 } 682 683 // Rely on the host to maintain the file status flags for this file 684 // description rather than maintain it ourselves. Admittedly, this 685 // is suboptimal (and possibly error prone), but it is difficult to 686 // maintain the flags by tracking them across the different descriptors 687 // (that refer to this file description) caused by clone, dup, and 688 // subsequent fcntls. 689 case F_GETFL: 690 case F_SETFL: { 691 arg = p->getSyscallArg(tc, index); 692 int rv = fcntl(sim_fd, cmd, arg); 693 return (rv == -1) ? -errno : rv; 694 } 695 696 default: 697 warn("fcntl: unsupported command %d\n", cmd); 698 return 0; 699 } 700} 701 702SyscallReturn 703fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 704{ 705 int index = 0; 706 int tgt_fd = p->getSyscallArg(tc, index); 707 708 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 709 if (!hbfdp) 710 return -EBADF; 711 int sim_fd = hbfdp->getSimFD(); 712 713 int cmd = p->getSyscallArg(tc, index); 714 switch (cmd) { 715 case 33: //F_GETLK64 716 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 717 return -EMFILE; 718 719 case 34: // F_SETLK64 720 case 35: // F_SETLKW64 721 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 722 tgt_fd); 723 return -EMFILE; 724 725 default: 726 // not sure if this is totally valid, but we'll pass it through 727 // to the underlying OS 728 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 729 return fcntl(sim_fd, cmd); 730 } 731} 732 733SyscallReturn 734pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 735 ThreadContext *tc) 736{ 737 int sim_fds[2], tgt_fds[2]; 738 739 int pipe_retval = pipe(sim_fds); 740 if (pipe_retval < 0) 741 return pipe_retval; 742 743 auto rend = PipeFDEntry::EndType::read; 744 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 745 746 auto wend = PipeFDEntry::EndType::write; 747 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 748 749 tgt_fds[0] = process->fds->allocFD(rpfd); 750 tgt_fds[1] = process->fds->allocFD(wpfd); 751 752 /** 753 * Now patch the read object to record the target file descriptor chosen 754 * as the write end of the pipe. 755 */ 756 rpfd->setPipeReadSource(tgt_fds[1]); 757 758 /** 759 * Alpha Linux convention for pipe() is that fd[0] is returned as 760 * the return value of the function, and fd[1] is returned in r20. 761 */ 762 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 763 return sim_fds[0]; 764} 765 766SyscallReturn 767setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 768 ThreadContext *tc) 769{ 770 int index = 0; 771 int pid = process->getSyscallArg(tc, index); 772 int pgid = process->getSyscallArg(tc, index); 773 774 if (pgid < 0) 775 return -EINVAL; 776 777 if (pid == 0) { 778 process->setpgid(process->pid()); 779 return 0; 780 } 781 782 Process *matched_ph = NULL; 783 System *sysh = tc->getSystemPtr(); 784 785 // Retrieves process pointer from active/suspended thread contexts. 786 for (int i = 0; i < sysh->numContexts(); i++) { 787 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 788 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 789 Process *walk_ph = (Process*)temp_h; 790 791 if (walk_ph && walk_ph->pid() == process->pid()) 792 matched_ph = walk_ph; 793 } 794 } 795 796 assert(matched_ph != NULL); 797 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 798 799 return 0; 800} 801 802SyscallReturn 803getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 804 ThreadContext *tc) 805{ 806 // Make up a PID. There's no interprocess communication in 807 // fake_syscall mode, so there's no way for a process to know it's 808 // not getting a unique value. 809 810 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 811 return process->pid(); 812} 813 814 815SyscallReturn 816getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 817 ThreadContext *tc) 818{ 819 // Make up a UID and EUID... it shouldn't matter, and we want the 820 // simulation to be deterministic. 821 822 // EUID goes in r20. 823 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 824 return process->uid(); // UID 825} 826 827 828SyscallReturn 829getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 830 ThreadContext *tc) 831{ 832 // Get current group ID. EGID goes in r20. 833 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 834 return process->gid(); 835} 836 837 838SyscallReturn 839setuidFunc(SyscallDesc *desc, int callnum, Process *process, 840 ThreadContext *tc) 841{ 842 // can't fathom why a benchmark would call this. 843 int index = 0; 844 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 845 return 0; 846} 847 848SyscallReturn 849getpidFunc(SyscallDesc *desc, int callnum, Process *process, 850 ThreadContext *tc) 851{ 852 return process->tgid(); 853} 854 855SyscallReturn 856gettidFunc(SyscallDesc *desc, int callnum, Process *process, 857 ThreadContext *tc) 858{ 859 return process->pid(); 860} 861 862SyscallReturn 863getppidFunc(SyscallDesc *desc, int callnum, Process *process, 864 ThreadContext *tc) 865{ 866 return process->ppid(); 867} 868 869SyscallReturn 870getuidFunc(SyscallDesc *desc, int callnum, Process *process, 871 ThreadContext *tc) 872{ 873 return process->uid(); // UID 874} 875 876SyscallReturn 877geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 878 ThreadContext *tc) 879{ 880 return process->euid(); // UID 881} 882 883SyscallReturn 884getgidFunc(SyscallDesc *desc, int callnum, Process *process, 885 ThreadContext *tc) 886{ 887 return process->gid(); 888} 889 890SyscallReturn 891getegidFunc(SyscallDesc *desc, int callnum, Process *process, 892 ThreadContext *tc) 893{ 894 return process->egid(); 895} 896 897SyscallReturn 898fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 899{ 900#if NO_FALLOCATE 901 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 902#else 903 int index = 0; 904 int tgt_fd = p->getSyscallArg(tc, index); 905 int mode = p->getSyscallArg(tc, index); 906 off_t offset = p->getSyscallArg(tc, index); 907 off_t len = p->getSyscallArg(tc, index); 908 909 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 910 if (!ffdp) 911 return -EBADF; 912 int sim_fd = ffdp->getSimFD(); 913 914 int result = fallocate(sim_fd, mode, offset, len); 915 if (result < 0) 916 return -errno; 917#endif 918 return 0; 919} 920 921SyscallReturn 922accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 923 int index) 924{ 925 string path; 926 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 927 return -EFAULT; 928 929 // Adjust path for current working directory 930 path = p->fullPath(path); 931 932 mode_t mode = p->getSyscallArg(tc, index); 933 934 int result = access(path.c_str(), mode); 935 return (result == -1) ? -errno : result; 936} 937 938SyscallReturn 939accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 940{ 941 return accessFunc(desc, callnum, p, tc, 0); 942} 943 944