From fb82171685deb20e55158d11403921cc74621305 Mon Sep 17 00:00:00 2001 From: Jelle van den Hooff Date: Fri, 6 Dec 2024 11:37:00 -0800 Subject: [PATCH] simulation: format byte buffers slightly nicer --- internal/gosimlog/main.go | 14 +++++ internal/simulation/os_linux.go | 100 ++++++++++++++++---------------- 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/internal/gosimlog/main.go b/internal/gosimlog/main.go index c26adf0..70e3f68 100644 --- a/internal/gosimlog/main.go +++ b/internal/gosimlog/main.go @@ -2,6 +2,7 @@ package gosimlog import ( "bytes" + "encoding/base64" "encoding/json" "errors" "fmt" @@ -9,6 +10,7 @@ import ( "reflect" "runtime" "slices" + "strconv" "strings" "time" ) @@ -77,6 +79,18 @@ func unmarshalWithExtraFields(data []byte, value any, extra *[]UnknownField, kno if err := d.Decode(&value); err != nil { return err } + + // decode base64 binary in values and make it easier to read + // TODO: make this less hacky, it would be nice to support + // "types" broadly (time, references to steps/machines/FDs, + // binary data, other stuff) and format them nicely + const base64Prefix = `"base64:` + if len(value) > 0 && bytes.HasPrefix(value, []byte(base64Prefix)) { + if maybeBytes, err := base64.StdEncoding.AppendDecode(nil, value[len(base64Prefix):len(value)-1]); err == nil { + *extra = append(*extra, UnknownField{Key: key, Value: strconv.QuoteToASCII(string(maybeBytes))}) + continue + } + } *extra = append(*extra, UnknownField{Key: key, Value: string(value)}) } } diff --git a/internal/simulation/os_linux.go b/internal/simulation/os_linux.go index 1a24258..f028dc4 100644 --- a/internal/simulation/os_linux.go +++ b/internal/simulation/os_linux.go @@ -4,6 +4,7 @@ package simulation import ( "bytes" + "encoding/base64" "encoding/binary" "errors" "fmt" @@ -92,6 +93,43 @@ func logSyscallExit(name string, invocation *syscallabi.Syscall, attrs ...any) { slog.Info("ret "+name, attrs...) } +func byteDataAttr(key string, value []byte) slog.Attr { + return slog.String(key, "base64:"+base64.StdEncoding.EncodeToString(value)) +} + +func fdAttr(name string, fd int) slog.Attr { + switch fd { + case _AT_FDCWD: + return slog.String(name, "AT_FDCWD") + default: + return slog.Int(name, fd) + } +} + +func addrAttr(addr unsafe.Pointer, addrlen Socklen) slog.Attr { + parsedAddr, parseErr := readAddr(addr, addrlen) + if parseErr != 0 { + return slog.Any("addr", parseErr) + } else { + return slog.Any("addr", parsedAddr) + } +} + +func int8ArrayToString(key string, value []int8) slog.Attr { + n := 0 + for i, c := range value { + if c == 0 { + n = i + break + } + } + b := make([]byte, n) + for i := range n { + b[i] = byte(value[i]) + } + return slog.String(key, string(b)) +} + // logfFor logs the given format and args on the goroutine from the passed // invocation. func (l *LinuxOS) logfFor(invocation *syscallabi.Syscall, format string, args ...any) { @@ -327,15 +365,6 @@ func (l *LinuxOS) SysOpenat(dirfd int, path string, flags int, mode uint32, invo return fd, nil } -func fdAttr(name string, fd int) slog.Attr { - switch fd { - case _AT_FDCWD: - return slog.String(name, "AT_FDCWD") - default: - return slog.Int(name, fd) - } -} - var openatFlags = &gosimlog.BitflagFormatter{ Choices: []gosimlog.BitflagChoice{ { @@ -420,8 +449,6 @@ func (l *LinuxOS) SysGetdents64(fd int, data syscallabi.ByteSliceView, invocatio return 0, syscall.EINVAL } - l.logfFor(invocation, "getdents64 %d %d", fd, data.Len()) - fdInternal, ok := l.files[fd] if !ok { return 0, syscall.EBADFD @@ -436,6 +463,7 @@ func (l *LinuxOS) SysGetdents64(fd int, data syscallabi.ByteSliceView, invocatio return 0, nil } + // TODO: make this iteration work with some kind of pointer entries, err := l.machine.filesystem.ReadDir(f.inode) if err != nil { return 0, syscall.EINVAL // XXX? @@ -531,9 +559,7 @@ func (l *LinuxOS) SysWrite(fd int, data syscallabi.ByteSliceView, invocation *sy if fd == syscall.Stdout || fd == syscall.Stderr { buf := make([]byte, data.Len()) data.Read(buf) - // TODO: use a custom machine here? - // TODO: iterate over buf line-by-line? buf = bytes.TrimSuffix(buf, []byte("\n")) var source string @@ -592,7 +618,7 @@ func (l *LinuxOS) SysWrite(fd int, data syscallabi.ByteSliceView, invocation *sy func (customSyscallLogger) LogEntrySysWrite(fd int, p []byte, syscall *syscallabi.Syscall) { // TODO: format these []byte attrs nicer: handle both ascii and binary gracefully - logSyscallEntry("SysWrite", syscall, "fd", fd, "p", string(p)) + logSyscallEntry("SysWrite", syscall, "fd", fd, byteDataAttr("p", p)) } func (customSyscallLogger) LogExitSysWrite(fd int, p []byte, syscall *syscallabi.Syscall, n int, err error) { @@ -650,7 +676,7 @@ func (customSyscallLogger) LogEntrySysRead(fd int, p []byte, syscall *syscallabi } func (customSyscallLogger) LogExitSysRead(fd int, p []byte, syscall *syscallabi.Syscall, n int, err error) { - logSyscallExit("SysRead", syscall, "n", n, "err", err, "p[:n]", string(p[:n])) + logSyscallExit("SysRead", syscall, "n", n, "err", err, byteDataAttr("p", p[:n])) } func (l *LinuxOS) SysFallocate(fd int, mode uint32, off int64, len int64, invocation *syscallabi.Syscall) (err error) { @@ -781,13 +807,11 @@ func (l *LinuxOS) SysPwrite64(fd int, data syscallabi.ByteSliceView, offset int6 retn := l.machine.filesystem.Write(f.inode, offset, data) - l.logfFor(invocation, "writeat %d %d %q %d", fd, retn, data, offset) - return retn, nil } func (customSyscallLogger) LogEntrySysPwrite64(fd int, p []byte, offset int64, syscall *syscallabi.Syscall) { - logSyscallEntry("SysPwrite64", syscall, "fd", fd, "offset", offset, "p", string(p)) + logSyscallEntry("SysPwrite64", syscall, "fd", fd, "offset", offset, byteDataAttr("p", p)) } func (customSyscallLogger) LogExitSysPwrite64(fd int, p []byte, offset int64, syscall *syscallabi.Syscall, n int, err error) { @@ -817,8 +841,6 @@ func (l *LinuxOS) SysPread64(fd int, data syscallabi.ByteSliceView, offset int64 retn := l.machine.filesystem.Read(f.inode, offset, data) - l.logfFor(invocation, "readat %d %d %d", fd, data.Len() /*, data[:retn]*/, offset) - return retn, nil } @@ -827,7 +849,7 @@ func (customSyscallLogger) LogEntrySysPread64(fd int, p []byte, offset int64, sy } func (customSyscallLogger) LogExitSysPread64(fd int, p []byte, offset int64, syscall *syscallabi.Syscall, n int, err error) { - logSyscallExit("SysPread64", syscall, "n", n, "err", err, "p[:n]", string(p[:n])) + logSyscallExit("SysPread64", syscall, "n", n, "err", err, byteDataAttr("p", p[:n])) } func (l *LinuxOS) SysFsync(fd int, invocation *syscallabi.Syscall) error { @@ -1212,15 +1234,6 @@ func (l *LinuxOS) SysBind(fd int, addrPtr unsafe.Pointer, addrlen Socklen, invoc return nil } -func addrAttr(addr unsafe.Pointer, addrlen Socklen) slog.Attr { - parsedAddr, parseErr := readAddr(addr, addrlen) - if parseErr != 0 { - return slog.Any("addr", parseErr) - } else { - return slog.Any("addr", parsedAddr) - } -} - func (customSyscallLogger) LogEntrySysBind(s int, addr unsafe.Pointer, addrlen Socklen, syscall *syscallabi.Syscall) { logSyscallEntry("SysBind", syscall, "fd", s, addrAttr(addr, addrlen)) } @@ -1490,8 +1503,6 @@ func (l *LinuxOS) SysChdir(path string, invocation *syscallabi.Syscall) (err err return syscall.EINVAL } - l.logfFor(invocation, "chdir %s", path) - newDirinode, err := l.machine.filesystem.Getdirinode(l.workdirInode, path) if err != nil { return err @@ -1685,8 +1696,6 @@ func (l *LinuxOS) SysGetrandom(ptr syscallabi.ByteSliceView, flags int, invocati return 0, syscall.EINVAL } - l.logfFor(invocation, "getrandom %d %d", ptr.Len(), flags) - if flags != 0 { return 0, syscall.EINVAL } @@ -1702,6 +1711,14 @@ func (l *LinuxOS) SysGetrandom(ptr syscallabi.ByteSliceView, flags int, invocati return n, nil } +func (customSyscallLogger) LogEntrySysGetrandom(buf []byte, flags int, syscall *syscallabi.Syscall) { + // logSyscallEntry("SysGetrandom", syscall) +} + +func (customSyscallLogger) LogExitSysGetrandom(buf []byte, flags int, syscall *syscallabi.Syscall, n int, err error) { + // logSyscallExit("SysGetrandom", syscall) +} + func (l *LinuxOS) SysGetpid(invocation *syscallabi.Syscall) int { // TODO: return some random number instead? return 42 @@ -1728,21 +1745,6 @@ func (l *LinuxOS) SysUname(buf syscallabi.ValueView[Utsname], invocation *syscal return nil } -func int8ArrayToString(key string, value []int8) slog.Attr { - n := 0 - for i, c := range value { - if c == 0 { - n = i - break - } - } - b := make([]byte, n) - for i := range n { - b[i] = byte(value[i]) - } - return slog.String(key, string(b)) -} - func (customSyscallLogger) LogEntrySysUname(buf *Utsname, syscall *syscallabi.Syscall) { logSyscallEntry("SysUname", syscall) }