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