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
5package bpf
6
7import (
8	"encoding/binary"
9	"fmt"
10)
11
12func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
13	return aluOpCommon(ins.Op, regA, ins.Val)
14}
15
16func 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
29func 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
58func jumpIf(ins JumpIf, regA uint32) int {
59	return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
60}
61
62func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
63	return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
64}
65
66func 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
95func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
96	offset := int(ins.Off)
97	size := int(ins.Size)
98
99	return loadCommon(in, offset, size)
100}
101
102func 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
113func 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
122func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
123	offset := int(ins.Off) + int(regX)
124	size := int(ins.Size)
125
126	return loadCommon(in, offset, size)
127}
128
129func 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
141func inBounds(inLen int, offset int, size int) bool {
142	return offset+size <= inLen
143}
144
145func 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
162func 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
173func 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}
183