func (k *CgcKernel) Random(buf co.Obuf, size uint32, ret co.Obuf) { tmp := make([]byte, size) n, _ := rand.Read(tmp) tmp = tmp[:n] buf.Pack(tmp) ret.Pack(uint32(n)) }
func (k *PosixKernel) Time(out co.Obuf) uint64 { t := time.Now().Unix() if out.Addr != 0 { out.Pack(struc.Size_t(t)) } return uint64(t) }
func (k *PosixKernel) ClockGettime(_ int, out co.Obuf) uint64 { ts := syscall.NsecToTimespec(time.Now().UnixNano()) err := out.Pack(&native.Timespec{int64(ts.Sec), int64(ts.Nsec)}) if err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *CgcKernel) Transmit(fd co.Fd, buf co.Buf, size co.Len, ret co.Obuf) int { mem, _ := k.U.MemRead(buf.Addr, uint64(size)) n, err := syscall.Write(int(fd), mem) if err != nil { return -1 // FIXME } ret.Pack(int32(n)) return 0 }
func (k *CgcKernel) Allocate(size uint32, executable int32, ret co.Obuf) int { mmap, _ := k.U.Mmap(0, uint64(size)) mmap.Desc = "heap" if executable != 0 { k.U.MemProtect(mmap.Addr, mmap.Size, uc.PROT_ALL) } ret.Pack(uint32(mmap.Addr)) return 0 }
func (k *PosixKernel) Fstatfs(fd co.Fd, statfs co.Obuf) uint64 { var tmp syscall.Statfs_t if err := syscall.Fstatfs(int(fd), &tmp); err != nil { return Errno(err) } if err := statfs.Pack(&tmp); err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *CgcKernel) Receive(fd co.Fd, buf co.Obuf, size co.Len, ret co.Obuf) int { tmp := make([]byte, size) n, err := syscall.Read(int(fd), tmp) if err != nil { return -1 // FIXME } buf.Pack(tmp[:n]) ret.Pack(int32(n)) return 0 }
func (k *PosixKernel) Socketpair(domain, typ, proto int, vector co.Obuf) uint64 { pair, err := syscall.Socketpair(domain, typ, proto) if err != nil { return Errno(err) } if err := vector.Pack(pair); err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *PosixKernel) Statfs(path string, statfs co.Obuf) uint64 { var tmp syscall.Statfs_t if err := syscall.Statfs(path, &tmp); err != nil { return Errno(err) } if err := statfs.Pack(&tmp); err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *LinuxKernel) Gettimeofday(tp co.Obuf, tz *native.Timespec) uint64 { now := time.Now() res := native.Timespec{ Sec: int64(now.Unix()), Nsec: int64(now.Nanosecond()), } if err := tp.Pack(&res); err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *PosixKernel) Lstat(path string, buf co.Obuf) uint64 { var stat syscall.Stat_t if err := syscall.Lstat(path, &stat); err != nil { return Errno(err) } targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits()) if err := buf.Pack(targetStat); err != nil { panic(err) } return 0 }
func (k *PosixKernel) Pread64(fd co.Fd, buf co.Obuf, size co.Len, offset int64) uint64 { p := make([]byte, size) n, err := syscall.Pread(int(fd), p, offset) if err != nil { return Errno(err) } if err := buf.Pack(p); err != nil { return UINT64_MAX // FIXME } return uint64(n) }
func (k *PosixKernel) Getcwd(buf co.Obuf, size co.Len) uint64 { wd, _ := os.Getwd() size -= 1 if co.Len(len(wd)) > size { wd = wd[:size] } if err := buf.Pack(wd + "\x00"); err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *PosixKernel) Read(fd co.Fd, buf co.Obuf, size co.Len) uint64 { tmp := make([]byte, size) n, err := syscall.Read(int(fd), tmp) if err != nil { return Errno(err) } if err := buf.Pack(tmp[:n]); err != nil { return UINT64_MAX // FIXME } return uint64(n) }
func (k *PosixKernel) Fstat(fd co.Fd, buf co.Obuf) uint64 { var stat syscall.Stat_t if err := syscall.Fstat(int(fd), &stat); err != nil { return Errno(err) } targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits()) if err := buf.Pack(targetStat); err != nil { panic(err) } return 0 }
func (k *PosixKernel) ClockGettime(_ int, out co.Obuf) uint64 { var err error ts := syscall.NsecToTimespec(time.Now().UnixNano()) if k.U.Bits() == 64 { err = out.Pack(&Timespec64{ts.Sec, ts.Nsec}) } else { err = out.Pack(&Timespec{int32(ts.Sec), int32(ts.Nsec)}) } if err != nil { return UINT64_MAX // FIXME } return 0 }
func (k *PosixKernel) ClockGetres(clockid int, out co.Obuf) uint64 { // TODO: I'm just assuming you have a nanosecond-accurate clock available if out.Addr != 0 { res := native.Timespec{ Sec: 0, Nsec: 1, } if err := out.Pack(&res); err != nil { return UINT64_MAX // FIXME } } return 0 }
func (k *PosixKernel) Stat(path string, buf co.Obuf) uint64 { // TODO: centralize path hook if strings.HasPrefix(path, "/") { path = k.U.PrefixPath(path, false) } var stat syscall.Stat_t if err := syscall.Stat(path, &stat); err != nil { return Errno(err) } targetStat := NewTargetStat(&stat, k.U.OS(), k.U.Bits()) if err := buf.Pack(targetStat); err != nil { panic(err) } return 0 }
func (k *CgcKernel) Fdwait(nfds int, reads, writes, timeoutBuf co.Buf, readyFds co.Obuf) int { var readSet, writeSet *native.Fdset32 var timeout native.Timespec reads.Unpack(&readSet) writes.Unpack(&writeSet) timeoutBuf.Unpack(&timeout) readNative := readSet.Native() writeNative := writeSet.Native() n, err := native.Select(nfds, readNative, writeNative, &timeout) if err != nil { return -1 // FIXME? } else { readyFds.Pack(int32(n)) } return 0 }
func (k *PosixKernel) Readlink(path string, buf co.Obuf, size co.Len) uint64 { // TODO: full proc emulation layer // maybe have a syscall pre-hook for this after ghostrace makes it generic // or specifically have path hooks and use that to implement prefix as well var name string var err error if path == "/proc/self/exe" && k.U.OS() == "linux" { name = k.U.Exe() } else { name, err = os.Readlink(path) if err != nil { return UINT64_MAX // FIXME } } if len(name) > int(size) { name = name[:size] } if err := buf.Pack([]byte(name)); err != nil { return UINT64_MAX // FIXME } return uint64(len(name)) }
func (k *LinuxKernel) getdents(dirfd co.Fd, buf co.Obuf, count uint64, bits uint) uint64 { dir, ok := k.Files[dirfd] if !ok { return UINT64_MAX // FIXME } dents := dir.Dirents if dents == nil { dent, err := os.Lstat(path.Join(dir.Path, "..")) if err == nil { dents = append(dents, fileInfoProxy{dent, ".."}) } dent, err = os.Lstat(dir.Path) if err == nil { dents = append(dents, fileInfoProxy{dent, "."}) } contents, err := ioutil.ReadDir(dir.Path) if err != nil { return UINT64_MAX // FIXME } dents = append(dents, contents...) dir.Dirents = dents } if dir.Offset >= uint64(len(dents)) { return 0 } dents = dents[dir.Offset:] written := 0 offset := dir.Offset out := buf.Struc() for i, f := range dents { // TODO: syscall.Stat_t portability? inode := f.Sys().(*syscall.Stat_t).Ino // figure out file mode mode := f.Mode() fileType := DT_REG if f.IsDir() { fileType = DT_DIR } else if mode&os.ModeNamedPipe > 0 { fileType = DT_FIFO } else if mode&os.ModeSymlink > 0 { fileType = DT_LNK } else if mode&os.ModeDevice > 0 { if mode&os.ModeCharDevice > 0 { fileType = DT_CHR } else { fileType = DT_BLK } } else if mode&os.ModeSocket > 0 { fileType = DT_SOCK } // TODO: does inode get truncated? guess it depends on guest LFS support var ent interface{} if bits == 64 { ent = &Dirent64{inode, dir.Offset + uint64(i), 0, fileType, f.Name() + "\x00"} } else { ent = &Dirent{inode, dir.Offset + uint64(i), 0, f.Name() + "\x00", fileType} } size, _ := struc.Sizeof(ent) if uint64(written+size) > count { break } offset++ if bits == 64 { ent.(*Dirent64).Len = size } else { ent.(*Dirent).Len = size } written += size if err := out.Pack(ent); err != nil { return UINT64_MAX // FIXME } } dir.Offset = offset return uint64(written) }
func (k *LinuxKernel) Getdents(dirfd co.Fd, buf co.Obuf, count uint64) uint64 { dirPath, err := posix.PathFromFd(int(dirfd)) if err != nil { return UINT64_MAX // FIXME } dents, err := ioutil.ReadDir(dirPath) if err != nil { return UINT64_MAX // FIXME } // figure out our offset // TODO: maybe figure out how a real kernel does this in := k.U.StrucAt(buf.Addr) var offset, read uint64 // TODO: DRY? :( var ent interface{} if k.U.Bits() == 64 { ent = &Dirent64{} } else { ent = &Dirent{} } for { tmp := ent.(*Dirent64) if err := in.Unpack(ent); err != nil { break } size, _ := struc.Sizeof(ent) if read+uint64(size) > count { break } if tmp.Off > 0 { offset = tmp.Off } if tmp.Len == 0 { break } } if offset >= uint64(len(dents)) { return 0 } dents = dents[offset:] written := 0 for i, f := range dents { // TODO: syscall.Stat_t portability? inode := f.Sys().(*syscall.Stat_t).Ino // figure out file mode mode := f.Mode() fileType := DT_REG if f.IsDir() { fileType = DT_DIR } else if mode&os.ModeNamedPipe > 0 { fileType = DT_FIFO } else if mode&os.ModeSymlink > 0 { fileType = DT_LNK } else if mode&os.ModeDevice > 0 { if mode&os.ModeCharDevice > 0 { fileType = DT_CHR } else { fileType = DT_BLK } } else if mode&os.ModeSocket > 0 { fileType = DT_SOCK } // TODO: does inode get truncated? I guess there's getdents64 var ent interface{} if k.U.Bits() == 64 { ent = &Dirent64{inode, uint64(i), 0, f.Name() + "\x00", fileType} } else { ent = &Dirent{inode, uint64(i), 0, f.Name() + "\x00", fileType} } size, _ := struc.Sizeof(ent) if uint64(written+size) > count { break } if k.U.Bits() == 64 { ent.(*Dirent64).Len = size } else { ent.(*Dirent).Len = size } written += size if err := buf.Pack(ent); err != nil { return UINT64_MAX // FIXME } } return uint64(written) }
func putfdset(b co.Obuf, fdset *syscall.FdSet) error { if fdset != nil && b.Addr != 0 { return b.Pack(fdset) } return nil }