syscall_emul.cc revision 11911:fecd8de0ec8e
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 <csignal> 38#include <iostream> 39#include <string> 40 41#include "arch/utility.hh" 42#include "base/chunk_generator.hh" 43#include "base/trace.hh" 44#include "config/the_isa.hh" 45#include "cpu/thread_context.hh" 46#include "mem/page_table.hh" 47#include "sim/process.hh" 48#include "sim/sim_exit.hh" 49#include "sim/syscall_debug_macros.hh" 50#include "sim/syscall_desc.hh" 51#include "sim/system.hh" 52 53using namespace std; 54using namespace TheISA; 55 56SyscallReturn 57unimplementedFunc(SyscallDesc *desc, int callnum, Process *process, 58 ThreadContext *tc) 59{ 60 fatal("syscall %s (#%d) unimplemented.", desc->name(), callnum); 61 62 return 1; 63} 64 65 66SyscallReturn 67ignoreFunc(SyscallDesc *desc, int callnum, Process *process, 68 ThreadContext *tc) 69{ 70 if (desc->needWarning()) { 71 warn("ignoring syscall %s(...)%s", desc->name(), desc->warnOnce() ? 72 "\n (further warnings will be suppressed)" : ""); 73 } 74 75 return 0; 76} 77 78static void 79exitFutexWake(ThreadContext *tc, Addr addr, uint64_t tgid) 80{ 81 // Clear value at address pointed to by thread's childClearTID field. 82 BufferArg ctidBuf(addr, sizeof(long)); 83 long *ctid = (long *)ctidBuf.bufferPtr(); 84 *ctid = 0; 85 ctidBuf.copyOut(tc->getMemProxy()); 86 87 FutexMap &futex_map = tc->getSystemPtr()->futexMap; 88 // Wake one of the waiting threads. 89 futex_map.wakeup(addr, tgid, 1); 90} 91 92static SyscallReturn 93exitImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 94 bool group) 95{ 96 int index = 0; 97 int status = p->getSyscallArg(tc, index); 98 99 System *sys = tc->getSystemPtr(); 100 101 int activeContexts = 0; 102 for (auto &system: sys->systemList) 103 activeContexts += system->numRunningContexts(); 104 if (activeContexts == 1) { 105 exitSimLoop("exiting with last active thread context", status & 0xff); 106 return status; 107 } 108 109 if (group) 110 *p->exitGroup = true; 111 112 if (p->childClearTID) 113 exitFutexWake(tc, p->childClearTID, p->tgid()); 114 115 bool last_thread = true; 116 Process *parent = nullptr, *tg_lead = nullptr; 117 for (int i = 0; last_thread && i < sys->numContexts(); i++) { 118 Process *walk; 119 if (!(walk = sys->threadContexts[i]->getProcessPtr())) 120 continue; 121 122 /** 123 * Threads in a thread group require special handing. For instance, 124 * we send the SIGCHLD signal so that it appears that it came from 125 * the head of the group. We also only delete file descriptors if 126 * we are the last thread in the thread group. 127 */ 128 if (walk->pid() == p->tgid()) 129 tg_lead = walk; 130 131 if ((sys->threadContexts[i]->status() != ThreadContext::Halted) 132 && (walk != p)) { 133 /** 134 * Check if we share thread group with the pointer; this denotes 135 * that we are not the last thread active in the thread group. 136 * Note that setting this to false also prevents further 137 * iterations of the loop. 138 */ 139 if (walk->tgid() == p->tgid()) 140 last_thread = false; 141 142 /** 143 * A corner case exists which involves execve(). After execve(), 144 * the execve will enable SIGCHLD in the process. The problem 145 * occurs when the exiting process is the root process in the 146 * system; there is no parent to receive the signal. We obviate 147 * this problem by setting the root process' ppid to zero in the 148 * Python configuration files. We really should handle the 149 * root/execve specific case more gracefully. 150 */ 151 if (*p->sigchld && (p->ppid() != 0) && (walk->pid() == p->ppid())) 152 parent = walk; 153 } 154 } 155 156 if (last_thread) { 157 if (parent) { 158 assert(tg_lead); 159 sys->signalList.push_back(BasicSignal(tg_lead, parent, SIGCHLD)); 160 } 161 162 /** 163 * Run though FD array of the exiting process and close all file 164 * descriptors except for the standard file descriptors. 165 * (The standard file descriptors are shared with gem5.) 166 */ 167 for (int i = 0; i < p->fds->getSize(); i++) { 168 if ((*p->fds)[i]) 169 p->fds->closeFDEntry(i); 170 } 171 } 172 173 tc->halt(); 174 return status; 175} 176 177SyscallReturn 178exitFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 179{ 180 return exitImpl(desc, callnum, p, tc, false); 181} 182 183SyscallReturn 184exitGroupFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 185{ 186 return exitImpl(desc, callnum, p, tc, true); 187} 188 189SyscallReturn 190getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 191{ 192 return (int)PageBytes; 193} 194 195 196SyscallReturn 197brkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 198{ 199 // change brk addr to first arg 200 int index = 0; 201 Addr new_brk = p->getSyscallArg(tc, index); 202 203 std::shared_ptr<MemState> mem_state = p->memState; 204 Addr brk_point = mem_state->getBrkPoint(); 205 206 // in Linux at least, brk(0) returns the current break value 207 // (note that the syscall and the glibc function have different behavior) 208 if (new_brk == 0) 209 return brk_point; 210 211 if (new_brk > brk_point) { 212 // might need to allocate some new pages 213 for (ChunkGenerator gen(brk_point, 214 new_brk - brk_point, 215 PageBytes); !gen.done(); gen.next()) { 216 if (!p->pTable->translate(gen.addr())) 217 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 218 219 // if the address is already there, zero it out 220 else { 221 uint8_t zero = 0; 222 SETranslatingPortProxy &tp = tc->getMemProxy(); 223 224 // split non-page aligned accesses 225 Addr next_page = roundUp(gen.addr(), PageBytes); 226 uint32_t size_needed = next_page - gen.addr(); 227 tp.memsetBlob(gen.addr(), zero, size_needed); 228 if (gen.addr() + PageBytes > next_page && 229 next_page < new_brk && 230 p->pTable->translate(next_page)) { 231 size_needed = PageBytes - size_needed; 232 tp.memsetBlob(next_page, zero, size_needed); 233 } 234 } 235 } 236 } 237 238 mem_state->setBrkPoint(new_brk); 239 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 240 mem_state->getBrkPoint()); 241 return mem_state->getBrkPoint(); 242} 243 244SyscallReturn 245setTidAddressFunc(SyscallDesc *desc, int callnum, Process *process, 246 ThreadContext *tc) 247{ 248 int index = 0; 249 uint64_t tidPtr = process->getSyscallArg(tc, index); 250 251 process->childClearTID = tidPtr; 252 return process->pid(); 253} 254 255SyscallReturn 256closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 257{ 258 int index = 0; 259 int tgt_fd = p->getSyscallArg(tc, index); 260 261 return p->fds->closeFDEntry(tgt_fd); 262} 263 264 265SyscallReturn 266readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 267{ 268 int index = 0; 269 int tgt_fd = p->getSyscallArg(tc, index); 270 Addr buf_ptr = p->getSyscallArg(tc, index); 271 int nbytes = p->getSyscallArg(tc, index); 272 273 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 274 if (!hbfdp) 275 return -EBADF; 276 int sim_fd = hbfdp->getSimFD(); 277 278 BufferArg bufArg(buf_ptr, nbytes); 279 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 280 281 if (bytes_read > 0) 282 bufArg.copyOut(tc->getMemProxy()); 283 284 return bytes_read; 285} 286 287SyscallReturn 288writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 289{ 290 int index = 0; 291 int tgt_fd = p->getSyscallArg(tc, index); 292 Addr buf_ptr = p->getSyscallArg(tc, index); 293 int nbytes = p->getSyscallArg(tc, index); 294 295 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 296 if (!hbfdp) 297 return -EBADF; 298 int sim_fd = hbfdp->getSimFD(); 299 300 BufferArg bufArg(buf_ptr, nbytes); 301 bufArg.copyIn(tc->getMemProxy()); 302 303 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 304 305 fsync(sim_fd); 306 307 return bytes_written; 308} 309 310 311SyscallReturn 312lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 313{ 314 int index = 0; 315 int tgt_fd = p->getSyscallArg(tc, index); 316 uint64_t offs = p->getSyscallArg(tc, index); 317 int whence = p->getSyscallArg(tc, index); 318 319 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 320 if (!ffdp) 321 return -EBADF; 322 int sim_fd = ffdp->getSimFD(); 323 324 off_t result = lseek(sim_fd, offs, whence); 325 326 return (result == (off_t)-1) ? -errno : result; 327} 328 329 330SyscallReturn 331_llseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 332{ 333 int index = 0; 334 int tgt_fd = p->getSyscallArg(tc, index); 335 uint64_t offset_high = p->getSyscallArg(tc, index); 336 uint32_t offset_low = p->getSyscallArg(tc, index); 337 Addr result_ptr = p->getSyscallArg(tc, index); 338 int whence = p->getSyscallArg(tc, index); 339 340 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 341 if (!ffdp) 342 return -EBADF; 343 int sim_fd = ffdp->getSimFD(); 344 345 uint64_t offset = (offset_high << 32) | offset_low; 346 347 uint64_t result = lseek(sim_fd, offset, whence); 348 result = TheISA::htog(result); 349 350 if (result == (off_t)-1) 351 return -errno; 352 // Assuming that the size of loff_t is 64 bits on the target platform 353 BufferArg result_buf(result_ptr, sizeof(result)); 354 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 355 result_buf.copyOut(tc->getMemProxy()); 356 return 0; 357} 358 359 360SyscallReturn 361munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 362{ 363 // With mmap more fully implemented, it might be worthwhile to bite 364 // the bullet and implement munmap. Should allow us to reuse simulated 365 // memory. 366 return 0; 367} 368 369 370const char *hostname = "m5.eecs.umich.edu"; 371 372SyscallReturn 373gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 374{ 375 int index = 0; 376 Addr buf_ptr = p->getSyscallArg(tc, index); 377 int name_len = p->getSyscallArg(tc, index); 378 BufferArg name(buf_ptr, name_len); 379 380 strncpy((char *)name.bufferPtr(), hostname, name_len); 381 382 name.copyOut(tc->getMemProxy()); 383 384 return 0; 385} 386 387SyscallReturn 388getcwdFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 389{ 390 int result = 0; 391 int index = 0; 392 Addr buf_ptr = p->getSyscallArg(tc, index); 393 unsigned long size = p->getSyscallArg(tc, index); 394 BufferArg buf(buf_ptr, size); 395 396 // Is current working directory defined? 397 string cwd = p->getcwd(); 398 if (!cwd.empty()) { 399 if (cwd.length() >= size) { 400 // Buffer too small 401 return -ERANGE; 402 } 403 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 404 result = cwd.length(); 405 } else { 406 if (getcwd((char *)buf.bufferPtr(), size)) { 407 result = strlen((char *)buf.bufferPtr()); 408 } else { 409 result = -1; 410 } 411 } 412 413 buf.copyOut(tc->getMemProxy()); 414 415 return (result == -1) ? -errno : result; 416} 417 418SyscallReturn 419readlinkFunc(SyscallDesc *desc, int callnum, Process *process, 420 ThreadContext *tc) 421{ 422 return readlinkFunc(desc, callnum, process, tc, 0); 423} 424 425SyscallReturn 426readlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 427 int index) 428{ 429 string path; 430 431 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 432 return -EFAULT; 433 434 // Adjust path for current working directory 435 path = p->fullPath(path); 436 437 Addr buf_ptr = p->getSyscallArg(tc, index); 438 size_t bufsiz = p->getSyscallArg(tc, index); 439 440 BufferArg buf(buf_ptr, bufsiz); 441 442 int result = -1; 443 if (path != "/proc/self/exe") { 444 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 445 } else { 446 // Emulate readlink() called on '/proc/self/exe' should return the 447 // absolute path of the binary running in the simulated system (the 448 // Process' executable). It is possible that using this path in 449 // the simulated system will result in unexpected behavior if: 450 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 451 // called binary calls readlink(). 452 // 2) The host's full path to the running benchmark changes from one 453 // simulation to another. This can result in different simulated 454 // performance since the simulated system will process the binary 455 // path differently, even if the binary itself does not change. 456 457 // Get the absolute canonical path to the running application 458 char real_path[PATH_MAX]; 459 char *check_real_path = realpath(p->progName(), real_path); 460 if (!check_real_path) { 461 fatal("readlink('/proc/self/exe') unable to resolve path to " 462 "executable: %s", p->progName()); 463 } 464 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 465 size_t real_path_len = strlen(real_path); 466 if (real_path_len > bufsiz) { 467 // readlink will truncate the contents of the 468 // path to ensure it is no more than bufsiz 469 result = bufsiz; 470 } else { 471 result = real_path_len; 472 } 473 474 // Issue a warning about potential unexpected results 475 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 476 "results in various settings.\n Returning '%s'\n", 477 (char*)buf.bufferPtr()); 478 } 479 480 buf.copyOut(tc->getMemProxy()); 481 482 return (result == -1) ? -errno : result; 483} 484 485SyscallReturn 486unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 487{ 488 return unlinkHelper(desc, num, p, tc, 0); 489} 490 491SyscallReturn 492unlinkHelper(SyscallDesc *desc, int num, Process *p, ThreadContext *tc, 493 int index) 494{ 495 string path; 496 497 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 498 return -EFAULT; 499 500 // Adjust path for current working directory 501 path = p->fullPath(path); 502 503 int result = unlink(path.c_str()); 504 return (result == -1) ? -errno : result; 505} 506 507 508SyscallReturn 509mkdirFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 510{ 511 string path; 512 513 int index = 0; 514 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 515 return -EFAULT; 516 517 // Adjust path for current working directory 518 path = p->fullPath(path); 519 520 mode_t mode = p->getSyscallArg(tc, index); 521 522 int result = mkdir(path.c_str(), mode); 523 return (result == -1) ? -errno : result; 524} 525 526SyscallReturn 527renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 528{ 529 string old_name; 530 531 int index = 0; 532 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 533 return -EFAULT; 534 535 string new_name; 536 537 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 538 return -EFAULT; 539 540 // Adjust path for current working directory 541 old_name = p->fullPath(old_name); 542 new_name = p->fullPath(new_name); 543 544 int64_t result = rename(old_name.c_str(), new_name.c_str()); 545 return (result == -1) ? -errno : result; 546} 547 548SyscallReturn 549truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 550{ 551 string path; 552 553 int index = 0; 554 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 555 return -EFAULT; 556 557 off_t length = p->getSyscallArg(tc, index); 558 559 // Adjust path for current working directory 560 path = p->fullPath(path); 561 562 int result = truncate(path.c_str(), length); 563 return (result == -1) ? -errno : result; 564} 565 566SyscallReturn 567ftruncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 568{ 569 int index = 0; 570 int tgt_fd = p->getSyscallArg(tc, index); 571 off_t length = p->getSyscallArg(tc, index); 572 573 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 574 if (!ffdp) 575 return -EBADF; 576 int sim_fd = ffdp->getSimFD(); 577 578 int result = ftruncate(sim_fd, length); 579 return (result == -1) ? -errno : result; 580} 581 582SyscallReturn 583truncate64Func(SyscallDesc *desc, int num, 584 Process *process, ThreadContext *tc) 585{ 586 int index = 0; 587 string path; 588 589 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 590 return -EFAULT; 591 592 int64_t length = process->getSyscallArg(tc, index, 64); 593 594 // Adjust path for current working directory 595 path = process->fullPath(path); 596 597#if NO_STAT64 598 int result = truncate(path.c_str(), length); 599#else 600 int result = truncate64(path.c_str(), length); 601#endif 602 return (result == -1) ? -errno : result; 603} 604 605SyscallReturn 606ftruncate64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 607{ 608 int index = 0; 609 int tgt_fd = p->getSyscallArg(tc, index); 610 int64_t length = p->getSyscallArg(tc, index, 64); 611 612 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 613 if (!ffdp) 614 return -EBADF; 615 int sim_fd = ffdp->getSimFD(); 616 617#if NO_STAT64 618 int result = ftruncate(sim_fd, length); 619#else 620 int result = ftruncate64(sim_fd, length); 621#endif 622 return (result == -1) ? -errno : result; 623} 624 625SyscallReturn 626umaskFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc) 627{ 628 // Letting the simulated program change the simulator's umask seems like 629 // a bad idea. Compromise by just returning the current umask but not 630 // changing anything. 631 mode_t oldMask = umask(0); 632 umask(oldMask); 633 return (int)oldMask; 634} 635 636SyscallReturn 637chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 638{ 639 string path; 640 641 int index = 0; 642 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 643 return -EFAULT; 644 645 /* XXX endianess */ 646 uint32_t owner = p->getSyscallArg(tc, index); 647 uid_t hostOwner = owner; 648 uint32_t group = p->getSyscallArg(tc, index); 649 gid_t hostGroup = group; 650 651 // Adjust path for current working directory 652 path = p->fullPath(path); 653 654 int result = chown(path.c_str(), hostOwner, hostGroup); 655 return (result == -1) ? -errno : result; 656} 657 658SyscallReturn 659fchownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 660{ 661 int index = 0; 662 int tgt_fd = p->getSyscallArg(tc, index); 663 664 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 665 if (!ffdp) 666 return -EBADF; 667 int sim_fd = ffdp->getSimFD(); 668 669 /* XXX endianess */ 670 uint32_t owner = p->getSyscallArg(tc, index); 671 uid_t hostOwner = owner; 672 uint32_t group = p->getSyscallArg(tc, index); 673 gid_t hostGroup = group; 674 675 int result = fchown(sim_fd, hostOwner, hostGroup); 676 return (result == -1) ? -errno : result; 677} 678 679/** 680 * FIXME: The file description is not shared among file descriptors created 681 * with dup. Really, it's difficult to maintain fields like file offset or 682 * flags since an update to such a field won't be reflected in the metadata 683 * for the fd entries that we maintain for checkpoint restoration. 684 */ 685SyscallReturn 686dupFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 687{ 688 int index = 0; 689 int tgt_fd = p->getSyscallArg(tc, index); 690 691 auto old_hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 692 if (!old_hbfdp) 693 return -EBADF; 694 int sim_fd = old_hbfdp->getSimFD(); 695 696 int result = dup(sim_fd); 697 if (result == -1) 698 return -errno; 699 700 auto new_hbfdp = std::dynamic_pointer_cast<HBFDEntry>(old_hbfdp->clone()); 701 new_hbfdp->setSimFD(result); 702 new_hbfdp->setCOE(false); 703 return p->fds->allocFD(new_hbfdp); 704} 705 706SyscallReturn 707dup2Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 708{ 709 int index = 0; 710 711 int old_tgt_fd = p->getSyscallArg(tc, index); 712 auto old_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[old_tgt_fd]); 713 if (!old_hbp) 714 return -EBADF; 715 int old_sim_fd = old_hbp->getSimFD(); 716 717 /** 718 * We need a valid host file descriptor number to be able to pass into 719 * the second parameter for dup2 (newfd), but we don't know what the 720 * viable numbers are; we execute the open call to retrieve one. 721 */ 722 int res_fd = dup2(old_sim_fd, open("/dev/null", O_RDONLY)); 723 if (res_fd == -1) 724 return -errno; 725 726 int new_tgt_fd = p->getSyscallArg(tc, index); 727 auto new_hbp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[new_tgt_fd]); 728 if (new_hbp) 729 p->fds->closeFDEntry(new_tgt_fd); 730 new_hbp = std::dynamic_pointer_cast<HBFDEntry>(old_hbp->clone()); 731 new_hbp->setSimFD(res_fd); 732 new_hbp->setCOE(false); 733 734 return p->fds->allocFD(new_hbp); 735} 736 737SyscallReturn 738fcntlFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 739{ 740 int arg; 741 int index = 0; 742 int tgt_fd = p->getSyscallArg(tc, index); 743 int cmd = p->getSyscallArg(tc, index); 744 745 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 746 if (!hbfdp) 747 return -EBADF; 748 int sim_fd = hbfdp->getSimFD(); 749 750 int coe = hbfdp->getCOE(); 751 752 switch (cmd) { 753 case F_GETFD: 754 return coe & FD_CLOEXEC; 755 756 case F_SETFD: { 757 arg = p->getSyscallArg(tc, index); 758 arg ? hbfdp->setCOE(true) : hbfdp->setCOE(false); 759 return 0; 760 } 761 762 // Rely on the host to maintain the file status flags for this file 763 // description rather than maintain it ourselves. Admittedly, this 764 // is suboptimal (and possibly error prone), but it is difficult to 765 // maintain the flags by tracking them across the different descriptors 766 // (that refer to this file description) caused by clone, dup, and 767 // subsequent fcntls. 768 case F_GETFL: 769 case F_SETFL: { 770 arg = p->getSyscallArg(tc, index); 771 int rv = fcntl(sim_fd, cmd, arg); 772 return (rv == -1) ? -errno : rv; 773 } 774 775 default: 776 warn("fcntl: unsupported command %d\n", cmd); 777 return 0; 778 } 779} 780 781SyscallReturn 782fcntl64Func(SyscallDesc *desc, int num, Process *p, ThreadContext *tc) 783{ 784 int index = 0; 785 int tgt_fd = p->getSyscallArg(tc, index); 786 787 auto hbfdp = std::dynamic_pointer_cast<HBFDEntry>((*p->fds)[tgt_fd]); 788 if (!hbfdp) 789 return -EBADF; 790 int sim_fd = hbfdp->getSimFD(); 791 792 int cmd = p->getSyscallArg(tc, index); 793 switch (cmd) { 794 case 33: //F_GETLK64 795 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 796 return -EMFILE; 797 798 case 34: // F_SETLK64 799 case 35: // F_SETLKW64 800 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 801 tgt_fd); 802 return -EMFILE; 803 804 default: 805 // not sure if this is totally valid, but we'll pass it through 806 // to the underlying OS 807 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 808 return fcntl(sim_fd, cmd); 809 } 810} 811 812SyscallReturn 813pipeImpl(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 814 bool pseudoPipe) 815{ 816 Addr tgt_addr = 0; 817 if (!pseudoPipe) { 818 int index = 0; 819 tgt_addr = p->getSyscallArg(tc, index); 820 } 821 822 int sim_fds[2], tgt_fds[2]; 823 824 int pipe_retval = pipe(sim_fds); 825 if (pipe_retval == -1) 826 return -errno; 827 828 auto rend = PipeFDEntry::EndType::read; 829 auto rpfd = std::make_shared<PipeFDEntry>(sim_fds[0], O_WRONLY, rend); 830 tgt_fds[0] = p->fds->allocFD(rpfd); 831 832 auto wend = PipeFDEntry::EndType::write; 833 auto wpfd = std::make_shared<PipeFDEntry>(sim_fds[1], O_RDONLY, wend); 834 tgt_fds[1] = p->fds->allocFD(wpfd); 835 836 /** 837 * Now patch the read object to record the target file descriptor chosen 838 * as the write end of the pipe. 839 */ 840 rpfd->setPipeReadSource(tgt_fds[1]); 841 842 /** 843 * Alpha Linux convention for pipe() is that fd[0] is returned as 844 * the return value of the function, and fd[1] is returned in r20. 845 */ 846 if (pseudoPipe) { 847 tc->setIntReg(SyscallPseudoReturnReg, tgt_fds[1]); 848 return tgt_fds[0]; 849 } 850 851 /** 852 * Copy the target file descriptors into buffer space and then copy 853 * the buffer space back into the target address space. 854 */ 855 BufferArg tgt_handle(tgt_addr, sizeof(int[2])); 856 int *buf_ptr = (int*)tgt_handle.bufferPtr(); 857 buf_ptr[0] = tgt_fds[0]; 858 buf_ptr[1] = tgt_fds[1]; 859 tgt_handle.copyOut(tc->getMemProxy()); 860 return 0; 861} 862 863SyscallReturn 864pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process, 865 ThreadContext *tc) 866{ 867 return pipeImpl(desc, callnum, process, tc, true); 868} 869 870SyscallReturn 871pipeFunc(SyscallDesc *desc, int callnum, Process *process, ThreadContext *tc) 872{ 873 return pipeImpl(desc, callnum, process, tc, false); 874} 875 876SyscallReturn 877setpgidFunc(SyscallDesc *desc, int callnum, Process *process, 878 ThreadContext *tc) 879{ 880 int index = 0; 881 int pid = process->getSyscallArg(tc, index); 882 int pgid = process->getSyscallArg(tc, index); 883 884 if (pgid < 0) 885 return -EINVAL; 886 887 if (pid == 0) { 888 process->setpgid(process->pid()); 889 return 0; 890 } 891 892 Process *matched_ph = NULL; 893 System *sysh = tc->getSystemPtr(); 894 895 // Retrieves process pointer from active/suspended thread contexts. 896 for (int i = 0; i < sysh->numContexts(); i++) { 897 if (sysh->threadContexts[i]->status() != ThreadContext::Halted) { 898 Process *temp_h = sysh->threadContexts[i]->getProcessPtr(); 899 Process *walk_ph = (Process*)temp_h; 900 901 if (walk_ph && walk_ph->pid() == process->pid()) 902 matched_ph = walk_ph; 903 } 904 } 905 906 assert(matched_ph != NULL); 907 matched_ph->setpgid((pgid == 0) ? matched_ph->pid() : pgid); 908 909 return 0; 910} 911 912SyscallReturn 913getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 914 ThreadContext *tc) 915{ 916 // Make up a PID. There's no interprocess communication in 917 // fake_syscall mode, so there's no way for a process to know it's 918 // not getting a unique value. 919 920 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 921 return process->pid(); 922} 923 924 925SyscallReturn 926getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 927 ThreadContext *tc) 928{ 929 // Make up a UID and EUID... it shouldn't matter, and we want the 930 // simulation to be deterministic. 931 932 // EUID goes in r20. 933 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); // EUID 934 return process->uid(); // UID 935} 936 937 938SyscallReturn 939getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process, 940 ThreadContext *tc) 941{ 942 // Get current group ID. EGID goes in r20. 943 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); // EGID 944 return process->gid(); 945} 946 947 948SyscallReturn 949setuidFunc(SyscallDesc *desc, int callnum, Process *process, 950 ThreadContext *tc) 951{ 952 // can't fathom why a benchmark would call this. 953 int index = 0; 954 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 955 return 0; 956} 957 958SyscallReturn 959getpidFunc(SyscallDesc *desc, int callnum, Process *process, 960 ThreadContext *tc) 961{ 962 return process->tgid(); 963} 964 965SyscallReturn 966gettidFunc(SyscallDesc *desc, int callnum, Process *process, 967 ThreadContext *tc) 968{ 969 return process->pid(); 970} 971 972SyscallReturn 973getppidFunc(SyscallDesc *desc, int callnum, Process *process, 974 ThreadContext *tc) 975{ 976 return process->ppid(); 977} 978 979SyscallReturn 980getuidFunc(SyscallDesc *desc, int callnum, Process *process, 981 ThreadContext *tc) 982{ 983 return process->uid(); // UID 984} 985 986SyscallReturn 987geteuidFunc(SyscallDesc *desc, int callnum, Process *process, 988 ThreadContext *tc) 989{ 990 return process->euid(); // UID 991} 992 993SyscallReturn 994getgidFunc(SyscallDesc *desc, int callnum, Process *process, 995 ThreadContext *tc) 996{ 997 return process->gid(); 998} 999 1000SyscallReturn 1001getegidFunc(SyscallDesc *desc, int callnum, Process *process, 1002 ThreadContext *tc) 1003{ 1004 return process->egid(); 1005} 1006 1007SyscallReturn 1008fallocateFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1009{ 1010#if NO_FALLOCATE 1011 warn("Host OS cannot support calls to fallocate. Ignoring syscall"); 1012#else 1013 int index = 0; 1014 int tgt_fd = p->getSyscallArg(tc, index); 1015 int mode = p->getSyscallArg(tc, index); 1016 off_t offset = p->getSyscallArg(tc, index); 1017 off_t len = p->getSyscallArg(tc, index); 1018 1019 auto ffdp = std::dynamic_pointer_cast<FileFDEntry>((*p->fds)[tgt_fd]); 1020 if (!ffdp) 1021 return -EBADF; 1022 int sim_fd = ffdp->getSimFD(); 1023 1024 int result = fallocate(sim_fd, mode, offset, len); 1025 if (result < 0) 1026 return -errno; 1027#endif 1028 return 0; 1029} 1030 1031SyscallReturn 1032accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc, 1033 int index) 1034{ 1035 string path; 1036 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 1037 return -EFAULT; 1038 1039 // Adjust path for current working directory 1040 path = p->fullPath(path); 1041 1042 mode_t mode = p->getSyscallArg(tc, index); 1043 1044 int result = access(path.c_str(), mode); 1045 return (result == -1) ? -errno : result; 1046} 1047 1048SyscallReturn 1049accessFunc(SyscallDesc *desc, int callnum, Process *p, ThreadContext *tc) 1050{ 1051 return accessFunc(desc, callnum, p, tc, 0); 1052} 1053 1054