Documentation ¶
Overview ¶
Package sbpf implements the Solana Bytecode Format.
Index ¶
- Constants
- Variables
- func GetOpcodeName(opc uint8) string
- func IsLongIns(op uint8) bool
- func PCHash(addr uint64) uint32
- func SymbolHash(s string) uint32
- type ExcBadAccess
- type ExcCallDest
- type Exception
- type Frame
- type Interpreter
- func (ip *Interpreter) Read(addr uint64, p []byte) error
- func (ip *Interpreter) Read16(addr uint64) (uint16, error)
- func (ip *Interpreter) Read32(addr uint64) (uint32, error)
- func (ip *Interpreter) Read64(addr uint64) (uint64, error)
- func (ip *Interpreter) Read8(addr uint64) (uint8, error)
- func (ip *Interpreter) Run() (err error)
- func (ip *Interpreter) Translate(addr uint64, size uint32, write bool) ([]byte, error)
- func (ip *Interpreter) VMContext() any
- func (ip *Interpreter) Write(addr uint64, p []byte) error
- func (ip *Interpreter) Write16(addr uint64, x uint16) error
- func (ip *Interpreter) Write32(addr uint64, x uint32) error
- func (ip *Interpreter) Write64(addr uint64, x uint64) error
- func (ip *Interpreter) Write8(addr uint64, x uint8) error
- type Program
- type Slot
- type Stack
- type Syscall
- type SyscallFunc0
- type SyscallFunc1
- type SyscallFunc2
- type SyscallFunc3
- type SyscallFunc4
- type SyscallFunc5
- type SyscallRegistry
- type TraceSink
- type VM
- type VMOpts
- type Verifier
Constants ¶
const ( ClassLd = uint8(iota) ClassLdx ClassSt ClassStx ClassAlu ClassJmp Class0x06 // reserved ClassAlu64 )
Op classes
const ( SizeW = uint8(iota * 0x08) SizeH SizeB SizeDw )
Size modes
const ( AddrImm = uint8(iota * 0x20) AddrAbs AddrInd AddrMem Addr0x80 // reserved Addr0xa0 // reserved AddrXadd )
Addressing modes
const ( SrcK = uint8(iota * 0x08) SrcX )
Source modes
const ( AluAdd = uint8(iota * 0x10) AluSub AluMul AluDiv AluOr AluAnd AluLsh AluRsh AluNeg AluMod AluXor AluMov AluArsh AluEnd AluSdiv )
ALU operations
const ( JumpAlways = uint8(iota * 0x10) JumpEq JumpGt JumpGe JumpSet JumpNe JumpSgt JumpSge JumpCall JumpExit JumpLt JumpLe JumpSlt JumpSle )
Jump operations
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
const ( VaddrProgram = uint64(0x1_0000_0000) VaddrStack = uint64(0x2_0000_0000) VaddrHeap = uint64(0x3_0000_0000) VaddrInput = uint64(0x4_0000_0000) )
Hardcoded addresses.
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 )
const ( // EntrypointHash equals SymbolHash("entrypoint") EntrypointHash = uint32(0x71e3cf81) )
const StackDepth = 64
StackDepth is the max frame count of the stack.
const StackFrameSize = 0x1000
StackFrameSize is the addressable memory within a stack frame.
Note that this constant cannot be changed trivially.
Variables ¶
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 PCHash ¶
PCHash returns the murmur3 32-bit hash of a program counter.
Used by VM for non-syscall functions
func SymbolHash ¶
SymbolHash returns the murmur3 32-bit hash of a symbol name.
Types ¶
type ExcBadAccess ¶
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 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) 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) VMContext ¶
func (ip *Interpreter) VMContext() any
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.
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 (*Stack) GetFrame ¶
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 ¶
GetFramePtr returns the current 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 SyscallFunc1 ¶
type SyscallFunc2 ¶
type SyscallFunc3 ¶
type SyscallFunc4 ¶
type SyscallFunc5 ¶
type SyscallRegistry ¶
func NewSyscallRegistry ¶
func NewSyscallRegistry() SyscallRegistry
type VM ¶
type VM interface { VMContext() any Translate(addr uint64, size uint32, write bool) ([]byte, error) 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.