|
|
// 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, value uint32) int { var ok bool inV := uint32(ins.Val)
switch ins.Cond { case JumpEqual: ok = value == inV case JumpNotEqual: ok = value != inV case JumpGreaterThan: ok = value > inV case JumpLessThan: ok = value < inV case JumpGreaterOrEqual: ok = value >= inV case JumpLessOrEqual: ok = value <= inV case JumpBitsSet: ok = (value & inV) != 0 case JumpBitsNotSet: ok = (value & inV) == 0 }
if ok { return int(ins.SkipTrue) }
return int(ins.SkipFalse) }
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) { offset := int(ins.Off) size := int(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 := int(ins.Size)
return loadCommon(in, offset, size) }
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) { offset := int(ins.Off)
if !inBounds(len(in), offset, 0) { 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 }
|