instructions.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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 opAddrModeIPv4HeaderLen:
  63. return LoadIPv4HeaderLen{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. // LoadIPv4HeaderLen loads into register X the length of the IPv4
  191. // header whose first byte is packet[Off].
  192. type LoadIPv4HeaderLen struct {
  193. Off uint32
  194. }
  195. // Assemble implements the Instruction Assemble method.
  196. func (a LoadIPv4HeaderLen) Assemble() (RawInstruction, error) {
  197. return assembleLoad(RegX, 1, opAddrModeIPv4HeaderLen, a.Off)
  198. }
  199. // LoadExtension invokes a linux-specific extension and stores the
  200. // result in register A.
  201. type LoadExtension struct {
  202. Num Extension
  203. }
  204. // Assemble implements the Instruction Assemble method.
  205. func (a LoadExtension) Assemble() (RawInstruction, error) {
  206. if a.Num == ExtLen {
  207. return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
  208. }
  209. return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num))
  210. }
  211. // StoreScratch stores register Src into scratch[N].
  212. type StoreScratch struct {
  213. Src Register
  214. N int // 0-15
  215. }
  216. // Assemble implements the Instruction Assemble method.
  217. func (a StoreScratch) Assemble() (RawInstruction, error) {
  218. if a.N < 0 || a.N > 15 {
  219. return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
  220. }
  221. var op uint16
  222. switch a.Src {
  223. case RegA:
  224. op = opClsStoreA
  225. case RegX:
  226. op = opClsStoreX
  227. default:
  228. return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
  229. }
  230. return RawInstruction{
  231. Op: op,
  232. K: uint32(a.N),
  233. }, nil
  234. }
  235. // ALUOpConstant executes A = A <Op> Val.
  236. type ALUOpConstant struct {
  237. Op ALUOp
  238. Val uint32
  239. }
  240. // Assemble implements the Instruction Assemble method.
  241. func (a ALUOpConstant) Assemble() (RawInstruction, error) {
  242. return RawInstruction{
  243. Op: opClsALU | opALUSrcConstant | uint16(a.Op),
  244. K: a.Val,
  245. }, nil
  246. }
  247. // ALUOpX executes A = A <Op> X
  248. type ALUOpX struct {
  249. Op ALUOp
  250. }
  251. // Assemble implements the Instruction Assemble method.
  252. func (a ALUOpX) Assemble() (RawInstruction, error) {
  253. return RawInstruction{
  254. Op: opClsALU | opALUSrcX | uint16(a.Op),
  255. }, nil
  256. }
  257. // NegateA executes A = -A.
  258. type NegateA struct{}
  259. // Assemble implements the Instruction Assemble method.
  260. func (a NegateA) Assemble() (RawInstruction, error) {
  261. return RawInstruction{
  262. Op: opClsALU | uint16(aluOpNeg),
  263. }, nil
  264. }
  265. // Jump skips the following Skip instructions in the program.
  266. type Jump struct {
  267. Skip uint32
  268. }
  269. // Assemble implements the Instruction Assemble method.
  270. func (a Jump) Assemble() (RawInstruction, error) {
  271. return RawInstruction{
  272. Op: opClsJump | opJumpAlways,
  273. K: a.Skip,
  274. }, nil
  275. }
  276. // JumpIf skips the following Skip instructions in the program if A
  277. // <Cond> Val is true.
  278. type JumpIf struct {
  279. Cond JumpTest
  280. Val uint32
  281. SkipTrue uint8
  282. SkipFalse uint8
  283. }
  284. // Assemble implements the Instruction Assemble method.
  285. func (a JumpIf) Assemble() (RawInstruction, error) {
  286. var (
  287. cond uint16
  288. flip bool
  289. )
  290. switch a.Cond {
  291. case JumpEqual:
  292. cond = opJumpEqual
  293. case JumpNotEqual:
  294. cond, flip = opJumpEqual, true
  295. case JumpGreaterThan:
  296. cond = opJumpGT
  297. case JumpLessThan:
  298. cond, flip = opJumpGE, true
  299. case JumpGreaterOrEqual:
  300. cond = opJumpGE
  301. case JumpLessOrEqual:
  302. cond, flip = opJumpGT, true
  303. case JumpBitsSet:
  304. cond = opJumpSet
  305. case JumpBitsNotSet:
  306. cond, flip = opJumpSet, true
  307. default:
  308. return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
  309. }
  310. jt, jf := a.SkipTrue, a.SkipFalse
  311. if flip {
  312. jt, jf = jf, jt
  313. }
  314. return RawInstruction{
  315. Op: opClsJump | cond,
  316. Jt: jt,
  317. Jf: jf,
  318. K: a.Val,
  319. }, nil
  320. }
  321. // RetA exits the BPF program, returning the value of register A.
  322. type RetA struct{}
  323. // Assemble implements the Instruction Assemble method.
  324. func (a RetA) Assemble() (RawInstruction, error) {
  325. return RawInstruction{
  326. Op: opClsReturn | opRetSrcA,
  327. }, nil
  328. }
  329. // RetConstant exits the BPF program, returning a constant value.
  330. type RetConstant struct {
  331. Val uint32
  332. }
  333. // Assemble implements the Instruction Assemble method.
  334. func (a RetConstant) Assemble() (RawInstruction, error) {
  335. return RawInstruction{
  336. Op: opClsReturn | opRetSrcConstant,
  337. K: a.Val,
  338. }, nil
  339. }
  340. // TXA copies the value of register X to register A.
  341. type TXA struct{}
  342. // Assemble implements the Instruction Assemble method.
  343. func (a TXA) Assemble() (RawInstruction, error) {
  344. return RawInstruction{
  345. Op: opClsMisc | opMiscTXA,
  346. }, nil
  347. }
  348. // TAX copies the value of register A to register X.
  349. type TAX struct{}
  350. // Assemble implements the Instruction Assemble method.
  351. func (a TAX) Assemble() (RawInstruction, error) {
  352. return RawInstruction{
  353. Op: opClsMisc | opMiscTAX,
  354. }, nil
  355. }
  356. func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
  357. var (
  358. cls uint16
  359. sz uint16
  360. )
  361. switch dst {
  362. case RegA:
  363. cls = opClsLoadA
  364. case RegX:
  365. cls = opClsLoadX
  366. default:
  367. return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
  368. }
  369. switch loadSize {
  370. case 1:
  371. sz = opLoadWidth1
  372. case 2:
  373. sz = opLoadWidth2
  374. case 4:
  375. sz = opLoadWidth4
  376. default:
  377. return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
  378. }
  379. return RawInstruction{
  380. Op: cls | sz | mode,
  381. K: k,
  382. }, nil
  383. }