syscall_emul.cc revision 11380:3370547fa302
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 != -1) 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 // given that we don't really implement mmap, munmap is really easy 328 return 0; 329} 330 331 332const char *hostname = "m5.eecs.umich.edu"; 333 334SyscallReturn 335gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 336{ 337 int index = 0; 338 Addr bufPtr = p->getSyscallArg(tc, index); 339 int name_len = p->getSyscallArg(tc, index); 340 BufferArg name(bufPtr, name_len); 341 342 strncpy((char *)name.bufferPtr(), hostname, name_len); 343 344 name.copyOut(tc->getMemProxy()); 345 346 return 0; 347} 348 349SyscallReturn 350getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 351{ 352 int result = 0; 353 int index = 0; 354 Addr bufPtr = p->getSyscallArg(tc, index); 355 unsigned long size = p->getSyscallArg(tc, index); 356 BufferArg buf(bufPtr, size); 357 358 // Is current working directory defined? 359 string cwd = p->getcwd(); 360 if (!cwd.empty()) { 361 if (cwd.length() >= size) { 362 // Buffer too small 363 return -ERANGE; 364 } 365 strncpy((char *)buf.bufferPtr(), cwd.c_str(), size); 366 result = cwd.length(); 367 } else { 368 if (getcwd((char *)buf.bufferPtr(), size) != NULL) { 369 result = strlen((char *)buf.bufferPtr()); 370 } else { 371 result = -1; 372 } 373 } 374 375 buf.copyOut(tc->getMemProxy()); 376 377 return (result == -1) ? -errno : result; 378} 379 380/// Target open() handler. 381SyscallReturn 382readlinkFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 383 ThreadContext *tc) 384{ 385 return readlinkFunc(desc, callnum, process, tc, 0); 386} 387 388SyscallReturn 389readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 390 int index) 391{ 392 string path; 393 394 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 395 return -EFAULT; 396 397 // Adjust path for current working directory 398 path = p->fullPath(path); 399 400 Addr bufPtr = p->getSyscallArg(tc, index); 401 size_t bufsiz = p->getSyscallArg(tc, index); 402 403 BufferArg buf(bufPtr, bufsiz); 404 405 int result = -1; 406 if (path != "/proc/self/exe") { 407 result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz); 408 } else { 409 // Emulate readlink() called on '/proc/self/exe' should return the 410 // absolute path of the binary running in the simulated system (the 411 // LiveProcess' executable). It is possible that using this path in 412 // the simulated system will result in unexpected behavior if: 413 // 1) One binary runs another (e.g., -c time -o "my_binary"), and 414 // called binary calls readlink(). 415 // 2) The host's full path to the running benchmark changes from one 416 // simulation to another. This can result in different simulated 417 // performance since the simulated system will process the binary 418 // path differently, even if the binary itself does not change. 419 420 // Get the absolute canonical path to the running application 421 char real_path[PATH_MAX]; 422 char *check_real_path = realpath(p->progName(), real_path); 423 if (!check_real_path) { 424 fatal("readlink('/proc/self/exe') unable to resolve path to " 425 "executable: %s", p->progName()); 426 } 427 strncpy((char*)buf.bufferPtr(), real_path, bufsiz); 428 size_t real_path_len = strlen(real_path); 429 if (real_path_len > bufsiz) { 430 // readlink will truncate the contents of the 431 // path to ensure it is no more than bufsiz 432 result = bufsiz; 433 } else { 434 result = real_path_len; 435 } 436 437 // Issue a warning about potential unexpected results 438 warn_once("readlink() called on '/proc/self/exe' may yield unexpected " 439 "results in various settings.\n Returning '%s'\n", 440 (char*)buf.bufferPtr()); 441 } 442 443 buf.copyOut(tc->getMemProxy()); 444 445 return (result == -1) ? -errno : result; 446} 447 448SyscallReturn 449unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 450{ 451 return unlinkHelper(desc, num, p, tc, 0); 452} 453 454SyscallReturn 455unlinkHelper(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc, 456 int index) 457{ 458 string path; 459 460 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 461 return -EFAULT; 462 463 // Adjust path for current working directory 464 path = p->fullPath(path); 465 466 int result = unlink(path.c_str()); 467 return (result == -1) ? -errno : result; 468} 469 470 471SyscallReturn 472mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 473{ 474 string path; 475 476 int index = 0; 477 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 478 return -EFAULT; 479 480 // Adjust path for current working directory 481 path = p->fullPath(path); 482 483 mode_t mode = p->getSyscallArg(tc, index); 484 485 int result = mkdir(path.c_str(), mode); 486 return (result == -1) ? -errno : result; 487} 488 489SyscallReturn 490renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 491{ 492 string old_name; 493 494 int index = 0; 495 if (!tc->getMemProxy().tryReadString(old_name, p->getSyscallArg(tc, index))) 496 return -EFAULT; 497 498 string new_name; 499 500 if (!tc->getMemProxy().tryReadString(new_name, p->getSyscallArg(tc, index))) 501 return -EFAULT; 502 503 // Adjust path for current working directory 504 old_name = p->fullPath(old_name); 505 new_name = p->fullPath(new_name); 506 507 int64_t result = rename(old_name.c_str(), new_name.c_str()); 508 return (result == -1) ? -errno : result; 509} 510 511SyscallReturn 512truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 513{ 514 string path; 515 516 int index = 0; 517 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 518 return -EFAULT; 519 520 off_t length = p->getSyscallArg(tc, index); 521 522 // Adjust path for current working directory 523 path = p->fullPath(path); 524 525 int result = truncate(path.c_str(), length); 526 return (result == -1) ? -errno : result; 527} 528 529SyscallReturn 530ftruncateFunc(SyscallDesc *desc, int num, 531 LiveProcess *process, ThreadContext *tc) 532{ 533 int index = 0; 534 int tgt_fd = process->getSyscallArg(tc, index); 535 off_t length = process->getSyscallArg(tc, index); 536 537 int sim_fd = process->getSimFD(tgt_fd); 538 if (sim_fd < 0) 539 return -EBADF; 540 541 int result = ftruncate(sim_fd, length); 542 return (result == -1) ? -errno : result; 543} 544 545SyscallReturn 546truncate64Func(SyscallDesc *desc, int num, 547 LiveProcess *process, ThreadContext *tc) 548{ 549 int index = 0; 550 string path; 551 552 if (!tc->getMemProxy().tryReadString(path, process->getSyscallArg(tc, index))) 553 return -EFAULT; 554 555 int64_t length = process->getSyscallArg(tc, index, 64); 556 557 // Adjust path for current working directory 558 path = process->fullPath(path); 559 560#if NO_STAT64 561 int result = truncate(path.c_str(), length); 562#else 563 int result = truncate64(path.c_str(), length); 564#endif 565 return (result == -1) ? -errno : result; 566} 567 568SyscallReturn 569ftruncate64Func(SyscallDesc *desc, int num, 570 LiveProcess *process, ThreadContext *tc) 571{ 572 int index = 0; 573 int tgt_fd = process->getSyscallArg(tc, index); 574 int64_t length = process->getSyscallArg(tc, index, 64); 575 576 int sim_fd = process->getSimFD(tgt_fd); 577 if (sim_fd < 0) 578 return -EBADF; 579 580#if NO_STAT64 581 int result = ftruncate(sim_fd, length); 582#else 583 int result = ftruncate64(sim_fd, length); 584#endif 585 return (result == -1) ? -errno : result; 586} 587 588SyscallReturn 589umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 590{ 591 // Letting the simulated program change the simulator's umask seems like 592 // a bad idea. Compromise by just returning the current umask but not 593 // changing anything. 594 mode_t oldMask = umask(0); 595 umask(oldMask); 596 return (int)oldMask; 597} 598 599SyscallReturn 600chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc) 601{ 602 string path; 603 604 int index = 0; 605 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 606 return -EFAULT; 607 608 /* XXX endianess */ 609 uint32_t owner = p->getSyscallArg(tc, index); 610 uid_t hostOwner = owner; 611 uint32_t group = p->getSyscallArg(tc, index); 612 gid_t hostGroup = group; 613 614 // Adjust path for current working directory 615 path = p->fullPath(path); 616 617 int result = chown(path.c_str(), hostOwner, hostGroup); 618 return (result == -1) ? -errno : result; 619} 620 621SyscallReturn 622fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 623{ 624 int index = 0; 625 int tgt_fd = process->getSyscallArg(tc, index); 626 627 int sim_fd = process->getSimFD(tgt_fd); 628 if (sim_fd < 0) 629 return -EBADF; 630 631 /* XXX endianess */ 632 uint32_t owner = process->getSyscallArg(tc, index); 633 uid_t hostOwner = owner; 634 uint32_t group = process->getSyscallArg(tc, index); 635 gid_t hostGroup = group; 636 637 int result = fchown(sim_fd, hostOwner, hostGroup); 638 return (result == -1) ? -errno : result; 639} 640 641 642SyscallReturn 643dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc) 644{ 645 int index = 0; 646 int tgt_fd = process->getSyscallArg(tc, index); 647 648 int sim_fd = process->getSimFD(tgt_fd); 649 if (sim_fd < 0) 650 return -EBADF; 651 652 FDEntry *fde = process->getFDEntry(tgt_fd); 653 654 int result = dup(sim_fd); 655 return (result == -1) ? -errno : 656 process->allocFD(result, fde->filename, fde->flags, fde->mode, false); 657} 658 659 660SyscallReturn 661fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process, 662 ThreadContext *tc) 663{ 664 int index = 0; 665 int tgt_fd = process->getSyscallArg(tc, index); 666 667 int sim_fd = process->getSimFD(tgt_fd); 668 if (sim_fd < 0) 669 return -EBADF; 670 671 int cmd = process->getSyscallArg(tc, index); 672 switch (cmd) { 673 case 0: // F_DUPFD 674 // if we really wanted to support this, we'd need to do it 675 // in the target fd space. 676 warn("fcntl(%d, F_DUPFD) not supported, error returned\n", tgt_fd); 677 return -EMFILE; 678 679 case 1: // F_GETFD (get close-on-exec flag) 680 case 2: // F_SETFD (set close-on-exec flag) 681 return 0; 682 683 case 3: // F_GETFL (get file flags) 684 case 4: // F_SETFL (set file flags) 685 // not sure if this is totally valid, but we'll pass it through 686 // to the underlying OS 687 warn("fcntl(%d, %d) passed through to host\n", tgt_fd, cmd); 688 return fcntl(sim_fd, cmd); 689 // return 0; 690 691 case 7: // F_GETLK (get lock) 692 case 8: // F_SETLK (set lock) 693 case 9: // F_SETLKW (set lock and wait) 694 // don't mess with file locking... just act like it's OK 695 warn("File lock call (fcntl(%d, %d)) ignored.\n", tgt_fd, cmd); 696 return 0; 697 698 default: 699 warn("Unknown fcntl command %d\n", cmd); 700 return 0; 701 } 702} 703 704SyscallReturn 705fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process, 706 ThreadContext *tc) 707{ 708 int index = 0; 709 int tgt_fd = process->getSyscallArg(tc, index); 710 711 int sim_fd = process->getSimFD(tgt_fd); 712 if (sim_fd < 0) 713 return -EBADF; 714 715 int cmd = process->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, LiveProcess *process, 738 ThreadContext *tc) 739{ 740 int fds[2], sim_fds[2]; 741 int pipe_retval = pipe(fds); 742 743 if (pipe_retval < 0) { 744 // error 745 return pipe_retval; 746 } 747 748 sim_fds[0] = process->allocFD(fds[0], "PIPE-READ", O_WRONLY, -1, true); 749 sim_fds[1] = process->allocFD(fds[1], "PIPE-WRITE", O_RDONLY, -1, true); 750 751 process->setReadPipeSource(sim_fds[0], sim_fds[1]); 752 // Alpha Linux convention for pipe() is that fd[0] is returned as 753 // the return value of the function, and fd[1] is returned in r20. 754 tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]); 755 return sim_fds[0]; 756} 757 758 759SyscallReturn 760getpidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 761 ThreadContext *tc) 762{ 763 // Make up a PID. There's no interprocess communication in 764 // fake_syscall mode, so there's no way for a process to know it's 765 // not getting a unique value. 766 767 tc->setIntReg(SyscallPseudoReturnReg, process->ppid()); 768 return process->pid(); 769} 770 771 772SyscallReturn 773getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 774 ThreadContext *tc) 775{ 776 // Make up a UID and EUID... it shouldn't matter, and we want the 777 // simulation to be deterministic. 778 779 // EUID goes in r20. 780 tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID 781 return process->uid(); // UID 782} 783 784 785SyscallReturn 786getgidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 787 ThreadContext *tc) 788{ 789 // Get current group ID. EGID goes in r20. 790 tc->setIntReg(SyscallPseudoReturnReg, process->egid()); //EGID 791 return process->gid(); 792} 793 794 795SyscallReturn 796setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 797 ThreadContext *tc) 798{ 799 // can't fathom why a benchmark would call this. 800 int index = 0; 801 warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, index)); 802 return 0; 803} 804 805SyscallReturn 806getpidFunc(SyscallDesc *desc, int callnum, LiveProcess *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()); //PID 814 return process->pid(); 815} 816 817SyscallReturn 818getppidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 819 ThreadContext *tc) 820{ 821 return process->ppid(); 822} 823 824SyscallReturn 825getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 826 ThreadContext *tc) 827{ 828 return process->uid(); // UID 829} 830 831SyscallReturn 832geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 833 ThreadContext *tc) 834{ 835 return process->euid(); // UID 836} 837 838SyscallReturn 839getgidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 840 ThreadContext *tc) 841{ 842 return process->gid(); 843} 844 845SyscallReturn 846getegidFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 847 ThreadContext *tc) 848{ 849 return process->egid(); 850} 851 852 853SyscallReturn 854cloneFunc(SyscallDesc *desc, int callnum, LiveProcess *process, 855 ThreadContext *tc) 856{ 857 int index = 0; 858 IntReg flags = process->getSyscallArg(tc, index); 859 IntReg newStack = process->getSyscallArg(tc, index); 860 861 DPRINTF(SyscallVerbose, "In sys_clone:\n"); 862 DPRINTF(SyscallVerbose, " Flags=%llx\n", flags); 863 DPRINTF(SyscallVerbose, " Child stack=%llx\n", newStack); 864 865 866 if (flags != 0x10f00) { 867 warn("This sys_clone implementation assumes flags " 868 "CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD " 869 "(0x10f00), and may not work correctly with given flags " 870 "0x%llx\n", flags); 871 } 872 873 ThreadContext* ctc; // child thread context 874 if ( ( ctc = process->findFreeContext() ) != NULL ) { 875 DPRINTF(SyscallVerbose, " Found unallocated thread context\n"); 876 877 ctc->clearArchRegs(); 878 879 // Arch-specific cloning code 880 #if THE_ISA == ALPHA_ISA or THE_ISA == X86_ISA 881 // Cloning the misc. regs for these archs is enough 882 TheISA::copyMiscRegs(tc, ctc); 883 #elif THE_ISA == SPARC_ISA 884 TheISA::copyRegs(tc, ctc); 885 886 // TODO: Explain what this code actually does :-) 887 ctc->setIntReg(NumIntArchRegs + 6, 0); 888 ctc->setIntReg(NumIntArchRegs + 4, 0); 889 ctc->setIntReg(NumIntArchRegs + 3, NWindows - 2); 890 ctc->setIntReg(NumIntArchRegs + 5, NWindows); 891 ctc->setMiscReg(MISCREG_CWP, 0); 892 ctc->setIntReg(NumIntArchRegs + 7, 0); 893 ctc->setMiscRegNoEffect(MISCREG_TL, 0); 894 ctc->setMiscReg(MISCREG_ASI, ASI_PRIMARY); 895 896 for (int y = 8; y < 32; y++) 897 ctc->setIntReg(y, tc->readIntReg(y)); 898 #elif THE_ISA == ARM_ISA 899 TheISA::copyRegs(tc, ctc); 900 #else 901 fatal("sys_clone is not implemented for this ISA\n"); 902 #endif 903 904 // Set up stack register 905 ctc->setIntReg(TheISA::StackPointerReg, newStack); 906 907 // Set up syscall return values in parent and child 908 ctc->setIntReg(ReturnValueReg, 0); // return value, child 909 910 // Alpha needs SyscallSuccessReg=0 in child 911 #if THE_ISA == ALPHA_ISA 912 ctc->setIntReg(TheISA::SyscallSuccessReg, 0); 913 #endif 914 915 // In SPARC/Linux, clone returns 0 on pseudo-return register if 916 // parent, non-zero if child 917 #if THE_ISA == SPARC_ISA 918 tc->setIntReg(TheISA::SyscallPseudoReturnReg, 0); 919 ctc->setIntReg(TheISA::SyscallPseudoReturnReg, 1); 920 #endif 921 922 ctc->pcState(tc->nextInstAddr()); 923 924 ctc->activate(); 925 926 // Should return nonzero child TID in parent's syscall return register, 927 // but for our pthread library any non-zero value will work 928 return 1; 929 } else { 930 fatal("Called sys_clone, but no unallocated thread contexts found!\n"); 931 return 0; 932 } 933} 934 935SyscallReturn 936accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc, 937 int index) 938{ 939 string path; 940 if (!tc->getMemProxy().tryReadString(path, p->getSyscallArg(tc, index))) 941 return -EFAULT; 942 943 // Adjust path for current working directory 944 path = p->fullPath(path); 945 946 mode_t mode = p->getSyscallArg(tc, index); 947 948 int result = access(path.c_str(), mode); 949 return (result == -1) ? -errno : result; 950} 951 952SyscallReturn 953accessFunc(SyscallDesc *desc, int callnum, LiveProcess *p, ThreadContext *tc) 954{ 955 return accessFunc(desc, callnum, p, tc, 0); 956} 957 958