sbf

package
v0.0.0-...-3423c7d Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 4, 2023 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package sbf implements the Solana Bytecode Format.

Index

Constants

View Source
const (
	ClassLd = uint8(iota)
	ClassLdx
	ClassSt
	ClassStx
	ClassAlu
	ClassJmp
	Class0x06 // reserved
	ClassAlu64
)

Op classes

View Source
const (
	SizeW = uint8(iota * 0x08)
	SizeH
	SizeB
	SizeDw
)

Size modes

View Source
const (
	AddrImm = uint8(iota * 0x20)
	AddrAbs
	AddrInd
	AddrMem
	Addr0x80 // reserved
	Addr0xa0 // reserved
	AddrXadd
)

Addressing modes

View Source
const (
	SrcK = uint8(iota * 0x08)
	SrcX
)

Source modes

View Source
const (
	AluAdd = uint8(iota * 0x10)
	AluSub
	AluMul
	AluDiv
	AluOr
	AluAnd
	AluLsh
	AluRsh
	AluNeg
	AluMod
	AluXor
	AluMov
	AluArsh
	AluEnd
	AluSdiv
)

ALU operations

View Source
const (
	JumpAlways = uint8(iota * 0x10)
	JumpEq
	JumpGt
	JumpGe
	JumpSet
	JumpNe
	JumpSgt
	JumpSge
	JumpCall
	JumpExit
	JumpLt
	JumpLe
	JumpSlt
	JumpSle
)

Jump operations

