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