Implement verifier as writer
This commit is contained in:
parent
684de95198
commit
d95d27f8fe
148
go/vm/debug.go
148
go/vm/debug.go
@ -1,121 +1,165 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ToString verifies all instructions in bytecode and returns an assmebly code instruction for it.
|
||||||
func ToString(b []byte) (string, error) {
|
func ToString(b []byte) (string, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
n, err := ParseAll(b, buf)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
log.Printf("Total %v bytes written to string buffer", n)
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseAll parses and verifies all instructions from bytecode.
|
||||||
|
//
|
||||||
|
// If writer is not nil, the parsed instruction as assembly code line string is written to it.
|
||||||
|
//
|
||||||
|
// Bytecode is consumed (and written) one instruction at a time.
|
||||||
|
//
|
||||||
|
// It fails on any parse error encountered before the bytecode EOF is reached.
|
||||||
|
func ParseAll(b []byte, w io.Writer) (int, error) {
|
||||||
var s string
|
var s string
|
||||||
|
var rs string
|
||||||
|
var rn int
|
||||||
running := true
|
running := true
|
||||||
for running {
|
for running {
|
||||||
op, bb, err := opSplit(b)
|
op, bb, err := opSplit(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return rn, err
|
||||||
}
|
}
|
||||||
opString := OpcodeString[op]
|
s = OpcodeString[op]
|
||||||
if opString == "" {
|
if s == "" {
|
||||||
return "", fmt.Errorf("unknown opcode: %v", op)
|
return rn, fmt.Errorf("unknown opcode: %v", op)
|
||||||
}
|
}
|
||||||
s += opString
|
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case CATCH:
|
case CATCH:
|
||||||
r, n, m, bb, err := ParseCatch(b)
|
r, n, m, bb, err := ParseCatch(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
vv := 0
|
||||||
|
if m {
|
||||||
|
vv = 1
|
||||||
|
}
|
||||||
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s %v %v # invertmatch=%v\n", s, r, n, vv, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vv := 0
|
|
||||||
if m {
|
|
||||||
vv = 1
|
|
||||||
}
|
|
||||||
s = fmt.Sprintf("%s %s %v %v # invertmatch=%v", s, r, n, vv, m)
|
|
||||||
case CROAK:
|
case CROAK:
|
||||||
n, m, bb, err := ParseCroak(b)
|
n, m, bb, err := ParseCroak(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
vv := 0
|
||||||
|
if m {
|
||||||
|
vv = 1
|
||||||
|
}
|
||||||
|
rs = fmt.Sprintf("%s %v %v # invertmatch=%v\n", s, n, vv, m)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
vv := 0
|
|
||||||
if m {
|
|
||||||
vv = 1
|
|
||||||
}
|
|
||||||
s = fmt.Sprintf("%s %v %v # invertmatch=%v", s, n, vv, m)
|
|
||||||
case LOAD:
|
case LOAD:
|
||||||
r, n, bb, err := ParseLoad(b)
|
r, n, bb, err := ParseLoad(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s %v\n", s, r, n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s %v", s, r, n)
|
|
||||||
case RELOAD:
|
case RELOAD:
|
||||||
r, bb, err := ParseReload(b)
|
r, bb, err := ParseReload(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s\n", s, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s", s, r)
|
|
||||||
case MAP:
|
case MAP:
|
||||||
r, bb, err := ParseMap(b)
|
r, bb, err := ParseMap(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s\n", s, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s", s, r)
|
|
||||||
case MOVE:
|
case MOVE:
|
||||||
r, bb, err := ParseMove(b)
|
r, bb, err := ParseMove(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s\n", s, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s", s, r)
|
|
||||||
case INCMP:
|
case INCMP:
|
||||||
r, v, bb, err := ParseInCmp(b)
|
r, v, bb, err := ParseInCmp(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s %s\n", s, r, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s %s", s, r, v)
|
|
||||||
case HALT:
|
case HALT:
|
||||||
b, err = ParseHalt(b)
|
b, err = ParseHalt(b)
|
||||||
if err != nil {
|
rs = "HALT\n"
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
case MSIZE:
|
case MSIZE:
|
||||||
r, v, bb, err := ParseMSize(b)
|
r, v, bb, err := ParseMSize(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %v %v\n", s, r, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %v %v", s, r, v)
|
|
||||||
case MOUT:
|
case MOUT:
|
||||||
r, v, bb, err := ParseMOut(b)
|
r, v, bb, err := ParseMOut(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s \"%s\"", s, r, v)
|
|
||||||
case MNEXT:
|
case MNEXT:
|
||||||
r, v, bb, err := ParseMNext(b)
|
r, v, bb, err := ParseMNext(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s \"%s\"", s, r, v)
|
|
||||||
case MPREV:
|
case MPREV:
|
||||||
r, v, bb, err := ParseMPrev(b)
|
r, v, bb, err := ParseMPrev(b)
|
||||||
b = bb
|
b = bb
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return "", err
|
if w != nil {
|
||||||
|
rs = fmt.Sprintf("%s %s \"%s\"\n", s, r, v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
s = fmt.Sprintf("%s %s \"%s\"", s, r, v)
|
|
||||||
}
|
}
|
||||||
s += "\n"
|
if err != nil {
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
if w != nil {
|
||||||
|
n, err := io.WriteString(w, rs)
|
||||||
|
if err != nil {
|
||||||
|
return rn, err
|
||||||
|
}
|
||||||
|
rn += n
|
||||||
|
log.Printf("wrote %v bytes from instruction %v", n, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
//rs += "\n"
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
running = false
|
running = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s, nil
|
return rn, nil
|
||||||
}
|
}
|
||||||
|
@ -152,3 +152,18 @@ HALT
|
|||||||
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
t.Fatalf("expected:\n\t%v\ngot:\n\t%v", expect, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVerifyMultiple(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)
|
||||||
|
n, err := ParseAll(b, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if n != 0 {
|
||||||
|
t.Fatalf("expected write count to be 0, was %v (how is that possible)", n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user