sbf: hello world
This commit is contained in:
parent
c3c4f02ef1
commit
196e826d6b
|
@ -56,11 +56,11 @@ func (i *Interpreter) Run() (err error) {
|
|||
|
||||
// TODO step to next instruction
|
||||
|
||||
mainLoop:
|
||||
for {
|
||||
// Fetch
|
||||
ins := i.getSlot(pc)
|
||||
// Execute
|
||||
pc++
|
||||
switch ins.Op() {
|
||||
case OpLdxb:
|
||||
vma := uint64(int64(r[ins.Src()]) + int64(ins.Off()))
|
||||
|
@ -373,15 +373,20 @@ func (i *Interpreter) Run() (err error) {
|
|||
case OpCallx:
|
||||
panic("callx not implemented")
|
||||
case OpExit:
|
||||
return nil
|
||||
// TODO implement function returns
|
||||
break mainLoop
|
||||
default:
|
||||
panic(fmt.Sprintf("unimplemented opcode %#02x", ins.Op()))
|
||||
}
|
||||
// Post execute
|
||||
if err != nil {
|
||||
// TODO return CPU exception error type here
|
||||
return err
|
||||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Interpreter) getSlot(pc int64) Slot {
|
||||
|
|
|
@ -13,6 +13,7 @@ func clampAddUint64(x uint64, y uint64) uint64 {
|
|||
return z
|
||||
}
|
||||
|
||||
/*
|
||||
func clampSubUint64(x uint64, y uint64) uint64 {
|
||||
z, borrow := bits.Sub64(x, y, 0)
|
||||
if borrow != 0 {
|
||||
|
@ -20,6 +21,7 @@ func clampSubUint64(x uint64, y uint64) uint64 {
|
|||
}
|
||||
return z
|
||||
}
|
||||
*/
|
||||
|
||||
type addrRange struct {
|
||||
min, max uint64
|
||||
|
|
|
@ -49,8 +49,7 @@ type Loader struct {
|
|||
entrypoint uint64 // program counter
|
||||
|
||||
// Symbols
|
||||
funcs map[uint32]uint64
|
||||
syscalls map[uint32]string
|
||||
funcs map[uint32]uint64
|
||||
}
|
||||
|
||||
// Bounds checks
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/certusone/radiance/pkg/sbf"
|
||||
"github.com/spaolacci/murmur3"
|
||||
)
|
||||
|
||||
// relocate applies ELF relocations (for syscalls and position-independent code).
|
||||
|
@ -57,7 +56,7 @@ func (l *Loader) fixupRelativeCalls() error {
|
|||
}
|
||||
|
||||
func (l *Loader) registerFunc(target uint64) (uint32, error) {
|
||||
hash := PCHash(target)
|
||||
hash := sbf.PCHash(target)
|
||||
// TODO check for collision with syscalls
|
||||
if _, ok := l.funcs[hash]; ok {
|
||||
return 0, fmt.Errorf("symbol hash collision")
|
||||
|
@ -155,7 +154,7 @@ func (l *Loader) applyReloc(reloc *elf.Rel64) error {
|
|||
}
|
||||
} else {
|
||||
// Syscall
|
||||
hash = SymbolHash(name)
|
||||
hash = sbf.SymbolHash(name)
|
||||
// TODO check whether syscall is known
|
||||
}
|
||||
|
||||
|
@ -175,24 +174,6 @@ func (l *Loader) getEntrypoint() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
// EntrypointHash equals SymbolHash("entrypoint")
|
||||
EntrypointHash = uint32(0x71e3cf81)
|
||||
)
|
||||
|
||||
// SymbolHash returns the murmur3 32-bit hash of a symbol name.
|
||||
func SymbolHash(s string) uint32 {
|
||||
return murmur3.Sum32([]byte(s))
|
||||
}
|
||||
|
||||
// PCHash returns the murmur3 32-bit hash of a program counter.
|
||||
func PCHash(addr uint64) uint32 {
|
||||
// TODO this is kinda pointless …
|
||||
var key [8]byte
|
||||
binary.LittleEndian.PutUint64(key[:], addr)
|
||||
return murmur3.Sum32(key[:])
|
||||
}
|
||||
|
||||
// Relocation types for eBPF.
|
||||
type R_BPF int
|
||||
|
||||
|
|
|
@ -41,12 +41,12 @@ func (s Slot) Op() uint8 {
|
|||
|
||||
// Dst returns the destination register field.
|
||||
func (s Slot) Dst() uint8 {
|
||||
return uint8(s>>12) & 0xF
|
||||
return uint8(s>>8) & 0xF
|
||||
}
|
||||
|
||||
// Src returns the source register field.
|
||||
func (s Slot) Src() uint8 {
|
||||
return uint8(s>>8) & 0xF
|
||||
return uint8(s>>12) & 0xF
|
||||
}
|
||||
|
||||
// Off returns the offset field.
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package sbf
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/spaolacci/murmur3"
|
||||
)
|
||||
|
||||
const (
|
||||
// EntrypointHash equals SymbolHash("entrypoint")
|
||||
EntrypointHash = uint32(0x71e3cf81)
|
||||
)
|
||||
|
||||
// SymbolHash returns the murmur3 32-bit hash of a symbol name.
|
||||
func SymbolHash(s string) uint32 {
|
||||
return murmur3.Sum32([]byte(s))
|
||||
}
|
||||
|
||||
// PCHash returns the murmur3 32-bit hash of a program counter.
|
||||
//
|
||||
// Used by VM for non-syscall functions
|
||||
func PCHash(addr uint64) uint32 {
|
||||
// TODO this is kinda pointless …
|
||||
var key [8]byte
|
||||
binary.LittleEndian.PutUint64(key[:], addr)
|
||||
return murmur3.Sum32(key[:])
|
||||
}
|
||||
|
||||
type SyscallRegistry map[uint32]Syscall
|
||||
|
||||
func NewSyscallRegistry() SyscallRegistry {
|
||||
return make(SyscallRegistry)
|
||||
}
|
||||
|
||||
func (s SyscallRegistry) Register(name string, syscall Syscall) (hash uint32, ok bool) {
|
||||
hash = SymbolHash(name)
|
||||
if _, exist := s[hash]; exist {
|
||||
return 0, false // collision or duplicate
|
||||
}
|
||||
s[hash] = syscall
|
||||
ok = true
|
||||
return
|
||||
}
|
|
@ -27,7 +27,7 @@ type VMOpts struct {
|
|||
// Machine parameters
|
||||
StackSize int
|
||||
HeapSize int
|
||||
Syscalls map[uint32]Syscall
|
||||
Syscalls SyscallRegistry
|
||||
|
||||
// Execution parameters
|
||||
Context any // passed to syscalls
|
||||
|
@ -65,3 +65,41 @@ func NewExcBadAccess(addr uint64, size uint32, write bool, reason string) ExcBad
|
|||
func (e ExcBadAccess) Error() string {
|
||||
return fmt.Sprintf("bad memory access at %#x (size=%d write=%v), reason: %s", e.Addr, e.Size, e.Write, e.Reason)
|
||||
}
|
||||
|
||||
// Convenience Methods
|
||||
|
||||
type SyscallFunc0 func(vm VM, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc0) Invoke(vm VM, _, _, _, _, _ uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, cuIn)
|
||||
}
|
||||
|
||||
type SyscallFunc1 func(vm VM, r1 uint64, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc1) Invoke(vm VM, r1, _, _, _, _ uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, r1, cuIn)
|
||||
}
|
||||
|
||||
type SyscallFunc2 func(vm VM, r1, r2 uint64, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc2) Invoke(vm VM, r1, r2, _, _, _ uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, r1, r2, cuIn)
|
||||
}
|
||||
|
||||
type SyscallFunc3 func(vm VM, r1, r2, r3 uint64, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc3) Invoke(vm VM, r1, r2, r3, _, _ uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, r1, r2, r3, cuIn)
|
||||
}
|
||||
|
||||
type SyscallFunc4 func(vm VM, r1, r2, r3, r4 uint64, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc4) Invoke(vm VM, r1, r2, r3, r4, _ uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, r1, r2, r3, r4, cuIn)
|
||||
}
|
||||
|
||||
type SyscallFunc5 func(vm VM, r1, r2, r3, r4, r5 uint64, cuIn int64) (r0 uint64, cuOut int64, err error)
|
||||
|
||||
func (f SyscallFunc5) Invoke(vm VM, r1, r2, r3, r4, r5 uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
return f(vm, r1, r2, r3, r4, r5, cuIn)
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
package loader
|
||||
package sealevel
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"github.com/certusone/radiance/fixtures"
|
||||
"github.com/certusone/radiance/pkg/sbf"
|
||||
"github.com/certusone/radiance/pkg/sbf/loader"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestInterpreter_Noop(t *testing.T) {
|
||||
loader, err := NewLoaderFromBytes(soNoop)
|
||||
// TODO simplify API?
|
||||
loader, err := loader.NewLoaderFromBytes(fixtures.SBF(t, "noop.so"))
|
||||
require.NotNil(t, loader)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -19,11 +22,16 @@ func TestInterpreter_Noop(t *testing.T) {
|
|||
|
||||
require.NoError(t, program.Verify())
|
||||
|
||||
syscalls := sbf.NewSyscallRegistry()
|
||||
syscalls.Register("log", SyscallLog)
|
||||
syscalls.Register("log_64", SyscallLog64)
|
||||
|
||||
interpreter := sbf.NewInterpreter(program, &sbf.VMOpts{
|
||||
StackSize: 1024,
|
||||
HeapSize: 1024, // TODO
|
||||
Input: nil,
|
||||
MaxCU: 10000,
|
||||
Syscalls: syscalls,
|
||||
})
|
||||
require.NotNil(t, interpreter)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package sealevel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/certusone/radiance/pkg/sbf"
|
||||
)
|
||||
|
||||
// TODO These are naive stubs
|
||||
|
||||
func SyscallLogImpl(vm sbf.VM, r1, r2 uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
buf := make([]byte, r2)
|
||||
if err = vm.Read(r1, buf); err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println("Program Log:", strings.Trim(string(buf), " \t\x00"))
|
||||
//panic("log syscall unimplemented")
|
||||
return
|
||||
}
|
||||
|
||||
var SyscallLog = sbf.SyscallFunc2(SyscallLogImpl)
|
||||
|
||||
func SyscallLog64Impl(vm sbf.VM, r1, r2, r3, r4, r5 uint64, cuIn int64) (r0 uint64, cuOut int64, err error) {
|
||||
fmt.Printf("Program Log: r1=%#x r2=%#x r3=%#x r4=%#x r5=%#x\n", r1, r2, r3, r4, r5)
|
||||
return
|
||||
}
|
||||
|
||||
var SyscallLog64 = sbf.SyscallFunc5(SyscallLog64Impl)
|
Loading…
Reference in New Issue