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