View Source
const (
	OpLddw = ClassLd | AddrImm | SizeDw

	OpLdxb  = ClassLdx | AddrMem | SizeB
	OpLdxh  = ClassLdx | AddrMem | SizeH
	OpLdxw  = ClassLdx | AddrMem | SizeW
	OpLdxdw = ClassLdx | AddrMem | SizeDw
	OpStb   = ClassSt | AddrMem | SizeB
	OpSth   = ClassSt | AddrMem | SizeH
	OpStw   = ClassSt | AddrMem | SizeW
	OpStdw  = ClassSt | AddrMem | SizeDw
	OpStxb  = ClassStx | AddrMem | SizeB
	OpStxh  = ClassStx | AddrMem | SizeH
	OpStxw  = ClassStx | AddrMem | SizeW
	OpStxdw = ClassStx | AddrMem | SizeDw

	OpAdd32Imm  = ClassAlu | SrcK | AluAdd
	OpAdd32Reg  = ClassAlu | SrcX | AluAdd
	OpSub32Imm  = ClassAlu | SrcK | AluSub
	OpSub32Reg  = ClassAlu | SrcX | AluSub
	OpMul32Imm  = ClassAlu | SrcK | AluMul
	OpMul32Reg  = ClassAlu | SrcX | AluMul
	OpDiv32Imm  = ClassAlu | SrcK | AluDiv
	OpDiv32Reg  = ClassAlu | SrcX | AluDiv
	OpOr32Imm   = ClassAlu | SrcK | AluOr
	OpOr32Reg   = ClassAlu | SrcX | AluOr
	OpAnd32Imm  = ClassAlu | SrcK | AluAnd
	OpAnd32Reg  = ClassAlu | SrcX | AluAnd
	OpLsh32Imm  = ClassAlu | SrcK | AluLsh
	OpLsh32Reg  = ClassAlu | SrcX | AluLsh
	OpRsh32Imm  = ClassAlu | SrcK | AluRsh
	OpRsh32Reg  = ClassAlu | SrcX | AluRsh
	OpNeg32     = ClassAlu | AluNeg
	OpMod32Imm  = ClassAlu | SrcK | AluMod
	OpMod32Reg  = ClassAlu | SrcX | AluMod
	OpXor32Imm  = ClassAlu | SrcK | AluXor
	OpXor32Reg  = ClassAlu | SrcX | AluXor
	OpMov32Imm  = ClassAlu | SrcK | AluMov
	OpMov32Reg  = ClassAlu | SrcX | AluMov
	OpArsh32Imm = ClassAlu | SrcK | AluArsh
	OpArsh32Reg = ClassAlu | SrcX | AluArsh
	OpSdiv32Imm = ClassAlu | SrcK | AluSdiv
	OpSdiv32Reg = ClassAlu | SrcX | AluSdiv
	OpLe        = ClassAlu | SrcK | AluEnd
	OpBe        = ClassAlu | SrcX | AluEnd

	OpAdd64Imm  = ClassAlu64 | SrcK | AluAdd
	OpAdd64Reg  = ClassAlu64 | SrcX | AluAdd
	OpSub64Imm  = ClassAlu64 | SrcK | AluSub
	OpSub64Reg  = ClassAlu64 | SrcX | AluSub
	OpMul64Imm  = ClassAlu64 | SrcK | AluMul
	OpMul64Reg  = ClassAlu64 | SrcX | AluMul
	OpDiv64Imm  = ClassAlu64 | SrcK | AluDiv
	OpDiv64Reg  = ClassAlu64 | SrcX | AluDiv
	OpOr64Imm   = ClassAlu64 | SrcK | AluOr
	OpOr64Reg   = ClassAlu64 | SrcX | AluOr
	OpAnd64Imm  = ClassAlu64 | SrcK | AluAnd
	OpAnd64Reg  = ClassAlu64 | SrcX | AluAnd
	OpLsh64Imm  = ClassAlu64 | SrcK | AluLsh
	OpLsh64Reg  = ClassAlu64 | SrcX | AluLsh
	OpRsh64Imm  = ClassAlu64 | SrcK | AluRsh
	OpRsh64Reg  = ClassAlu64 | SrcX | AluRsh
	OpNeg64     = ClassAlu64 | AluNeg
	OpMod64Imm  = ClassAlu64 | SrcK | AluMod
	OpMod64Reg  = ClassAlu64 | SrcX | AluMod
	OpXor64Imm  = ClassAlu64 | SrcK | AluXor
	OpXor64Reg  = ClassAlu64 | SrcX | AluXor
	OpMov64Imm  = ClassAlu64 | SrcK | AluMov
	OpMov64Reg  = ClassAlu64 | SrcX | AluMov
	OpArsh64Imm = ClassAlu64 | SrcK | AluArsh
	OpArsh64Reg = ClassAlu64 | SrcX | AluArsh
	OpSdiv64Imm = ClassAlu64 | SrcK | AluSdiv
	OpSdiv64Reg = ClassAlu64 | SrcX | AluSdiv

	OpJa      = ClassJmp | JumpAlways
	OpJeqImm  = ClassJmp | SrcK | JumpEq
	OpJeqReg  = ClassJmp | SrcX | JumpEq
	OpJgtImm  = ClassJmp | SrcK | JumpGt
	OpJgtReg  = ClassJmp | SrcX | JumpGt
	OpJgeImm  = ClassJmp | SrcK | JumpGe
	OpJgeReg  = ClassJmp | SrcX | JumpGe
	OpJltImm  = ClassJmp | SrcK | JumpLt
	OpJltReg  = ClassJmp | SrcX | JumpLt
	OpJleImm  = ClassJmp | SrcK | JumpLe
	OpJleReg  = ClassJmp | SrcX | JumpLe
	OpJsetImm = ClassJmp | SrcK | JumpSet
	OpJsetReg = ClassJmp | SrcX | JumpSet
	OpJneImm  = ClassJmp | SrcK | JumpNe
	OpJneReg  = ClassJmp | SrcX | JumpNe
	OpJsgtImm = ClassJmp | SrcK | JumpSgt
	OpJsgtReg = ClassJmp | SrcX | JumpSgt
	OpJsgeImm = ClassJmp | SrcK | JumpSge
	OpJsgeReg = ClassJmp | SrcX | JumpSge
	OpJsltImm = ClassJmp | SrcK | JumpSlt
	OpJsltReg = ClassJmp | SrcX | JumpSlt
	OpJsleImm = ClassJmp | SrcK | JumpSle
	OpJsleReg = ClassJmp | SrcX | JumpSle

	OpCall  = ClassJmp | SrcK | JumpCall
	OpCallx = ClassJmp | SrcX | JumpCall
	OpExit  = ClassJmp | JumpExit
)

Opcodes

View Source
const (
	VaddrProgram = uint64(0x1_0000_0000)
	VaddrStack   = uint64(0x2_0000_0000)
	VaddrHeap    = uint64(0x3_0000_0000)
	VaddrInput   = uint64(0x4_0000_0000)
)

Hardcoded addresses.

View Source
const (
	// SlotSize is the size of one instruction slot.
	SlotSize = 8
	// MinInsSize is the size of the shortest possible instruction
	MinInsSize = SlotSize
	// MaxInsSize is the size of the longest possible instruction (lddw)
	MaxInsSize = 2 * SlotSize
)
View Source
const (
	// EntrypointHash equals SymbolHash("entrypoint")
	EntrypointHash = uint32(0x71e3cf81)
)
View Source
const StackDepth = 64

StackDepth is the max frame count of the stack.

View Source
const StackFrameSize = 0x1000

StackFrameSize is the addressable memory within a stack frame.

Note that this constant cannot be changed trivially.

Variables

