Extended Berkeley Packet Filter (eBPF) assembler and virtual machine
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.

249 lines
5.4KB

  1. package ebpf
  2. import "fmt"
  3. // Jump skips the following Skip instructions in the program.
  4. type Jump struct {
  5. Offset uint16
  6. }
  7. // Assemble implements the Instruction Assemble method.
  8. func (a Jump) Assemble() (RawInstruction, error) {
  9. return RawInstruction{
  10. Op: opClassJump | jumpOp,
  11. Offset: int16(a.Offset),
  12. }, nil
  13. }
  14. // String returns the instruction in assembler notation.
  15. func (a Jump) String() string {
  16. return fmt.Sprintf("ja +%d", a.Offset)
  17. }
  18. // JumpTest is a comparison operator used in conditional jumps.
  19. type JumpTest uint8
  20. // Supported operators for conditional jumps.
  21. const (
  22. JumpEqual JumpTest = iota // K == A
  23. JumpGreater // K > A
  24. JumpGreaterOrEqual // K >= A
  25. JumpSet // K & A
  26. JumpNotEqual // K != A
  27. JumpSignedGreater // K > A
  28. JumpSignedGreaterOrEqual // K >= A
  29. JumpLess // K < A
  30. JumpLessOrEqual // K <= A
  31. JumpSignedLess // K < A
  32. JumpSignedLessOrEqual // K <= A
  33. )
  34. func (cond JumpTest) Match(dst, src uint64) bool {
  35. switch cond {
  36. case JumpEqual:
  37. return dst == src
  38. case JumpGreater:
  39. return dst > src
  40. case JumpGreaterOrEqual:
  41. return dst >= src
  42. case JumpSet:
  43. return dst&src != 0
  44. case JumpNotEqual:
  45. return dst != src
  46. case JumpSignedGreater:
  47. return int64(dst) > int64(src)
  48. case JumpSignedGreaterOrEqual:
  49. return int64(dst) >= int64(src)
  50. case JumpLess:
  51. return dst < src
  52. case JumpLessOrEqual:
  53. return dst <= src
  54. case JumpSignedLess:
  55. return int64(dst) < int64(src)
  56. case JumpSignedLessOrEqual:
  57. return int64(dst) <= int64(src)
  58. default:
  59. return false
  60. }
  61. }
  62. func (cond JumpTest) String() string {
  63. switch cond {
  64. case JumpEqual:
  65. return "jeq"
  66. case JumpGreater:
  67. return "jgt"
  68. case JumpGreaterOrEqual:
  69. return "jge"
  70. case JumpSet:
  71. return "jset"
  72. case JumpNotEqual:
  73. return "jne"
  74. case JumpSignedGreater:
  75. return "jsgt"
  76. case JumpSignedGreaterOrEqual:
  77. return "jsge"
  78. case JumpLess:
  79. return "jlt"
  80. case JumpLessOrEqual:
  81. return "jle"
  82. case JumpSignedLess:
  83. return "jslt"
  84. case JumpSignedLessOrEqual:
  85. return "jsle"
  86. default:
  87. return ""
  88. }
  89. }
  90. func (cond JumpTest) CFormat() string {
  91. switch cond {
  92. case JumpEqual:
  93. return "%s == %s"
  94. case JumpGreater:
  95. return "%s > %s"
  96. case JumpGreaterOrEqual:
  97. return "%s >= %s"
  98. case JumpSet:
  99. return "%s & %s"
  100. case JumpNotEqual:
  101. return "%s != %s"
  102. case JumpSignedGreater:
  103. return "(int64_t)(%s) > (int64_t)(%s)"
  104. case JumpSignedGreaterOrEqual:
  105. return "(int64_t)(%s) >= (int64_t)(%s)"
  106. case JumpLess:
  107. return "%s < %s"
  108. case JumpLessOrEqual:
  109. return "%s <= %s"
  110. case JumpSignedLess:
  111. return "(int64_t)(%s) < (int64_t)(%s)"
  112. case JumpSignedLessOrEqual:
  113. return "(int64_t)(%s) <= (int64_t)(%s)"
  114. default:
  115. return ""
  116. }
  117. }
  118. func jumpOpToTest(op Opcode) JumpTest {
  119. switch op {
  120. case jumpOpEqual:
  121. return JumpEqual
  122. case jumpOpGreater:
  123. return JumpGreater
  124. case jumpOpGreaterOrEqual:
  125. return JumpGreaterOrEqual
  126. case jumpOpSet:
  127. return JumpSet
  128. case jumpOpNotEqual:
  129. return JumpNotEqual
  130. case jumpOpSignedGreater:
  131. return JumpSignedGreater
  132. case jumpOpSignedGreaterOrEqual:
  133. return JumpSignedGreaterOrEqual
  134. case jumpOpLess:
  135. return JumpLess
  136. case jumpOpLessOrEqual:
  137. return JumpLessOrEqual
  138. case jumpOpSignedLess:
  139. return JumpSignedLess
  140. case jumpOpSignedLessOrEqual:
  141. return JumpLessOrEqual
  142. default:
  143. return 0xff
  144. }
  145. }
  146. // JumpIf performs a conditional jump.
  147. type JumpIf struct {
  148. Cond JumpTest
  149. Dst Register
  150. Value uint32
  151. Offset uint16
  152. }
  153. func (a JumpIf) Assemble() (RawInstruction, error) {
  154. return jumpToRaw(a.Cond, true, a.Dst, a.Value, a.Offset)
  155. }
  156. func (a JumpIf) String() string {
  157. return fmt.Sprintf("%s %s, %d, +%d", a.Cond, a.Dst, a.Value, a.Offset)
  158. }
  159. type JumpIfX struct {
  160. Cond JumpTest
  161. Dst, Src Register
  162. Offset uint16
  163. }
  164. func (a JumpIfX) Assemble() (RawInstruction, error) {
  165. return jumpToRaw(a.Cond, false, a.Dst, uint32(a.Src), a.Offset)
  166. }
  167. func (a JumpIfX) String() string {
  168. return fmt.Sprintf("%s %s, %s, +%d", a.Cond, a.Dst, a.Src, a.Offset)
  169. }
  170. func jumpToRaw(test JumpTest, immediate bool, dst Register, value uint32, offset uint16) (RawInstruction, error) {
  171. var (
  172. cond Opcode
  173. )
  174. switch test {
  175. case JumpEqual:
  176. cond = jumpOpEqual
  177. case JumpGreater:
  178. cond = jumpOpGreater
  179. case JumpGreaterOrEqual:
  180. cond = jumpOpGreaterOrEqual
  181. case JumpNotEqual:
  182. cond = jumpOpNotEqual
  183. case JumpSignedGreater:
  184. cond = jumpOpSignedGreater
  185. case JumpSignedGreaterOrEqual:
  186. cond = jumpOpSignedGreaterOrEqual
  187. case JumpLess:
  188. cond = jumpOpLess
  189. case JumpLessOrEqual:
  190. cond = jumpOpLessOrEqual
  191. case JumpSignedLess:
  192. cond = jumpOpSignedLess
  193. case JumpSignedLessOrEqual:
  194. cond = jumpOpSignedLessOrEqual
  195. default:
  196. return RawInstruction{}, fmt.Errorf("ebpf: unknown JumpTest %v", test)
  197. }
  198. if immediate {
  199. return RawInstruction{
  200. Op: opClassJump | cond | jumpSourceImmediate,
  201. Dst: dst,
  202. Offset: int16(offset),
  203. Immediate: uint64(value),
  204. }, nil
  205. }
  206. return RawInstruction{
  207. Op: opClassJump | cond | jumpSourceX,
  208. Dst: dst,
  209. Src: Register(value & 0x0f),
  210. Offset: int16(offset),
  211. }, nil
  212. }
  213. // Exit the eBPF program and return the value of R0.
  214. type Exit struct{}
  215. func (a Exit) Assemble() (RawInstruction, error) {
  216. return RawInstruction{
  217. Op: opClassJump | jumpOpExit,
  218. }, nil
  219. }
  220. func (Exit) String() string {
  221. return "exit"
  222. }
  223. var (
  224. _ Instruction = (*Jump)(nil)
  225. _ Instruction = (*Exit)(nil)
  226. )