sbpf

package
v0.1.0-alpha.1 Latest Latest
Warning

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

Go to latest
Published: Jan 15, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package sbpf implements the Solana Bytecode Format.

Index

Constants

View Source
const (
	ClassLd = uint8(iota)
	ClassLdx
	ClassSt
	ClassStx
	ClassAlu
	ClassJmp
	ClassPqr
	ClassAlu64
)

Op classes

View Source
const (
	SizeW = uint8(iota * 0x08)
	SizeH
	SizeB
	SizeDw
	Size1B = 0x20
	Size2B = 0x30
	Size4B = 0x80
	Size8B = 0x90
)

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
	AluHor
)

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 (
	PqrUhmul = uint8(0x20)
	PqrUdiv  = uint8(0x40)
	PqrUrem  = uint8(0x60)
	PqrLmul  = uint8(0x80)
	PqrShmul = uint8(0xa0)
	PqrSdiv  = uint8(0xc0)
	PqrSrem  = uint8(0xe0)
)

PQR 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
	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
	OpHor64Imm  = ClassAlu64 | SrcK | AluHor

	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

	OpLmul32Imm = ClassPqr | SrcK | PqrLmul
	OpLmul32Reg = ClassPqr | SrcX | PqrLmul
	//OpUhmul32Imm = ClassPqr | SrcK | PqrUhmul
	//OpUhmul32Reg = ClassPqr | SrcX | PqrUhmul
	OpUdiv32Imm = ClassPqr | SrcK | PqrUdiv
	OpUdiv32Reg = ClassPqr | SrcX | PqrUdiv
	OpUrem32Imm = ClassPqr | SrcK | PqrUrem
	OpUrem32Reg = ClassPqr | SrcX | PqrUrem
	//OpShmul32Imm = ClassPqr | SrcK | PqrShmul
	//OpShmul32Reg = ClassPqr | SrcX | PqrShmul
	OpSdiv32Imm = ClassPqr | SrcK | PqrSdiv
	OpSdiv32Reg = ClassPqr | SrcX | PqrSdiv
	OpSrem32Imm = ClassPqr | SrcK | PqrSrem
	OpSrem32Reg = ClassPqr | SrcX | PqrSrem

	OpLmul64Imm  = ClassPqr | SizeB | SrcK | PqrLmul
	OpLmul64Reg  = ClassPqr | SizeB | SrcX | PqrLmul
	OpUhmul64Imm = ClassPqr | SizeB | SrcK | PqrUhmul
	OpUhmul64Reg = ClassPqr | SizeB | SrcX | PqrUhmul
	OpUdiv64Imm  = ClassPqr | SizeB | SrcK | PqrUdiv
	OpUdiv64Reg  = ClassPqr | SizeB | SrcX | PqrUdiv
	OpUrem64Imm  = ClassPqr | SizeB | SrcK | PqrUrem
	OpUrem64Reg  = ClassPqr | SizeB | SrcX | PqrUrem
	OpShmul64Imm = ClassPqr | SizeB | SrcK | PqrShmul
	OpShmul64Reg = ClassPqr | SizeB | SrcX | PqrShmul
	OpSdiv64Imm  = ClassPqr | SizeB | SrcK | PqrSdiv
	OpSdiv64Reg  = ClassPqr | SizeB | SrcX | PqrSdiv
	OpSrem64Imm  = ClassPqr | SizeB | SrcK | PqrSrem
	OpSrem64Reg  = ClassPqr | SizeB | SrcX | PqrSrem

	OpLd1BReg = ClassAlu | SrcX | Size1B
	OpLd2BReg = ClassAlu | SrcX | Size2B
	OpLd4BReg = ClassAlu | SrcX | Size4B
	OpLd8BReg = ClassAlu | SrcX | Size8B
	OpSt1BImm = ClassAlu64 | SrcK | Size1B
	OpSt2BImm = ClassAlu64 | SrcK | Size2B
	OpSt4BImm = ClassAlu64 | SrcK | Size4B
	OpSt8BImm = ClassAlu64 | SrcK | Size8B
	OpSt1BReg = ClassAlu64 | SrcX | Size1B
	OpSt2BReg = ClassAlu64 | SrcX | Size2B
	OpSt4BReg = ClassAlu64 | SrcX | Size4B
	OpSt8BReg = ClassAlu64 | SrcX | Size8B
)

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 (
	StackFrameSize          = 0x1000
	StackMax                = 64 * StackFrameSize
	DynamicStackFramesAlign = 64
)

StackFrameSize is the addressable memory within a stack frame.

Note that this constant cannot be changed trivially.

View Source
const (
	// EntrypointHash equals SymbolHash("entrypoint")
	EntrypointHash = uint32(0x71e3cf81)
)
View Source
const StackDepth = 64

