// Copyright 2016 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package bpfimport ()// A VM is an emulated BPF virtual machine.typeVMstruct { filter []Instruction}// NewVM returns a new VM using the input BPF program.func ( []Instruction) (*VM, error) {iflen() == 0 {returnnil, errors.New("one or more Instructions must be specified") }for , := range { := len() - ( + 1)switch ins := .(type) {// Check for out-of-bounds jumps in instructionscaseJump:if <= int(.Skip) {returnnil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", .Skip) }caseJumpIf:if <= int(.SkipTrue) {returnnil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", .SkipTrue) }if <= int(.SkipFalse) {returnnil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", .SkipFalse) }caseJumpIfX:if <= int(.SkipTrue) {returnnil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", .SkipTrue) }if <= int(.SkipFalse) {returnnil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", .SkipFalse) }// Check for division or modulus by zerocaseALUOpConstant:if .Val != 0 {break }switch .Op {caseALUOpDiv, ALUOpMod:returnnil, errors.New("cannot divide by zero using ALUOpConstant") }// Check for unknown extensionscaseLoadExtension:switch .Num {caseExtLen:default:returnnil, fmt.Errorf("extension %d not implemented", .Num) } } }// Make sure last instruction is a return instructionswitch [len()-1].(type) {caseRetA, RetConstant:default:returnnil, errors.New("BPF program must end with RetA or RetConstant") }// Though our VM works using disassembled instructions, we // attempt to assemble the input filter anyway to ensure it is compatible // with an operating system VM. , := Assemble()return &VM{filter: , }, }// Run runs the VM's BPF program against the input bytes.// Run returns the number of bytes accepted by the BPF program, and any errors// which occurred while processing the program.func ( *VM) ( []byte) (int, error) {var (// Registers of the virtual machineuint32uint32 [16]uint32// OK is true if the program should continue processing the next // instruction, or false if not, causing the loop to break = true )// TODO(mdlayher): implement: // - NegateA: // - would require a change from uint32 registers to int32 // registers// TODO(mdlayher): add interop tests that check signedness of ALU // operations against kernel implementation, and make sure Go // implementation matches behaviorfor := 0; < len(.filter) && ; ++ { := .filter[]switch ins := .(type) {caseALUOpConstant: = aluOpConstant(, )caseALUOpX: , = aluOpX(, , )caseJump: += int(.Skip)caseJumpIf: := jumpIf(, ) += caseJumpIfX: := jumpIfX(, , ) += caseLoadAbsolute: , = loadAbsolute(, )caseLoadConstant: , = loadConstant(, , )caseLoadExtension: = loadExtension(, )caseLoadIndirect: , = loadIndirect(, , )caseLoadMemShift: , = loadMemShift(, )caseLoadScratch: , = loadScratch(, , , )caseRetA:returnint(), nilcaseRetConstant:returnint(.Val), nilcaseStoreScratch: = storeScratch(, , , )caseTAX: = caseTXA: = default:return0, fmt.Errorf("unknown Instruction at index %d: %T", , ) } }return0, nil}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.