View Source
var (
	ExcDivideByZero   = errors.New("division by zero")
	ExcDivideOverflow = errors.New("divide overflow")
	ExcOutOfCU        = errors.New("compute unit overrun")
	ExcCallDepth      = errors.New("call depth exceeded")
)

Exception codes.

Functions

func GetOpcodeName

func GetOpcodeName(opc uint8) string

func IsLongIns

func IsLongIns(op uint8) bool

func PCHash

func PCHash(addr uint64) uint32

PCHash returns the murmur3 32-bit hash of a program counter.

Used by VM for non-syscall functions

func SymbolHash

func SymbolHash(s string) uint32

SymbolHash returns the murmur3 32-bit hash of a symbol name.

Types

type ExcBadAccess

type ExcBadAccess struct {
	Addr   uint64
	Size   uint32
	Write  bool
	Reason string
}

func NewExcBadAccess

func NewExcBadAccess(addr uint64, size uint32, write bool, reason string) ExcBadAccess

func (ExcBadAccess) Error

func (e ExcBadAccess) Error() string

type ExcCallDest

type ExcCallDest struct {
	Imm uint32
}

func (ExcCallDest) Error

func (e ExcCallDest) Error() string

type Exception

type Exception struct {
	PC     int64
	Detail error
}

func (*Exception) Error

func (e *Exception) Error() string

func (*Exception) Unwrap

func (e *Exception) Unwrap() error

type Frame

type Frame struct {
	FramePtr uint64
	NVRegs   [4]uint64
	RetAddr  int64
}

Frame is an entry on the shadow stack.

type Interpreter

type Interpreter struct {
	// contains filtered or unexported fields
}

Interpreter implements the SBF core in pure Go.

func NewInterpreter

func NewInterpreter(p *Program, opts *VMOpts) *Interpreter

NewInterpreter creates a new interpreter instance for a program execution.

The caller must create a new interpreter object for every new execution. In other words, Run may only be called once per interpreter.

func (*Interpreter) Read

func (ip *Interpreter) Read(addr uint64, p []byte) error

func (*Interpreter) Read16

func (ip *Interpreter) Read16(addr uint64) (uint16, error)

func (*Interpreter) Read32

func (ip *Interpreter) Read32(addr uint64) (uint32, error)

func (*Interpreter) Read64

func (ip *Interpreter) Read64(addr uint64) (uint64, error)

func (*Interpreter) Read8

func (ip *Interpreter) Read8(addr uint64) (uint8, error)

func (*Interpreter) Run

func (ip *Interpreter) Run() (err error)

Run executes the program.

This function may panic given code that doesn't pass the static verifier.

func (*Interpreter) Translate

func (ip *Interpreter) Translate(addr uint64, size uint32, write bool) (unsafe.Pointer, error)

func (*Interpreter) VMContext

func (ip *Interpreter) VMContext() any

func (*Interpreter) Write

func (ip *Interpreter) Write(addr uint64, p []byte) error

func (*Interpreter) Write16

func (ip *Interpreter) Write16(addr uint64, x uint16) error

func (*Interpreter) Write32

func (ip *Interpreter) Write32(addr uint64, x uint32) error

func (*Interpreter) Write64

func (ip *Interpreter) Write64(addr uint64, x uint64) error

func (*Interpreter) Write8

func (ip *Interpreter) Write8(addr uint64, x uint8) error

type Program

type Program struct {
	RO         []byte // read-only segment containing text and ELFs
	Text       []byte
	TextVA     uint64
	Entrypoint uint64 // PC
	Funcs      map[uint32]int64
}

Program is a loaded SBF program.

func (*Program) Verify

func (p *Program) Verify() error

Verify runs the static bytecode verifier.

type Slot

type Slot uint64

Slot holds the content of one instruction slot.

func GetSlot

func GetSlot(buf []byte) Slot

GetSlot reads an instruction slot from memory.

func (Slot) Dst

func (s Slot) Dst() uint8

Dst returns the destination register field.

func (Slot) Imm

func (s Slot) Imm() int32

Imm returns the immediate field.

func (Slot) Off

func (s Slot) Off() int16

Off returns the offset field.

func (Slot) Op

func (s Slot) Op() uint8

Op returns the opcode field.

func (Slot) Src

func (s Slot) Src() uint8

Src returns the source register field.

func (Slot) Uimm

func (s Slot) Uimm() uint32

Uimm returns the immediate field as unsigned.

type Stack

type Stack struct {
	// contains filtered or unexported fields
}

Stack is the VM's call frame stack.

Memory stack

The memory stack resides in addressable memory at VaddrStack.

It is split into statically sized stack frames (StackFrameSize). Each frame stores spilled function arguments and local variables. The frame pointer (r10) points to the highest address in the current frame.

