syscall_emul.hh revision 10318:98771a936b61
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
443/// Pseudo Funcs  - These functions use a different return convension,
444/// returning a second value in a register other than the normal return register
445SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
446                             LiveProcess *process, ThreadContext *tc);
447
448/// Target getpidPseudo() handler.
449SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
450                               LiveProcess *p, ThreadContext *tc);
451
452/// Target getuidPseudo() handler.
453SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
454                               LiveProcess *p, ThreadContext *tc);
455
456/// Target getgidPseudo() handler.
457SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
458                               LiveProcess *p, ThreadContext *tc);
459
460
461/// A readable name for 1,000,000, for converting microseconds to seconds.
462const int one_million = 1000000;
463
464/// Approximate seconds since the epoch (1/1/1970).  About a billion,
465/// by my reckoning.  We want to keep this a constant (not use the
466/// real-world time) to keep simulations repeatable.
467const unsigned seconds_since_epoch = 1000000000;
468
469/// Helper function to convert current elapsed time to seconds and
470/// microseconds.
471template <class T1, class T2>
472void
473getElapsedTime(T1 &sec, T2 &usec)
474{
475    int elapsed_usecs = curTick() / SimClock::Int::us;
476    sec = elapsed_usecs / one_million;
477    usec = elapsed_usecs % one_million;
478}
479
480//////////////////////////////////////////////////////////////////////
481//
482// The following emulation functions are generic, but need to be
483// templated to account for differences in types, constants, etc.
484//
485//////////////////////////////////////////////////////////////////////
486
487#if NO_STAT64
488    typedef struct stat hst_stat;
489    typedef struct stat hst_stat64;
490#else
491    typedef struct stat hst_stat;
492    typedef struct stat64 hst_stat64;
493#endif
494
495//// Helper function to convert a host stat buffer to a target stat
496//// buffer.  Also copies the target buffer out to the simulated
497//// memory space.  Used by stat(), fstat(), and lstat().
498
499template <typename target_stat, typename host_stat>
500static void
501convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
502{
503    using namespace TheISA;
504
505    if (fakeTTY)
506        tgt->st_dev = 0xA;
507    else
508        tgt->st_dev = host->st_dev;
509    tgt->st_dev = TheISA::htog(tgt->st_dev);
510    tgt->st_ino = host->st_ino;
511    tgt->st_ino = TheISA::htog(tgt->st_ino);
512    tgt->st_mode = host->st_mode;
513    if (fakeTTY) {
514        // Claim to be a character device
515        tgt->st_mode &= ~S_IFMT;    // Clear S_IFMT
516        tgt->st_mode |= S_IFCHR;    // Set S_IFCHR
517    }
518    tgt->st_mode = TheISA::htog(tgt->st_mode);
519    tgt->st_nlink = host->st_nlink;
520    tgt->st_nlink = TheISA::htog(tgt->st_nlink);
521    tgt->st_uid = host->st_uid;
522    tgt->st_uid = TheISA::htog(tgt->st_uid);
523    tgt->st_gid = host->st_gid;
524    tgt->st_gid = TheISA::htog(tgt->st_gid);
525    if (fakeTTY)
526        tgt->st_rdev = 0x880d;
527    else
528        tgt->st_rdev = host->st_rdev;
529    tgt->st_rdev = TheISA::htog(tgt->st_rdev);
530    tgt->st_size = host->st_size;
531    tgt->st_size = TheISA::htog(tgt->st_size);
532    tgt->st_atimeX = host->st_atime;
533    tgt->st_atimeX = TheISA::htog(tgt->st_atimeX);
534    tgt->st_mtimeX = host->st_mtime;
535    tgt->st_mtimeX = TheISA::htog(tgt->st_mtimeX);
536    tgt->st_ctimeX = host->st_ctime;
537    tgt->st_ctimeX = TheISA::htog(tgt->st_ctimeX);
538    // Force the block size to be 8k. This helps to ensure buffered io works
539    // consistently across different hosts.
540    tgt->st_blksize = 0x2000;
541    tgt->st_blksize = TheISA::htog(tgt->st_blksize);
542    tgt->st_blocks = host->st_blocks;
543    tgt->st_blocks = TheISA::htog(tgt->st_blocks);
544}
545
546// Same for stat64
547
548template <typename target_stat, typename host_stat64>
549static void
550convertStat64Buf(target_stat &tgt, host_stat64 *host, bool fakeTTY = false)
551{
552    using namespace TheISA;
553
554    convertStatBuf<target_stat, host_stat64>(tgt, host, fakeTTY);
555#if defined(STAT_HAVE_NSEC)
556    tgt->st_atime_nsec = host->st_atime_nsec;
557    tgt->st_atime_nsec = TheISA::htog(tgt->st_atime_nsec);
558    tgt->st_mtime_nsec = host->st_mtime_nsec;
559    tgt->st_mtime_nsec = TheISA::htog(tgt->st_mtime_nsec);
560    tgt->st_ctime_nsec = host->st_ctime_nsec;
561    tgt->st_ctime_nsec = TheISA::htog(tgt->st_ctime_nsec);
562#else
563    tgt->st_atime_nsec = 0;
564    tgt->st_mtime_nsec = 0;
565    tgt->st_ctime_nsec = 0;
566#endif
567}
568
569//Here are a couple convenience functions
570template<class OS>
571static void
572copyOutStatBuf(SETranslatingPortProxy &mem, Addr addr,
573        hst_stat *host, bool fakeTTY = false)
574{
575    typedef TypedBufferArg<typename OS::tgt_stat> tgt_stat_buf;
576    tgt_stat_buf tgt(addr);
577    convertStatBuf<tgt_stat_buf, hst_stat>(tgt, host, fakeTTY);
578    tgt.copyOut(mem);
579}
580
581template<class OS>
582static void
583copyOutStat64Buf(SETranslatingPortProxy &mem, Addr addr,
584        hst_stat64 *host, bool fakeTTY = false)
585{
586    typedef TypedBufferArg<typename OS::tgt_stat64> tgt_stat_buf;
587    tgt_stat_buf tgt(addr);
588    convertStat64Buf<tgt_stat_buf, hst_stat64>(tgt, host, fakeTTY);
589    tgt.copyOut(mem);
590}
591
592/// Target ioctl() handler.  For the most part, programs call ioctl()
593/// only to find out if their stdout is a tty, to determine whether to
594/// do line or block buffering.  We always claim that output fds are
595/// not TTYs to provide repeatable results.
596template <class OS>
597SyscallReturn
598ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
599          ThreadContext *tc)
600{
601    int index = 0;
602    int fd = process->getSyscallArg(tc, index);
603    unsigned req = process->getSyscallArg(tc, index);
604
605    DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
606
607    if (fd < 0 || process->sim_fd(fd) < 0) {
608        // doesn't map to any simulator fd: not a valid target fd
609        return -EBADF;
610    }
611
612    if (OS::isTtyReq(req)) {
613        return -ENOTTY;
614    }
615
616    warn("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ \n",
617         fd, req, tc->pcState());
618    return -ENOTTY;
619}
620
621template <class OS>
622static SyscallReturn
623openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
624         ThreadContext *tc, int index)
625{
626    std::string path;
627
628    if (!tc->getMemProxy().tryReadString(path,
629                process->getSyscallArg(tc, index)))
630        return -EFAULT;
631
632    if (path == "/dev/sysdev0") {
633        // This is a memory-mapped high-resolution timer device on Alpha.
634        // We don't support it, so just punt.
635        warn("Ignoring open(%s, ...)\n", path);
636        return -ENOENT;
637    }
638
639    int tgtFlags = process->getSyscallArg(tc, index);
640    int mode = process->getSyscallArg(tc, index);
641    int hostFlags = 0;
642
643    // translate open flags
644    for (int i = 0; i < OS::NUM_OPEN_FLAGS; i++) {
645        if (tgtFlags & OS::openFlagTable[i].tgtFlag) {
646            tgtFlags &= ~OS::openFlagTable[i].tgtFlag;
647            hostFlags |= OS::openFlagTable[i].hostFlag;
648        }
649    }
650
651    // any target flags left?
652    if (tgtFlags != 0)
653        warn("Syscall: open: cannot decode flags 0x%x", tgtFlags);
654
655#ifdef __CYGWIN32__
656    hostFlags |= O_BINARY;
657#endif
658
659    // Adjust path for current working directory
660    path = process->fullPath(path);
661
662    DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
663
664    int fd;
665    int local_errno;
666    if (startswith(path, "/proc/") || startswith(path, "/system/") ||
667        startswith(path, "/platform/") || startswith(path, "/sys/")) {
668        // It's a proc/sys entry and requires special handling
669        fd = OS::openSpecialFile(path, process, tc);
670        local_errno = ENOENT;
671     } else {
672        // open the file
673        fd = open(path.c_str(), hostFlags, mode);
674        local_errno = errno;
675     }
676
677    if (fd == -1)
678        return -local_errno;
679
680    return process->alloc_fd(fd, path.c_str(), hostFlags, mode, false);
681}
682
683/// Target open() handler.
684template <class OS>
685SyscallReturn
686openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
687         ThreadContext *tc)
688{
689    return openFunc<OS>(desc, callnum, process, tc, 0);
690}
691
692/// Target openat() handler.
693template <class OS>
694SyscallReturn
695openatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
696         ThreadContext *tc)
697{
698    int index = 0;
699    int dirfd = process->getSyscallArg(tc, index);
700    if (dirfd != OS::TGT_AT_FDCWD)
701        warn("openat: first argument not AT_FDCWD; unlikely to work");
702    return openFunc<OS>(desc, callnum, process, tc, 1);
703}
704
705/// Target facessat() handler
706template <class OS>
707SyscallReturn
708faccessatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
709        ThreadContext *tc)
710{
711    int index = 0;
712    int dirfd = process->getSyscallArg(tc, index);
713    if (dirfd != OS::TGT_AT_FDCWD)
714        warn("faccessat: first argument not AT_FDCWD; unlikely to work");
715    return accessFunc(desc, callnum, process, tc, 1);
716}
717
718/// Target readlinkat() handler
719template <class OS>
720SyscallReturn
721readlinkatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
722        ThreadContext *tc)
723{
724    int index = 0;
725    int dirfd = process->getSyscallArg(tc, index);
726    if (dirfd != OS::TGT_AT_FDCWD)
727        warn("openat: first argument not AT_FDCWD; unlikely to work");
728    return readlinkFunc(desc, callnum, process, tc, 1);
729}
730
731/// Target sysinfo() handler.
732template <class OS>
733SyscallReturn
734sysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
735         ThreadContext *tc)
736{
737
738    int index = 0;
739    TypedBufferArg<typename OS::tgt_sysinfo>
740        sysinfo(process->getSyscallArg(tc, index));
741
742    sysinfo->uptime=seconds_since_epoch;
743    sysinfo->totalram=process->system->memSize();
744
745    sysinfo.copyOut(tc->getMemProxy());
746
747    return 0;
748}
749
750/// Target chmod() handler.
751template <class OS>
752SyscallReturn
753chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
754          ThreadContext *tc)
755{
756    std::string path;
757
758    int index = 0;
759    if (!tc->getMemProxy().tryReadString(path,
760                process->getSyscallArg(tc, index))) {
761        return -EFAULT;
762    }
763
764    uint32_t mode = process->getSyscallArg(tc, index);
765    mode_t hostMode = 0;
766
767    // XXX translate mode flags via OS::something???
768    hostMode = mode;
769
770    // Adjust path for current working directory
771    path = process->fullPath(path);
772
773    // do the chmod
774    int result = chmod(path.c_str(), hostMode);
775    if (result < 0)
776        return -errno;
777
778    return 0;
779}
780
781
782/// Target fchmod() handler.
783template <class OS>
784SyscallReturn
785fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
786           ThreadContext *tc)
787{
788    int index = 0;
789    int fd = process->getSyscallArg(tc, index);
790    if (fd < 0 || process->sim_fd(fd) < 0) {
791        // doesn't map to any simulator fd: not a valid target fd
792        return -EBADF;
793    }
794
795    uint32_t mode = process->getSyscallArg(tc, index);
796    mode_t hostMode = 0;
797
798    // XXX translate mode flags via OS::someting???
799    hostMode = mode;
800
801    // do the fchmod
802    int result = fchmod(process->sim_fd(fd), hostMode);
803    if (result < 0)
804        return -errno;
805
806    return 0;
807}
808
809/// Target mremap() handler.
810template <class OS>
811SyscallReturn
812mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
813{
814    int index = 0;
815    Addr start = process->getSyscallArg(tc, index);
816    uint64_t old_length = process->getSyscallArg(tc, index);
817    uint64_t new_length = process->getSyscallArg(tc, index);
818    uint64_t flags = process->getSyscallArg(tc, index);
819    uint64_t provided_address = 0;
820    bool use_provided_address = flags & OS::TGT_MREMAP_FIXED;
821
822    if (use_provided_address)
823        provided_address = process->getSyscallArg(tc, index);
824
825    if ((start % TheISA::PageBytes != 0) ||
826        (new_length % TheISA::PageBytes != 0) ||
827        (provided_address % TheISA::PageBytes != 0)) {
828        warn("mremap failing: arguments not page aligned");
829        return -EINVAL;
830    }
831
832    if (new_length > old_length) {
833        if ((start + old_length) == process->mmap_end &&
834            (!use_provided_address || provided_address == start)) {
835            uint64_t diff = new_length - old_length;
836            process->allocateMem(process->mmap_end, diff);
837            process->mmap_end += diff;
838            return start;
839        } else {
840            if (!use_provided_address && !(flags & OS::TGT_MREMAP_MAYMOVE)) {
841                warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
842                return -ENOMEM;
843            } else {
844                uint64_t new_start = use_provided_address ?
845                    provided_address : process->mmap_end;
846                process->pTable->remap(start, old_length, new_start);
847                warn("mremapping to new vaddr %08p-%08p, adding %d\n",
848                     new_start, new_start + new_length,
849                     new_length - old_length);
850                // add on the remaining unallocated pages
851                process->allocateMem(new_start + old_length,
852                                     new_length - old_length,
853                                     use_provided_address /* clobber */);
854                if (!use_provided_address)
855                    process->mmap_end += new_length;
856                if (use_provided_address &&
857                    new_start + new_length > process->mmap_end) {
858                    // something fishy going on here, at least notify the user
859                    // @todo: increase mmap_end?
860                    warn("mmap region limit exceeded with MREMAP_FIXED\n");
861                }
862                warn("returning %08p as start\n", new_start);
863                return new_start;
864            }
865        }
866    } else {
867        if (use_provided_address && provided_address != start)
868            process->pTable->remap(start, new_length, provided_address);
869        process->pTable->unmap(start + new_length, old_length - new_length);
870        return use_provided_address ? provided_address : start;
871    }
872}
873
874/// Target stat() handler.
875template <class OS>
876SyscallReturn
877statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
878         ThreadContext *tc)
879{
880    std::string path;
881
882    int index = 0;
883    if (!tc->getMemProxy().tryReadString(path,
884                process->getSyscallArg(tc, index))) {
885        return -EFAULT;
886    }
887    Addr bufPtr = process->getSyscallArg(tc, index);
888
889    // Adjust path for current working directory
890    path = process->fullPath(path);
891
892    struct stat hostBuf;
893    int result = stat(path.c_str(), &hostBuf);
894
895    if (result < 0)
896        return -errno;
897
898    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
899
900    return 0;
901}
902
903
904/// Target stat64() handler.
905template <class OS>
906SyscallReturn
907stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
908           ThreadContext *tc)
909{
910    std::string path;
911
912    int index = 0;
913    if (!tc->getMemProxy().tryReadString(path,
914                process->getSyscallArg(tc, index)))
915        return -EFAULT;
916    Addr bufPtr = process->getSyscallArg(tc, index);
917
918    // Adjust path for current working directory
919    path = process->fullPath(path);
920
921#if NO_STAT64
922    struct stat  hostBuf;
923    int result = stat(path.c_str(), &hostBuf);
924#else
925    struct stat64 hostBuf;
926    int result = stat64(path.c_str(), &hostBuf);
927#endif
928
929    if (result < 0)
930        return -errno;
931
932    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
933
934    return 0;
935}
936
937
938/// Target fstatat64() handler.
939template <class OS>
940SyscallReturn
941fstatat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
942              ThreadContext *tc)
943{
944    int index = 0;
945    int dirfd = process->getSyscallArg(tc, index);
946    if (dirfd != OS::TGT_AT_FDCWD)
947        warn("openat: first argument not AT_FDCWD; unlikely to work");
948
949    std::string path;
950    if (!tc->getMemProxy().tryReadString(path,
951                process->getSyscallArg(tc, index)))
952        return -EFAULT;
953    Addr bufPtr = process->getSyscallArg(tc, index);
954
955    // Adjust path for current working directory
956    path = process->fullPath(path);
957
958#if NO_STAT64
959    struct stat  hostBuf;
960    int result = stat(path.c_str(), &hostBuf);
961#else
962    struct stat64 hostBuf;
963    int result = stat64(path.c_str(), &hostBuf);
964#endif
965
966    if (result < 0)
967        return -errno;
968
969    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
970
971    return 0;
972}
973
974
975/// Target fstat64() handler.
976template <class OS>
977SyscallReturn
978fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
979            ThreadContext *tc)
980{
981    int index = 0;
982    int fd = process->getSyscallArg(tc, index);
983    Addr bufPtr = process->getSyscallArg(tc, index);
984    if (fd < 0 || process->sim_fd(fd) < 0) {
985        // doesn't map to any simulator fd: not a valid target fd
986        return -EBADF;
987    }
988
989#if NO_STAT64
990    struct stat  hostBuf;
991    int result = fstat(process->sim_fd(fd), &hostBuf);
992#else
993    struct stat64  hostBuf;
994    int result = fstat64(process->sim_fd(fd), &hostBuf);
995#endif
996
997    if (result < 0)
998        return -errno;
999
1000    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1001
1002    return 0;
1003}
1004
1005
1006/// Target lstat() handler.
1007template <class OS>
1008SyscallReturn
1009lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1010          ThreadContext *tc)
1011{
1012    std::string path;
1013
1014    int index = 0;
1015    if (!tc->getMemProxy().tryReadString(path,
1016                process->getSyscallArg(tc, index))) {
1017        return -EFAULT;
1018    }
1019    Addr bufPtr = process->getSyscallArg(tc, index);
1020
1021    // Adjust path for current working directory
1022    path = process->fullPath(path);
1023
1024    struct stat hostBuf;
1025    int result = lstat(path.c_str(), &hostBuf);
1026
1027    if (result < 0)
1028        return -errno;
1029
1030    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1031
1032    return 0;
1033}
1034
1035/// Target lstat64() handler.
1036template <class OS>
1037SyscallReturn
1038lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
1039            ThreadContext *tc)
1040{
1041    std::string path;
1042
1043    int index = 0;
1044    if (!tc->getMemProxy().tryReadString(path,
1045                process->getSyscallArg(tc, index))) {
1046        return -EFAULT;
1047    }
1048    Addr bufPtr = process->getSyscallArg(tc, index);
1049
1050    // Adjust path for current working directory
1051    path = process->fullPath(path);
1052
1053#if NO_STAT64
1054    struct stat hostBuf;
1055    int result = lstat(path.c_str(), &hostBuf);
1056#else
1057    struct stat64 hostBuf;
1058    int result = lstat64(path.c_str(), &hostBuf);
1059#endif
1060
1061    if (result < 0)
1062        return -errno;
1063
1064    copyOutStat64Buf<OS>(tc->getMemProxy(), bufPtr, &hostBuf);
1065
1066    return 0;
1067}
1068
1069/// Target fstat() handler.
1070template <class OS>
1071SyscallReturn
1072fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1073          ThreadContext *tc)
1074{
1075    int index = 0;
1076    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1077    Addr bufPtr = process->getSyscallArg(tc, index);
1078
1079    DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
1080
1081    if (fd < 0)
1082        return -EBADF;
1083
1084    struct stat hostBuf;
1085    int result = fstat(fd, &hostBuf);
1086
1087    if (result < 0)
1088        return -errno;
1089
1090    copyOutStatBuf<OS>(tc->getMemProxy(), bufPtr, &hostBuf, (fd == 1));
1091
1092    return 0;
1093}
1094
1095
1096/// Target statfs() handler.
1097template <class OS>
1098SyscallReturn
1099statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1100           ThreadContext *tc)
1101{
1102    std::string path;
1103
1104    int index = 0;
1105    if (!tc->getMemProxy().tryReadString(path,
1106                process->getSyscallArg(tc, index))) {
1107        return -EFAULT;
1108    }
1109    Addr bufPtr = process->getSyscallArg(tc, index);
1110
1111    // Adjust path for current working directory
1112    path = process->fullPath(path);
1113
1114    struct statfs hostBuf;
1115    int result = statfs(path.c_str(), &hostBuf);
1116
1117    if (result < 0)
1118        return -errno;
1119
1120    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1121
1122    return 0;
1123}
1124
1125
1126/// Target fstatfs() handler.
1127template <class OS>
1128SyscallReturn
1129fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1130            ThreadContext *tc)
1131{
1132    int index = 0;
1133    int fd = process->sim_fd(process->getSyscallArg(tc, index));
1134    Addr bufPtr = process->getSyscallArg(tc, index);
1135
1136    if (fd < 0)
1137        return -EBADF;
1138
1139    struct statfs hostBuf;
1140    int result = fstatfs(fd, &hostBuf);
1141
1142    if (result < 0)
1143        return -errno;
1144
1145    OS::copyOutStatfsBuf(tc->getMemProxy(), bufPtr, &hostBuf);
1146
1147    return 0;
1148}
1149
1150
1151/// Target writev() handler.
1152template <class OS>
1153SyscallReturn
1154writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1155           ThreadContext *tc)
1156{
1157    int index = 0;
1158    int fd = process->getSyscallArg(tc, index);
1159    if (fd < 0 || process->sim_fd(fd) < 0) {
1160        // doesn't map to any simulator fd: not a valid target fd
1161        return -EBADF;
1162    }
1163
1164    SETranslatingPortProxy &p = tc->getMemProxy();
1165    uint64_t tiov_base = process->getSyscallArg(tc, index);
1166    size_t count = process->getSyscallArg(tc, index);
1167    struct iovec hiov[count];
1168    for (size_t i = 0; i < count; ++i) {
1169        typename OS::tgt_iovec tiov;
1170
1171        p.readBlob(tiov_base + i*sizeof(typename OS::tgt_iovec),
1172                   (uint8_t*)&tiov, sizeof(typename OS::tgt_iovec));
1173        hiov[i].iov_len = TheISA::gtoh(tiov.iov_len);
1174        hiov[i].iov_base = new char [hiov[i].iov_len];
1175        p.readBlob(TheISA::gtoh(tiov.iov_base), (uint8_t *)hiov[i].iov_base,
1176                   hiov[i].iov_len);
1177    }
1178
1179    int result = writev(process->sim_fd(fd), hiov, count);
1180
1181    for (size_t i = 0; i < count; ++i)
1182        delete [] (char *)hiov[i].iov_base;
1183
1184    if (result < 0)
1185        return -errno;
1186
1187    return 0;
1188}
1189
1190
1191/// Target mmap() handler.
1192///
1193/// We don't really handle mmap().  If the target is mmaping an
1194/// anonymous region or /dev/zero, we can get away with doing basically
1195/// nothing (since memory is initialized to zero and the simulator
1196/// doesn't really check addresses anyway).
1197///
1198template <class OS>
1199SyscallReturn
1200mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
1201{
1202    int index = 0;
1203    Addr start = p->getSyscallArg(tc, index);
1204    uint64_t length = p->getSyscallArg(tc, index);
1205    index++; // int prot = p->getSyscallArg(tc, index);
1206    int flags = p->getSyscallArg(tc, index);
1207    int tgt_fd = p->getSyscallArg(tc, index);
1208    // int offset = p->getSyscallArg(tc, index);
1209
1210    if (length > 0x100000000ULL)
1211        warn("mmap length argument %#x is unreasonably large.\n", length);
1212
1213    if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
1214        Process::FdMap *fd_map = p->sim_fd_obj(tgt_fd);
1215        if (!fd_map || fd_map->fd < 0) {
1216            warn("mmap failing: target fd %d is not valid\n", tgt_fd);
1217            return -EBADF;
1218        }
1219
1220        if (fd_map->filename != "/dev/zero") {
1221            // This is very likely broken, but leave a warning here
1222            // (rather than panic) in case /dev/zero is known by
1223            // another name on some platform
1224            warn("allowing mmap of file %s; mmap not supported on files"
1225                 " other than /dev/zero\n", fd_map->filename);
1226        }
1227    }
1228
1229    if ((start  % TheISA::PageBytes) != 0 ||
1230        (length % TheISA::PageBytes) != 0) {
1231        warn("mmap failing: arguments not page-aligned: "
1232             "start 0x%x length 0x%x",
1233             start, length);
1234        return -EINVAL;
1235    }
1236
1237    // are we ok with clobbering existing mappings?  only set this to
1238    // true if the user has been warned.
1239    bool clobber = false;
1240
1241    // try to use the caller-provided address if there is one
1242    bool use_provided_address = (start != 0);
1243
1244    if (use_provided_address) {
1245        // check to see if the desired address is already in use
1246        if (!p->pTable->isUnmapped(start, length)) {
1247            // there are existing mappings in the desired range
1248            // whether we clobber them or not depends on whether the caller
1249            // specified MAP_FIXED
1250            if (flags & OS::TGT_MAP_FIXED) {
1251                // MAP_FIXED specified: clobber existing mappings
1252                warn("mmap: MAP_FIXED at 0x%x overwrites existing mappings\n",
1253                     start);
1254                clobber = true;
1255            } else {
1256                // MAP_FIXED not specified: ignore suggested start address
1257                warn("mmap: ignoring suggested map address 0x%x\n", start);
1258                use_provided_address = false;
1259            }
1260        }
1261    }
1262
1263    if (!use_provided_address) {
1264        // no address provided, or provided address unusable:
1265        // pick next address from our "mmap region"
1266        if (OS::mmapGrowsDown()) {
1267            start = p->mmap_end - length;
1268            p->mmap_end = start;
1269        } else {
1270            start = p->mmap_end;
1271            p->mmap_end += length;
1272        }
1273    }
1274
1275    p->allocateMem(start, length, clobber);
1276
1277    return start;
1278}
1279
1280/// Target getrlimit() handler.
1281template <class OS>
1282SyscallReturn
1283getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1284        ThreadContext *tc)
1285{
1286    int index = 0;
1287    unsigned resource = process->getSyscallArg(tc, index);
1288    TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, index));
1289
1290    switch (resource) {
1291        case OS::TGT_RLIMIT_STACK:
1292            // max stack size in bytes: make up a number (8MB for now)
1293            rlp->rlim_cur = rlp->rlim_max = 8 * 1024 * 1024;
1294            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1295            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1296            break;
1297
1298        case OS::TGT_RLIMIT_DATA:
1299            // max data segment size in bytes: make up a number
1300            rlp->rlim_cur = rlp->rlim_max = 256 * 1024 * 1024;
1301            rlp->rlim_cur = TheISA::htog(rlp->rlim_cur);
1302            rlp->rlim_max = TheISA::htog(rlp->rlim_max);
1303            break;
1304
1305        default:
1306            std::cerr << "getrlimitFunc: unimplemented resource " << resource
1307                << std::endl;
1308            abort();
1309            break;
1310    }
1311
1312    rlp.copyOut(tc->getMemProxy());
1313    return 0;
1314}
1315
1316/// Target gettimeofday() handler.
1317template <class OS>
1318SyscallReturn
1319gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1320        ThreadContext *tc)
1321{
1322    int index = 0;
1323    TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, index));
1324
1325    getElapsedTime(tp->tv_sec, tp->tv_usec);
1326    tp->tv_sec += seconds_since_epoch;
1327    tp->tv_sec = TheISA::htog(tp->tv_sec);
1328    tp->tv_usec = TheISA::htog(tp->tv_usec);
1329
1330    tp.copyOut(tc->getMemProxy());
1331
1332    return 0;
1333}
1334
1335
1336/// Target utimes() handler.
1337template <class OS>
1338SyscallReturn
1339utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1340           ThreadContext *tc)
1341{
1342    std::string path;
1343
1344    int index = 0;
1345    if (!tc->getMemProxy().tryReadString(path,
1346                process->getSyscallArg(tc, index))) {
1347        return -EFAULT;
1348    }
1349
1350    TypedBufferArg<typename OS::timeval [2]>
1351        tp(process->getSyscallArg(tc, index));
1352    tp.copyIn(tc->getMemProxy());
1353
1354    struct timeval hostTimeval[2];
1355    for (int i = 0; i < 2; ++i)
1356    {
1357        hostTimeval[i].tv_sec = TheISA::gtoh((*tp)[i].tv_sec);
1358        hostTimeval[i].tv_usec = TheISA::gtoh((*tp)[i].tv_usec);
1359    }
1360
1361    // Adjust path for current working directory
1362    path = process->fullPath(path);
1363
1364    int result = utimes(path.c_str(), hostTimeval);
1365
1366    if (result < 0)
1367        return -errno;
1368
1369    return 0;
1370}
1371/// Target getrusage() function.
1372template <class OS>
1373SyscallReturn
1374getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1375              ThreadContext *tc)
1376{
1377    int index = 0;
1378    int who = process->getSyscallArg(tc, index); // THREAD, SELF, or CHILDREN
1379    TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, index));
1380
1381    rup->ru_utime.tv_sec = 0;
1382    rup->ru_utime.tv_usec = 0;
1383    rup->ru_stime.tv_sec = 0;
1384    rup->ru_stime.tv_usec = 0;
1385    rup->ru_maxrss = 0;
1386    rup->ru_ixrss = 0;
1387    rup->ru_idrss = 0;
1388    rup->ru_isrss = 0;
1389    rup->ru_minflt = 0;
1390    rup->ru_majflt = 0;
1391    rup->ru_nswap = 0;
1392    rup->ru_inblock = 0;
1393    rup->ru_oublock = 0;
1394    rup->ru_msgsnd = 0;
1395    rup->ru_msgrcv = 0;
1396    rup->ru_nsignals = 0;
1397    rup->ru_nvcsw = 0;
1398    rup->ru_nivcsw = 0;
1399
1400    switch (who) {
1401      case OS::TGT_RUSAGE_SELF:
1402        getElapsedTime(rup->ru_utime.tv_sec, rup->ru_utime.tv_usec);
1403        rup->ru_utime.tv_sec = TheISA::htog(rup->ru_utime.tv_sec);
1404        rup->ru_utime.tv_usec = TheISA::htog(rup->ru_utime.tv_usec);
1405        break;
1406
1407      case OS::TGT_RUSAGE_CHILDREN:
1408        // do nothing.  We have no child processes, so they take no time.
1409        break;
1410
1411      default:
1412        // don't really handle THREAD or CHILDREN, but just warn and
1413        // plow ahead
1414        warn("getrusage() only supports RUSAGE_SELF.  Parameter %d ignored.",
1415             who);
1416    }
1417
1418    rup.copyOut(tc->getMemProxy());
1419
1420    return 0;
1421}
1422
1423/// Target times() function.
1424template <class OS>
1425SyscallReturn
1426timesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1427           ThreadContext *tc)
1428{
1429    int index = 0;
1430    TypedBufferArg<typename OS::tms> bufp(process->getSyscallArg(tc, index));
1431
1432    // Fill in the time structure (in clocks)
1433    int64_t clocks = curTick() * OS::M5_SC_CLK_TCK / SimClock::Int::s;
1434    bufp->tms_utime = clocks;
1435    bufp->tms_stime = 0;
1436    bufp->tms_cutime = 0;
1437    bufp->tms_cstime = 0;
1438
1439    // Convert to host endianness
1440    bufp->tms_utime = TheISA::htog(bufp->tms_utime);
1441
1442    // Write back
1443    bufp.copyOut(tc->getMemProxy());
1444
1445    // Return clock ticks since system boot
1446    return clocks;
1447}
1448
1449/// Target time() function.
1450template <class OS>
1451SyscallReturn
1452timeFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
1453           ThreadContext *tc)
1454{
1455    typename OS::time_t sec, usec;
1456    getElapsedTime(sec, usec);
1457    sec += seconds_since_epoch;
1458
1459    int index = 0;
1460    Addr taddr = (Addr)process->getSyscallArg(tc, index);
1461    if(taddr != 0) {
1462        typename OS::time_t t = sec;
1463        t = TheISA::htog(t);
1464        SETranslatingPortProxy &p = tc->getMemProxy();
1465        p.writeBlob(taddr, (uint8_t*)&t, (int)sizeof(typename OS::time_t));
1466    }
1467    return sec;
1468}
1469
1470
1471#endif // __SIM_SYSCALL_EMUL_HH__
1472