instructions.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 "fmt"
  6. // An Instruction is one instruction executed by the BPF virtual
  7. // machine.
  8. type Instruction interface {
  9. // Assemble assembles the Instruction into a RawInstruction.
  10. Assemble() (RawInstruction, error)
  11. }
  12. // A RawInstruction is a raw BPF virtual machine instruction.
  13. type RawInstruction struct {
  14. // Operation to execute.
  15. Op uint16
  16. // For conditional jump instructions, the number of instructions
  17. // to skip if the condition is true/false.
  18. Jt uint8
  19. Jf uint8
  20. // Constant parameter. The meaning depends on the Op.
  21. K uint32
  22. }
  23. // Assemble implements the Instruction Assemble method.
  24. func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
  25. // Disassemble parses ri into an Instruction and returns it. If ri is
  26. // not recognized by this package, ri itself is returned.
  27. func (ri RawInstruction) Disassemble() Instruction {
  28. switch ri.Op & opMaskCls {
  29. case opClsLoadA, opClsLoadX:
  30. reg := Register(ri.Op & opMaskLoadDest)
  31. sz := 0
  32. switch ri.Op & opMaskLoadWidth {
  33. case opLoadWidth4:
  34. sz = 4
  35. case opLoadWidth2:
  36. sz = 2
  37. case opLoadWidth1:
  38. sz = 1
  39. default:
  40. return ri
  41. }
  42. switch ri.Op & opMaskLoadMode {
  43. case opAddrModeImmediate:
  44. if sz != 4 {
  45. return ri
  46. }
  47. return LoadConstant{Dst: reg, Val: ri.K}
  48. case opAddrModeScratch:
  49. if sz != 4 || ri.K > 15 {
  50. return ri
  51. }
  52. return LoadScratch{Dst: reg, N: int(ri.K)}
  53. case opAddrModeAbsolute:
  54. return LoadAbsolute{Size: sz, Off: ri.K}
  55. case opAddrModeIndirect:
  56. return LoadIndirect{Size: sz, Off: ri.K}
  57. case opAddrModePacketLen:
  58. if sz != 4 {
  59. return ri
  60. }
  61. return LoadExtension{Num: ExtLen}
  62. case opAddrModeMemShift:
  63. return LoadMemShift{Off: ri.K}
  64. default:
  65. return ri
  66. }
  67. case opClsStoreA:
  68. if ri.Op != opClsStoreA || ri.K > 15 {
  69. return ri
  70. }
  71. return StoreScratch{Src: RegA, N: int(ri.K)}
  72. case opClsStoreX:
  73. if ri.Op != opClsStoreX || ri.K > 15 {
  74. return ri
  75. }
  76. return StoreScratch{Src: RegX, N: int(ri.K)}
  77. case opClsALU:
  78. switch op := ALUOp(ri.Op & opMaskOperator); op {
  79. case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
  80. if ri.Op&opMaskOperandSrc != 0 {
  81. return ALUOpX{Op: op}
  82. }
  83. return ALUOpConstant{Op: op, Val: ri.K}
  84. case aluOpNeg:
  85. return NegateA{}
  86. default:
  87. return ri
  88. }
  89. case opClsJump:
  90. if ri.Op&opMaskJumpConst != opClsJump {
  91. return ri
  92. }
  93. switch ri.Op & opMaskJumpCond {
  94. case opJumpAlways:
  95. return Jump{Skip: ri.K}
  96. case opJumpEqual:
  97. return JumpIf{
  98. Cond: JumpEqual,
  99. Val: ri.K,
  100. SkipTrue: ri.Jt,
  101. SkipFalse: ri.Jf,
  102. }
  103. case opJumpGT:
  104. return JumpIf{
  105. Cond: JumpGreaterThan,
  106. Val: ri.K,
  107. SkipTrue: ri.Jt,
  108. SkipFalse: ri.Jf,
  109. }
  110. case opJumpGE:
  111. return JumpIf{
  112. Cond: JumpGreaterOrEqual,
  113. Val: ri.K,
  114. SkipTrue: ri.Jt,
  115. SkipFalse: ri.Jf,
  116. }
  117. case opJumpSet:
  118. return JumpIf{
  119. Cond: JumpBitsSet,
  120. Val: ri.K,
  121. SkipTrue: ri.Jt,
  122. SkipFalse: ri.Jf,
  123. }
  124. default:
  125. return ri
  126. }
  127. case opClsReturn:
  128. switch ri.Op {
  129. case opClsReturn | opRetSrcA:
  130. return RetA{}
  131. case opClsReturn | opRetSrcConstant:
  132. return RetConstant{Val: ri.K}
  133. default:
  134. return ri
  135. }
  136. case opClsMisc:
  137. switch ri.Op {
  138. case opClsMisc | opMiscTAX:
  139. return TAX{}
  140. case opClsMisc | opMiscTXA:
  141. return TXA{}
  142. default:
  143. return ri
  144. }
  145. default:
  146. panic("unreachable") // switch is exhaustive on the bit pattern
  147. }
  148. }
  149. // LoadConstant loads Val into register Dst.
  150. type LoadConstant struct {
  151. Dst Register
  152. Val uint32
  153. }
  154. // Assemble implements the Instruction Assemble method.
  155. func (a LoadConstant) Assemble() (RawInstruction, error) {
  156. return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
  157. }
  158. // LoadScratch loads scratch[N] into register Dst.
  159. type LoadScratch struct {
  160. Dst Register
  161. N int // 0-15
  162. }
  163. // Assemble implements the Instruction Assemble method.
  164. func (a LoadScratch) Assemble() (RawInstruction, error) {
  165. if a.N < 0 || a.N > 15 {
  166. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  167. }
  168. return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
  169. }
  170. // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
  171. // register A.
  172. type LoadAbsolute struct {
  173. Off uint32
  174. Size int // 1, 2 or 4
  175. }
  176. // Assemble implements the Instruction Assemble method.
  177. func (a LoadAbsolute) Assemble() (RawInstruction, error) {
  178. return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
  179. }
  180. // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
  181. // into register A.
  182. type LoadIndirect struct {
  183. Off uint32
  184. Size int // 1, 2 or 4
  185. }
  186. // Assemble implements the Instruction Assemble method.
  187. func (a LoadIndirect) Assemble() (RawInstruction, error) {
  188. return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
  189. }
  190. // LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
  191. // by 4 and stores the result in register X.
  192. //
  193. // This instruction is mainly useful to load into X the length of an
  194. // IPv4 packet header in a single instruction, rather than have to do
  195. // the arithmetic on the header's first byte by hand.
  196. type LoadMemShift struct {
  197. Off uint32
  198. }
  199. // Assemble implements the Instruction Assemble method.
  200. func (a LoadMemShift) Assemble() (RawInstruction, error) {
  201. return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
  202. }
  203. // LoadExtension invokes a linux-specific extension and stores the
  204. // result in register A.
  205. type LoadExtension struct {
  206. Num Extension
  207. }
  208. // Assemble implements the Instruction Assemble method.
  209. func (a LoadExtension) Assemble() (RawInstruction, error) {
  210. if a.Num == ExtLen {
  211. return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
  212. }
  213. return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num))
  214. }
  215. // StoreScratch stores register Src into scratch[N].
  216. type StoreScratch struct {
  217. Src Register
  218. N int // 0-15
  219. }
  220. // Assemble implements the Instruction Assemble method.
  221. func (a StoreScratch) Assemble() (RawInstruction, error) {
  222. if a.N < 0 || a.N > 15 {
  223. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  224. }
  225. var op uint16
  226. switch a.Src {
  227. case RegA:
  228. op = opClsStoreA
  229. case RegX:
  230. op = opClsStoreX
  231. default:
  232. return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
  233. }
  234. return RawInstruction{
  235. Op: op,
  236. K: uint32(a.N),
  237. }, nil
  238. }
  239. // ALUOpConstant executes A = A <Op> Val.
  240. type ALUOpConstant struct {
  241. Op ALUOp
  242. Val uint32
  243. }
  244. // Assemble implements the Instruction Assemble method.
  245. func (a ALUOpConstant) Assemble() (RawInstruction, error) {
  246. return RawInstruction{
  247. Op: opClsALU | opALUSrcConstant | uint16(a.Op),
  248. K: a.Val,
  249. }, nil
  250. }
  251. // ALUOpX executes A = A <Op> X
  252. type ALUOpX struct {
  253. Op ALUOp
  254. }
  255. // Assemble implements the Instruction Assemble method.
  256. func (a ALUOpX) Assemble() (RawInstruction, error) {
  257. return RawInstruction{
  258. Op: opClsALU | opALUSrcX | uint16(a.Op),
  259. }, nil
  260. }
  261. // NegateA executes A = -A.
  262. type NegateA struct{}
  263. // Assemble implements the Instruction Assemble method.
  264. func (a NegateA) Assemble() (RawInstruction, error) {
  265. return RawInstruction{
  266. Op: opClsALU | uint16(aluOpNeg),
  267. }, nil
  268. }
  269. // Jump skips the following Skip instructions in the program.
  270. type Jump struct {
  271. Skip uint32
  272. }
  273. // Assemble implements the Instruction Assemble method.
  274. func (a Jump) Assemble() (RawInstruction, error) {
  275. return RawInstruction{
  276. Op: opClsJump | opJumpAlways,
  277. K: a.Skip,
  278. }, nil
  279. }
  280. // JumpIf skips the following Skip instructions in the program if A
  281. // <Cond> Val is true.
  282. type JumpIf struct {
  283. Cond JumpTest
  284. Val uint32
  285. SkipTrue uint8
  286. SkipFalse uint8
  287. }
  288. // Assemble implements the Instruction Assemble method.
  289. func (a JumpIf) Assemble() (RawInstruction, error) {
  290. var (
  291. cond uint16
  292. flip bool
  293. )
  294. switch a.Cond {
  295. case JumpEqual:
  296. cond = opJumpEqual
  297. case JumpNotEqual:
  298. cond, flip = opJumpEqual, true
  299. case JumpGreaterThan:
  300. cond = opJumpGT
  301. case JumpLessThan:
  302. cond, flip = opJumpGE, true
  303. case JumpGreaterOrEqual:
  304. cond = opJumpGE
  305. case JumpLessOrEqual:
  306. cond, flip = opJumpGT, true
  307. case JumpBitsSet:
  308. cond = opJumpSet
  309. case JumpBitsNotSet:
  310. cond, flip = opJumpSet, true
  311. default:
  312. return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
  313. }
  314. jt, jf := a.SkipTrue, a.SkipFalse
  315. if flip {
  316. jt, jf = jf, jt
  317. }
  318. return RawInstruction{
  319. Op: opClsJump | cond,
  320. Jt: jt,
  321. Jf: jf,
  322. K: a.Val,
  323. }, nil
  324. }
  325. // RetA exits the BPF program, returning the value of register A.
  326. type RetA struct{}
  327. // Assemble implements the Instruction Assemble method.
  328. func (a RetA) Assemble() (RawInstruction, error) {
  329. return RawInstruction{
  330. Op: opClsReturn | opRetSrcA,
  331. }, nil
  332. }
  333. // RetConstant exits the BPF program, returning a constant value.
  334. type RetConstant struct {
  335. Val uint32
  336. }
  337. // Assemble implements the Instruction Assemble method.
  338. func (a RetConstant) Assemble() (RawInstruction, error) {
  339. return RawInstruction{
  340. Op: opClsReturn | opRetSrcConstant,
  341. K: a.Val,
  342. }, nil
  343. }
  344. // TXA copies the value of register X to register A.
  345. type TXA struct{}
  346. // Assemble implements the Instruction Assemble method.
  347. func (a TXA) Assemble() (RawInstruction, error) {
  348. return RawInstruction{
  349. Op: opClsMisc | opMiscTXA,
  350. }, nil
  351. }
  352. // TAX copies the value of register A to register X.
  353. type TAX struct{}
  354. // Assemble implements the Instruction Assemble method.
  355. func (a TAX) Assemble() (RawInstruction, error) {
  356. return RawInstruction{
  357. Op: opClsMisc | opMiscTAX,
  358. }, nil
  359. }
  360. func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
  361. var (
  362. cls uint16
  363. sz uint16
  364. )
  365. switch dst {
  366. case RegA:
  367. cls = opClsLoadA
  368. case RegX:
  369. cls = opClsLoadX
  370. default:
  371. return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
  372. }
  373. switch loadSize {
  374. case 1:
  375. sz = opLoadWidth1
  376. case 2:
  377. sz = opLoadWidth2
  378. case 4:
  379. sz = opLoadWidth4
  380. default:
  381. return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
  382. }
  383. return RawInstruction{
  384. Op: cls | sz | mode,
  385. K: k,
  386. }, nil
  387. }