StackDepth is the max frame count of the stack.

Variables

View Source
var (
	ExcDivideByZero   = errors.New("divide by zero at BPF instruction")
	ExcDivideOverflow = errors.New("divide overflow")
	ExcOutOfCU        = errors.New("compute unit overrun")
	ExcCallDepth      = errors.New("call depth exceeded")
	ExcInvalidInstr   = errors.New("invalid instruction - feature not enabled")

	ExcUnsupportedInstruction = errors.New("unsupported BPF instruction")
)

Exception codes.

View Source
var GapMask = uint64(0xFFFFFFFFFFFFF000)
View Source
var (
	// Also applies to interpreter heap.
	UsePool = true
)

Functions

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   uint64
	Write  bool
	Reason string
}

func NewExcBadAccess

func NewExcBadAccess(addr uint64, size uint64, 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) ComputeMeter

func (ip *Interpreter) ComputeMeter() *cu.ComputeMeter

func (*Interpreter) DueInstrCount

func (ip *Interpreter) DueInstrCount() uint64

func (*Interpreter) Finish

func (ip *Interpreter) Finish()

func (*Interpreter) GetOpcodeName

func (ip *Interpreter) GetOpcodeName(opc uint8) string

func (*Interpreter) HeapMax

func (ip *Interpreter) HeapMax() uint64

func (*Interpreter) HeapSize

func (ip *Interpreter) HeapSize() uint64

func (*Interpreter) PrevInstrMeter

func (ip *Interpreter) PrevInstrMeter() uint64

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() (ret uint64, cuConsumed uint64, err error)

Run executes the program.

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

func (*Interpreter) SetPrevInstrMeter

func (ip *Interpreter) SetPrevInstrMeter(num uint64)

func (*Interpreter) Translate

func (ip *Interpreter) Translate(addr uint64, size uint64, write bool) ([]byte, error)

func (*Interpreter) UpdateHeapSize

func (ip *Interpreter) UpdateHeapSize(size uint64)

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        []Slot
	TextVA      uint64
	Entrypoint  uint64 // PC
	Funcs       map[uint32]int64
	SbpfVersion sbpfver.SbpfVersion
}

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 (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(sbpfVer sbpfver.SbpfVersion) Stack

func (*Stack) Finish

func (s *Stack) Finish()

func (*Stack) GetFrame

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

GetFrame returns underlying memory as a slice for a given stack address

func (*Stack) GetFramePtr

func (s *Stack) GetFramePtr() uint64

GetFramePtr returns the current frame pointer.

func (*Stack) Pop

func (s *Stack) Pop(regs []uint64) (int64, bool)

Pop exits the last call frame.

Restores saved nonvolatile regs into provided slice. Returns saved return address and returns true upon success, and returns false if no call frames are left.

func (*Stack) Push

func (s *Stack) Push(regs []uint64, ret int64) bool

Push allocates a new call frame.

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

type Syscall

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

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

type SyscallFunc0

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

func (SyscallFunc0) Invoke

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

type SyscallFunc1

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

func (SyscallFunc1) Invoke

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

type SyscallFunc2

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

func (SyscallFunc2) Invoke

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

type SyscallFunc3

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

func (SyscallFunc3) Invoke

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

type SyscallFunc4

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

func (SyscallFunc4) Invoke

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

type SyscallFunc5

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

func (SyscallFunc5) Invoke

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

type SyscallRegistry

type SyscallRegistry func(uint32) (Syscall, bool)

func (SyscallRegistry) ExistsByHash

func (s SyscallRegistry) ExistsByHash(hash uint32) bool

type TraceSink

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

type VM

type VM interface {
	VMContext() any

	HeapMax() uint64
	HeapSize() uint64
	UpdateHeapSize(size uint64)

	Translate(addr uint64, size uint64, write bool) ([]byte, error)

	DueInstrCount() uint64
	PrevInstrMeter() uint64
	SetPrevInstrMeter(num uint64)
	ComputeMeter() *cu.ComputeMeter

	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
	HeapMax       int
	Syscalls      SyscallRegistry
	Tracer        TraceSink
	EnableTracing bool

	// Execution parameters
	Context      any // passed to syscalls
	MaxCU        int
	ComputeMeter *cu.ComputeMeter
	Input        []byte // mapped at VaddrInput

	// Debug
	ProgramId   solana.PublicKey
	TxSignature solana.Signature
}

VMOpts specifies virtual machine parameters.

type Verifier

type Verifier struct {
	Program *Program
	// contains filtered or unexported fields
}

func NewVerifier

func NewVerifier(p *Program) *Verifier

func (*Verifier) VerifyProgram

func (v *Verifier) VerifyProgram() 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