vm_instructions.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. package bpf
  5. import (
  6. "encoding/binary"
  7. "fmt"
  8. )
  9. func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
  10. return aluOpCommon(ins.Op, regA, ins.Val)
  11. }
  12. func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
  13. // Guard against division or modulus by zero by terminating
  14. // the program, as the OS BPF VM does
  15. if regX == 0 {
  16. switch ins.Op {
  17. case ALUOpDiv, ALUOpMod:
  18. return 0, false
  19. }
  20. }
  21. return aluOpCommon(ins.Op, regA, regX), true
  22. }
  23. func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
  24. switch op {
  25. case ALUOpAdd:
  26. return regA + value
  27. case ALUOpSub:
  28. return regA - value
  29. case ALUOpMul:
  30. return regA * value
  31. case ALUOpDiv:
  32. // Division by zero not permitted by NewVM and aluOpX checks
  33. return regA / value
  34. case ALUOpOr:
  35. return regA | value
  36. case ALUOpAnd:
  37. return regA & value
  38. case ALUOpShiftLeft:
  39. return regA << value
  40. case ALUOpShiftRight:
  41. return regA >> value
  42. case ALUOpMod:
  43. // Modulus by zero not permitted by NewVM and aluOpX checks
  44. return regA % value
  45. case ALUOpXor:
  46. return regA ^ value
  47. default:
  48. return regA
  49. }
  50. }
  51. func jumpIf(ins JumpIf, value uint32) int {
  52. var ok bool
  53. inV := uint32(ins.Val)
  54. switch ins.Cond {
  55. case JumpEqual:
  56. ok = value == inV
  57. case JumpNotEqual:
  58. ok = value != inV
  59. case JumpGreaterThan:
  60. ok = value > inV
  61. case JumpLessThan:
  62. ok = value < inV
  63. case JumpGreaterOrEqual:
  64. ok = value >= inV
  65. case JumpLessOrEqual:
  66. ok = value <= inV
  67. case JumpBitsSet:
  68. ok = (value & inV) != 0
  69. case JumpBitsNotSet:
  70. ok = (value & inV) == 0
  71. }
  72. if ok {
  73. return int(ins.SkipTrue)
  74. }
  75. return int(ins.SkipFalse)
  76. }
  77. func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
  78. offset := int(ins.Off)
  79. size := int(ins.Size)
  80. return loadCommon(in, offset, size)
  81. }
  82. func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
  83. switch ins.Dst {
  84. case RegA:
  85. regA = ins.Val
  86. case RegX:
  87. regX = ins.Val
  88. }
  89. return regA, regX
  90. }
  91. func loadExtension(ins LoadExtension, in []byte) uint32 {
  92. switch ins.Num {
  93. case ExtLen:
  94. return uint32(len(in))
  95. default:
  96. panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
  97. }
  98. }
  99. func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
  100. offset := int(ins.Off) + int(regX)
  101. size := int(ins.Size)
  102. return loadCommon(in, offset, size)
  103. }
  104. func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
  105. offset := int(ins.Off)
  106. if !inBounds(len(in), offset, 0) {
  107. return 0, false
  108. }
  109. // Mask off high 4 bits and multiply low 4 bits by 4
  110. return uint32(in[offset]&0x0f) * 4, true
  111. }
  112. func inBounds(inLen int, offset int, size int) bool {
  113. return offset+size <= inLen
  114. }
  115. func loadCommon(in []byte, offset int, size int) (uint32, bool) {
  116. if !inBounds(len(in), offset, size) {
  117. return 0, false
  118. }
  119. switch size {
  120. case 1:
  121. return uint32(in[offset]), true
  122. case 2:
  123. return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
  124. case 4:
  125. return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
  126. default:
  127. panic(fmt.Sprintf("invalid load size: %d", size))
  128. }
  129. }
  130. func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
  131. switch ins.Dst {
  132. case RegA:
  133. regA = regScratch[ins.N]
  134. case RegX:
  135. regX = regScratch[ins.N]
  136. }
  137. return regA, regX
  138. }
  139. func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
  140. switch ins.Src {
  141. case RegA:
  142. regScratch[ins.N] = regA
  143. case RegX:
  144. regScratch[ins.N] = regX
  145. }
  146. return regScratch
  147. }