diff --git a/cmd/land/main.go b/cmd/land/main.go index 38dd16d..c8cb572 100644 --- a/cmd/land/main.go +++ b/cmd/land/main.go @@ -1,3 +1,50 @@ package main -func main() {} +import ( + "context" + "flag" + "os" + + "github.com/Xe/ln" +) + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + flag.Parse() + + if flag.NArg() != 1 { + ln.Fatal(ctx, ln.Info("please pass a webassembly file to run")) + } + + fname := flag.Arg(0) + fin, err := os.Open(fname) + if err != nil { + ln.FatalErr(ctx, err, ln.F{"msg": "can't open file", "fname": fname}) + } + defer fin.Close() + + p, err := NewProcess(fin) + if err != nil { + ln.FatalErr(ctx, err, ln.F{"msg": "can't create process", "fname": fname}) + } + + foundMain := false + mainID := uint32(0) + for name, entry := range p.mod.Export.Entries { + if name == "main" && entry.FieldStr == "main" { + mainID = entry.Index + foundMain = true + break + } + } + + if !foundMain { + ln.Fatal(ctx, ln.F{"msg": "no main function exported"}) + } + + _, err = p.vm.ExecCode(int64(mainID)) + if err != nil { + ln.FatalErr(ctx, err) + } +} diff --git a/cmd/land/process.go b/cmd/land/process.go index 74c6a23..e27781d 100644 --- a/cmd/land/process.go +++ b/cmd/land/process.go @@ -2,31 +2,50 @@ package main import ( gcontext "context" + "errors" + "io" "os" "reflect" "github.com/Xe/ln" - "github.com/Xe/uuid" "github.com/go-interpreter/wagon/exec" "github.com/go-interpreter/wagon/validate" "github.com/go-interpreter/wagon/wasm" ) +// Process is a larger level wrapper around a webassembly VM that gives it +// system call access. type Process struct { - id string - vm *exec.VM + id int32 + vm *exec.VM + mod *wasm.Module } -func NewProcess(vm *exec.VM) *Process { - p := &Process{ - id: uuid.New(), - vm: vm, +// NewProcess constructs a new webassembly process based on the input webassembly module as a reader. +func NewProcess(fin io.Reader) (*Process, error) { + p := &Process{} + + mod, err := wasm.ReadModule(fin, p.importer) + if err != nil { + return nil, err } - return p + if mod.Memory == nil { + return nil, errors.New("must declare a memory, sorry :(") + } + + vm, err := exec.NewVM(mod) + if err != nil { + return nil, err + } + + p.mod = mod + p.vm = vm + + return p, nil } -func (p Process) importer(name string) (*wasm.Module, error) { +func (p *Process) importer(name string) (*wasm.Module, error) { switch name { case "env": m := wasm.NewModule() @@ -78,14 +97,19 @@ func (p Process) importer(name string) (*wasm.Module, error) { } } -// ID returns the process ID string. -func (p Process) ID() string { return p.id } +// ID returns the process ID. +func (p Process) ID() int32 { return p.id } // VM returns the webassembly VM used to execute code. This isn't thread-safe. func (p Process) VM() *exec.VM { return p.vm } func (p *Process) log(ptr int32, len int32) int32 { - data := p.vm.Memory()[ptr : ptr+len] + mem := p.vm.Memory() + if mem == nil { + panic("memory is nil, wtf") + } + + data := mem[ptr : ptr+len] ln.Log(gcontext.Background(), ln.F{"data": data, "data_string": string(data), "pid": p.id}) return 0