syscall_emul.hh revision 10485:5aa65300f44f
1/*
2 * Copyright (c) 2012-2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2003-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Steve Reinhardt
41 *          Kevin Lim
42 */
43
44#ifndef __SIM_SYSCALL_EMUL_HH__
45#define __SIM_SYSCALL_EMUL_HH__
46
47#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
48  defined(__FreeBSD__) || defined(__CYGWIN__) || \
49  defined(__NetBSD__))
50
51///
52/// @file syscall_emul.hh
53///
54/// This file defines objects used to emulate syscalls from the target
55/// application on the host machine.
56
57#ifdef __CYGWIN32__
58#include <sys/fcntl.h>  // for O_BINARY
59#endif
60#include <sys/stat.h>
61#include <sys/time.h>
62#include <sys/uio.h>
63#include <fcntl.h>
64
65#include <cerrno>
66#include <string>
67
68#include "base/chunk_generator.hh"
69#include "base/intmath.hh"      // for RoundUp
70#include "base/misc.hh"
71#include "base/trace.hh"
72#include "base/types.hh"
73#include "config/the_isa.hh"
74#include "cpu/base.hh"
75#include "cpu/thread_context.hh"
76#include "debug/SyscallVerbose.hh"
77#include "mem/page_table.hh"
78#include "mem/se_translating_port_proxy.hh"
79#include "sim/byteswap.hh"
80#include "sim/process.hh"
81#include "sim/syscallreturn.hh"
82#include "sim/system.hh"
83
84///
85/// System call descriptor.
86///
87class SyscallDesc {
88
89  public:
90
91    /// Typedef for target syscall handler functions.
92    typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
93                           LiveProcess *, ThreadContext *);
94
95    const char *name;   //!< Syscall name (e.g., "open").
96    FuncPtr funcPtr;    //!< Pointer to emulation function.
97    int flags;          //!< Flags (see Flags enum).
98
99    /// Flag values for controlling syscall behavior.
100    enum Flags {
101        /// Don't set return regs according to funcPtr return value.
102        /// Used for syscalls with non-standard return conventions
103        /// that explicitly set the ThreadContext regs (e.g.,
104        /// sigreturn).
105        SuppressReturnValue = 1
106    };
107
108    /// Constructor.
109    SyscallDesc(const char *_name, FuncPtr _funcPtr, int _flags = 0)
110        : name(_name), funcPtr(_funcPtr), flags(_flags)
111    {
112    }
113
114    /// Emulate the syscall.  Public interface for calling through funcPtr.
115    void doSyscall(int callnum, LiveProcess *proc, ThreadContext *tc);
116};
117
118
119class BaseBufferArg {
120
121  public:
122
123    BaseBufferArg(Addr _addr, int _size) : addr(_addr), size(_size)
124    {
125        bufPtr = new uint8_t[size];
126        // clear out buffer: in case we only partially populate this,
127        // and then do a copyOut(), we want to make sure we don't
128        // introduce any random junk into the simulated address space
129        memset(bufPtr, 0, size);
130    }
131
132    virtual ~BaseBufferArg() { delete [] bufPtr; }
133
134    //
135    // copy data into simulator space (read from target memory)
136    //
137    virtual bool copyIn(SETranslatingPortProxy &memproxy)
138    {
139        memproxy.readBlob(addr, bufPtr, size);
140        return true;    // no EFAULT detection for now
141    }
142
143    //
144    // copy data out of simulator space (write to target memory)
145    //
146    virtual bool copyOut(SETranslatingPortProxy &memproxy)
147    {
148        memproxy.writeBlob(addr, bufPtr, size);
149        return true;    // no EFAULT detection for now
150    }
151
152  protected:
153    Addr addr;
154    int size;
155    uint8_t *bufPtr;
156};
157
158
159class BufferArg : public BaseBufferArg
160{
161  public:
162    BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
163    void *bufferPtr()   { return bufPtr; }
164};
165
166template <class T>
167class TypedBufferArg : public BaseBufferArg
168{
169  public:
170    // user can optionally specify a specific number of bytes to
171    // allocate to deal with those structs that have variable-size
172    // arrays at the end
173    TypedBufferArg(Addr _addr, int _size = sizeof(T))
174        : BaseBufferArg(_addr, _size)
175    { }
176
177    // type case
178    operator T*() { return (T *)bufPtr; }
179
180    // dereference operators
181    T &operator*()       { return *((T *)bufPtr); }
182    T* operator->()      { return (T *)bufPtr; }
183    T &operator[](int i) { return ((T *)bufPtr)[i]; }
184};
185
186//////////////////////////////////////////////////////////////////////
187//
188// The following emulation functions are generic enough that they
189// don't need to be recompiled for different emulated OS's.  They are
190// defined in sim/syscall_emul.cc.
191//
192//////////////////////////////////////////////////////////////////////
193
194
195/// Handler for unimplemented syscalls that we haven't thought about.
196SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
197                                LiveProcess *p, ThreadContext *tc);
198
199/// Handler for unimplemented syscalls that we never intend to
200/// implement (signal handling, etc.) and should not affect the correct
201/// behavior of the program.  Print a warning only if the appropriate
202/// trace flag is enabled.  Return success to the target program.
203SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
204                         LiveProcess *p, ThreadContext *tc);
205SyscallReturn ignoreWarnOnceFunc(SyscallDesc *desc, int num,
206                         LiveProcess *p, ThreadContext *tc);
207
208/// Target exit() handler: terminate current context.
209SyscallReturn exitFunc(SyscallDesc *desc, int num,
210                       LiveProcess *p, ThreadContext *tc);
211
212/// Target exit_group() handler: terminate simulation. (exit all threads)
213SyscallReturn exitGroupFunc(SyscallDesc *desc, int num,
214                       LiveProcess *p, ThreadContext *tc);
215
216/// Target getpagesize() handler.
217SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
218                              LiveProcess *p, ThreadContext *tc);
219
220/// Target brk() handler: set brk address.
221SyscallReturn brkFunc(SyscallDesc *desc, int num,
222                      LiveProcess *p, ThreadContext *tc);
223
224/// Target close() handler.
225SyscallReturn closeFunc(SyscallDesc *desc, int num,
226                        LiveProcess *p, ThreadContext *tc);
227
228/// Target read() handler.
229SyscallReturn readFunc(SyscallDesc *desc, int num,
230                       LiveProcess *p, ThreadContext *tc);
231
232/// Target write() handler.
233SyscallReturn writeFunc(SyscallDesc *desc, int num,
234                        LiveProcess *p, ThreadContext *tc);
235
236/// Target lseek() handler.
237SyscallReturn lseekFunc(SyscallDesc *desc, int num,
238                        LiveProcess *p, ThreadContext *tc);
239
240/// Target _llseek() handler.
241SyscallReturn _llseekFunc(SyscallDesc *desc, int num,
242                        LiveProcess *p, ThreadContext *tc);
243
244/// Target munmap() handler.
245SyscallReturn munmapFunc(SyscallDesc *desc, int num,
246                         LiveProcess *p, ThreadContext *tc);
247
248/// Target gethostname() handler.
249SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
250                              LiveProcess *p, ThreadContext *tc);
251
252/// Target getcwd() handler.
253SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
254                         LiveProcess *p, ThreadContext *tc);
255
256/// Target readlink() handler.
257SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
258                           LiveProcess *p, ThreadContext *tc,
259                           int index = 0);
260SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
261                           LiveProcess *p, ThreadContext *tc);
262
263/// Target unlink() handler.
264SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
265                         LiveProcess *p, ThreadContext *tc);
266
267/// Target mkdir() handler.
268SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
269                        LiveProcess *p, ThreadContext *tc);
270
271/// Target rename() handler.
272SyscallReturn renameFunc(SyscallDesc *desc, int num,
273                         LiveProcess *p, ThreadContext *tc);
274
275
276/// Target truncate() handler.
277SyscallReturn truncateFunc(SyscallDesc *desc, int num,
278                           LiveProcess *p, ThreadContext *tc);
279
280
281/// Target ftruncate() handler.
282SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
283                            LiveProcess *p, ThreadContext *tc);
284
285
286/// Target truncate64() handler.
287SyscallReturn truncate64Func(SyscallDesc *desc, int num,
288                             LiveProcess *p, ThreadContext *tc);
289
290/// Target ftruncate64() handler.
291SyscallReturn ftruncate64Func(SyscallDesc *desc, int num,
292                              LiveProcess *p, ThreadContext *tc);
293
294
295/// Target umask() handler.
296SyscallReturn umaskFunc(SyscallDesc *desc, int num,
297                        LiveProcess *p, ThreadContext *tc);
298
299
300/// Target chown() handler.
301SyscallReturn chownFunc(SyscallDesc *desc, int num,
302                        LiveProcess *p, ThreadContext *tc);
303
304
305/// Target fchown() handler.
306SyscallReturn fchownFunc(SyscallDesc *desc, int num,
307                         LiveProcess *p, ThreadContext *tc);
308
309/// Target dup() handler.
310SyscallReturn dupFunc(SyscallDesc *desc, int num,
311                      LiveProcess *process, ThreadContext *tc);
312
313/// Target fnctl() handler.
314SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
315                        LiveProcess *process, ThreadContext *tc);
316
317/// Target fcntl64() handler.
318SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
319                        LiveProcess *process, ThreadContext *tc);
320
321/// Target setuid() handler.
322SyscallReturn setuidFunc(SyscallDesc *desc, int num,
323                               LiveProcess *p, ThreadContext *tc);
324
325/// Target getpid() handler.
326SyscallReturn getpidFunc(SyscallDesc *desc, int num,
327                               LiveProcess *p, ThreadContext *tc);
328
329/// Target getuid() handler.
330SyscallReturn getuidFunc(SyscallDesc *desc, int num,
331                               LiveProcess *p, ThreadContext *tc);
332
333/// Target getgid() handler.
334SyscallReturn getgidFunc(SyscallDesc *desc, int num,
335                               LiveProcess *p, ThreadContext *tc);
336
337/// Target getppid() handler.
338SyscallReturn getppidFunc(SyscallDesc *desc, int num,
339                               LiveProcess *p, ThreadContext *tc);
340
341/// Target geteuid() handler.
342SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
343                               LiveProcess *p, ThreadContext *tc);
344
345/// Target getegid() handler.
346SyscallReturn getegidFunc(SyscallDesc *desc, int num,
347                               LiveProcess *p, ThreadContext *tc);
348
349/// Target clone() handler.
350SyscallReturn cloneFunc(SyscallDesc *desc, int num,
351                               LiveProcess *p, ThreadContext *tc);
352
353/// Target access() handler
354SyscallReturn accessFunc(SyscallDesc *desc, int num,
355                               LiveProcess *p, ThreadContext *tc);
356SyscallReturn accessFunc(SyscallDesc *desc, int num,
357                               LiveProcess *p, ThreadContext *tc,
358                               int index);
359
360/// Futex system call
361///  Implemented by Daniel Sanchez
362///  Used by printf's in multi-threaded apps
363template <class OS>
364SyscallReturn
365futexFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
366          ThreadContext *tc)
367{
368    int index_uaddr = 0;
369    int index_op = 1;
370    int index_val = 2;
371    int index_timeout = 3;
372
373    uint64_t uaddr = process->getSyscallArg(tc, index_uaddr);
374    int op = process->getSyscallArg(tc, index_op);
375    int val = process->getSyscallArg(tc, index_val);
376    uint64_t timeout = process->getSyscallArg(tc, index_timeout);
377
378    std::map<uint64_t, std::list<ThreadContext *> * >
379        &futex_map = tc->getSystemPtr()->futexMap;
380
381    DPRINTF(SyscallVerbose, "In sys_futex: Address=%llx, op=%d, val=%d\n",
382            uaddr, op, val);
383
384    op &= ~OS::TGT_FUTEX_PRIVATE_FLAG;
385
386    if (op == OS::TGT_FUTEX_WAIT) {
387        if (timeout != 0) {
388            warn("sys_futex: FUTEX_WAIT with non-null timeout unimplemented;"
389                 "we'll wait indefinitely");
390        }
391
392        uint8_t *buf = new uint8_t[sizeof(int)];
393        tc->getMemProxy().readBlob((Addr)uaddr, buf, (int)sizeof(int));
394        int mem_val = *((int *)buf);
395        delete buf;
396
397        if(val != mem_val) {
398            DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, read: %d, "
399                                    "expected: %d\n", mem_val, val);
400            return -OS::TGT_EWOULDBLOCK;
401        }
402
403        // Queue the thread context
404        std::list<ThreadContext *> * tcWaitList;
405        if (futex_map.count(uaddr)) {
406            tcWaitList = futex_map.find(uaddr)->second;
407        } else {
408            tcWaitList = new std::list<ThreadContext *>();
409            futex_map.insert(std::pair< uint64_t,
410                            std::list<ThreadContext *> * >(uaddr, tcWaitList));
411        }
412        tcWaitList->push_back(tc);
413        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAIT, suspending calling "
414                                "thread context\n");
415        tc->suspend();
416        return 0;
417    } else if (op == OS::TGT_FUTEX_WAKE){
418        int wokenUp = 0;
419        std::list<ThreadContext *> * tcWaitList;
420        if (futex_map.count(uaddr)) {
421            tcWaitList = futex_map.find(uaddr)->second;
422            while (tcWaitList->size() > 0 && wokenUp < val) {
423                tcWaitList->front()->activate();
424                tcWaitList->pop_front();
425                wokenUp++;
426            }
427            if(tcWaitList->empty()) {
428                futex_map.erase(uaddr);
429                delete tcWaitList;
430            }
431        }
432        DPRINTF(SyscallVerbose, "sys_futex: FUTEX_WAKE, activated %d waiting "
433                                "thread contexts\n", wokenUp);
434        return wokenUp;
435    } else {
436        warn("sys_futex: op %d is not implemented, just returning...", op);
437        return 0;
438    }
439
440}
441
442/// Target getdents() handler.
443SyscallReturn getdentsFunc(SyscallDesc *desc, int num,
444                           LiveProcess *process, ThreadContext *tc);
445
446/// Target getdents64() handler.
447SyscallReturn getdents64Func(SyscallDesc *desc, int num,
448                             LiveProcess *process, ThreadContext *tc);
449
450
451/// Pseudo Funcs  - These functions use a different return convension,
452/// returning a second value in a register other than the normal return register
453SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
454                             LiveProcess *process, ThreadContext *tc);
455
456/// Target getpidPseudo() handler.
457SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
458                               LiveProcess *p, ThreadContext *tc);
459
460/// Target getuidPseudo() handler.
461SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
462                               LiveProcess *p, ThreadContext *tc);
463
464/// Target getgidPseudo() handler.
465SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
466                               LiveProcess *p, ThreadContext *tc);
467
468
469/// A readable name for 1,000,000, for converting microseconds to seconds.
470const int one_million = 1000000;
471
472/// Approximate seconds since the epoch (1/1/1970).  About a billion,
473/// by my reckoning.  We want to keep this a constant (not use the
474/// real-world time) to keep simulations repeatable.
475const unsigned seconds_since_epoch = 1000000000;
476
477/// Helper function to convert current elapsed time to seconds and
478/// microseconds.
479template <class T1, class T2>
480void
481getElapsedTime(T1 &sec, T2 &usec)
482{
483    int elapsed_usecs = curTick() / SimClock::Int::us;
484    sec = elapsed_usecs / one_million;
485    usec = elapsed_usecs % one_million;
486}
487
488//////////////////////////////////////////////////////////////////////
489//
490// The following emulation functions are generic, but need to be
491// templated to account for differences in types, constants, etc.
492//
493//////////////////////////////////////////////////////////////////////
494
495#if NO_STAT64
496    typedef struct stat hst_stat;
497    typedef struct stat hst_stat64;
498#else
499    typedef struct stat hst_stat;
500    typedef struct stat64 hst_stat64;
501#endif
502
503//// Helper function to convert a host stat buffer to a target stat
504//// buffer.  Also copies the target buffer out to the simulated
505//// memory space.  Used by stat(), fstat(), and lstat().
506
507template <typename target_stat, typename host_stat>
508static void
509convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
510{
511    using namespace TheISA;
512
513    if (fakeTTY)
514        tgt->st_dev = 0xA;
515    else
516        tgt->st_dev = host->st_dev;
517    tgt->st_dev = TheISA::htog(tgt->st_dev);
518    tgt->st_ino = host->st_ino;
519    tgt->st_ino = TheISA::htog(tgt->st_ino);
520    tgt->st_mode = host->st_mode;
521    if (fakeTTY) {
522        // Claim to be a character device
523        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
524        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
525    }
526    tgt->st_mode = TheISA::htog(tgt->st_mode);
527    tgt->st_nlink = host->st_nlink;
528    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
529    tgt->st_uid = host->st_uid;
530    tgt->st_uid = TheISA::htog(tgt->st_uid);
531    tgt->st_gid = host->st_gid;
532    tgt->st_gid = TheISA::htog(tgt->st_gid);
533    if (fakeTTY)
534        tgt->st_rdev = 0x880d;
535    else
536        tgt->st_rdev = host->st_rdev;
537    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
538    tgt->st_size = host->st_size;
539    tgt->st_size = TheISA::htog(tgt->st_size);
540    tgt->st_atimeX = host->st_atime;
541    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
542    tgt->st_mtimeX = host->st_mtime;
543    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
544    tgt->st_ctimeX = host->st_ctime;
545    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
546    // Force the block size to be 8k. This helps to ensure buffered io works
547    // consistently across different hosts.
548    tgt->st_blksize = 0x2000;
549    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
550    tgt->st_blocks = host->st_blocks;
551    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
552}
553
554// Same for stat64
555
556template <typename target_stat, typename host_stat64>
557static void
558convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
559{
560    using namespace TheISA;
561
562    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
563#if defined(STAT_HAVE_NSEC)
564    tgt->st_atime_nsec = host->st_atime_nsec;
565    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
566    tgt->st_mtime_nsec = host->st_mtime_nsec;
567    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
568    tgt->st_ctime_nsec = host->st_ctime_nsec;
569    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
570#else
571    tgt->st_atime_nsec = 0;
572    tgt->st_mtime_nsec = 0;
573    tgt->st_ctime_nsec = 0;
574#endif
575}
576
577//Here are a couple convenience functions
578template<class OS>
579static void
580copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
581        hst_stat *host, bool fakeTTY = false)
582{
583    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
584    tgt_stat_buf tgt(addr);
585    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
586    tgt.copyOut(mem);
587}
588
589template<class OS>
590static void
591copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
592        hst_stat64 *host, bool fakeTTY = false)
593{
594    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
595    tgt_stat_buf tgt(addr);
596    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
597    tgt.copyOut(mem);
598}
599
600/// Target ioctl() handler.  For the most part, programs call ioctl()
601/// only to find out if their stdout is a tty, to determine whether to
602/// do line or block buffering.  We always claim that output fds are
603/// not TTYs to provide repeatable results.
604template <class OS>
605SyscallReturn
606ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
607          ThreadContext *tc)
608{
609    int index = 0;
610    int fd = process->getSyscallArg(tc, index);
611    unsigned req = process->getSyscallArg(tc, index);
612
613    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
614
615    if (fd < 0 || process->sim_fd(fd) < 0) {
616        // doesn't map to any simulator fd: not a valid target fd
617        return -EBADF;
618    }
619
620    if (OS::isTtyReq(req)) {
621        return -ENOTTY;
622    }
623
624    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
625         fd, req, tc->pcState());
626    return -ENOTTY;
627}
628
629template <class OS>
630static SyscallReturn
631openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
632         ThreadContext *tc, int index)
633{
634    std::string path;
635
636    if (!tc->getMemProxy().tryReadString(path,
637                process->getSyscallArg(tc, index)))
638        return -EFAULT;
639
640    if (path == "/dev/sysdev0") {
641        // This is a memory-mapped high-resolution timer device on Alpha.
642        // We don't support it, so just punt.
643        warn("Ignoring open(%s, ...)\n", path);
644        return -ENOENT;
645    }
646
647    int tgtFlags = process->getSyscallArg(tc, index);
648    int mode = process->getSyscallArg(tc, index);
649    int hostFlags = 0;
650
651    // translate open flags
652    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
653        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
654            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
655            hostFlags |= OS::openFlagTable[i].hostFlag;
656        }
657    }
658
659    // any target flags left?
660    if (tgtFlags != 0)
661        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
662
663#ifdef __CYGWIN32__
664    hostFlags |= O_BINARY;
665#endif
666
667    // Adjust path for current working directory
668    path = process->fullPath(path);
669
670    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
671
672    int fd;
673    int local_errno;
674    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
675        startswith(path, "/platform/") || startswith(path, "/sys/")) {
676        // It's a proc/sys entry and requires special handling
677        fd = OS::openSpecialFile(path, process, tc);
678        local_errno = ENOENT;
679     } else {
680        // open the file
681        fd = open(path.c_str(), hostFlags, mode);
682        local_errno = errno;
683     }
684
685    if (fd == -1)
686        return -local_errno;
687
688    return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false);
689}
690
691/// Target open() handler.
692template <class OS>
693SyscallReturn
694openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
695         ThreadContext *tc)
696{
697    return openFunc<OS>(desc, callnum, process, tc, 0);
698}
699
700/// Target openat() handler.
701template <class OS>
702SyscallReturn
703openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
704         ThreadContext *tc)
705{
706    int index = 0;
707    int dirfd = process->getSyscallArg(tc, index);
708    if (dirfd != OS::TGT_AT_FDCWD)
709        warn("openat: first argument not AT_FDCWD; unlikely to work");
710    return openFunc<OS>(desc, callnum, process, tc, 1);
711}
712
713/// Target facessat() handler
714template <class OS>
715SyscallReturn
716faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
717        ThreadContext *tc)
718{
719    int index = 0;
720    int dirfd = process->getSyscallArg(tc, index);
721    if (dirfd != OS::TGT_AT_FDCWD)
722        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
723    return accessFunc(desc, callnum, process, tc, 1);
724}
725
726/// Target readlinkat() handler
727template <class OS>
728SyscallReturn
729readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
730        ThreadContext *tc)
731{
732    int index = 0;
733    int dirfd = process->getSyscallArg(tc, index);
734    if (dirfd != OS::TGT_AT_FDCWD)
735        warn("openat: first argument not AT_FDCWD; unlikely to work");
736    return readlinkFunc(desc, callnum, process, tc, 1);
737}
738
739/// Target sysinfo() handler.
740template <class OS>
741SyscallReturn
742sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
743         ThreadContext *tc)
744{
745
746    int index = 0;
747    TypedBufferArg<typename OS::tgt_sysinfo>
748        sysinfo(process->getSyscallArg(tc, index));
749
750    sysinfo->uptime=seconds_since_epoch;
751    sysinfo->totalram=process->system->memSize();
752
753    sysinfo.copyOut(tc->getMemProxy());
754
755    return 0;
756}
757
758/// Target chmod() handler.
759template <class OS>
760SyscallReturn
761chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
762          ThreadContext *tc)
763{
764    std::string path;
765
766    int index = 0;
767    if (!tc->getMemProxy().tryReadString(path,
768                process->getSyscallArg(tc, index))) {
769        return -EFAULT;
770    }
771
772    uint32_t mode = process->getSyscallArg(tc, index);
773    mode_t hostMode = 0;
774
775    // XXX translate mode flags via OS::something???
776    hostMode = mode;
777
778    // Adjust path for current working directory
779    path = process->fullPath(path);
780
781    // do the chmod
782    int result = chmod(path.c_str(), hostMode);
783    if (result < 0)
784        return -errno;
785
786    return 0;
787}
788
789
790/// Target fchmod() handler.
791template <class OS>
792SyscallReturn
793fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
794           ThreadContext *tc)
795{
796    int index = 0;
797    int fd = process->getSyscallArg(tc, index);
798    if (fd < 0 || process->sim_fd(fd) < 0) {
799        // doesn't map to any simulator fd: not a valid target fd
800        return -EBADF;
801    }
802
803    uint32_t mode = process->getSyscallArg(tc, index);
804    mode_t hostMode = 0;
805
806    // XXX translate mode flags via OS::someting???
807    hostMode = mode;
808
809    // do the fchmod
810    int result = fchmod(process->sim_fd(fd), hostMode);
811    if (result < 0)
812        return -errno;
813
814    return 0;
815}
816
817/// Target mremap() handler.
818template <class OS>
819SyscallReturn
820mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
821{
822    int index = 0;
823    Addr start = process->getSyscallArg(tc, index);
824    uint64_t old_length = process->getSyscallArg(tc, index);
825    uint64_t new_length = process->getSyscallArg(tc, index);
826    uint64_t flags = process->getSyscallArg(tc, index);
827    uint64_t provided_address = 0;
828    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
829
830    if (use_provided_address)
831        provided_address = process->getSyscallArg(tc, index);
832
833    if ((start % TheISA::PageBytes != 0) ||
834        (new_length % TheISA::PageBytes != 0) ||
835        (provided_address % TheISA::PageBytes != 0)) {
836        warn("mremap failing: arguments not page aligned");
837        return -EINVAL;
838    }
839
840    if (new_length > old_length) {
841        if ((start + old_length) == process->mmap_end &&
842            (!use_provided_address || provided_address == start)) {
843            uint64_t diff = new_length - old_length;
844            process->allocateMem(process->mmap_end, diff);
845            process->mmap_end += diff;
846            return start;
847        } else {
848            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
849                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
850                return -ENOMEM;
851            } else {
852                uint64_t new_start = use_provided_address ?
853                    provided_address : process->mmap_end;
854                process->pTable->remap(start, old_length, new_start);
855                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
856                     new_start, new_start + new_length,
857                     new_length - old_length);
858                // add on the remaining unallocated pages
859                process->allocateMem(new_start + old_length,
860                                     new_length - old_length,
861                                     use_provided_address /* clobber */);
862                if (!use_provided_address)
863                    process->mmap_end += new_length;
864                if (use_provided_address &&
865                    new_start + new_length > process->mmap_end) {
866                    // something fishy going on here, at least notify the user
867                    // @todo: increase mmap_end?
868                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
869                }
870                warn("returning %08p as start\n", new_start);
871                return new_start;
872            }
873        }
874    } else {
875        if (use_provided_address && provided_address != start)
876            process->pTable->remap(start, new_length, provided_address);
877        process->pTable->unmap(start + new_length, old_length - new_length);
878        return use_provided_address ? provided_address : start;
879    }
880}
881
882/// Target stat() handler.
883template <class OS>
884SyscallReturn
885statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
886         ThreadContext *tc)
887{
888    std::string path;
889
890    int index = 0;
891    if (!tc->getMemProxy().tryReadString(path,
892                process->getSyscallArg(tc, index))) {
893        return -EFAULT;
894    }
895    Addr bufPtr = process->getSyscallArg(tc, index);
896
897    // Adjust path for current working directory
898    path = process->fullPath(path);
899
900    struct stat hostBuf;
901    int result = stat(path.c_str(), &hostBuf);
902
903    if (result < 0)
904        return -errno;
905
906    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
907
908    return 0;
909}
910
911
912/// Target stat64() handler.
913template <class OS>
914SyscallReturn
915stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
916           ThreadContext *tc)
917{
918    std::string path;
919
920    int index = 0;
921    if (!tc->getMemProxy().tryReadString(path,
922                process->getSyscallArg(tc, index)))
923        return -EFAULT;
924    Addr bufPtr = process->getSyscallArg(tc, index);
925
926    // Adjust path for current working directory
927    path = process->fullPath(path);
928
929#if NO_STAT64
930    struct stat  hostBuf;
931    int result = stat(path.c_str(), &hostBuf);
932#else
933    struct stat64 hostBuf;
934    int result = stat64(path.c_str(), &hostBuf);
935#endif
936
937    if (result < 0)
938        return -errno;
939
940    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
941
942    return 0;
943}
944
945
946/// Target fstatat64() handler.
947template <class OS>
948SyscallReturn
949fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
950              ThreadContext *tc)
951{
952    int index = 0;
953    int dirfd = process->getSyscallArg(tc, index);
954    if (dirfd != OS::TGT_AT_FDCWD)
955        warn("openat: first argument not AT_FDCWD; unlikely to work");
956
957    std::string path;
958    if (!tc->getMemProxy().tryReadString(path,
959                process->getSyscallArg(tc, index)))
960        return -EFAULT;
961    Addr bufPtr = process->getSyscallArg(tc, index);
962
963    // Adjust path for current working directory
964    path = process->fullPath(path);
965
966#if NO_STAT64
967    struct stat  hostBuf;
968    int result = stat(path.c_str(), &hostBuf);
969#else
970    struct stat64 hostBuf;
971    int result = stat64(path.c_str(), &hostBuf);
972#endif
973
974    if (result < 0)
975        return -errno;
976
977    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
978
979    return 0;
980}
981
982
983/// Target fstat64() handler.
984template <class OS>
985SyscallReturn
986fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
987            ThreadContext *tc)
988{
989    int index = 0;
990    int fd = process->getSyscallArg(tc, index);
991    Addr bufPtr = process->getSyscallArg(tc, index);
992    if (fd < 0 || process->sim_fd(fd) < 0) {
993        // doesn't map to any simulator fd: not a valid target fd
994        return -EBADF;
995    }
996
997#if NO_STAT64
998    struct stat  hostBuf;
999    int result = fstat(process->sim_fd(fd), &hostBuf);
1000#else
1001    struct stat64  hostBuf;
1002    int result = fstat64(process->sim_fd(fd), &hostBuf);
1003#endif
1004
1005    if (result < 0)
1006        return -errno;
1007
1008    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1009
1010    return 0;
1011}
1012
1013
1014/// Target lstat() handler.
1015template <class OS>
1016SyscallReturn
1017lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1018          ThreadContext *tc)
1019{
1020    std::string path;
1021
1022    int index = 0;
1023    if (!tc->getMemProxy().tryReadString(path,
1024                process->getSyscallArg(tc, index))) {
1025        return -EFAULT;
1026    }
1027    Addr bufPtr = process->getSyscallArg(tc, index);
1028
1029    // Adjust path for current working directory
1030    path = process->fullPath(path);
1031
1032    struct stat hostBuf;
1033    int result = lstat(path.c_str(), &hostBuf);
1034
1035    if (result < 0)
1036        return -errno;
1037
1038    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1039
1040    return 0;
1041}
1042
1043/// Target lstat64() handler.
1044template <class OS>
1045SyscallReturn
1046lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1047            ThreadContext *tc)
1048{
1049    std::string path;
1050
1051    int index = 0;
1052    if (!tc->getMemProxy().tryReadString(path,
1053                process->getSyscallArg(tc, index))) {
1054        return -EFAULT;
1055    }
1056    Addr bufPtr = process->getSyscallArg(tc, index);
1057
1058    // Adjust path for current working directory
1059    path = process->fullPath(path);
1060
1061#if NO_STAT64
1062    struct stat hostBuf;
1063    int result = lstat(path.c_str(), &hostBuf);
1064#else
1065    struct stat64 hostBuf;
1066    int result = lstat64(path.c_str(), &hostBuf);
1067#endif
1068
1069    if (result < 0)
1070        return -errno;
1071
1072    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1073
1074    return 0;
1075}
1076
1077/// Target fstat() handler.
1078template <class OS>
1079SyscallReturn
1080fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1081          ThreadContext *tc)
1082{
1083    int index = 0;
1084    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1085    Addr bufPtr = process->getSyscallArg(tc, index);
1086
1087    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
1088
1089    if (fd < 0)
1090        return -EBADF;
1091
1092    struct stat hostBuf;
1093    int result = fstat(fd, &hostBuf);
1094
1095    if (result < 0)
1096        return -errno;
1097
1098    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1099
1100    return 0;
1101}
1102
1103
1104/// Target statfs() handler.
1105template <class OS>
1106SyscallReturn
1107statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1108           ThreadContext *tc)
1109{
1110    std::string path;
1111
1112    int index = 0;
1113    if (!tc->getMemProxy().tryReadString(path,
1114                process->getSyscallArg(tc, index))) {
1115        return -EFAULT;
1116    }
1117    Addr bufPtr = process->getSyscallArg(tc, index);
1118
1119    // Adjust path for current working directory
1120    path = process->fullPath(path);
1121
1122    struct statfs hostBuf;
1123    int result = statfs(path.c_str(), &hostBuf);
1124
1125    if (result < 0)
1126        return -errno;
1127
1128    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1129
1130    return 0;
1131}
1132
1133
1134/// Target fstatfs() handler.
1135template <class OS>
1136SyscallReturn
1137fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1138            ThreadContext *tc)
1139{
1140    int index = 0;
1141    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1142    Addr bufPtr = process->getSyscallArg(tc, index);
1143
1144    if (fd < 0)
1145        return -EBADF;
1146
1147    struct statfs hostBuf;
1148    int result = fstatfs(fd, &hostBuf);
1149
1150    if (result < 0)
1151        return -errno;
1152
1153    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1154
1155    return 0;
1156}
1157
1158
1159/// Target writev() handler.
1160template <class OS>
1161SyscallReturn
1162writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1163           ThreadContext *tc)
1164{
1165    int index = 0;
1166    int fd = process->getSyscallArg(tc, index);
1167    if (fd < 0 || process->sim_fd(fd) < 0) {
1168        // doesn't map to any simulator fd: not a valid target fd
1169        return -EBADF;
1170    }
1171
1172    SETranslatingPortProxy &p = tc->getMemProxy();
1173    uint64_t tiov_base = process->getSyscallArg(tc, index);
1174    size_t count = process->getSyscallArg(tc, index);
1175    struct iovec hiov[count];
1176    for (size_t i = 0; i < count; ++i) {
1177        typename OS::tgt_iovec tiov;
1178
1179        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1180                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1181        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1182        hiov[i].iov_base = new char [hiov[i].iov_len];
1183        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1184                   hiov[i].iov_len);
1185    }
1186
1187    int result = writev(process->sim_fd(fd), hiov, count);
1188
1189    for (size_t i = 0; i < count; ++i)
1190        delete [] (char *)hiov[i].iov_base;
1191
1192    if (result < 0)
1193        return -errno;
1194
1195    return 0;
1196}
1197
1198
1199/// Target mmap() handler.
1200///
1201/// We don't really handle mmap().  If the target is mmaping an
1202/// anonymous region or /dev/zero, we can get away with doing basically
1203/// nothing (since memory is initialized to zero and the simulator
1204/// doesn't really check addresses anyway).
1205///
1206template <class OS>
1207SyscallReturn
1208mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1209{
1210    int index = 0;
1211    Addr start = p->getSyscallArg(tc, index);
1212    uint64_t length = p->getSyscallArg(tc, index);
1213    index++; // int prot = p->getSyscallArg(tc, index);
1214    int flags = p->getSyscallArg(tc, index);
1215    int tgt_fd = p->getSyscallArg(tc, index);
1216    // int offset = p->getSyscallArg(tc, index);
1217
1218    if (length > 0x100000000ULL)
1219        warn("mmap length argument %#x is unreasonably large.\n", length);
1220
1221    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
1222        Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd);
1223        if (!fd_map || fd_map->fd < 0) {
1224            warn("mmap failing: target fd %d is not valid\n", tgt_fd);
1225            return -EBADF;
1226        }
1227
1228        if (fd_map->filename != "/dev/zero") {
1229            // This is very likely broken, but leave a warning here
1230            // (rather than panic) in case /dev/zero is known by
1231            // another name on some platform
1232            warn("allowing mmap of file %s; mmap not supported on files"
1233                 " other than /dev/zero\n", fd_map->filename);
1234        }
1235    }
1236
1237    if ((start  % TheISA::PageBytes) != 0 ||
1238        (length % TheISA::PageBytes) != 0) {
1239        warn("mmap failing: arguments not page-aligned: "
1240             "start 0x%x length 0x%x",
1241             start, length);
1242        return -EINVAL;
1243    }
1244
1245    // are we ok with clobbering existing mappings?  only set this to
1246    // true if the user has been warned.
1247    bool clobber = false;
1248
1249    // try to use the caller-provided address if there is one
1250    bool use_provided_address = (start != 0);
1251
1252    if (use_provided_address) {
1253        // check to see if the desired address is already in use
1254        if (!p->pTable->isUnmapped(start, length)) {
1255            // there are existing mappings in the desired range
1256            // whether we clobber them or not depends on whether the caller
1257            // specified MAP_FIXED
1258            if (flags & OS::TGT_MAP_FIXED) {
1259                // MAP_FIXED specified: map attempt fails
1260                return -EINVAL;
1261            } else {
1262                // MAP_FIXED not specified: ignore suggested start address
1263                warn("mmap: ignoring suggested map address 0x%x\n", start);
1264                use_provided_address = false;
1265            }
1266        }
1267    }
1268
1269    if (!use_provided_address) {
1270        // no address provided, or provided address unusable:
1271        // pick next address from our "mmap region"
1272        if (OS::mmapGrowsDown()) {
1273            start = p->mmap_end - length;
1274            p->mmap_end = start;
1275        } else {
1276            start = p->mmap_end;
1277            p->mmap_end += length;
1278        }
1279    }
1280
1281    p->allocateMem(start, length, clobber);
1282
1283    return start;
1284}
1285
1286/// Target getrlimit() handler.
1287template <class OS>
1288SyscallReturn
1289getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1290        ThreadContext *tc)
1291{
1292    int index = 0;
1293    unsigned resource = process->getSyscallArg(tc, index);
1294    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1295
1296    switch (resource) {
1297        case OS::TGT_RLIMIT_STACK:
1298            // max stack size in bytes: make up a number (8MB for now)
1299            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1300            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1301            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1302            break;
1303
1304        case OS::TGT_RLIMIT_DATA:
1305            // max data segment size in bytes: make up a number
1306            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1307            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1308            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1309            break;
1310
1311        default:
1312            std::cerr << "getrlimitFunc: unimplemented resource " << resource
1313                << std::endl;
1314            abort();
1315            break;
1316    }
1317
1318    rlp.copyOut(tc->getMemProxy());
1319    return 0;
1320}
1321
1322/// Target gettimeofday() handler.
1323template <class OS>
1324SyscallReturn
1325gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1326        ThreadContext *tc)
1327{
1328    int index = 0;
1329    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1330
1331    getElapsedTime(tp->tv_sec, tp->tv_usec);
1332    tp->tv_sec += seconds_since_epoch;
1333    tp->tv_sec = TheISA::htog(tp->tv_sec);
1334    tp->tv_usec = TheISA::htog(tp->tv_usec);
1335
1336    tp.copyOut(tc->getMemProxy());
1337
1338    return 0;
1339}
1340
1341
1342/// Target utimes() handler.
1343template <class OS>
1344SyscallReturn
1345utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1346           ThreadContext *tc)
1347{
1348    std::string path;
1349
1350    int index = 0;
1351    if (!tc->getMemProxy().tryReadString(path,
1352                process->getSyscallArg(tc, index))) {
1353        return -EFAULT;
1354    }
1355
1356    TypedBufferArg<typename OS::timeval [2]>
1357        tp(process->getSyscallArg(tc, index));
1358    tp.copyIn(tc->getMemProxy());
1359
1360    struct timeval hostTimeval[2];
1361    for (int i = 0; i < 2; ++i)
1362    {
1363        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1364        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1365    }
1366
1367    // Adjust path for current working directory
1368    path = process->fullPath(path);
1369
1370    int result = utimes(path.c_str(), hostTimeval);
1371
1372    if (result < 0)
1373        return -errno;
1374
1375    return 0;
1376}
1377/// Target getrusage() function.
1378template <class OS>
1379SyscallReturn
1380getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1381              ThreadContext *tc)
1382{
1383    int index = 0;
1384    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1385    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1386
1387    rup->ru_utime.tv_sec = 0;
1388    rup->ru_utime.tv_usec = 0;
1389    rup->ru_stime.tv_sec = 0;
1390    rup->ru_stime.tv_usec = 0;
1391    rup->ru_maxrss = 0;
1392    rup->ru_ixrss = 0;
1393    rup->ru_idrss = 0;
1394    rup->ru_isrss = 0;
1395    rup->ru_minflt = 0;
1396    rup->ru_majflt = 0;
1397    rup->ru_nswap = 0;
1398    rup->ru_inblock = 0;
1399    rup->ru_oublock = 0;
1400    rup->ru_msgsnd = 0;
1401    rup->ru_msgrcv = 0;
1402    rup->ru_nsignals = 0;
1403    rup->ru_nvcsw = 0;
1404    rup->ru_nivcsw = 0;
1405
1406    switch (who) {
1407      case OS::TGT_RUSAGE_SELF:
1408        getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1409        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1410        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1411        break;
1412
1413      case OS::TGT_RUSAGE_CHILDREN:
1414        // do nothing.  We have no child processes, so they take no time.
1415        break;
1416
1417      default:
1418        // don't really handle THREAD or CHILDREN, but just warn and
1419        // plow ahead
1420        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1421             who);
1422    }
1423
1424    rup.copyOut(tc->getMemProxy());
1425
1426    return 0;
1427}
1428
1429/// Target times() function.
1430template <class OS>
1431SyscallReturn
1432timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1433           ThreadContext *tc)
1434{
1435    int index = 0;
1436    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1437
1438    // Fill in the time structure (in clocks)
1439    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1440    bufp->tms_utime = clocks;
1441    bufp->tms_stime = 0;
1442    bufp->tms_cutime = 0;
1443    bufp->tms_cstime = 0;
1444
1445    // Convert to host endianness
1446    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1447
1448    // Write back
1449    bufp.copyOut(tc->getMemProxy());
1450
1451    // Return clock ticks since system boot
1452    return clocks;
1453}
1454
1455/// Target time() function.
1456template <class OS>
1457SyscallReturn
1458timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1459           ThreadContext *tc)
1460{
1461    typename OS::time_t sec, usec;
1462    getElapsedTime(sec, usec);
1463    sec += seconds_since_epoch;
1464
1465    int index = 0;
1466    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1467    if(taddr != 0) {
1468        typename OS::time_t t = sec;
1469        t = TheISA::htog(t);
1470        SETranslatingPortProxy &p = tc->getMemProxy();
1471        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1472    }
1473    return sec;
1474}
1475
1476
1477#endif // __SIM_SYSCALL_EMUL_HH__
1478