instructions.go 10 KB

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