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