syscall_emul.cc (12796:16dffc0e6c7f) syscall_emul.cc (13031:47510ddc366d)
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