syscall_emul.cc revision 11905:4a771f8756ad
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 { 182 size_needed = PageBytes - size_needed; 183 tp.memsetBlob(next_page, zero, size_needed); 184 } 185 } 186 } 187 } 188 189 mem_state->setBrkPoint(new_brk); 190 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 191 mem_state->getBrkPoint()); 192 return mem_state->getBrkPoint(); 193} 194 195SyscallReturn 196setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process, 197 ThreadContext *tc) 198{ 199 int index = 0; 200 uint64_t tidPtr = process->getSyscallArg(tc, index); 201 202 process->childClearTID = tidPtr; 203 return process->pid(); 204} 205 206SyscallReturn 207closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 208{ 209 int index = 0; 210 int tgt_fd = p->getSyscallArg(tc, index); 211 212 return p->fds->closeFDEntry(tgt_fd); 213} 214 215 216SyscallReturn 217readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 218{ 219 int index = 0; 220 int tgt_fd = p->getSyscallArg(tc, index); 221 Addr bufPtr = p->getSyscallArg(tc, index); 222 int nbytes = p->getSyscallArg(tc, index); 223 224 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 225 if (!hbfdp) 226 return -EBADF; 227 int sim_fd = hbfdp->getSimFD(); 228 229 BufferArg bufArg(bufPtr, nbytes); 230 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 231 232 if (bytes_read > 0) 233 bufArg.copyOut(tc->getMemProxy()); 234 235 return bytes_read; 236} 237 238SyscallReturn 239writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 240{ 241 int index = 0; 242 int tgt_fd = p->getSyscallArg(tc, index); 243 Addr bufPtr = p->getSyscallArg(tc, index); 244 int nbytes = p->getSyscallArg(tc, index); 245 246 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 247 if (!hbfdp) 248 return -EBADF; 249 int sim_fd = hbfdp->getSimFD(); 250 251 BufferArg bufArg(bufPtr, nbytes); 252 bufArg.copyIn(tc->getMemProxy()); 253 254 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 255 256 fsync(sim_fd); 257 258 return bytes_written; 259} 260 261 262SyscallReturn 263lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 264{ 265 int index = 0; 266 int tgt_fd = p->getSyscallArg(tc, index); 267 uint64_t offs = p->getSyscallArg(tc, index); 268 int whence = p->getSyscallArg(tc, index); 269 270 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 271 if (!ffdp) 272 return -EBADF; 273 int sim_fd = ffdp->getSimFD(); 274 275 off_t result = lseek(sim_fd, offs, whence); 276 277 return (result == (off_t)-1) ? -errno : result; 278} 279 280 281SyscallReturn 282_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 283{ 284 int index = 0; 285 int tgt_fd = p->getSyscallArg(tc, index); 286 uint64_t offset_high = p->getSyscallArg(tc, index); 287 uint32_t offset_low = p->getSyscallArg(tc, index); 288 Addr result_ptr = p->getSyscallArg(tc, index); 289 int whence = p->getSyscallArg(tc, index); 290 291 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 292 if (!ffdp) 293 return -EBADF; 294 int sim_fd = ffdp->getSimFD(); 295 296 uint64_t offset = (offset_high << 32) | offset_low; 297 298 uint64_t result = lseek(sim_fd, offset, whence); 299 result = TheISA::htog(result); 300 301 if (result == (off_t)-1) 302 return -errno; 303 // Assuming that the size of loff_t is 64 bits on the target platform 304 BufferArg result_buf(result_ptr, sizeof(result)); 305 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 306 result_buf.copyOut(tc->getMemProxy()); 307 return 0; 308} 309 310 311SyscallReturn 312munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 313{ 314 // With mmap more fully implemented, it might be worthwhile to bite 315 // the bullet and implement munmap. Should allow us to reuse simulated 316 // memory. 317 return 0; 318} 319 320 321const char *hostname = "m5.eecs.umich.edu"; 322 323SyscallReturn 324gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 325{ 326 int index = 0; 327 Addr bufPtr = p->getSyscallArg(tc, index); 328 int name_len = p->getSyscallArg(tc, index); 329 BufferArg name(bufPtr, name_len); 330 331 strncpy((char *)name.bufferPtr(), hostname, name_len); 332 333 name.copyOut(tc->getMemProxy()); 334 335 return 0; 336} 337 338SyscallReturn 339getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 340{ 341 int result = 0; 342 int index = 0; 343 Addr bufPtr = p->getSyscallArg(tc, index); 344 unsigned long size = p->getSyscallArg(tc, index); 345 BufferArg buf(bufPtr, size); 346 347 // Is current working directory defined? 348 string cwd = p->getcwd(); 349 if (!cwd.empty()) { 350 if (cwd.length() >= size) { 351 // Buffer too small 352 return -ERANGE; 353 } 354 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 355 result = cwd.length(); 356 } else { 357 if (getcwd((char *)buf.bufferPtr(), size)) { 358 result = strlen((char *)buf.bufferPtr()); 359 } else { 360 result = -1; 361 } 362 } 363 364 buf.copyOut(tc->getMemProxy()); 365 366 return (result == -1) ? -errno : result; 367} 368 369/// Target open() handler. 370SyscallReturn 371readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 372 ThreadContext *tc) 373{ 374 return readlinkFunc(desc, callnum, process, tc, 0); 375} 376 377SyscallReturn 378readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 379 int index) 380{ 381 string path; 382 383 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 384 return -EFAULT; 385 386 // Adjust path for current working directory 387 path = p->fullPath(path); 388 389 Addr bufPtr = p->getSyscallArg(tc, index); 390 size_t bufsiz = p->getSyscallArg(tc, index); 391 392 BufferArg buf(bufPtr, bufsiz); 393 394 int result = -1; 395 if (path != "/proc/self/exe") { 396 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 397 } else { 398 // Emulate readlink() called on '/proc/self/exe' should return the 399 // absolute path of the binary running in the simulated system (the 400 // Process' executable). It is possible that using this path in 401 // the simulated system will result in unexpected behavior if: 402 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 403 // called binary calls readlink(). 404 // 2) The host's full path to the running benchmark changes from one 405 // simulation to another. This can result in different simulated 406 // performance since the simulated system will process the binary 407 // path differently, even if the binary itself does not change. 408 409 // Get the absolute canonical path to the running application 410 char real_path[PATH_MAX]; 411 char *check_real_path = realpath(p->progName(), real_path); 412 if (!check_real_path) { 413 fatal("readlink('/proc/self/exe') unable to resolve path to " 414 "executable: %s", p->progName()); 415 } 416 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 417 size_t real_path_len = strlen(real_path); 418 if (real_path_len > bufsiz) { 419 // readlink will truncate the contents of the 420 // path to ensure it is no more than bufsiz 421 result = bufsiz; 422 } else { 423 result = real_path_len; 424 } 425 426 // Issue a warning about potential unexpected results 427 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 428 "results in various settings.\n Returning '%s'\n", 429 (char*)buf.bufferPtr()); 430 } 431 432 buf.copyOut(tc->getMemProxy()); 433 434 return (result == -1) ? -errno : result; 435} 436 437SyscallReturn 438unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 439{ 440 return unlinkHelper(desc, num, p, tc, 0); 441} 442 443SyscallReturn 444unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 445 int index) 446{ 447 string path; 448 449 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 450 return -EFAULT; 451 452 // Adjust path for current working directory 453 path = p->fullPath(path); 454 455 int result = unlink(path.c_str()); 456 return (result == -1) ? -errno : result; 457} 458 459 460SyscallReturn 461mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 462{ 463 string path; 464 465 int index = 0; 466 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 467 return -EFAULT; 468 469 // Adjust path for current working directory 470 path = p->fullPath(path); 471 472 mode_t mode = p->getSyscallArg(tc, index); 473 474 int result = mkdir(path.c_str(), mode); 475 return (result == -1) ? -errno : result; 476} 477 478SyscallReturn 479renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 480{ 481 string old_name; 482 483 int index = 0; 484 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 485 return -EFAULT; 486 487 string new_name; 488 489 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 490 return -EFAULT; 491 492 // Adjust path for current working directory 493 old_name = p->fullPath(old_name); 494 new_name = p->fullPath(new_name); 495 496 int64_t result = rename(old_name.c_str(), new_name.c_str()); 497 return (result == -1) ? -errno : result; 498} 499 500SyscallReturn 501truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 502{ 503 string path; 504 505 int index = 0; 506 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 507 return -EFAULT; 508 509 off_t length = p->getSyscallArg(tc, index); 510 511 // Adjust path for current working directory 512 path = p->fullPath(path); 513 514 int result = truncate(path.c_str(), length); 515 return (result == -1) ? -errno : result; 516} 517 518SyscallReturn 519ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 520{ 521 int index = 0; 522 int tgt_fd = p->getSyscallArg(tc, index); 523 off_t length = p->getSyscallArg(tc, index); 524 525 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 526 if (!ffdp) 527 return -EBADF; 528 int sim_fd = ffdp->getSimFD(); 529 530 int result = ftruncate(sim_fd, length); 531 return (result == -1) ? -errno : result; 532} 533 534SyscallReturn 535truncate64Func(SyscallDesc *desc, int num, 536 Process *process, ThreadContext *tc) 537{ 538 int index = 0; 539 string path; 540 541 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 542 return -EFAULT; 543 544 int64_t length = process->getSyscallArg(tc, index, 64); 545 546 // Adjust path for current working directory 547 path = process->fullPath(path); 548 549#if NO_STAT64 550 int result = truncate(path.c_str(), length); 551#else 552 int result = truncate64(path.c_str(), length); 553#endif 554 return (result == -1) ? -errno : result; 555} 556 557SyscallReturn 558ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 559{ 560 int index = 0; 561 int tgt_fd = p->getSyscallArg(tc, index); 562 int64_t length = p->getSyscallArg(tc, index, 64); 563 564 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 565 if (!ffdp) 566 return -EBADF; 567 int sim_fd = ffdp->getSimFD(); 568 569#if NO_STAT64 570 int result = ftruncate(sim_fd, length); 571#else 572 int result = ftruncate64(sim_fd, length); 573#endif 574 return (result == -1) ? -errno : result; 575} 576 577SyscallReturn 578umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 579{ 580 // Letting the simulated program change the simulator's umask seems like 581 // a bad idea. Compromise by just returning the current umask but not 582 // changing anything. 583 mode_t oldMask = umask(0); 584 umask(oldMask); 585 return (int)oldMask; 586} 587 588SyscallReturn 589chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 590{ 591 string path; 592 593 int index = 0; 594 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 595 return -EFAULT; 596 597 /* XXX endianess */ 598 uint32_t owner = p->getSyscallArg(tc, index); 599 uid_t hostOwner = owner; 600 uint32_t group = p->getSyscallArg(tc, index); 601 gid_t hostGroup = group; 602 603 // Adjust path for current working directory 604 path = p->fullPath(path); 605 606 int result = chown(path.c_str(), hostOwner, hostGroup); 607 return (result == -1) ? -errno : result; 608} 609 610SyscallReturn 611fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 612{ 613 int index = 0; 614 int tgt_fd = p->getSyscallArg(tc, index); 615 616 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 617 if (!ffdp) 618 return -EBADF; 619 int sim_fd = ffdp->getSimFD(); 620 621 /* XXX endianess */ 622 uint32_t owner = p->getSyscallArg(tc, index); 623 uid_t hostOwner = owner; 624 uint32_t group = p->getSyscallArg(tc, index); 625 gid_t hostGroup = group; 626 627 int result = fchown(sim_fd, hostOwner, hostGroup); 628 return (result == -1) ? -errno : result; 629} 630 631 632/** 633 * TODO: there's a bit more involved here since file descriptors created with 634 * dup are supposed to share a file description. So, there is a problem with 635 * maintaining fields like file offset or flags since an update to such a 636 * field won't be reflected in the metadata for the fd entries that we 637 * maintain to hold metadata for checkpoint restoration. 638 */ 639SyscallReturn 640dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 641{ 642 int index = 0; 643 int tgt_fd = p->getSyscallArg(tc, index); 644 645 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 646 if (!old_hbfdp) 647 return -EBADF; 648 int sim_fd = old_hbfdp->getSimFD(); 649 650 int result = dup(sim_fd); 651 int local_errno = errno; 652 653 std::shared_ptr<FDEntry> new_fdep = old_hbfdp->clone(); 654 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(new_fdep); 655 new_hbfdp->setSimFD(result); 656 657 return (result == -1) ? -local_errno : p->fds->allocFD(new_fdep); 658} 659 660SyscallReturn 661fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 662{ 663 int arg; 664 int index = 0; 665 int tgt_fd = p->getSyscallArg(tc, index); 666 int cmd = p->getSyscallArg(tc, index); 667 668 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 669 if (!hbfdp) 670 return -EBADF; 671 int sim_fd = hbfdp->getSimFD(); 672 673 int coe = hbfdp->getCOE(); 674 675 switch (cmd) { 676 case F_GETFD: 677 return coe & FD_CLOEXEC; 678 679 case F_SETFD: { 680 arg = p->getSyscallArg(tc, index); 681 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 682 return 0; 683 } 684 685 // Rely on the host to maintain the file status flags for this file 686 // description rather than maintain it ourselves. Admittedly, this 687 // is suboptimal (and possibly error prone), but it is difficult to 688 // maintain the flags by tracking them across the different descriptors 689 // (that refer to this file description) caused by clone, dup, and 690 // subsequent fcntls. 691 case F_GETFL: 692 case F_SETFL: { 693 arg = p->getSyscallArg(tc, index); 694 int rv = fcntl(sim_fd, cmd, arg); 695 return (rv == -1) ? -errno : rv; 696 } 697 698 default: 699 warn("fcntl: unsupported command %d\n", cmd); 700 return 0; 701 } 702} 703 704SyscallReturn 705fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 706{ 707 int index = 0; 708 int tgt_fd = p->getSyscallArg(tc, index); 709 710 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 711 if (!hbfdp) 712 return -EBADF; 713 int sim_fd = hbfdp->getSimFD(); 714 715 int cmd = p->getSyscallArg(tc, index); 716 switch (cmd) { 717 case 33: //F_GETLK64 718 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 719 return -EMFILE; 720 721 case 34: // F_SETLK64 722 case 35: // F_SETLKW64 723 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 724 tgt_fd); 725 return -EMFILE; 726 727 default: 728 // not sure if this is totally valid, but we'll pass it through 729 // to the underlying OS 730 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 731 return fcntl(sim_fd, cmd); 732 // return 0; 733 } 734} 735 736SyscallReturn 737pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 738 ThreadContext *tc) 739{ 740 int sim_fds[2], tgt_fds[2]; 741 742 int pipe_retval = pipe(sim_fds); 743 if (pipe_retval < 0) 744 return pipe_retval; 745 746 auto rend = PipeFDEntry::EndType::read; 747 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 748 749 auto wend = PipeFDEntry::EndType::write; 750 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 751 752 tgt_fds[0] = process->fds->allocFD(rpfd); 753 tgt_fds[1] = process->fds->allocFD(wpfd); 754 755 /** 756 * Now patch the read object to record the target file descriptor chosen 757 * as the write end of the pipe. 758 */ 759 rpfd->setPipeReadSource(tgt_fds[1]); 760 761 /** 762 * Alpha Linux convention for pipe() is that fd[0] is returned as 763 * the return value of the function, and fd[1] is returned in r20. 764 */ 765 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 766 return sim_fds[0]; 767} 768 769SyscallReturn 770setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 771 ThreadContext *tc) 772{ 773 int index = 0; 774 int pid = process->getSyscallArg(tc, index); 775 int pgid = process->getSyscallArg(tc, index); 776 777 if (pgid < 0) 778 return -EINVAL; 779 780 if (pid == 0) { 781 process->setpgid(process->pid()); 782 return 0; 783 } 784 785 Process *matched_ph = NULL; 786 System *sysh = tc->getSystemPtr(); 787 788 // Retrieves process pointer from active/suspended thread contexts. 789 for (int i = 0; i < sysh->numContexts(); i++) { 790 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 791 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 792 Process *walk_ph = (Process*)temp_h; 793 794 if (walk_ph && walk_ph->pid() == process->pid()) 795 matched_ph = walk_ph; 796 } 797 } 798 799 assert(matched_ph != NULL); 800 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 801 802 return 0; 803} 804 805SyscallReturn 806getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 807 ThreadContext *tc) 808{ 809 // Make up a PID. There's no interprocess communication in 810 // fake_syscall mode, so there's no way for a process to know it's 811 // not getting a unique value. 812 813 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 814 return process->pid(); 815} 816 817 818SyscallReturn 819getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 820 ThreadContext *tc) 821{ 822 // Make up a UID and EUID... it shouldn't matter, and we want the 823 // simulation to be deterministic. 824 825 // EUID goes in r20. 826 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 827 return process->uid(); // UID 828} 829 830 831SyscallReturn 832getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 833 ThreadContext *tc) 834{ 835 // Get current group ID. EGID goes in r20. 836 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 837 return process->gid(); 838} 839 840 841SyscallReturn 842setuidFunc(SyscallDesc *desc, int callnum, Process *process, 843 ThreadContext *tc) 844{ 845 // can't fathom why a benchmark would call this. 846 int index = 0; 847 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 848 return 0; 849} 850 851SyscallReturn 852getpidFunc(SyscallDesc *desc, int callnum, Process *process, 853 ThreadContext *tc) 854{ 855 return process->tgid(); 856} 857 858SyscallReturn 859gettidFunc(SyscallDesc *desc, int callnum, Process *process, 860 ThreadContext *tc) 861{ 862 return process->pid(); 863} 864 865SyscallReturn 866getppidFunc(SyscallDesc *desc, int callnum, Process *process, 867 ThreadContext *tc) 868{ 869 return process->ppid(); 870} 871 872SyscallReturn 873getuidFunc(SyscallDesc *desc, int callnum, Process *process, 874 ThreadContext *tc) 875{ 876 return process->uid(); // UID 877} 878 879SyscallReturn 880geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 881 ThreadContext *tc) 882{ 883 return process->euid(); // UID 884} 885 886SyscallReturn 887getgidFunc(SyscallDesc *desc, int callnum, Process *process, 888 ThreadContext *tc) 889{ 890 return process->gid(); 891} 892 893SyscallReturn 894getegidFunc(SyscallDesc *desc, int callnum, Process *process, 895 ThreadContext *tc) 896{ 897 return process->egid(); 898} 899 900SyscallReturn 901fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 902{ 903#if NO_FALLOCATE 904 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 905#else 906 int index = 0; 907 int tgt_fd = p->getSyscallArg(tc, index); 908 int mode = p->getSyscallArg(tc, index); 909 off_t offset = p->getSyscallArg(tc, index); 910 off_t len = p->getSyscallArg(tc, index); 911 912 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 913 if (!ffdp) 914 return -EBADF; 915 int sim_fd = ffdp->getSimFD(); 916 917 int result = fallocate(sim_fd, mode, offset, len); 918 if (result < 0) 919 return -errno; 920#endif 921 return 0; 922} 923 924SyscallReturn 925accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 926 int index) 927{ 928 string path; 929 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 930 return -EFAULT; 931 932 // Adjust path for current working directory 933 path = p->fullPath(path); 934 935 mode_t mode = p->getSyscallArg(tc, index); 936 937 int result = access(path.c_str(), mode); 938 return (result == -1) ? -errno : result; 939} 940 941SyscallReturn 942accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 943{ 944 return accessFunc(desc, callnum, p, tc, 0); 945} 946 947