Add disasembler-ish - bytecode to instruction debug output
This commit is contained in:
parent
aec0564cea
commit
ac4a2bac00
@ -163,6 +163,15 @@ If `data_directory` is not set, current directory will be used.
|
|||||||
if `root_symbol` is not set, the symbol `root` will be used.
|
if `root_symbol` is not set, the symbol `root` will be used.
|
||||||
|
|
||||||
|
|
||||||
|
### Disassembler
|
||||||
|
|
||||||
|
`go run ./dev/testdata/ <binary_file>`
|
||||||
|
|
||||||
|
The output from this tool is to be considered debugging output, as the assembly language isn't formalized yet.
|
||||||
|
|
||||||
|
In the meantime, it will at least list all the instructions, and thus validate the file.
|
||||||
|
|
||||||
|
|
||||||
### Assembler
|
### Assembler
|
||||||
|
|
||||||
**TBD**
|
**TBD**
|
||||||
|
27
go/dev/disasm/main.go
Normal file
27
go/dev/disasm/main.go
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"git.defalsify.org/festive/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if (len(os.Args) < 2) {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fp := os.Args[1]
|
||||||
|
v, err := ioutil.ReadFile(fp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "read error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
r, err := vm.ToString(v)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "parse error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf(r)
|
||||||
|
}
|
93
go/vm/debug.go
Normal file
93
go/vm/debug.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func ToString(b []byte) (string, error) {
|
||||||
|
var s string
|
||||||
|
running := true
|
||||||
|
for running {
|
||||||
|
op, bb, err := opSplit(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
opString := OpcodeString[op]
|
||||||
|
if opString == "" {
|
||||||
|
return "", fmt.Errorf("unknown opcode: %v", op)
|
||||||
|
}
|
||||||
|
s += opString
|
||||||
|
|
||||||
|
switch op {
|
||||||
|
case CATCH:
|
||||||
|
r, n, m, bb, err := ParseCatch(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
vv := 0
|
||||||
|
if m {
|
||||||
|
vv = 1
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s %v %v # invertmatch=%v", s, r, n, vv, m)
|
||||||
|
case CROAK:
|
||||||
|
n, m, bb, err := ParseCroak(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
vv := 0
|
||||||
|
if m {
|
||||||
|
vv = 1
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %v %v # invertmatch=%v", s, n, vv, m)
|
||||||
|
case LOAD:
|
||||||
|
r, n, bb, err := ParseLoad(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s %v", s, r, n)
|
||||||
|
case RELOAD:
|
||||||
|
r, bb, err := ParseReload(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s", s, r)
|
||||||
|
case MAP:
|
||||||
|
r, bb, err := ParseMap(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s", s, r)
|
||||||
|
case MOVE:
|
||||||
|
r, bb, err := ParseMove(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s", s, r)
|
||||||
|
case INCMP:
|
||||||
|
r, v, bb, err := ParseInCmp(b)
|
||||||
|
b = bb
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = fmt.Sprintf("%s %s %s", s, r, v)
|
||||||
|
case HALT:
|
||||||
|
b, err = ParseHalt(b)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s += "\n"
|
||||||
|
if len(b) == 0 {
|
||||||
|
running = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
114
go/vm/debug_test.go
Normal file
114
go/vm/debug_test.go
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func TestToString(t *testing.T) {
|
||||||
|
var b []byte
|
||||||
|
var r string
|
||||||
|
var expect string
|
||||||
|
var err error
|
||||||
|
|
||||||
|
b = NewLine(nil, CATCH, []string{"xyzzy"}, []byte{0x0d}, []uint8{1})
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "CATCH xyzzy 13 1 # invertmatch=true\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, CROAK, nil, []byte{0x0d}, []uint8{1})
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "CROAK 13 1 # invertmatch=true\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, LOAD, []string{"foo"}, []byte{0x0a}, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "LOAD foo 10\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, RELOAD, []string{"bar"}, nil, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "RELOAD bar\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, MAP, []string{"inky_pinky"}, nil, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "MAP inky_pinky\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, MOVE, []string{"blinky_clyde"}, nil, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "MOVE blinky_clyde\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, HALT, nil, nil, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "HALT\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
b = NewLine(nil, INCMP, []string{"13", "baz"}, nil, nil)
|
||||||
|
r, err = ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect = "INCMP 13 baz\n"
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToStringMultiple(t *testing.T) {
|
||||||
|
b := NewLine(nil, INCMP, []string{"1", "foo"}, nil, nil)
|
||||||
|
b = NewLine(b, INCMP, []string{"2", "bar"}, nil, nil)
|
||||||
|
b = NewLine(b, CATCH, []string{"aiee"}, []byte{0x02, 0x9a}, []uint8{0})
|
||||||
|
b = NewLine(b, LOAD, []string{"inky"}, []byte{0x2a}, nil)
|
||||||
|
b = NewLine(b, HALT, nil, nil, nil)
|
||||||
|
r, err := ToString(b)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expect := `INCMP 1 foo
|
||||||
|
INCMP 2 bar
|
||||||
|
CATCH aiee 666 0 # invertmatch=false
|
||||||
|
LOAD inky 42
|
||||||
|
HALT
|
||||||
|
`
|
||||||
|
if r != expect {
|
||||||
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
|
}
|
||||||
|
}
|
@ -17,3 +17,17 @@ const (
|
|||||||
INCMP = 8
|
INCMP = 8
|
||||||
_MAX = 8
|
_MAX = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
OpcodeString = map[Opcode]string{
|
||||||
|
NOOP: "NOOP",
|
||||||
|
CATCH: "CATCH",
|
||||||
|
CROAK: "CROAK",
|
||||||
|
LOAD: "LOAD",
|
||||||
|
RELOAD: "RELOAD",
|
||||||
|
MAP: "MAP",
|
||||||
|
MOVE: "MOVE",
|
||||||
|
HALT: "HALT",
|
||||||
|
INCMP: "INCMP",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@ -19,13 +19,11 @@ import (
|
|||||||
func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) ([]byte, error) {
|
||||||
running := true
|
running := true
|
||||||
for running {
|
for running {
|
||||||
log.Printf("code before 0x%x", b)
|
|
||||||
op, bb, err := opSplit(b)
|
op, bb, err := opSplit(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
b = bb
|
b = bb
|
||||||
log.Printf("code after 0x%x", b)
|
|
||||||
switch op {
|
switch op {
|
||||||
case CATCH:
|
case CATCH:
|
||||||
b, err = RunCatch(b, st, rs, ctx)
|
b, err = RunCatch(b, st, rs, ctx)
|
||||||
@ -41,7 +39,6 @@ func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) (
|
|||||||
b, err = RunMove(b, st, rs, ctx)
|
b, err = RunMove(b, st, rs, ctx)
|
||||||
case INCMP:
|
case INCMP:
|
||||||
b, err = RunInCmp(b, st, rs, ctx)
|
b, err = RunInCmp(b, st, rs, ctx)
|
||||||
log.Printf("bb %v", b)
|
|
||||||
case HALT:
|
case HALT:
|
||||||
b, err = RunHalt(b, st, rs, ctx)
|
b, err = RunHalt(b, st, rs, ctx)
|
||||||
return b, err
|
return b, err
|
||||||
@ -51,7 +48,6 @@ func Run(b []byte, st *state.State, rs resource.Resource, ctx context.Context) (
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return b, err
|
return b, err
|
||||||
}
|
}
|
||||||
log.Printf("aa %v", b)
|
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return []byte{}, nil
|
return []byte{}, nil
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"git.defalsify.org/festive/state"
|
"git.defalsify.org/festive/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Parse(b []byte) (Opcode, []byte, error) {
|
func ParseOp(b []byte) (Opcode, []byte, error) {
|
||||||
op, b, err := opSplit(b)
|
op, b, err := opSplit(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NOOP, b, err
|
return NOOP, b, err
|
||||||
|
Loading…
Reference in New Issue
Block a user