vm_instructions.go (3964B)
1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package bpf 6 7 import ( 8 "encoding/binary" 9 "fmt" 10 ) 11 12 func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 { 13 return aluOpCommon(ins.Op, regA, ins.Val) 14 } 15 16 func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) { 17 // Guard against division or modulus by zero by terminating 18 // the program, as the OS BPF VM does 19 if regX == 0 { 20 switch ins.Op { 21 case ALUOpDiv, ALUOpMod: 22 return 0, false 23 } 24 } 25 26 return aluOpCommon(ins.Op, regA, regX), true 27 } 28 29 func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 { 30 switch op { 31 case ALUOpAdd: 32 return regA + value 33 case ALUOpSub: 34 return regA - value 35 case ALUOpMul: 36 return regA * value 37 case ALUOpDiv: 38 // Division by zero not permitted by NewVM and aluOpX checks 39 return regA / value 40 case ALUOpOr: 41 return regA | value 42 case ALUOpAnd: 43 return regA & value 44 case ALUOpShiftLeft: 45 return regA << value 46 case ALUOpShiftRight: 47 return regA >> value 48 case ALUOpMod: 49 // Modulus by zero not permitted by NewVM and aluOpX checks 50 return regA % value 51 case ALUOpXor: 52 return regA ^ value 53 default: 54 return regA 55 } 56 } 57 58 func jumpIf(ins JumpIf, regA uint32) int { 59 return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val) 60 } 61 62 func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int { 63 return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX) 64 } 65 66 func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int { 67 var ok bool 68 69 switch cond { 70 case JumpEqual: 71 ok = regA == value 72 case JumpNotEqual: 73 ok = regA != value 74 case JumpGreaterThan: 75 ok = regA > value 76 case JumpLessThan: 77 ok = regA < value 78 case JumpGreaterOrEqual: 79 ok = regA >= value 80 case JumpLessOrEqual: 81 ok = regA <= value 82 case JumpBitsSet: 83 ok = (regA & value) != 0 84 case JumpBitsNotSet: 85 ok = (regA & value) == 0 86 } 87 88 if ok { 89 return int(skipTrue) 90 } 91 92 return int(skipFalse) 93 } 94 95 func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) { 96 offset := int(ins.Off) 97 size := ins.Size 98 99 return loadCommon(in, offset, size) 100 } 101 102 func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) { 103 switch ins.Dst { 104 case RegA: 105 regA = ins.Val 106 case RegX: 107 regX = ins.Val 108 } 109 110 return regA, regX 111 } 112 113 func loadExtension(ins LoadExtension, in []byte) uint32 { 114 switch ins.Num { 115 case ExtLen: 116 return uint32(len(in)) 117 default: 118 panic(fmt.Sprintf("unimplemented extension: %d", ins.Num)) 119 } 120 } 121 122 func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) { 123 offset := int(ins.Off) + int(regX) 124 size := ins.Size 125 126 return loadCommon(in, offset, size) 127 } 128 129 func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) { 130 offset := int(ins.Off) 131 132 // Size of LoadMemShift is always 1 byte 133 if !inBounds(len(in), offset, 1) { 134 return 0, false 135 } 136 137 // Mask off high 4 bits and multiply low 4 bits by 4 138 return uint32(in[offset]&0x0f) * 4, true 139 } 140 141 func inBounds(inLen int, offset int, size int) bool { 142 return offset+size <= inLen 143 } 144 145 func loadCommon(in []byte, offset int, size int) (uint32, bool) { 146 if !inBounds(len(in), offset, size) { 147 return 0, false 148 } 149 150 switch size { 151 case 1: 152 return uint32(in[offset]), true 153 case 2: 154 return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true 155 case 4: 156 return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true 157 default: 158 panic(fmt.Sprintf("invalid load size: %d", size)) 159 } 160 } 161 162 func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) { 163 switch ins.Dst { 164 case RegA: 165 regA = regScratch[ins.N] 166 case RegX: 167 regX = regScratch[ins.N] 168 } 169 170 return regA, regX 171 } 172 173 func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 { 174 switch ins.Src { 175 case RegA: 176 regScratch[ins.N] = regA 177 case RegX: 178 regScratch[ins.N] = regX 179 } 180 181 return regScratch 182 }