syscall_emul.hh revision 10486
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        (provided_address % TheISA::PageBytes != 0)) {
835        warn("mremap failing: arguments not page aligned");
836        return -EINVAL;
837    }
838
839    new_length = roundUp(new_length, TheISA::PageBytes);
840
841    if (new_length > old_length) {
842        if ((start + old_length) == process->mmap_end &&
843            (!use_provided_address || provided_address == start)) {
844            uint64_t diff = new_length - old_length;
845            process->allocateMem(process->mmap_end, diff);
846            process->mmap_end += diff;
847            return start;
848        } else {
849            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
850                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
851                return -ENOMEM;
852            } else {
853                uint64_t new_start = use_provided_address ?
854                    provided_address : process->mmap_end;
855                process->pTable->remap(start, old_length, new_start);
856                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
857                     new_start, new_start + new_length,
858                     new_length - old_length);
859                // add on the remaining unallocated pages
860                process->allocateMem(new_start + old_length,
861                                     new_length - old_length,
862                                     use_provided_address /* clobber */);
863                if (!use_provided_address)
864                    process->mmap_end += new_length;
865                if (use_provided_address &&
866                    new_start + new_length > process->mmap_end) {
867                    // something fishy going on here, at least notify the user
868                    // @todo: increase mmap_end?
869                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
870                }
871                warn("returning %08p as start\n", new_start);
872                return new_start;
873            }
874        }
875    } else {
876        if (use_provided_address && provided_address != start)
877            process->pTable->remap(start, new_length, provided_address);
878        process->pTable->unmap(start + new_length, old_length - new_length);
879        return use_provided_address ? provided_address : start;
880    }
881}
882
883/// Target stat() handler.
884template <class OS>
885SyscallReturn
886statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
887         ThreadContext *tc)
888{
889    std::string path;
890
891    int index = 0;
892    if (!tc->getMemProxy().tryReadString(path,
893                process->getSyscallArg(tc, index))) {
894        return -EFAULT;
895    }
896    Addr bufPtr = process->getSyscallArg(tc, index);
897
898    // Adjust path for current working directory
899    path = process->fullPath(path);
900
901    struct stat hostBuf;
902    int result = stat(path.c_str(), &hostBuf);
903
904    if (result < 0)
905        return -errno;
906
907    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
908
909    return 0;
910}
911
912
913/// Target stat64() handler.
914template <class OS>
915SyscallReturn
916stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
917           ThreadContext *tc)
918{
919    std::string path;
920
921    int index = 0;
922    if (!tc->getMemProxy().tryReadString(path,
923                process->getSyscallArg(tc, index)))
924        return -EFAULT;
925    Addr bufPtr = process->getSyscallArg(tc, index);
926
927    // Adjust path for current working directory
928    path = process->fullPath(path);
929
930#if NO_STAT64
931    struct stat  hostBuf;
932    int result = stat(path.c_str(), &hostBuf);
933#else
934    struct stat64 hostBuf;
935    int result = stat64(path.c_str(), &hostBuf);
936#endif
937
938    if (result < 0)
939        return -errno;
940
941    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
942
943    return 0;
944}
945
946
947/// Target fstatat64() handler.
948template <class OS>
949SyscallReturn
950fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
951              ThreadContext *tc)
952{
953    int index = 0;
954    int dirfd = process->getSyscallArg(tc, index);
955    if (dirfd != OS::TGT_AT_FDCWD)
956        warn("openat: first argument not AT_FDCWD; unlikely to work");
957
958    std::string path;
959    if (!tc->getMemProxy().tryReadString(path,
960                process->getSyscallArg(tc, index)))
961        return -EFAULT;
962    Addr bufPtr = process->getSyscallArg(tc, index);
963
964    // Adjust path for current working directory
965    path = process->fullPath(path);
966
967#if NO_STAT64
968    struct stat  hostBuf;
969    int result = stat(path.c_str(), &hostBuf);
970#else
971    struct stat64 hostBuf;
972    int result = stat64(path.c_str(), &hostBuf);
973#endif
974
975    if (result < 0)
976        return -errno;
977
978    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
979
980    return 0;
981}
982
983
984/// Target fstat64() handler.
985template <class OS>
986SyscallReturn
987fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
988            ThreadContext *tc)
989{
990    int index = 0;
991    int fd = process->getSyscallArg(tc, index);
992    Addr bufPtr = process->getSyscallArg(tc, index);
993    if (fd < 0 || process->sim_fd(fd) < 0) {
994        // doesn't map to any simulator fd: not a valid target fd
995        return -EBADF;
996    }
997
998#if NO_STAT64
999    struct stat  hostBuf;
1000    int result = fstat(process->sim_fd(fd), &hostBuf);
1001#else
1002    struct stat64  hostBuf;
1003    int result = fstat64(process->sim_fd(fd), &hostBuf);
1004#endif
1005
1006    if (result < 0)
1007        return -errno;
1008
1009    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1010
1011    return 0;
1012}
1013
1014
1015/// Target lstat() handler.
1016template <class OS>
1017SyscallReturn
1018lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1019          ThreadContext *tc)
1020{
1021    std::string path;
1022
1023    int index = 0;
1024    if (!tc->getMemProxy().tryReadString(path,
1025                process->getSyscallArg(tc, index))) {
1026        return -EFAULT;
1027    }
1028    Addr bufPtr = process->getSyscallArg(tc, index);
1029
1030    // Adjust path for current working directory
1031    path = process->fullPath(path);
1032
1033    struct stat hostBuf;
1034    int result = lstat(path.c_str(), &hostBuf);
1035
1036    if (result < 0)
1037        return -errno;
1038
1039    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1040
1041    return 0;
1042}
1043
1044/// Target lstat64() handler.
1045template <class OS>
1046SyscallReturn
1047lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1048            ThreadContext *tc)
1049{
1050    std::string path;
1051
1052    int index = 0;
1053    if (!tc->getMemProxy().tryReadString(path,
1054                process->getSyscallArg(tc, index))) {
1055        return -EFAULT;
1056    }
1057    Addr bufPtr = process->getSyscallArg(tc, index);
1058
1059    // Adjust path for current working directory
1060    path = process->fullPath(path);
1061
1062#if NO_STAT64
1063    struct stat hostBuf;
1064    int result = lstat(path.c_str(), &hostBuf);
1065#else
1066    struct stat64 hostBuf;
1067    int result = lstat64(path.c_str(), &hostBuf);
1068#endif
1069
1070    if (result < 0)
1071        return -errno;
1072
1073    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1074
1075    return 0;
1076}
1077
1078/// Target fstat() handler.
1079template <class OS>
1080SyscallReturn
1081fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1082          ThreadContext *tc)
1083{
1084    int index = 0;
1085    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1086    Addr bufPtr = process->getSyscallArg(tc, index);
1087
1088    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
1089
1090    if (fd < 0)
1091        return -EBADF;
1092
1093    struct stat hostBuf;
1094    int result = fstat(fd, &hostBuf);
1095
1096    if (result < 0)
1097        return -errno;
1098
1099    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1100
1101    return 0;
1102}
1103
1104
1105/// Target statfs() handler.
1106template <class OS>
1107SyscallReturn
1108statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1109           ThreadContext *tc)
1110{
1111    std::string path;
1112
1113    int index = 0;
1114    if (!tc->getMemProxy().tryReadString(path,
1115                process->getSyscallArg(tc, index))) {
1116        return -EFAULT;
1117    }
1118    Addr bufPtr = process->getSyscallArg(tc, index);
1119
1120    // Adjust path for current working directory
1121    path = process->fullPath(path);
1122
1123    struct statfs hostBuf;
1124    int result = statfs(path.c_str(), &hostBuf);
1125
1126    if (result < 0)
1127        return -errno;
1128
1129    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1130
1131    return 0;
1132}
1133
1134
1135/// Target fstatfs() handler.
1136template <class OS>
1137SyscallReturn
1138fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1139            ThreadContext *tc)
1140{
1141    int index = 0;
1142    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1143    Addr bufPtr = process->getSyscallArg(tc, index);
1144
1145    if (fd < 0)
1146        return -EBADF;
1147
1148    struct statfs hostBuf;
1149    int result = fstatfs(fd, &hostBuf);
1150
1151    if (result < 0)
1152        return -errno;
1153
1154    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1155
1156    return 0;
1157}
1158
1159
1160/// Target writev() handler.
1161template <class OS>
1162SyscallReturn
1163writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1164           ThreadContext *tc)
1165{
1166    int index = 0;
1167    int fd = process->getSyscallArg(tc, index);
1168    if (fd < 0 || process->sim_fd(fd) < 0) {
1169        // doesn't map to any simulator fd: not a valid target fd
1170        return -EBADF;
1171    }
1172
1173    SETranslatingPortProxy &p = tc->getMemProxy();
1174    uint64_t tiov_base = process->getSyscallArg(tc, index);
1175    size_t count = process->getSyscallArg(tc, index);
1176    struct iovec hiov[count];
1177    for (size_t i = 0; i < count; ++i) {
1178        typename OS::tgt_iovec tiov;
1179
1180        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1181                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1182        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1183        hiov[i].iov_base = new char [hiov[i].iov_len];
1184        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1185                   hiov[i].iov_len);
1186    }
1187
1188    int result = writev(process->sim_fd(fd), hiov, count);
1189
1190    for (size_t i = 0; i < count; ++i)
1191        delete [] (char *)hiov[i].iov_base;
1192
1193    if (result < 0)
1194        return -errno;
1195
1196    return 0;
1197}
1198
1199
1200/// Target mmap() handler.
1201///
1202/// We don't really handle mmap().  If the target is mmaping an
1203/// anonymous region or /dev/zero, we can get away with doing basically
1204/// nothing (since memory is initialized to zero and the simulator
1205/// doesn't really check addresses anyway).
1206///
1207template <class OS>
1208SyscallReturn
1209mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1210{
1211    int index = 0;
1212    Addr start = p->getSyscallArg(tc, index);
1213    uint64_t length = p->getSyscallArg(tc, index);
1214    index++; // int prot = p->getSyscallArg(tc, index);
1215    int flags = p->getSyscallArg(tc, index);
1216    int tgt_fd = p->getSyscallArg(tc, index);
1217    int offset = p->getSyscallArg(tc, index);
1218
1219    if (length > 0x100000000ULL)
1220        warn("mmap length argument %#x is unreasonably large.\n", length);
1221
1222    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
1223        Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd);
1224        if (!fd_map || fd_map->fd < 0) {
1225            warn("mmap failing: target fd %d is not valid\n", tgt_fd);
1226            return -EBADF;
1227        }
1228
1229        if (fd_map->filename != "/dev/zero") {
1230            // This is very likely broken, but leave a warning here
1231            // (rather than panic) in case /dev/zero is known by
1232            // another name on some platform
1233            warn("allowing mmap of file %s; mmap not supported on files"
1234                 " other than /dev/zero\n", fd_map->filename);
1235        }
1236    }
1237
1238    length = roundUp(length, TheISA::PageBytes);
1239
1240    if ((start  % TheISA::PageBytes) != 0 ||
1241        (offset % TheISA::PageBytes) != 0) {
1242        warn("mmap failing: arguments not page-aligned: "
1243             "start 0x%x offset 0x%x",
1244             start, offset);
1245        return -EINVAL;
1246    }
1247
1248    // are we ok with clobbering existing mappings?  only set this to
1249    // true if the user has been warned.
1250    bool clobber = false;
1251
1252    // try to use the caller-provided address if there is one
1253    bool use_provided_address = (start != 0);
1254
1255    if (use_provided_address) {
1256        // check to see if the desired address is already in use
1257        if (!p->pTable->isUnmapped(start, length)) {
1258            // there are existing mappings in the desired range
1259            // whether we clobber them or not depends on whether the caller
1260            // specified MAP_FIXED
1261            if (flags & OS::TGT_MAP_FIXED) {
1262                // MAP_FIXED specified: map attempt fails
1263                return -EINVAL;
1264            } else {
1265                // MAP_FIXED not specified: ignore suggested start address
1266                warn("mmap: ignoring suggested map address 0x%x\n", start);
1267                use_provided_address = false;
1268            }
1269        }
1270    }
1271
1272    if (!use_provided_address) {
1273        // no address provided, or provided address unusable:
1274        // pick next address from our "mmap region"
1275        if (OS::mmapGrowsDown()) {
1276            start = p->mmap_end - length;
1277            p->mmap_end = start;
1278        } else {
1279            start = p->mmap_end;
1280            p->mmap_end += length;
1281        }
1282    }
1283
1284    p->allocateMem(start, length, clobber);
1285
1286    return start;
1287}
1288
1289/// Target getrlimit() handler.
1290template <class OS>
1291SyscallReturn
1292getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1293        ThreadContext *tc)
1294{
1295    int index = 0;
1296    unsigned resource = process->getSyscallArg(tc, index);
1297    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1298
1299    switch (resource) {
1300        case OS::TGT_RLIMIT_STACK:
1301            // max stack size in bytes: make up a number (8MB for now)
1302            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1303            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1304            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1305            break;
1306
1307        case OS::TGT_RLIMIT_DATA:
1308            // max data segment size in bytes: make up a number
1309            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1310            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1311            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1312            break;
1313
1314        default:
1315            std::cerr << "getrlimitFunc: unimplemented resource " << resource
1316                << std::endl;
1317            abort();
1318            break;
1319    }
1320
1321    rlp.copyOut(tc->getMemProxy());
1322    return 0;
1323}
1324
1325/// Target gettimeofday() handler.
1326template <class OS>
1327SyscallReturn
1328gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1329        ThreadContext *tc)
1330{
1331    int index = 0;
1332    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1333
1334    getElapsedTime(tp->tv_sec, tp->tv_usec);
1335    tp->tv_sec += seconds_since_epoch;
1336    tp->tv_sec = TheISA::htog(tp->tv_sec);
1337    tp->tv_usec = TheISA::htog(tp->tv_usec);
1338
1339    tp.copyOut(tc->getMemProxy());
1340
1341    return 0;
1342}
1343
1344
1345/// Target utimes() handler.
1346template <class OS>
1347SyscallReturn
1348utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1349           ThreadContext *tc)
1350{
1351    std::string path;
1352
1353    int index = 0;
1354    if (!tc->getMemProxy().tryReadString(path,
1355                process->getSyscallArg(tc, index))) {
1356        return -EFAULT;
1357    }
1358
1359    TypedBufferArg<typename OS::timeval [2]>
1360        tp(process->getSyscallArg(tc, index));
1361    tp.copyIn(tc->getMemProxy());
1362
1363    struct timeval hostTimeval[2];
1364    for (int i = 0; i < 2; ++i)
1365    {
1366        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1367        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1368    }
1369
1370    // Adjust path for current working directory
1371    path = process->fullPath(path);
1372
1373    int result = utimes(path.c_str(), hostTimeval);
1374
1375    if (result < 0)
1376        return -errno;
1377
1378    return 0;
1379}
1380/// Target getrusage() function.
1381template <class OS>
1382SyscallReturn
1383getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1384              ThreadContext *tc)
1385{
1386    int index = 0;
1387    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1388    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1389
1390    rup->ru_utime.tv_sec = 0;
1391    rup->ru_utime.tv_usec = 0;
1392    rup->ru_stime.tv_sec = 0;
1393    rup->ru_stime.tv_usec = 0;
1394    rup->ru_maxrss = 0;
1395    rup->ru_ixrss = 0;
1396    rup->ru_idrss = 0;
1397    rup->ru_isrss = 0;
1398    rup->ru_minflt = 0;
1399    rup->ru_majflt = 0;
1400    rup->ru_nswap = 0;
1401    rup->ru_inblock = 0;
1402    rup->ru_oublock = 0;
1403    rup->ru_msgsnd = 0;
1404    rup->ru_msgrcv = 0;
1405    rup->ru_nsignals = 0;
1406    rup->ru_nvcsw = 0;
1407    rup->ru_nivcsw = 0;
1408
1409    switch (who) {
1410      case OS::TGT_RUSAGE_SELF:
1411        getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1412        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1413        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1414        break;
1415
1416      case OS::TGT_RUSAGE_CHILDREN:
1417        // do nothing.  We have no child processes, so they take no time.
1418        break;
1419
1420      default:
1421        // don't really handle THREAD or CHILDREN, but just warn and
1422        // plow ahead
1423        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1424             who);
1425    }
1426
1427    rup.copyOut(tc->getMemProxy());
1428
1429    return 0;
1430}
1431
1432/// Target times() function.
1433template <class OS>
1434SyscallReturn
1435timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1436           ThreadContext *tc)
1437{
1438    int index = 0;
1439    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1440
1441    // Fill in the time structure (in clocks)
1442    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1443    bufp->tms_utime = clocks;
1444    bufp->tms_stime = 0;
1445    bufp->tms_cutime = 0;
1446    bufp->tms_cstime = 0;
1447
1448    // Convert to host endianness
1449    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1450
1451    // Write back
1452    bufp.copyOut(tc->getMemProxy());
1453
1454    // Return clock ticks since system boot
1455    return clocks;
1456}
1457
1458/// Target time() function.
1459template <class OS>
1460SyscallReturn
1461timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1462           ThreadContext *tc)
1463{
1464    typename OS::time_t sec, usec;
1465    getElapsedTime(sec, usec);
1466    sec += seconds_since_epoch;
1467
1468    int index = 0;
1469    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1470    if(taddr != 0) {
1471        typename OS::time_t t = sec;
1472        t = TheISA::htog(t);
1473        SETranslatingPortProxy &p = tc->getMemProxy();
1474        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1475    }
1476    return sec;
1477}
1478
1479
1480#endif // __SIM_SYSCALL_EMUL_HH__
1481