syscall_emul.cc revision 11684
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 <fcntl.h> 33#include <unistd.h> 34 35#include <cstdio> 36#include <iostream> 37#include <string> 38 39#include "arch/utility.hh" 40#include "base/chunk_generator.hh" 41#include "base/trace.hh" 42#include "config/the_isa.hh" 43#include "cpu/base.hh" 44#include "cpu/thread_context.hh" 45#include "debug/SyscallBase.hh" 46#include "debug/SyscallVerbose.hh" 47#include "mem/page_table.hh" 48#include "sim/process.hh" 49#include "sim/sim_exit.hh" 50#include "sim/syscall_emul.hh" 51#include "sim/system.hh" 52 53using namespace std; 54using namespace TheISA; 55 56void 57SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc) 58{ 59 if (DTRACE(SyscallBase)) { 60 int index = 0; 61 IntReg arg[6] M5_VAR_USED; 62 63 // we can't just put the calls to getSyscallArg() in the 64 // DPRINTF arg list, because C++ doesn't guarantee their order 65 for (int i = 0; i < 6; ++i) 66 arg[i] = process->getSyscallArg(tc, index); 67 68 // Linux supports up to six system call arguments through registers 69 // so we want to print all six. Check to the relevant man page to 70 // verify how many are actually used by a given system call. 71 DPRINTF_SYSCALL(Base, 72 "%s called w/arguments %d, %d, %d, %d, %d, %d\n", 73 name, arg[0], arg[1], arg[2], arg[3], arg[4], 74 arg[5]); 75 } 76 77 SyscallReturn retval = (*funcPtr)(this, callnum, process, tc); 78 79 if (retval.needsRetry()) { 80 DPRINTF_SYSCALL(Base, "%s needs retry\n", name); 81 } else { 82 DPRINTF_SYSCALL(Base, "%s returns %d\n", name, 83 retval.encodedValue()); 84 } 85 86 if (!(flags & SyscallDesc::SuppressReturnValue) && !retval.needsRetry()) 87 process->setSyscallReturn(tc, retval); 88} 89 90 91SyscallReturn 92unimplementedFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 93 ThreadContext *tc) 94{ 95 fatal("syscall %s (#%d) unimplemented.", desc->name, callnum); 96 97 return 1; 98} 99 100 101SyscallReturn 102ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 103 ThreadContext *tc) 104{ 105 int index = 0; 106 const char *extra_text = ""; 107 108 if (desc->warnOnce()) { 109 if (desc->warned) 110 return 0; 111 112 desc->warned = true; 113 extra_text = "\n (further warnings will be suppressed)"; 114 } 115 116 warn("ignoring syscall %s(%d, ...)%s", desc->name, 117 process->getSyscallArg(tc, index), extra_text); 118 119 return 0; 120} 121 122 123SyscallReturn 124exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 125 ThreadContext *tc) 126{ 127 if (process->system->numRunningContexts() == 1) { 128 // Last running context... exit simulator 129 int index = 0; 130 exitSimLoop("target called exit()", 131 process->getSyscallArg(tc, index) & 0xff); 132 } else { 133 // other running threads... just halt this one 134 tc->halt(); 135 } 136 137 return 1; 138} 139 140 141SyscallReturn 142exitGroupFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 143 ThreadContext *tc) 144{ 145 // halt all threads belonging to this process 146 for (auto i: process->contextIds) { 147 process->system->getThreadContext(i)->halt(); 148 } 149 150 if (!process->system->numRunningContexts()) { 151 // all threads belonged to this process... exit simulator 152 int index = 0; 153 exitSimLoop("target called exit()", 154 process->getSyscallArg(tc, index) & 0xff); 155 } 156 157 return 1; 158} 159 160 161SyscallReturn 162getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 163{ 164 return (int)PageBytes; 165} 166 167 168SyscallReturn 169brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 170{ 171 // change brk addr to first arg 172 int index = 0; 173 Addr new_brk = p->getSyscallArg(tc, index); 174 175 // in Linux at least, brk(0) returns the current break value 176 // (note that the syscall and the glibc function have different behavior) 177 if (new_brk == 0) 178 return p->brk_point; 179 180 if (new_brk > p->brk_point) { 181 // might need to allocate some new pages 182 for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point, 183 PageBytes); !gen.done(); gen.next()) { 184 if (!p->pTable->translate(gen.addr())) 185 p->allocateMem(roundDown(gen.addr(), PageBytes), PageBytes); 186 187 // if the address is already there, zero it out 188 else { 189 uint8_t zero = 0; 190 SETranslatingPortProxy &tp = tc->getMemProxy(); 191 192 // split non-page aligned accesses 193 Addr next_page = roundUp(gen.addr(), PageBytes); 194 uint32_t size_needed = next_page - gen.addr(); 195 tp.memsetBlob(gen.addr(), zero, size_needed); 196 if (gen.addr() + PageBytes > next_page && 197 next_page < new_brk && 198 p->pTable->translate(next_page)) 199 { 200 size_needed = PageBytes - size_needed; 201 tp.memsetBlob(next_page, zero, size_needed); 202 } 203 } 204 } 205 } 206 207 p->brk_point = new_brk; 208 DPRINTF_SYSCALL(Verbose, "brk: break point changed to: %#X\n", 209 p->brk_point); 210 return p->brk_point; 211} 212 213 214SyscallReturn 215closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 216{ 217 int index = 0; 218 int tgt_fd = p->getSyscallArg(tc, index); 219 220 int sim_fd = p->getSimFD(tgt_fd); 221 if (sim_fd < 0) 222 return -EBADF; 223 224 int status = 0; 225 if (sim_fd > 2) 226 status = close(sim_fd); 227 if (status >= 0) 228 p->resetFDEntry(tgt_fd); 229 return status; 230} 231 232 233SyscallReturn 234readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 235{ 236 int index = 0; 237 int tgt_fd = p->getSyscallArg(tc, index); 238 Addr bufPtr = p->getSyscallArg(tc, index); 239 int nbytes = p->getSyscallArg(tc, index); 240 BufferArg bufArg(bufPtr, nbytes); 241 242 int sim_fd = p->getSimFD(tgt_fd); 243 if (sim_fd < 0) 244 return -EBADF; 245 246 int bytes_read = read(sim_fd, bufArg.bufferPtr(), nbytes); 247 248 if (bytes_read > 0) 249 bufArg.copyOut(tc->getMemProxy()); 250 251 return bytes_read; 252} 253 254SyscallReturn 255writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 256{ 257 int index = 0; 258 int tgt_fd = p->getSyscallArg(tc, index); 259 Addr bufPtr = p->getSyscallArg(tc, index); 260 int nbytes = p->getSyscallArg(tc, index); 261 BufferArg bufArg(bufPtr, nbytes); 262 263 int sim_fd = p->getSimFD(tgt_fd); 264 if (sim_fd < 0) 265 return -EBADF; 266 267 bufArg.copyIn(tc->getMemProxy()); 268 269 int bytes_written = write(sim_fd, bufArg.bufferPtr(), nbytes); 270 271 fsync(sim_fd); 272 273 return bytes_written; 274} 275 276 277SyscallReturn 278lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 279{ 280 int index = 0; 281 int tgt_fd = p->getSyscallArg(tc, index); 282 uint64_t offs = p->getSyscallArg(tc, index); 283 int whence = p->getSyscallArg(tc, index); 284 285 int sim_fd = p->getSimFD(tgt_fd); 286 if (sim_fd < 0) 287 return -EBADF; 288 289 off_t result = lseek(sim_fd, offs, whence); 290 291 return (result == (off_t)-1) ? -errno : result; 292} 293 294 295SyscallReturn 296_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 297{ 298 int index = 0; 299 int tgt_fd = p->getSyscallArg(tc, index); 300 uint64_t offset_high = p->getSyscallArg(tc, index); 301 uint32_t offset_low = p->getSyscallArg(tc, index); 302 Addr result_ptr = p->getSyscallArg(tc, index); 303 int whence = p->getSyscallArg(tc, index); 304 305 int sim_fd = p->getSimFD(tgt_fd); 306 if (sim_fd < 0) 307 return -EBADF; 308 309 uint64_t offset = (offset_high << 32) | offset_low; 310 311 uint64_t result = lseek(sim_fd, offset, whence); 312 result = TheISA::htog(result); 313 314 if (result == (off_t)-1) 315 return -errno; 316 // Assuming that the size of loff_t is 64 bits on the target platform 317 BufferArg result_buf(result_ptr, sizeof(result)); 318 memcpy(result_buf.bufferPtr(), &result, sizeof(result)); 319 result_buf.copyOut(tc->getMemProxy()); 320 return 0; 321} 322 323 324SyscallReturn 325munmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 326{ 327 // With mmap more fully implemented, it might be worthwhile to bite 328 // the bullet and implement munmap. Should allow us to reuse simulated 329 // memory. 330 return 0; 331} 332 333 334const char *hostname = "m5.eecs.umich.edu"; 335 336SyscallReturn 337gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 338{ 339 int index = 0; 340 Addr bufPtr = p->getSyscallArg(tc, index); 341 int name_len = p->getSyscallArg(tc, index); 342 BufferArg name(bufPtr, name_len); 343 344 strncpy((char *)name.bufferPtr(), hostname, name_len); 345 346 name.copyOut(tc->getMemProxy()); 347 348 return 0; 349} 350 351SyscallReturn 352getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 353{ 354 int result = 0; 355 int index = 0; 356 Addr bufPtr = p->getSyscallArg(tc, index); 357 unsigned long size = p->getSyscallArg(tc, index); 358 BufferArg buf(bufPtr, size); 359 360 // Is current working directory defined? 361 string cwd = p->getcwd(); 362 if (!cwd.empty()) { 363 if (cwd.length() >= size) { 364 // Buffer too small 365 return -ERANGE; 366 } 367 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 368 result = cwd.length(); 369 } else { 370 if (getcwd((char *)buf.bufferPtr(), size) != NULL) { 371 result = strlen((char *)buf.bufferPtr()); 372 } else { 373 result = -1; 374 } 375 } 376 377 buf.copyOut(tc->getMemProxy()); 378 379 return (result == -1) ? -errno : result; 380} 381 382/// Target open() handler. 383SyscallReturn 384readlinkFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 385 ThreadContext *tc) 386{ 387 return readlinkFunc(desc, callnum, process, tc, 0); 388} 389 390SyscallReturn 391readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 392 int index) 393{ 394 string path; 395 396 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 397 return -EFAULT; 398 399 // Adjust path for current working directory 400 path = p->fullPath(path); 401 402 Addr bufPtr = p->getSyscallArg(tc, index); 403 size_t bufsiz = p->getSyscallArg(tc, index); 404 405 BufferArg buf(bufPtr, bufsiz); 406 407 int result = -1; 408 if (path != "/proc/self/exe") { 409 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 410 } else { 411 // Emulate readlink() called on '/proc/self/exe' should return the 412 // absolute path of the binary running in the simulated system (the 413 // LiveProcess' executable). It is possible that using this path in 414 // the simulated system will result in unexpected behavior if: 415 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 416 // called binary calls readlink(). 417 // 2) The host's full path to the running benchmark changes from one 418 // simulation to another. This can result in different simulated 419 // performance since the simulated system will process the binary 420 // path differently, even if the binary itself does not change. 421 422 // Get the absolute canonical path to the running application 423 char real_path[PATH_MAX]; 424 char *check_real_path = realpath(p->progName(), real_path); 425 if (!check_real_path) { 426 fatal("readlink('/proc/self/exe') unable to resolve path to " 427 "executable: %s", p->progName()); 428 } 429 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 430 size_t real_path_len = strlen(real_path); 431 if (real_path_len > bufsiz) { 432 // readlink will truncate the contents of the 433 // path to ensure it is no more than bufsiz 434 result = bufsiz; 435 } else { 436 result = real_path_len; 437 } 438 439 // Issue a warning about potential unexpected results 440 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 441 "results in various settings.\n Returning '%s'\n", 442 (char*)buf.bufferPtr()); 443 } 444 445 buf.copyOut(tc->getMemProxy()); 446 447 return (result == -1) ? -errno : result; 448} 449 450SyscallReturn 451unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 452{ 453 return unlinkHelper(desc, num, p, tc, 0); 454} 455 456SyscallReturn 457unlinkHelper(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 458 int index) 459{ 460 string path; 461 462 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 463 return -EFAULT; 464 465 // Adjust path for current working directory 466 path = p->fullPath(path); 467 468 int result = unlink(path.c_str()); 469 return (result == -1) ? -errno : result; 470} 471 472 473SyscallReturn 474mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 475{ 476 string path; 477 478 int index = 0; 479 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 480 return -EFAULT; 481 482 // Adjust path for current working directory 483 path = p->fullPath(path); 484 485 mode_t mode = p->getSyscallArg(tc, index); 486 487 int result = mkdir(path.c_str(), mode); 488 return (result == -1) ? -errno : result; 489} 490 491SyscallReturn 492renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 493{ 494 string old_name; 495 496 int index = 0; 497 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 498 return -EFAULT; 499 500 string new_name; 501 502 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 503 return -EFAULT; 504 505 // Adjust path for current working directory 506 old_name = p->fullPath(old_name); 507 new_name = p->fullPath(new_name); 508 509 int64_t result = rename(old_name.c_str(), new_name.c_str()); 510 return (result == -1) ? -errno : result; 511} 512 513SyscallReturn 514truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 515{ 516 string path; 517 518 int index = 0; 519 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 520 return -EFAULT; 521 522 off_t length = p->getSyscallArg(tc, index); 523 524 // Adjust path for current working directory 525 path = p->fullPath(path); 526 527 int result = truncate(path.c_str(), length); 528 return (result == -1) ? -errno : result; 529} 530 531SyscallReturn 532ftruncateFunc(SyscallDesc *desc, int num, 533 LiveProcess *process, ThreadContext *tc) 534{ 535 int index = 0; 536 int tgt_fd = process->getSyscallArg(tc, index); 537 off_t length = process->getSyscallArg(tc, index); 538 539 int sim_fd = process->getSimFD(tgt_fd); 540 if (sim_fd < 0) 541 return -EBADF; 542 543 int result = ftruncate(sim_fd, length); 544 return (result == -1) ? -errno : result; 545} 546 547SyscallReturn 548truncate64Func(SyscallDesc *desc, int num, 549 LiveProcess *process, ThreadContext *tc) 550{ 551 int index = 0; 552 string path; 553 554 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 555 return -EFAULT; 556 557 int64_t length = process->getSyscallArg(tc, index, 64); 558 559 // Adjust path for current working directory 560 path = process->fullPath(path); 561 562#if NO_STAT64 563 int result = truncate(path.c_str(), length); 564#else 565 int result = truncate64(path.c_str(), length); 566#endif 567 return (result == -1) ? -errno : result; 568} 569 570SyscallReturn 571ftruncate64Func(SyscallDesc *desc, int num, 572 LiveProcess *process, ThreadContext *tc) 573{ 574 int index = 0; 575 int tgt_fd = process->getSyscallArg(tc, index); 576 int64_t length = process->getSyscallArg(tc, index, 64); 577 578 int sim_fd = process->getSimFD(tgt_fd); 579 if (sim_fd < 0) 580 return -EBADF; 581 582#if NO_STAT64 583 int result = ftruncate(sim_fd, length); 584#else 585 int result = ftruncate64(sim_fd, length); 586#endif 587 return (result == -1) ? -errno : result; 588} 589 590SyscallReturn 591umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 592{ 593 // Letting the simulated program change the simulator's umask seems like 594 // a bad idea. Compromise by just returning the current umask but not 595 // changing anything. 596 mode_t oldMask = umask(0); 597 umask(oldMask); 598 return (int)oldMask; 599} 600 601SyscallReturn 602chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 603{ 604 string path; 605 606 int index = 0; 607 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 608 return -EFAULT; 609 610 /* XXX endianess */ 611 uint32_t owner = p->getSyscallArg(tc, index); 612 uid_t hostOwner = owner; 613 uint32_t group = p->getSyscallArg(tc, index); 614 gid_t hostGroup = group; 615 616 // Adjust path for current working directory 617 path = p->fullPath(path); 618 619 int result = chown(path.c_str(), hostOwner, hostGroup); 620 return (result == -1) ? -errno : result; 621} 622 623SyscallReturn 624fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 625{ 626 int index = 0; 627 int tgt_fd = process->getSyscallArg(tc, index); 628 629 int sim_fd = process->getSimFD(tgt_fd); 630 if (sim_fd < 0) 631 return -EBADF; 632 633 /* XXX endianess */ 634 uint32_t owner = process->getSyscallArg(tc, index); 635 uid_t hostOwner = owner; 636 uint32_t group = process->getSyscallArg(tc, index); 637 gid_t hostGroup = group; 638 639 int result = fchown(sim_fd, hostOwner, hostGroup); 640 return (result == -1) ? -errno : result; 641} 642 643 644SyscallReturn 645dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 646{ 647 int index = 0; 648 int tgt_fd = process->getSyscallArg(tc, index); 649 650 int sim_fd = process->getSimFD(tgt_fd); 651 if (sim_fd < 0) 652 return -EBADF; 653 654 FDEntry *fde = process->getFDEntry(tgt_fd); 655 656 int result = dup(sim_fd); 657 return (result == -1) ? -errno : 658 process->allocFD(result, fde->filename, fde->flags, fde->mode, false); 659} 660 661 662SyscallReturn 663fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, 664 ThreadContext *tc) 665{ 666 int index = 0; 667 int tgt_fd = process->getSyscallArg(tc, index); 668 669 int sim_fd = process->getSimFD(tgt_fd); 670 if (sim_fd < 0) 671 return -EBADF; 672 673 int cmd = process->getSyscallArg(tc, index); 674 switch (cmd) { 675 case 0: // F_DUPFD 676 // if we really wanted to support this, we'd need to do it 677 // in the target fd space. 678 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", tgt_fd); 679 return -EMFILE; 680 681 case 1: // F_GETFD (get close-on-exec flag) 682 case 2: // F_SETFD (set close-on-exec flag) 683 return 0; 684 685 case 3: // F_GETFL (get file flags) 686 case 4: // F_SETFL (set file flags) 687 // not sure if this is totally valid, but we'll pass it through 688 // to the underlying OS 689 warn("fcntl(%d, %d) passed through to host\n", tgt_fd, cmd); 690 return fcntl(sim_fd, cmd); 691 // return 0; 692 693 case 7: // F_GETLK (get lock) 694 case 8: // F_SETLK (set lock) 695 case 9: // F_SETLKW (set lock and wait) 696 // don't mess with file locking... just act like it's OK 697 warn("File lock call (fcntl(%d, %d)) ignored.\n", tgt_fd, cmd); 698 return 0; 699 700 default: 701 warn("Unknown fcntl command %d\n", cmd); 702 return 0; 703 } 704} 705 706SyscallReturn 707fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, 708 ThreadContext *tc) 709{ 710 int index = 0; 711 int tgt_fd = process->getSyscallArg(tc, index); 712 713 int sim_fd = process->getSimFD(tgt_fd); 714 if (sim_fd < 0) 715 return -EBADF; 716 717 int cmd = process->getSyscallArg(tc, index); 718 switch (cmd) { 719 case 33: //F_GETLK64 720 warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", tgt_fd); 721 return -EMFILE; 722 723 case 34: // F_SETLK64 724 case 35: // F_SETLKW64 725 warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", 726 tgt_fd); 727 return -EMFILE; 728 729 default: 730 // not sure if this is totally valid, but we'll pass it through 731 // to the underlying OS 732 warn("fcntl64(%d, %d) passed through to host\n", tgt_fd, cmd); 733 return fcntl(sim_fd, cmd); 734 // return 0; 735 } 736} 737 738SyscallReturn 739pipePseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 740 ThreadContext *tc) 741{ 742 int fds[2], sim_fds[2]; 743 int pipe_retval = pipe(fds); 744 745 if (pipe_retval < 0) { 746 // error 747 return pipe_retval; 748 } 749 750 sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true); 751 sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); 752 753 process->setReadPipeSource(sim_fds[0], sim_fds[1]); 754 // Alpha Linux convention for pipe() is that fd[0] is returned as 755 // the return value of the function, and fd[1] is returned in r20. 756 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 757 return sim_fds[0]; 758} 759 760 761SyscallReturn 762getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 763 ThreadContext *tc) 764{ 765 // Make up a PID. There's no interprocess communication in 766 // fake_syscall mode, so there's no way for a process to know it's 767 // not getting a unique value. 768 769 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 770 return process->pid(); 771} 772 773 774SyscallReturn 775getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 776 ThreadContext *tc) 777{ 778 // Make up a UID and EUID... it shouldn't matter, and we want the 779 // simulation to be deterministic. 780 781 // EUID goes in r20. 782 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 783 return process->uid(); // UID 784} 785 786 787SyscallReturn 788getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 789 ThreadContext *tc) 790{ 791 // Get current group ID. EGID goes in r20. 792 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 793 return process->gid(); 794} 795 796 797SyscallReturn 798setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 799 ThreadContext *tc) 800{ 801 // can't fathom why a benchmark would call this. 802 int index = 0; 803 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 804 return 0; 805} 806 807SyscallReturn 808getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 809 ThreadContext *tc) 810{ 811 // Make up a PID. There's no interprocess communication in 812 // fake_syscall mode, so there's no way for a process to know it's 813 // not getting a unique value. 814 815 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); //PID 816 return process->pid(); 817} 818 819SyscallReturn 820getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 821 ThreadContext *tc) 822{ 823 return process->ppid(); 824} 825 826SyscallReturn 827getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 828 ThreadContext *tc) 829{ 830 return process->uid(); // UID 831} 832 833SyscallReturn 834geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 835 ThreadContext *tc) 836{ 837 return process->euid(); // UID 838} 839 840SyscallReturn 841getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 842 ThreadContext *tc) 843{ 844 return process->gid(); 845} 846 847SyscallReturn 848getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 849 ThreadContext *tc) 850{ 851 return process->egid(); 852} 853 854 855SyscallReturn 856cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 857 ThreadContext *tc) 858{ 859 int index = 0; 860 IntReg flags = process->getSyscallArg(tc, index); 861 IntReg newStack = process->getSyscallArg(tc, index); 862 863 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 864 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 865 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 866 867 868 if (flags != 0x10f00) { 869 warn("This sys_clone implementation assumes flags " 870 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 871 "(0x10f00), and may not work correctly with given flags " 872 "0x%llx\n", flags); 873 } 874 875 ThreadContext* ctc; // child thread context 876 if ( ( ctc = process->findFreeContext() ) != NULL ) { 877 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 878 879 ctc->clearArchRegs(); 880 881 // Arch-specific cloning code 882 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 883 // Cloning the misc. regs for these archs is enough 884 TheISA::copyMiscRegs(tc, ctc); 885 #elif THE_ISA == SPARC_ISA 886 TheISA::copyRegs(tc, ctc); 887 888 // TODO: Explain what this code actually does :-) 889 ctc->setIntReg(NumIntArchRegs + 6, 0); 890 ctc->setIntReg(NumIntArchRegs + 4, 0); 891 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 892 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 893 ctc->setMiscReg(MISCREG_CWP, 0); 894 ctc->setIntReg(NumIntArchRegs + 7, 0); 895 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 896 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 897 898 for (int y = 8; y < 32; y++) 899 ctc->setIntReg(y, tc->readIntReg(y)); 900 #elif THE_ISA == ARM_ISA 901 TheISA::copyRegs(tc, ctc); 902 #else 903 fatal("sys_clone is not implemented for this ISA\n"); 904 #endif 905 906 // Set up stack register 907 ctc->setIntReg(TheISA::StackPointerReg, newStack); 908 909 // Set up syscall return values in parent and child 910 ctc->setIntReg(ReturnValueReg, 0); // return value, child 911 912 // Alpha needs SyscallSuccessReg=0 in child 913 #if THE_ISA == ALPHA_ISA 914 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 915 #endif 916 917 // In SPARC/Linux, clone returns 0 on pseudo-return register if 918 // parent, non-zero if child 919 #if THE_ISA == SPARC_ISA 920 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 921 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 922 #endif 923 924 ctc->pcState(tc->nextInstAddr()); 925 926 ctc->activate(); 927 928 // Should return nonzero child TID in parent's syscall return register, 929 // but for our pthread library any non-zero value will work 930 return 1; 931 } else { 932 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 933 return 0; 934 } 935} 936 937SyscallReturn 938accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc, 939 int index) 940{ 941 string path; 942 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 943 return -EFAULT; 944 945 // Adjust path for current working directory 946 path = p->fullPath(path); 947 948 mode_t mode = p->getSyscallArg(tc, index); 949 950 int result = access(path.c_str(), mode); 951 return (result == -1) ? -errno : result; 952} 953 954SyscallReturn 955accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc) 956{ 957 return accessFunc(desc, callnum, p, tc, 0); 958} 959 960