New frames get allocated upwards. Each frame is followed by a gap of size StackFrameSize.

[0x1_0000_0000]: Frame
[0x1_0000_1000]: Gap
[0x1_0000_2000]: Frame
[0x1_0000_3000]: Gap
...

Shadow stack

The shadow stack is not directly accessible from SBF. It stores return addresses and caller-preserved registers.

func NewStack

func NewStack() Stack

func (*Stack) GetFrame

func (s *Stack) GetFrame(addr uint32) []byte

GetFrame returns the stack frame memory slice containing the frame pointer.

The returned slice starts at the location within the frame as indicated by the address. To get the full frame, align the provided address by StackFrameSize.

Returns nil if the program tries to address a gap or out-of-bounds memory.

func (*Stack) GetFramePtr

func (s *Stack) GetFramePtr() uint64

GetFramePtr returns the current frame pointer.

func (*Stack) Pop

func (s *Stack) Pop(nvRegs *[4]uint64) (fp uint64, ret int64, ok bool)

Pop exits the last call frame.

Writes saved nonvolatile regs into provided slice. Returns saved return address, new frame pointer. Sets `ok` to false if no call frames are left.

func (*Stack) Push

func (s *Stack) Push(nvRegs *[4]uint64, ret int64) (fp uint64, ok bool)

Push allocates a new call frame.

Saves the given nonvolatile regs and return address. Returns the new frame pointer.

type Syscall

type Syscall interface {
	Invoke(vm VM, r1, r2, r3, r4, r5 uint64, cuIn int) (r0 uint64, cuOut int, err error)
}

Syscall are callback handles from VM to Go. (work in progress)

type SyscallFunc0

type SyscallFunc0 func(vm VM, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc0) Invoke

func (f SyscallFunc0) Invoke(vm VM, _, _, _, _, _ uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallFunc1

type SyscallFunc1 func(vm VM, r1 uint64, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc1) Invoke

func (f SyscallFunc1) Invoke(vm VM, r1, _, _, _, _ uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallFunc2

type SyscallFunc2 func(vm VM, r1, r2 uint64, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc2) Invoke

func (f SyscallFunc2) Invoke(vm VM, r1, r2, _, _, _ uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallFunc3

type SyscallFunc3 func(vm VM, r1, r2, r3 uint64, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc3) Invoke

func (f SyscallFunc3) Invoke(vm VM, r1, r2, r3, _, _ uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallFunc4

type SyscallFunc4 func(vm VM, r1, r2, r3, r4 uint64, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc4) Invoke

func (f SyscallFunc4) Invoke(vm VM, r1, r2, r3, r4, _ uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallFunc5

type SyscallFunc5 func(vm VM, r1, r2, r3, r4, r5 uint64, cuIn int) (r0 uint64, cuOut int, err error)

func (SyscallFunc5) Invoke

func (f SyscallFunc5) Invoke(vm VM, r1, r2, r3, r4, r5 uint64, cuIn int) (r0 uint64, cuOut int, err error)

type SyscallRegistry

type SyscallRegistry map[uint32]Syscall

func NewSyscallRegistry

func NewSyscallRegistry() SyscallRegistry

func (SyscallRegistry) Register

func (s SyscallRegistry) Register(name string, syscall Syscall) (hash uint32, ok bool)

type TraceSink

type TraceSink interface {
	Printf(format string, v ...any)
}

type VM

type VM interface {
	VMContext() any

	Read(addr uint64, p []byte) error
	Read8(addr uint64) (uint8, error)
	Read16(addr uint64) (uint16, error)
	Read32(addr uint64) (uint32, error)
	Read64(addr uint64) (uint64, error)

	Write(addr uint64, p []byte) error
	Write8(addr uint64, x uint8) error
	Write16(addr uint64, x uint16) error
	Write32(addr uint64, x uint32) error
	Write64(addr uint64, x uint64) error
}

VM is the virtual machine abstraction, implemented by each executor.

type VMOpts

type VMOpts struct {
	// Machine parameters
	HeapSize int
	Syscalls SyscallRegistry
	Tracer   TraceSink

	// Execution parameters
	Context any // passed to syscalls
	MaxCU   int
	Input   []byte // mapped at VaddrInput
}

VMOpts specifies virtual machine parameters.

type Verifier

type Verifier struct {
	Program *Program
}

func NewVerifier

func NewVerifier(p *Program) *Verifier

func (*Verifier) Verify

func (v *Verifier) Verify() error

Directories

Path Synopsis
Package loader implements an ELF loader for the Sealevel virtual machine.
Package loader implements an ELF loader for the Sealevel virtual machine.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL