You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

182 lines
3.8 KiB

  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, regA uint32) int {
  52. return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
  53. }
  54. func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
  55. return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
  56. }
  57. func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
  58. var ok bool
  59. switch cond {
  60. case JumpEqual:
  61. ok = regA == value
  62. case JumpNotEqual:
  63. ok = regA != value
  64. case JumpGreaterThan:
  65. ok = regA > value
  66. case JumpLessThan:
  67. ok = regA < value
  68. case JumpGreaterOrEqual:
  69. ok = regA >= value
  70. case JumpLessOrEqual:
  71. ok = regA <= value
  72. case JumpBitsSet:
  73. ok = (regA & value) != 0
  74. case JumpBitsNotSet:
  75. ok = (regA & value) == 0
  76. }
  77. if ok {
  78. return int(skipTrue)
  79. }
  80. return int(skipFalse)
  81. }
  82. func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
  83. offset := int(ins.Off)
  84. size := int(ins.Size)
  85. return loadCommon(in, offset, size)
  86. }
  87. func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
  88. switch ins.Dst {
  89. case RegA:
  90. regA = ins.Val
  91. case RegX:
  92. regX = ins.Val
  93. }
  94. return regA, regX
  95. }
  96. func loadExtension(ins LoadExtension, in []byte) uint32 {
  97. switch ins.Num {
  98. case ExtLen:
  99. return uint32(len(in))
  100. default:
  101. panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
  102. }
  103. }
  104. func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
  105. offset := int(ins.Off) + int(regX)
  106. size := int(ins.Size)
  107. return loadCommon(in, offset, size)
  108. }
  109. func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
  110. offset := int(ins.Off)
  111. if !inBounds(len(in), offset, 0) {
  112. return 0, false
  113. }
  114. // Mask off high 4 bits and multiply low 4 bits by 4
  115. return uint32(in[offset]&0x0f) * 4, true
  116. }
  117. func inBounds(inLen int, offset int, size int) bool {
  118. return offset+size <= inLen
  119. }
  120. func loadCommon(in []byte, offset int, size int) (uint32, bool) {
  121. if !inBounds(len(in), offset, size) {
  122. return 0, false
  123. }
  124. switch size {
  125. case 1:
  126. return uint32(in[offset]), true
  127. case 2:
  128. return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
  129. case 4:
  130. return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
  131. default:
  132. panic(fmt.Sprintf("invalid load size: %d", size))
  133. }
  134. }
  135. func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
  136. switch ins.Dst {
  137. case RegA:
  138. regA = regScratch[ins.N]
  139. case RegX:
  140. regX = regScratch[ins.N]
  141. }
  142. return regA, regX
  143. }
  144. func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
  145. switch ins.Src {
  146. case RegA:
  147. regScratch[ins.N] = regA
  148. case RegX:
  149. regScratch[ins.N] = regX
  150. }
  151. return regScratch
  152. }