183 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// 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 bpf
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/binary"
 | 
						|
	"fmt"
 | 
						|
)
 | 
						|
 | 
						|
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
 | 
						|
	return aluOpCommon(ins.Op, regA, ins.Val)
 | 
						|
}
 | 
						|
 | 
						|
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
 | 
						|
	// Guard against division or modulus by zero by terminating
 | 
						|
	// the program, as the OS BPF VM does
 | 
						|
	if regX == 0 {
 | 
						|
		switch ins.Op {
 | 
						|
		case ALUOpDiv, ALUOpMod:
 | 
						|
			return 0, false
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return aluOpCommon(ins.Op, regA, regX), true
 | 
						|
}
 | 
						|
 | 
						|
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
 | 
						|
	switch op {
 | 
						|
	case ALUOpAdd:
 | 
						|
		return regA + value
 | 
						|
	case ALUOpSub:
 | 
						|
		return regA - value
 | 
						|
	case ALUOpMul:
 | 
						|
		return regA * value
 | 
						|
	case ALUOpDiv:
 | 
						|
		// Division by zero not permitted by NewVM and aluOpX checks
 | 
						|
		return regA / value
 | 
						|
	case ALUOpOr:
 | 
						|
		return regA | value
 | 
						|
	case ALUOpAnd:
 | 
						|
		return regA & value
 | 
						|
	case ALUOpShiftLeft:
 | 
						|
		return regA << value
 | 
						|
	case ALUOpShiftRight:
 | 
						|
		return regA >> value
 | 
						|
	case ALUOpMod:
 | 
						|
		// Modulus by zero not permitted by NewVM and aluOpX checks
 | 
						|
		return regA % value
 | 
						|
	case ALUOpXor:
 | 
						|
		return regA ^ value
 | 
						|
	default:
 | 
						|
		return regA
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func jumpIf(ins JumpIf, regA uint32) int {
 | 
						|
	return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
 | 
						|
}
 | 
						|
 | 
						|
func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
 | 
						|
	return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
 | 
						|
}
 | 
						|
 | 
						|
func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
 | 
						|
	var ok bool
 | 
						|
 | 
						|
	switch cond {
 | 
						|
	case JumpEqual:
 | 
						|
		ok = regA == value
 | 
						|
	case JumpNotEqual:
 | 
						|
		ok = regA != value
 | 
						|
	case JumpGreaterThan:
 | 
						|
		ok = regA > value
 | 
						|
	case JumpLessThan:
 | 
						|
		ok = regA < value
 | 
						|
	case JumpGreaterOrEqual:
 | 
						|
		ok = regA >= value
 | 
						|
	case JumpLessOrEqual:
 | 
						|
		ok = regA <= value
 | 
						|
	case JumpBitsSet:
 | 
						|
		ok = (regA & value) != 0
 | 
						|
	case JumpBitsNotSet:
 | 
						|
		ok = (regA & value) == 0
 | 
						|
	}
 | 
						|
 | 
						|
	if ok {
 | 
						|
		return int(skipTrue)
 | 
						|
	}
 | 
						|
 | 
						|
	return int(skipFalse)
 | 
						|
}
 | 
						|
 | 
						|
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
 | 
						|
	offset := int(ins.Off)
 | 
						|
	size := ins.Size
 | 
						|
 | 
						|
	return loadCommon(in, offset, size)
 | 
						|
}
 | 
						|
 | 
						|
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
 | 
						|
	switch ins.Dst {
 | 
						|
	case RegA:
 | 
						|
		regA = ins.Val
 | 
						|
	case RegX:
 | 
						|
		regX = ins.Val
 | 
						|
	}
 | 
						|
 | 
						|
	return regA, regX
 | 
						|
}
 | 
						|
 | 
						|
func loadExtension(ins LoadExtension, in []byte) uint32 {
 | 
						|
	switch ins.Num {
 | 
						|
	case ExtLen:
 | 
						|
		return uint32(len(in))
 | 
						|
	default:
 | 
						|
		panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
 | 
						|
	offset := int(ins.Off) + int(regX)
 | 
						|
	size := ins.Size
 | 
						|
 | 
						|
	return loadCommon(in, offset, size)
 | 
						|
}
 | 
						|
 | 
						|
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
 | 
						|
	offset := int(ins.Off)
 | 
						|
 | 
						|
	// Size of LoadMemShift is always 1 byte
 | 
						|
	if !inBounds(len(in), offset, 1) {
 | 
						|
		return 0, false
 | 
						|
	}
 | 
						|
 | 
						|
	// Mask off high 4 bits and multiply low 4 bits by 4
 | 
						|
	return uint32(in[offset]&0x0f) * 4, true
 | 
						|
}
 | 
						|
 | 
						|
func inBounds(inLen int, offset int, size int) bool {
 | 
						|
	return offset+size <= inLen
 | 
						|
}
 | 
						|
 | 
						|
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
 | 
						|
	if !inBounds(len(in), offset, size) {
 | 
						|
		return 0, false
 | 
						|
	}
 | 
						|
 | 
						|
	switch size {
 | 
						|
	case 1:
 | 
						|
		return uint32(in[offset]), true
 | 
						|
	case 2:
 | 
						|
		return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
 | 
						|
	case 4:
 | 
						|
		return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
 | 
						|
	default:
 | 
						|
		panic(fmt.Sprintf("invalid load size: %d", size))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
 | 
						|
	switch ins.Dst {
 | 
						|
	case RegA:
 | 
						|
		regA = regScratch[ins.N]
 | 
						|
	case RegX:
 | 
						|
		regX = regScratch[ins.N]
 | 
						|
	}
 | 
						|
 | 
						|
	return regA, regX
 | 
						|
}
 | 
						|
 | 
						|
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
 | 
						|
	switch ins.Src {
 | 
						|
	case RegA:
 | 
						|
		regScratch[ins.N] = regA
 | 
						|
	case RegX:
 | 
						|
		regScratch[ins.N] = regX
 | 
						|
	}
 | 
						|
 | 
						|
	return regScratch
 | 
						|
}
 |