syscall_emul.cc revision 11908:2fd0307d03e9
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 * FIXME: The file description is not shared among file descriptors created 631 * with dup. Really, it's difficult to maintain fields like file offset or 632 * flags since an update to such a field won't be reflected in the metadata 633 * for the fd entries that we maintain for checkpoint restoration. 634 */ 635SyscallReturn 636dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 637{ 638 int index = 0; 639 int tgt_fd = p->getSyscallArg(tc, index); 640 641 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 642 if (!old_hbfdp) 643 return -EBADF; 644 int sim_fd = old_hbfdp->getSimFD(); 645 646 int result = dup(sim_fd); 647 if (result == -1) 648 return -errno; 649 650 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 651 new_hbfdp->setSimFD(result); 652 new_hbfdp->setCOE(false); 653 return p->fds->allocFD(new_hbfdp); 654} 655 656SyscallReturn 657dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 658{ 659 int index = 0; 660 661 int old_tgt_fd = p->getSyscallArg(tc, index); 662 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 663 if (!old_hbp) 664 return -EBADF; 665 int old_sim_fd = old_hbp->getSimFD(); 666 667 /** 668 * We need a valid host file descriptor number to be able to pass into 669 * the second parameter for dup2 (newfd), but we don't know what the 670 * viable numbers are; we execute the open call to retrieve one. 671 */ 672 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 673 if (res_fd == -1) 674 return -errno; 675 676 int new_tgt_fd = p->getSyscallArg(tc, index); 677 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 678 if (new_hbp) 679 p->fds->closeFDEntry(new_tgt_fd); 680 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 681 new_hbp->setSimFD(res_fd); 682 new_hbp->setCOE(false); 683 684 return p->fds->allocFD(new_hbp); 685} 686 687SyscallReturn 688fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 689{ 690 int arg; 691 int index = 0; 692 int tgt_fd = p->getSyscallArg(tc, index); 693 int cmd = p->getSyscallArg(tc, index); 694 695 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 696 if (!hbfdp) 697 return -EBADF; 698 int sim_fd = hbfdp->getSimFD(); 699 700 int coe = hbfdp->getCOE(); 701 702 switch (cmd) { 703 case F_GETFD: 704 return coe & FD_CLOEXEC; 705 706 case F_SETFD: { 707 arg = p->getSyscallArg(tc, index); 708 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 709 return 0; 710 } 711 712 // Rely on the host to maintain the file status flags for this file 713 // description rather than maintain it ourselves. Admittedly, this 714 // is suboptimal (and possibly error prone), but it is difficult to 715 // maintain the flags by tracking them across the different descriptors 716 // (that refer to this file description) caused by clone, dup, and 717 // subsequent fcntls. 718 case F_GETFL: 719 case F_SETFL: { 720 arg = p->getSyscallArg(tc, index); 721 int rv = fcntl(sim_fd, cmd, arg); 722 return (rv == -1) ? -errno : rv; 723 } 724 725 default: 726 warn("fcntl: unsupported command %d\n", cmd); 727 return 0; 728 } 729} 730 731SyscallReturn 732fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 733{ 734 int index = 0; 735 int tgt_fd = p->getSyscallArg(tc, index); 736 737 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 738 if (!hbfdp) 739 return -EBADF; 740 int sim_fd = hbfdp->getSimFD(); 741 742 int cmd = p->getSyscallArg(tc, index); 743 switch (cmd) { 744 case 33: //F_GETLK64 745 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 746 return -EMFILE; 747 748 case 34: // F_SETLK64 749 case 35: // F_SETLKW64 750 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 751 tgt_fd); 752 return -EMFILE; 753 754 default: 755 // not sure if this is totally valid, but we'll pass it through 756 // to the underlying OS 757 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 758 return fcntl(sim_fd, cmd); 759 } 760} 761 762SyscallReturn 763pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 764 bool pseudoPipe) 765{ 766 Addr tgt_addr = 0; 767 if (!pseudoPipe) { 768 int index = 0; 769 tgt_addr = p->getSyscallArg(tc, index); 770 } 771 772 int sim_fds[2], tgt_fds[2]; 773 774 int pipe_retval = pipe(sim_fds); 775 if (pipe_retval == -1) 776 return -errno; 777 778 auto rend = PipeFDEntry::EndType::read; 779 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 780 tgt_fds[0] = p->fds->allocFD(rpfd); 781 782 auto wend = PipeFDEntry::EndType::write; 783 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 784 tgt_fds[1] = p->fds->allocFD(wpfd); 785 786 /** 787 * Now patch the read object to record the target file descriptor chosen 788 * as the write end of the pipe. 789 */ 790 rpfd->setPipeReadSource(tgt_fds[1]); 791 792 /** 793 * Alpha Linux convention for pipe() is that fd[0] is returned as 794 * the return value of the function, and fd[1] is returned in r20. 795 */ 796 if (pseudoPipe) { 797 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 798 return tgt_fds[0]; 799 } 800 801 /** 802 * Copy the target file descriptors into buffer space and then copy 803 * the buffer space back into the target address space. 804 */ 805 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 806 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 807 buf_ptr[0] = tgt_fds[0]; 808 buf_ptr[1] = tgt_fds[1]; 809 tgt_handle.copyOut(tc->getMemProxy()); 810 return 0; 811} 812 813SyscallReturn 814pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 815 ThreadContext *tc) 816{ 817 return pipeImpl(desc, callnum, process, tc, true); 818} 819 820SyscallReturn 821pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 822{ 823 return pipeImpl(desc, callnum, process, tc, false); 824} 825 826SyscallReturn 827setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 828 ThreadContext *tc) 829{ 830 int index = 0; 831 int pid = process->getSyscallArg(tc, index); 832 int pgid = process->getSyscallArg(tc, index); 833 834 if (pgid < 0) 835 return -EINVAL; 836 837 if (pid == 0) { 838 process->setpgid(process->pid()); 839 return 0; 840 } 841 842 Process *matched_ph = NULL; 843 System *sysh = tc->getSystemPtr(); 844 845 // Retrieves process pointer from active/suspended thread contexts. 846 for (int i = 0; i < sysh->numContexts(); i++) { 847 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 848 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 849 Process *walk_ph = (Process*)temp_h; 850 851 if (walk_ph && walk_ph->pid() == process->pid()) 852 matched_ph = walk_ph; 853 } 854 } 855 856 assert(matched_ph != NULL); 857 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 858 859 return 0; 860} 861 862SyscallReturn 863getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 864 ThreadContext *tc) 865{ 866 // Make up a PID. There's no interprocess communication in 867 // fake_syscall mode, so there's no way for a process to know it's 868 // not getting a unique value. 869 870 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 871 return process->pid(); 872} 873 874 875SyscallReturn 876getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 877 ThreadContext *tc) 878{ 879 // Make up a UID and EUID... it shouldn't matter, and we want the 880 // simulation to be deterministic. 881 882 // EUID goes in r20. 883 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 884 return process->uid(); // UID 885} 886 887 888SyscallReturn 889getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 890 ThreadContext *tc) 891{ 892 // Get current group ID. EGID goes in r20. 893 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 894 return process->gid(); 895} 896 897 898SyscallReturn 899setuidFunc(SyscallDesc *desc, int callnum, Process *process, 900 ThreadContext *tc) 901{ 902 // can't fathom why a benchmark would call this. 903 int index = 0; 904 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 905 return 0; 906} 907 908SyscallReturn 909getpidFunc(SyscallDesc *desc, int callnum, Process *process, 910 ThreadContext *tc) 911{ 912 return process->tgid(); 913} 914 915SyscallReturn 916gettidFunc(SyscallDesc *desc, int callnum, Process *process, 917 ThreadContext *tc) 918{ 919 return process->pid(); 920} 921 922SyscallReturn 923getppidFunc(SyscallDesc *desc, int callnum, Process *process, 924 ThreadContext *tc) 925{ 926 return process->ppid(); 927} 928 929SyscallReturn 930getuidFunc(SyscallDesc *desc, int callnum, Process *process, 931 ThreadContext *tc) 932{ 933 return process->uid(); // UID 934} 935 936SyscallReturn 937geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 938 ThreadContext *tc) 939{ 940 return process->euid(); // UID 941} 942 943SyscallReturn 944getgidFunc(SyscallDesc *desc, int callnum, Process *process, 945 ThreadContext *tc) 946{ 947 return process->gid(); 948} 949 950SyscallReturn 951getegidFunc(SyscallDesc *desc, int callnum, Process *process, 952 ThreadContext *tc) 953{ 954 return process->egid(); 955} 956 957SyscallReturn 958fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 959{ 960#if NO_FALLOCATE 961 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 962#else 963 int index = 0; 964 int tgt_fd = p->getSyscallArg(tc, index); 965 int mode = p->getSyscallArg(tc, index); 966 off_t offset = p->getSyscallArg(tc, index); 967 off_t len = p->getSyscallArg(tc, index); 968 969 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 970 if (!ffdp) 971 return -EBADF; 972 int sim_fd = ffdp->getSimFD(); 973 974 int result = fallocate(sim_fd, mode, offset, len); 975 if (result < 0) 976 return -errno; 977#endif 978 return 0; 979} 980 981SyscallReturn 982accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 983 int index) 984{ 985 string path; 986 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 987 return -EFAULT; 988 989 // Adjust path for current working directory 990 path = p->fullPath(path); 991 992 mode_t mode = p->getSyscallArg(tc, index); 993 994 int result = access(path.c_str(), mode); 995 return (result == -1) ? -errno : result; 996} 997 998SyscallReturn 999accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1000{ 1001 return accessFunc(desc, callnum, p, tc, 0); 1002} 1003 1004