Commit 0e4d546c authored by protolambda's avatar protolambda

mipsevm: unicorn hooks + state encoding and set reg/mem funcs

parent 44d01c5b
package main package main
import (
"encoding/hex"
"fmt"
)
const ( const (
pageAddrSize = 10 pageAddrSize = 10
pageSize = 1 << pageAddrSize pageSize = 1 << pageAddrSize
pageAddrMask = pageSize - 1
) )
type Page [pageSize]byte type Page [pageSize]byte
func (p *Page) MarshalText() ([]byte, error) {
dst := make([]byte, hex.EncodedLen(len(p)))
hex.Encode(dst, p[:])
return dst, nil
}
func (p *Page) UnmarshalText(dat []byte) error {
if len(dat) != pageSize*2 {
return fmt.Errorf("expected %d hex chars, but got %d", pageSize*2, len(dat))
}
_, err := hex.Decode(p[:], dat)
return err
}
type State struct { type State struct {
PC uint32 PC uint32 `json:"pc"`
Registers [32]uint32 Hi uint32 `json:"hi"`
Hi, Lo uint32 // special registers Lo uint32 `json:"lo"`
Heap uint32 // to handle mmap growth Heap uint32 `json:"heap"` // to handle mmap growth
Memory map[uint32]*Page Registers [32]uint32 `json:"registers"`
Exit uint32 Memory map[uint32]*Page `json:"memory"`
Exited bool
}
// TODO hooks for unicorn to modify the state Exit uint32 `json:"exit"`
Exited bool `json:"exited"`
// TODO merkleization Step uint64 `json:"step"`
}
// TODO load from JSON // TODO: VM state pre-image:
// PC, Hi, Lo, Heap = 4 * 32/8 = 16 bytes
// Registers = 32 * 32/8 = 256 bytes
// Memory tree root = 32 bytes
// Misc exit/step data = TBD
// + proof(s) for memory leaf nodes
// TODO store to JSON func (s *State) ApplyRegisterDiff(regs [32]uint32, hi, lo uint32) {
for i := 0; i < 32; i++ {
s.Registers[i] = regs[i]
}
s.Hi = hi
s.Lo = lo
}
// TODO hooks to detect state reads/writes func (s *State) SetMemory(addr uint32, v uint32, size uint32) {
// -> maintain access-list for i := size; i > 0; i-- {
pageIndex := addr >> pageAddrSize
pageAddr := addr & pageAddrMask
p, ok := s.Memory[pageIndex]
if !ok {
panic(fmt.Errorf("missing page %x (addr write at %x)", pageIndex, addr))
}
b := uint8(v)
p[pageAddr] = b
v = v >> 8
addr += 1
}
}
// TODO load Unicorn with hooks // TODO merkleization
// TODO convert access-list to calldata and state-sets for EVM // TODO convert access-list to calldata and state-sets for EVM
package main
import (
"fmt"
"log"
uc "github.com/unicorn-engine/unicorn/bindings/go/unicorn"
)
func NewUnicorn() (uc.Unicorn, error) {
return uc.NewUnicorn(uc.ARCH_MIPS, uc.MODE_32|uc.MODE_BIG_ENDIAN)
}
func LoadUnicorn(st *State, mu uc.Unicorn) error {
// TODO mmap each page of state into unicorn
// TODO set all registers
return nil
}
func HookUnicorn(st *State, mu uc.Unicorn) error {
_, err := mu.HookAdd(uc.HOOK_INTR, func(mu uc.Unicorn, intno uint32) {
if intno != 17 {
log.Fatal("invalid interrupt ", intno, " at step ", steps)
}
syscallNum, _ := mu.RegRead(uc.MIPS_REG_V0)
// TODO process syscalls
switch syscallNum {
// TODO mmap
}
}, 0, 0)
if err != nil {
return fmt.Errorf("failed to set up interrupt/syscall hook: %w", err)
}
// Shout if Go mmap calls didn't allocate the memory properly
_, err = mu.HookAdd(uc.HOOK_MEM_WRITE_UNMAPPED, func(mu uc.Unicorn, typ int, addr uint64, size int, value int64) bool {
fmt.Printf("WRITE UNMAPPED typ %d addr %016x size %x value %x\n", typ, addr, size, value)
return false
}, 0, ^uint64(0))
if err != nil {
return fmt.Errorf("failed to set up unmapped-mem-write hook: %w", err)
}
_, err = mu.HookAdd(uc.HOOK_MEM_READ, func(mu uc.Unicorn, access int, addr64 uint64, size int, value int64) {
//rt := value
//rs := addr64 & 3
//addr := uint32(addr64 & 0xFFFFFFFC)
// TODO sanity check matches the state value
// TODO access-list entry
}, 0, 0x80000000)
if err != nil {
return fmt.Errorf("failed to set up mem-write hook: %w", err)
}
_, err = mu.HookAdd(uc.HOOK_MEM_WRITE, func(mu uc.Unicorn, access int, addr64 uint64, size int, value int64) {
//rt := value
//rs := addr64 & 3
//addr := uint32(addr64 & 0xFFFFFFFC)
// TODO write to state memory
}, 0, 0x80000000)
if err != nil {
return fmt.Errorf("failed to set up mem-write hook: %w", err)
}
_, err = mu.HookAdd(uc.HOOK_CODE, func(mu uc.Unicorn, addr uint64, size uint32) {
steps += 1
// TODO: diff all registers
}, 0, 0x80000000)
if err != nil {
return fmt.Errorf("failed to set up instruction hook: %w", err)
}
return nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment