golang.org/x/net@v0.25.1-0.20240516223405-c87a5b62e243/bpf/vm_instructions.go (about)

     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  }