gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }