1 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 2 // Copyright 2017 Alex Dukhno <alex.dukhno@icloud.com> 3 4 //! Module provides API to create eBPF programs by Rust programming language 5 6 use alloc::{vec, vec::Vec}; 7 8 use crate::ebpf::*; 9 10 /// Represents single eBPF instruction 11 pub trait Instruction: Sized { 12 /// returns instruction opt code 13 fn opt_code_byte(&self) -> u8; 14 15 /// returns destination register 16 fn get_dst(&self) -> u8 { 17 self.get_insn().dst 18 } 19 20 /// returns source register 21 fn get_src(&self) -> u8 { 22 self.get_insn().src 23 } 24 25 /// returns offset bytes 26 fn get_off(&self) -> i16 { 27 self.get_insn().off 28 } 29 30 /// returns immediate value 31 fn get_imm(&self) -> i32 { 32 self.get_insn().imm 33 } 34 35 /// sets destination register 36 fn set_dst(mut self, dst: u8) -> Self { 37 self.get_insn_mut().dst = dst; 38 self 39 } 40 41 /// sets source register 42 fn set_src(mut self, src: u8) -> Self { 43 self.get_insn_mut().src = src; 44 self 45 } 46 47 /// sets offset bytes 48 fn set_off(mut self, offset: i16) -> Self { 49 self.get_insn_mut().off = offset; 50 self 51 } 52 53 /// sets immediate value 54 fn set_imm(mut self, imm: i32) -> Self { 55 self.get_insn_mut().imm = imm; 56 self 57 } 58 59 /// get `ebpf::Insn` struct 60 fn get_insn(&self) -> &Insn; 61 62 /// get mutable `ebpf::Insn` struct 63 fn get_insn_mut(&mut self) -> &mut Insn; 64 } 65 66 /// General trait for `Instruction`s and `BpfCode`. 67 /// Provides functionality to transform `struct` into collection of bytes 68 pub trait IntoBytes { 69 /// type of targeted transformation 70 type Bytes; 71 72 /// consume `Self` with transformation into `Self::Bytes` 73 fn into_bytes(self) -> Self::Bytes; 74 } 75 76 /// General implementation of `IntoBytes` for `Instruction` 77 impl<'i, I: Instruction> IntoBytes for &'i I { 78 type Bytes = Vec<u8>; 79 80 /// transform immutable reference of `Instruction` into `Vec<u8>` with size of 8 81 /// [ 1 byte , 1 byte , 2 bytes, 4 bytes ] 82 /// [ OP_CODE, SRC_REG | DST_REG, OFFSET , IMMEDIATE ] 83 fn into_bytes(self) -> Self::Bytes { 84 let buffer = vec![ 85 self.opt_code_byte(), 86 self.get_src() << 4 | self.get_dst(), 87 self.get_off() as u8, 88 (self.get_off() >> 8) as u8, 89 self.get_imm() as u8, 90 (self.get_imm() >> 8) as u8, 91 (self.get_imm() >> 16) as u8, 92 (self.get_imm() >> 24) as u8, 93 ]; 94 buffer 95 } 96 } 97 98 /// BPF instruction stack in byte representation 99 #[derive(Default)] 100 pub struct BpfCode { 101 instructions: Vec<u8>, 102 } 103 104 impl BpfCode { 105 /// creates new empty BPF instruction stack 106 pub fn new() -> Self { 107 BpfCode { 108 instructions: vec![], 109 } 110 } 111 112 /// create ADD instruction 113 pub fn add(&mut self, source: Source, arch: Arch) -> Move { 114 self.mov_internal(source, arch, OpBits::Add) 115 } 116 117 /// create SUB instruction 118 pub fn sub(&mut self, source: Source, arch: Arch) -> Move { 119 self.mov_internal(source, arch, OpBits::Sub) 120 } 121 122 /// create MUL instruction 123 pub fn mul(&mut self, source: Source, arch: Arch) -> Move { 124 self.mov_internal(source, arch, OpBits::Mul) 125 } 126 127 /// create DIV instruction 128 pub fn div(&mut self, source: Source, arch: Arch) -> Move { 129 self.mov_internal(source, arch, OpBits::Div) 130 } 131 132 /// create OR instruction 133 pub fn bit_or(&mut self, source: Source, arch: Arch) -> Move { 134 self.mov_internal(source, arch, OpBits::BitOr) 135 } 136 137 /// create AND instruction 138 pub fn bit_and(&mut self, source: Source, arch: Arch) -> Move { 139 self.mov_internal(source, arch, OpBits::BitAnd) 140 } 141 142 /// create LSHIFT instruction 143 pub fn left_shift(&mut self, source: Source, arch: Arch) -> Move { 144 self.mov_internal(source, arch, OpBits::LShift) 145 } 146 147 /// create RSHIFT instruction 148 pub fn right_shift(&mut self, source: Source, arch: Arch) -> Move { 149 self.mov_internal(source, arch, OpBits::RShift) 150 } 151 152 /// create NEGATE instruction 153 pub fn negate(&mut self, arch: Arch) -> Move { 154 self.mov_internal(Source::Imm, arch, OpBits::Negate) 155 } 156 157 /// create MOD instruction 158 pub fn modulo(&mut self, source: Source, arch: Arch) -> Move { 159 self.mov_internal(source, arch, OpBits::Mod) 160 } 161 162 /// create XOR instruction 163 pub fn bit_xor(&mut self, source: Source, arch: Arch) -> Move { 164 self.mov_internal(source, arch, OpBits::BitXor) 165 } 166 167 /// create MOV instruction 168 pub fn mov(&mut self, source: Source, arch: Arch) -> Move { 169 self.mov_internal(source, arch, OpBits::Mov) 170 } 171 172 /// create SIGNED RSHIFT instruction 173 pub fn signed_right_shift(&mut self, source: Source, arch: Arch) -> Move { 174 self.mov_internal(source, arch, OpBits::SignRShift) 175 } 176 177 #[inline] 178 fn mov_internal(&mut self, source: Source, arch_bits: Arch, op_bits: OpBits) -> Move { 179 Move { 180 bpf_code: self, 181 src_bit: source, 182 op_bits, 183 arch_bits, 184 insn: Insn { 185 opc: 0x00, 186 dst: 0x00, 187 src: 0x00, 188 off: 0x00_00, 189 imm: 0x00_00_00_00, 190 }, 191 } 192 } 193 194 /// create byte swap instruction 195 pub fn swap_bytes(&mut self, endian: Endian) -> SwapBytes { 196 SwapBytes { 197 bpf_code: self, 198 endian, 199 insn: Insn { 200 opc: 0x00, 201 dst: 0x00, 202 src: 0x00, 203 off: 0x00_00, 204 imm: 0x00_00_00_00, 205 }, 206 } 207 } 208 209 /// create LOAD instruction, IMMEDIATE is the source 210 pub fn load(&mut self, mem_size: MemSize) -> Load { 211 self.load_internal(mem_size, Addressing::Imm, BPF_LD) 212 } 213 214 /// create ABSOLUTE LOAD instruction 215 pub fn load_abs(&mut self, mem_size: MemSize) -> Load { 216 self.load_internal(mem_size, Addressing::Abs, BPF_LD) 217 } 218 219 /// create INDIRECT LOAD instruction 220 pub fn load_ind(&mut self, mem_size: MemSize) -> Load { 221 self.load_internal(mem_size, Addressing::Ind, BPF_LD) 222 } 223 224 /// create LOAD instruction, MEMORY is the source 225 pub fn load_x(&mut self, mem_size: MemSize) -> Load { 226 self.load_internal(mem_size, Addressing::Mem, BPF_LDX) 227 } 228 229 #[inline] 230 fn load_internal(&mut self, mem_size: MemSize, addressing: Addressing, source: u8) -> Load { 231 Load { 232 bpf_code: self, 233 addressing, 234 mem_size, 235 source, 236 insn: Insn { 237 opc: 0x00, 238 dst: 0x00, 239 src: 0x00, 240 off: 0x00_00, 241 imm: 0x00_00_00_00, 242 }, 243 } 244 } 245 246 /// creates STORE instruction, IMMEDIATE is the source 247 pub fn store(&mut self, mem_size: MemSize) -> Store { 248 self.store_internal(mem_size, BPF_IMM) 249 } 250 251 /// creates STORE instruction, MEMORY is the source 252 pub fn store_x(&mut self, mem_size: MemSize) -> Store { 253 self.store_internal(mem_size, BPF_MEM | BPF_STX) 254 } 255 256 #[inline] 257 fn store_internal(&mut self, mem_size: MemSize, source: u8) -> Store { 258 Store { 259 bpf_code: self, 260 mem_size, 261 source, 262 insn: Insn { 263 opc: 0x00, 264 dst: 0x00, 265 src: 0x00, 266 off: 0x00_00, 267 imm: 0x00_00_00_00, 268 }, 269 } 270 } 271 272 /// create unconditional JMP instruction 273 pub fn jump_unconditional(&mut self) -> Jump { 274 self.jump_conditional(Cond::Abs, Source::Imm) 275 } 276 277 /// create conditional JMP instruction 278 pub fn jump_conditional(&mut self, cond: Cond, src_bit: Source) -> Jump { 279 Jump { 280 bpf_code: self, 281 cond, 282 src_bit, 283 insn: Insn { 284 opc: 0x00, 285 dst: 0x00, 286 src: 0x00, 287 off: 0x00_00, 288 imm: 0x00_00_00_00, 289 }, 290 } 291 } 292 293 /// create CALL instruction 294 pub fn call(&mut self) -> FunctionCall { 295 FunctionCall { 296 bpf_code: self, 297 insn: Insn { 298 opc: 0x00, 299 dst: 0x00, 300 src: 0x00, 301 off: 0x00_00, 302 imm: 0x00_00_00_00, 303 }, 304 } 305 } 306 307 /// create EXIT instruction 308 pub fn exit(&mut self) -> Exit { 309 Exit { 310 bpf_code: self, 311 insn: Insn { 312 opc: 0x00, 313 dst: 0x00, 314 src: 0x00, 315 off: 0x00_00, 316 imm: 0x00_00_00_00, 317 }, 318 } 319 } 320 } 321 322 /// Transform `BpfCode` into assemble representation 323 impl<'a> IntoBytes for &'a BpfCode { 324 type Bytes = &'a [u8]; 325 326 /// returns `BpfCode` instruction stack as `&[u8]` 327 fn into_bytes(self) -> Self::Bytes { 328 self.instructions.as_slice() 329 } 330 } 331 332 /// struct to represent `MOV ALU` instructions 333 pub struct Move<'i> { 334 bpf_code: &'i mut BpfCode, 335 src_bit: Source, 336 op_bits: OpBits, 337 arch_bits: Arch, 338 insn: Insn, 339 } 340 341 impl<'i> Move<'i> { 342 /// push MOV instruction into BpfCode instruction stack 343 pub fn push(self) -> &'i mut BpfCode { 344 let mut asm = self.into_bytes(); 345 self.bpf_code.instructions.append(&mut asm); 346 self.bpf_code 347 } 348 } 349 350 impl<'i> Instruction for Move<'i> { 351 fn opt_code_byte(&self) -> u8 { 352 let op_bits = self.op_bits as u8; 353 let src_bit = self.src_bit as u8; 354 let arch_bits = self.arch_bits as u8; 355 op_bits | src_bit | arch_bits 356 } 357 358 fn get_insn_mut(&mut self) -> &mut Insn { 359 &mut self.insn 360 } 361 362 fn get_insn(&self) -> &Insn { 363 &self.insn 364 } 365 } 366 367 #[derive(Copy, Clone, PartialEq, Eq)] 368 /// The source of ALU and JMP instructions 369 pub enum Source { 370 /// immediate field will be used as a source 371 Imm = BPF_IMM as isize, 372 /// src register will be used as a source 373 Reg = BPF_X as isize, 374 } 375 376 #[derive(Copy, Clone)] 377 enum OpBits { 378 Add = BPF_ADD as isize, 379 Sub = BPF_SUB as isize, 380 Mul = BPF_MUL as isize, 381 Div = BPF_DIV as isize, 382 BitOr = BPF_OR as isize, 383 BitAnd = BPF_AND as isize, 384 LShift = BPF_LSH as isize, 385 RShift = BPF_RSH as isize, 386 Negate = BPF_NEG as isize, 387 Mod = BPF_MOD as isize, 388 BitXor = BPF_XOR as isize, 389 Mov = BPF_MOV as isize, 390 SignRShift = BPF_ARSH as isize, 391 } 392 393 #[derive(Copy, Clone)] 394 /// Architecture of instructions 395 pub enum Arch { 396 /// 64-bit instructions 397 X64 = BPF_ALU64 as isize, 398 /// 32-bit instructions 399 X32 = BPF_ALU as isize, 400 } 401 402 /// struct representation of byte swap operation 403 pub struct SwapBytes<'i> { 404 bpf_code: &'i mut BpfCode, 405 endian: Endian, 406 insn: Insn, 407 } 408 409 impl<'i> SwapBytes<'i> { 410 /// push bytes swap instruction into BpfCode instruction stack 411 pub fn push(self) -> &'i mut BpfCode { 412 let mut asm = self.into_bytes(); 413 self.bpf_code.instructions.append(&mut asm); 414 self.bpf_code 415 } 416 } 417 418 impl<'i> Instruction for SwapBytes<'i> { 419 fn opt_code_byte(&self) -> u8 { 420 self.endian as u8 421 } 422 423 fn get_insn_mut(&mut self) -> &mut Insn { 424 &mut self.insn 425 } 426 427 fn get_insn(&self) -> &Insn { 428 &self.insn 429 } 430 } 431 432 #[derive(Copy, Clone)] 433 /// Bytes endian 434 pub enum Endian { 435 /// Little endian 436 Little = LE as isize, 437 /// Big endian 438 Big = BE as isize, 439 } 440 441 /// struct representation of LOAD instructions 442 pub struct Load<'i> { 443 bpf_code: &'i mut BpfCode, 444 addressing: Addressing, 445 mem_size: MemSize, 446 source: u8, 447 insn: Insn, 448 } 449 450 impl<'i> Load<'i> { 451 /// push LOAD instruction into BpfCode instruction stack 452 pub fn push(self) -> &'i mut BpfCode { 453 let mut asm = self.into_bytes(); 454 self.bpf_code.instructions.append(&mut asm); 455 self.bpf_code 456 } 457 } 458 459 impl<'i> Instruction for Load<'i> { 460 fn opt_code_byte(&self) -> u8 { 461 let size = self.mem_size as u8; 462 let addressing = self.addressing as u8; 463 addressing | size | self.source 464 } 465 466 fn get_insn_mut(&mut self) -> &mut Insn { 467 &mut self.insn 468 } 469 470 fn get_insn(&self) -> &Insn { 471 &self.insn 472 } 473 } 474 475 /// struct representation of STORE instructions 476 pub struct Store<'i> { 477 bpf_code: &'i mut BpfCode, 478 mem_size: MemSize, 479 source: u8, 480 insn: Insn, 481 } 482 483 impl<'i> Store<'i> { 484 /// push STORE instruction into BpfCode instruction stack 485 pub fn push(self) -> &'i mut BpfCode { 486 let mut asm = self.into_bytes(); 487 self.bpf_code.instructions.append(&mut asm); 488 self.bpf_code 489 } 490 } 491 492 impl<'i> Instruction for Store<'i> { 493 fn opt_code_byte(&self) -> u8 { 494 let size = self.mem_size as u8; 495 BPF_MEM | BPF_ST | size | self.source 496 } 497 498 fn get_insn_mut(&mut self) -> &mut Insn { 499 &mut self.insn 500 } 501 502 fn get_insn(&self) -> &Insn { 503 &self.insn 504 } 505 } 506 507 #[derive(Copy, Clone)] 508 /// Memory size for LOAD and STORE instructions 509 pub enum MemSize { 510 /// 8-bit size 511 Byte = BPF_B as isize, 512 /// 16-bit size 513 HalfWord = BPF_H as isize, 514 /// 32-bit size 515 Word = BPF_W as isize, 516 /// 64-bit size 517 DoubleWord = BPF_DW as isize, 518 } 519 520 #[derive(Copy, Clone)] 521 enum Addressing { 522 Imm = BPF_IMM as isize, 523 Abs = BPF_ABS as isize, 524 Ind = BPF_IND as isize, 525 Mem = BPF_MEM as isize, 526 } 527 528 /// struct representation of JMP instructions 529 pub struct Jump<'i> { 530 bpf_code: &'i mut BpfCode, 531 cond: Cond, 532 src_bit: Source, 533 insn: Insn, 534 } 535 536 impl<'i> Jump<'i> { 537 /// push JMP instruction into BpfCode instruction stack 538 pub fn push(self) -> &'i mut BpfCode { 539 let mut asm = self.into_bytes(); 540 self.bpf_code.instructions.append(&mut asm); 541 self.bpf_code 542 } 543 } 544 545 impl<'i> Instruction for Jump<'i> { 546 fn opt_code_byte(&self) -> u8 { 547 let cmp: u8 = self.cond as u8; 548 let src_bit = self.src_bit as u8; 549 cmp | src_bit | BPF_JMP 550 } 551 552 fn get_insn_mut(&mut self) -> &mut Insn { 553 &mut self.insn 554 } 555 556 fn get_insn(&self) -> &Insn { 557 &self.insn 558 } 559 } 560 561 #[derive(Copy, Clone, PartialEq, Eq)] 562 /// Conditions for JMP instructions 563 pub enum Cond { 564 /// Absolute or unconditional 565 Abs = BPF_JA as isize, 566 /// Jump if `==` 567 Equals = BPF_JEQ as isize, 568 /// Jump if `>` 569 Greater = BPF_JGT as isize, 570 /// Jump if `>=` 571 GreaterEquals = BPF_JGE as isize, 572 /// Jump if `<` 573 Lower = BPF_JLT as isize, 574 /// Jump if `<=` 575 LowerEquals = BPF_JLE as isize, 576 /// Jump if `src` & `dst` 577 BitAnd = BPF_JSET as isize, 578 /// Jump if `!=` 579 NotEquals = BPF_JNE as isize, 580 /// Jump if `>` (signed) 581 GreaterSigned = BPF_JSGT as isize, 582 /// Jump if `>=` (signed) 583 GreaterEqualsSigned = BPF_JSGE as isize, 584 /// Jump if `<` (signed) 585 LowerSigned = BPF_JSLT as isize, 586 /// Jump if `<=` (signed) 587 LowerEqualsSigned = BPF_JSLE as isize, 588 } 589 590 /// struct representation of CALL instruction 591 pub struct FunctionCall<'i> { 592 bpf_code: &'i mut BpfCode, 593 insn: Insn, 594 } 595 596 impl<'i> FunctionCall<'i> { 597 /// push CALL instruction into BpfCode instruction stack 598 pub fn push(self) -> &'i mut BpfCode { 599 let mut asm = self.into_bytes(); 600 self.bpf_code.instructions.append(&mut asm); 601 self.bpf_code 602 } 603 } 604 605 impl<'i> Instruction for FunctionCall<'i> { 606 fn opt_code_byte(&self) -> u8 { 607 BPF_CALL | BPF_JMP 608 } 609 610 fn get_insn_mut(&mut self) -> &mut Insn { 611 &mut self.insn 612 } 613 614 fn get_insn(&self) -> &Insn { 615 &self.insn 616 } 617 } 618 619 /// struct representation of EXIT instruction 620 pub struct Exit<'i> { 621 bpf_code: &'i mut BpfCode, 622 insn: Insn, 623 } 624 625 impl<'i> Exit<'i> { 626 /// push EXIT instruction into BpfCode instruction stack 627 pub fn push(self) -> &'i mut BpfCode { 628 let mut asm = self.into_bytes(); 629 self.bpf_code.instructions.append(&mut asm); 630 self.bpf_code 631 } 632 } 633 634 impl<'i> Instruction for Exit<'i> { 635 fn opt_code_byte(&self) -> u8 { 636 BPF_EXIT | BPF_JMP 637 } 638 639 fn get_insn_mut(&mut self) -> &mut Insn { 640 &mut self.insn 641 } 642 643 fn get_insn(&self) -> &Insn { 644 &self.insn 645 } 646 } 647 648 #[cfg(test)] 649 mod tests { 650 #[cfg(test)] 651 mod special { 652 use super::super::*; 653 654 #[test] 655 fn call_immediate() { 656 let mut program = BpfCode::new(); 657 program.call().set_imm(0x11_22_33_44).push(); 658 659 assert_eq!( 660 program.into_bytes(), 661 &[0x85, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11] 662 ); 663 } 664 665 #[test] 666 fn exit_operation() { 667 let mut program = BpfCode::new(); 668 program.exit().push(); 669 670 assert_eq!( 671 program.into_bytes(), 672 &[0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 673 ); 674 } 675 } 676 677 #[cfg(test)] 678 mod jump_instructions { 679 #[cfg(test)] 680 mod register { 681 use super::super::super::*; 682 683 #[test] 684 fn jump_on_dst_equals_src() { 685 let mut program = BpfCode::new(); 686 program 687 .jump_conditional(Cond::Equals, Source::Reg) 688 .set_dst(0x01) 689 .set_src(0x02) 690 .push(); 691 692 assert_eq!( 693 program.into_bytes(), 694 &[0x1d, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 695 ); 696 } 697 698 #[test] 699 fn jump_on_dst_greater_than_src() { 700 let mut program = BpfCode::new(); 701 program 702 .jump_conditional(Cond::Greater, Source::Reg) 703 .set_dst(0x03) 704 .set_src(0x02) 705 .push(); 706 707 assert_eq!( 708 program.into_bytes(), 709 &[0x2d, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 710 ); 711 } 712 713 #[test] 714 fn jump_on_dst_greater_or_equals_to_src() { 715 let mut program = BpfCode::new(); 716 program 717 .jump_conditional(Cond::GreaterEquals, Source::Reg) 718 .set_dst(0x04) 719 .set_src(0x01) 720 .push(); 721 722 assert_eq!( 723 program.into_bytes(), 724 &[0x3d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 725 ); 726 } 727 728 #[test] 729 fn jump_on_dst_lower_than_src() { 730 let mut program = BpfCode::new(); 731 program 732 .jump_conditional(Cond::Lower, Source::Reg) 733 .set_dst(0x03) 734 .set_src(0x02) 735 .push(); 736 737 assert_eq!( 738 program.into_bytes(), 739 &[0xad, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 740 ); 741 } 742 743 #[test] 744 fn jump_on_dst_lower_or_equals_to_src() { 745 let mut program = BpfCode::new(); 746 program 747 .jump_conditional(Cond::LowerEquals, Source::Reg) 748 .set_dst(0x04) 749 .set_src(0x01) 750 .push(); 751 752 assert_eq!( 753 program.into_bytes(), 754 &[0xbd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 755 ); 756 } 757 758 #[test] 759 fn jump_on_dst_bit_and_with_src_not_equal_zero() { 760 let mut program = BpfCode::new(); 761 program 762 .jump_conditional(Cond::BitAnd, Source::Reg) 763 .set_dst(0x05) 764 .set_src(0x02) 765 .push(); 766 767 assert_eq!( 768 program.into_bytes(), 769 &[0x4d, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 770 ); 771 } 772 773 #[test] 774 fn jump_on_dst_not_equals_src() { 775 let mut program = BpfCode::new(); 776 program 777 .jump_conditional(Cond::NotEquals, Source::Reg) 778 .set_dst(0x03) 779 .set_src(0x05) 780 .push(); 781 782 assert_eq!( 783 program.into_bytes(), 784 &[0x5d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 785 ); 786 } 787 788 #[test] 789 fn jump_on_dst_greater_than_src_signed() { 790 let mut program = BpfCode::new(); 791 program 792 .jump_conditional(Cond::GreaterSigned, Source::Reg) 793 .set_dst(0x04) 794 .set_src(0x01) 795 .push(); 796 797 assert_eq!( 798 program.into_bytes(), 799 &[0x6d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 800 ); 801 } 802 803 #[test] 804 fn jump_on_dst_greater_or_equals_src_signed() { 805 let mut program = BpfCode::new(); 806 program 807 .jump_conditional(Cond::GreaterEqualsSigned, Source::Reg) 808 .set_dst(0x01) 809 .set_src(0x03) 810 .push(); 811 812 assert_eq!( 813 program.into_bytes(), 814 &[0x7d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 815 ); 816 } 817 818 #[test] 819 fn jump_on_dst_lower_than_src_signed() { 820 let mut program = BpfCode::new(); 821 program 822 .jump_conditional(Cond::LowerSigned, Source::Reg) 823 .set_dst(0x04) 824 .set_src(0x01) 825 .push(); 826 827 assert_eq!( 828 program.into_bytes(), 829 &[0xcd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 830 ); 831 } 832 833 #[test] 834 fn jump_on_dst_lower_or_equals_src_signed() { 835 let mut program = BpfCode::new(); 836 program 837 .jump_conditional(Cond::LowerEqualsSigned, Source::Reg) 838 .set_dst(0x01) 839 .set_src(0x03) 840 .push(); 841 842 assert_eq!( 843 program.into_bytes(), 844 &[0xdd, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 845 ); 846 } 847 } 848 849 #[cfg(test)] 850 mod immediate { 851 use super::super::super::*; 852 853 #[test] 854 fn jump_to_label() { 855 let mut program = BpfCode::new(); 856 program.jump_unconditional().set_off(0x00_11).push(); 857 858 assert_eq!( 859 program.into_bytes(), 860 &[0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00] 861 ); 862 } 863 864 #[test] 865 fn jump_on_dst_equals_const() { 866 let mut program = BpfCode::new(); 867 program 868 .jump_conditional(Cond::Equals, Source::Imm) 869 .set_dst(0x01) 870 .set_imm(0x00_11_22_33) 871 .push(); 872 873 assert_eq!( 874 program.into_bytes(), 875 &[0x15, 0x01, 0x00, 0x00, 0x33, 0x22, 0x11, 0x00] 876 ); 877 } 878 879 #[test] 880 fn jump_on_dst_greater_than_const() { 881 let mut program = BpfCode::new(); 882 program 883 .jump_conditional(Cond::Greater, Source::Imm) 884 .set_dst(0x02) 885 .set_imm(0x00_11_00_11) 886 .push(); 887 888 assert_eq!( 889 program.into_bytes(), 890 &[0x25, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00] 891 ); 892 } 893 894 #[test] 895 fn jump_on_dst_greater_or_equals_to_const() { 896 let mut program = BpfCode::new(); 897 program 898 .jump_conditional(Cond::GreaterEquals, Source::Imm) 899 .set_dst(0x04) 900 .set_imm(0x00_22_11_00) 901 .push(); 902 903 assert_eq!( 904 program.into_bytes(), 905 &[0x35, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00] 906 ); 907 } 908 909 #[test] 910 fn jump_on_dst_lower_than_const() { 911 let mut program = BpfCode::new(); 912 program 913 .jump_conditional(Cond::Lower, Source::Imm) 914 .set_dst(0x02) 915 .set_imm(0x00_11_00_11) 916 .push(); 917 918 assert_eq!( 919 program.into_bytes(), 920 &[0xa5, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00] 921 ); 922 } 923 924 #[test] 925 fn jump_on_dst_lower_or_equals_to_const() { 926 let mut program = BpfCode::new(); 927 program 928 .jump_conditional(Cond::LowerEquals, Source::Imm) 929 .set_dst(0x04) 930 .set_imm(0x00_22_11_00) 931 .push(); 932 933 assert_eq!( 934 program.into_bytes(), 935 &[0xb5, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00] 936 ); 937 } 938 939 #[test] 940 fn jump_on_dst_bit_and_with_const_not_equal_zero() { 941 let mut program = BpfCode::new(); 942 program 943 .jump_conditional(Cond::BitAnd, Source::Imm) 944 .set_dst(0x05) 945 .push(); 946 947 assert_eq!( 948 program.into_bytes(), 949 &[0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 950 ); 951 } 952 953 #[test] 954 fn jump_on_dst_not_equals_const() { 955 let mut program = BpfCode::new(); 956 program 957 .jump_conditional(Cond::NotEquals, Source::Imm) 958 .set_dst(0x03) 959 .push(); 960 961 assert_eq!( 962 program.into_bytes(), 963 &[0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 964 ); 965 } 966 967 #[test] 968 fn jump_on_dst_greater_than_const_signed() { 969 let mut program = BpfCode::new(); 970 program 971 .jump_conditional(Cond::GreaterSigned, Source::Imm) 972 .set_dst(0x04) 973 .push(); 974 975 assert_eq!( 976 program.into_bytes(), 977 &[0x65, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 978 ); 979 } 980 981 #[test] 982 fn jump_on_dst_greater_or_equals_src_signed() { 983 let mut program = BpfCode::new(); 984 program 985 .jump_conditional(Cond::GreaterEqualsSigned, Source::Imm) 986 .set_dst(0x01) 987 .push(); 988 989 assert_eq!( 990 program.into_bytes(), 991 &[0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 992 ); 993 } 994 995 #[test] 996 fn jump_on_dst_lower_than_const_signed() { 997 let mut program = BpfCode::new(); 998 program 999 .jump_conditional(Cond::LowerSigned, Source::Imm) 1000 .set_dst(0x04) 1001 .push(); 1002 1003 assert_eq!( 1004 program.into_bytes(), 1005 &[0xc5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1006 ); 1007 } 1008 1009 #[test] 1010 fn jump_on_dst_lower_or_equals_src_signed() { 1011 let mut program = BpfCode::new(); 1012 program 1013 .jump_conditional(Cond::LowerEqualsSigned, Source::Imm) 1014 .set_dst(0x01) 1015 .push(); 1016 1017 assert_eq!( 1018 program.into_bytes(), 1019 &[0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1020 ); 1021 } 1022 } 1023 } 1024 1025 #[cfg(test)] 1026 mod store_instructions { 1027 use super::super::*; 1028 1029 #[test] 1030 fn store_word_from_dst_into_immediate_address() { 1031 let mut program = BpfCode::new(); 1032 program 1033 .store(MemSize::Word) 1034 .set_dst(0x01) 1035 .set_off(0x00_11) 1036 .set_imm(0x11_22_33_44) 1037 .push(); 1038 1039 assert_eq!( 1040 program.into_bytes(), 1041 &[0x62, 0x01, 0x11, 0x00, 0x44, 0x33, 0x22, 0x11] 1042 ); 1043 } 1044 1045 #[test] 1046 fn store_half_word_from_dst_into_immediate_address() { 1047 let mut program = BpfCode::new(); 1048 program 1049 .store(MemSize::HalfWord) 1050 .set_dst(0x02) 1051 .set_off(0x11_22) 1052 .push(); 1053 1054 assert_eq!( 1055 program.into_bytes(), 1056 &[0x6a, 0x02, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00] 1057 ); 1058 } 1059 1060 #[test] 1061 fn store_byte_from_dst_into_immediate_address() { 1062 let mut program = BpfCode::new(); 1063 program.store(MemSize::Byte).push(); 1064 1065 assert_eq!( 1066 program.into_bytes(), 1067 &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1068 ); 1069 } 1070 1071 #[test] 1072 fn store_double_word_from_dst_into_immediate_address() { 1073 let mut program = BpfCode::new(); 1074 program.store(MemSize::DoubleWord).push(); 1075 1076 assert_eq!( 1077 program.into_bytes(), 1078 &[0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1079 ); 1080 } 1081 1082 #[test] 1083 fn store_word_from_dst_into_src_address() { 1084 let mut program = BpfCode::new(); 1085 program 1086 .store_x(MemSize::Word) 1087 .set_dst(0x01) 1088 .set_src(0x02) 1089 .push(); 1090 1091 assert_eq!( 1092 program.into_bytes(), 1093 &[0x63, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1094 ); 1095 } 1096 1097 #[test] 1098 fn store_half_word_from_dst_into_src_address() { 1099 let mut program = BpfCode::new(); 1100 program.store_x(MemSize::HalfWord).push(); 1101 1102 assert_eq!( 1103 program.into_bytes(), 1104 &[0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1105 ); 1106 } 1107 1108 #[test] 1109 fn store_byte_from_dst_into_src_address() { 1110 let mut program = BpfCode::new(); 1111 program.store_x(MemSize::Byte).push(); 1112 1113 assert_eq!( 1114 program.into_bytes(), 1115 &[0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1116 ); 1117 } 1118 1119 #[test] 1120 fn store_double_word_from_dst_into_src_address() { 1121 let mut program = BpfCode::new(); 1122 program.store_x(MemSize::DoubleWord).push(); 1123 1124 assert_eq!( 1125 program.into_bytes(), 1126 &[0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1127 ); 1128 } 1129 } 1130 1131 #[cfg(test)] 1132 mod load_instructions { 1133 #[cfg(test)] 1134 mod register { 1135 use super::super::super::*; 1136 1137 #[test] 1138 fn load_word_from_set_src_with_offset() { 1139 let mut program = BpfCode::new(); 1140 program 1141 .load_x(MemSize::Word) 1142 .set_dst(0x01) 1143 .set_src(0x02) 1144 .set_off(0x00_02) 1145 .push(); 1146 1147 assert_eq!( 1148 program.into_bytes(), 1149 &[0x61, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00] 1150 ); 1151 } 1152 1153 #[test] 1154 fn load_half_word_from_set_src_with_offset() { 1155 let mut program = BpfCode::new(); 1156 program 1157 .load_x(MemSize::HalfWord) 1158 .set_dst(0x02) 1159 .set_src(0x01) 1160 .set_off(0x11_22) 1161 .push(); 1162 1163 assert_eq!( 1164 program.into_bytes(), 1165 &[0x69, 0x12, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00] 1166 ); 1167 } 1168 1169 #[test] 1170 fn load_byte_from_set_src_with_offset() { 1171 let mut program = BpfCode::new(); 1172 program 1173 .load_x(MemSize::Byte) 1174 .set_dst(0x01) 1175 .set_src(0x04) 1176 .set_off(0x00_11) 1177 .push(); 1178 1179 assert_eq!( 1180 program.into_bytes(), 1181 &[0x71, 0x41, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00] 1182 ); 1183 } 1184 1185 #[test] 1186 fn load_double_word_from_set_src_with_offset() { 1187 let mut program = BpfCode::new(); 1188 program 1189 .load_x(MemSize::DoubleWord) 1190 .set_dst(0x04) 1191 .set_src(0x05) 1192 .set_off(0x44_55) 1193 .push(); 1194 1195 assert_eq!( 1196 program.into_bytes(), 1197 &[0x79, 0x54, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00] 1198 ); 1199 } 1200 } 1201 1202 #[cfg(test)] 1203 mod immediate { 1204 use super::super::super::*; 1205 1206 #[test] 1207 fn load_double_word() { 1208 let mut program = BpfCode::new(); 1209 program 1210 .load(MemSize::DoubleWord) 1211 .set_dst(0x01) 1212 .set_imm(0x00_01_02_03) 1213 .push(); 1214 1215 assert_eq!( 1216 program.into_bytes(), 1217 &[0x18, 0x01, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00] 1218 ); 1219 } 1220 1221 #[test] 1222 fn load_abs_word() { 1223 let mut program = BpfCode::new(); 1224 program.load_abs(MemSize::Word).push(); 1225 1226 assert_eq!( 1227 program.into_bytes(), 1228 &[0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1229 ); 1230 } 1231 1232 #[test] 1233 fn load_abs_half_word() { 1234 let mut program = BpfCode::new(); 1235 program.load_abs(MemSize::HalfWord).set_dst(0x05).push(); 1236 1237 assert_eq!( 1238 program.into_bytes(), 1239 &[0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1240 ); 1241 } 1242 1243 #[test] 1244 fn load_abs_byte() { 1245 let mut program = BpfCode::new(); 1246 program.load_abs(MemSize::Byte).set_dst(0x01).push(); 1247 1248 assert_eq!( 1249 program.into_bytes(), 1250 &[0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1251 ); 1252 } 1253 1254 #[test] 1255 fn load_abs_double_word() { 1256 let mut program = BpfCode::new(); 1257 program 1258 .load_abs(MemSize::DoubleWord) 1259 .set_dst(0x01) 1260 .set_imm(0x01_02_03_04) 1261 .push(); 1262 1263 assert_eq!( 1264 program.into_bytes(), 1265 &[0x38, 0x01, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01] 1266 ); 1267 } 1268 1269 #[test] 1270 fn load_indirect_word() { 1271 let mut program = BpfCode::new(); 1272 program.load_ind(MemSize::Word).push(); 1273 1274 assert_eq!( 1275 program.into_bytes(), 1276 &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1277 ); 1278 } 1279 1280 #[test] 1281 fn load_indirect_half_word() { 1282 let mut program = BpfCode::new(); 1283 program.load_ind(MemSize::HalfWord).push(); 1284 1285 assert_eq!( 1286 program.into_bytes(), 1287 &[0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1288 ); 1289 } 1290 1291 #[test] 1292 fn load_indirect_byte() { 1293 let mut program = BpfCode::new(); 1294 program.load_ind(MemSize::Byte).push(); 1295 1296 assert_eq!( 1297 program.into_bytes(), 1298 &[0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1299 ); 1300 } 1301 1302 #[test] 1303 fn load_indirect_double_word() { 1304 let mut program = BpfCode::new(); 1305 program.load_ind(MemSize::DoubleWord).push(); 1306 1307 assert_eq!( 1308 program.into_bytes(), 1309 &[0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1310 ); 1311 } 1312 } 1313 } 1314 1315 #[cfg(test)] 1316 mod byte_swap_instructions { 1317 use super::super::*; 1318 1319 #[test] 1320 fn convert_host_to_little_endian_16bits() { 1321 let mut program = BpfCode::new(); 1322 program 1323 .swap_bytes(Endian::Little) 1324 .set_dst(0x01) 1325 .set_imm(0x00_00_00_10) 1326 .push(); 1327 1328 assert_eq!( 1329 program.into_bytes(), 1330 &[0xd4, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00] 1331 ); 1332 } 1333 1334 #[test] 1335 fn convert_host_to_little_endian_32bits() { 1336 let mut program = BpfCode::new(); 1337 program 1338 .swap_bytes(Endian::Little) 1339 .set_dst(0x02) 1340 .set_imm(0x00_00_00_20) 1341 .push(); 1342 1343 assert_eq!( 1344 program.into_bytes(), 1345 &[0xd4, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00] 1346 ); 1347 } 1348 1349 #[test] 1350 fn convert_host_to_little_endian_64bit() { 1351 let mut program = BpfCode::new(); 1352 program 1353 .swap_bytes(Endian::Little) 1354 .set_dst(0x03) 1355 .set_imm(0x00_00_00_40) 1356 .push(); 1357 1358 assert_eq!( 1359 program.into_bytes(), 1360 &[0xd4, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00] 1361 ); 1362 } 1363 1364 #[test] 1365 fn convert_host_to_big_endian_16bits() { 1366 let mut program = BpfCode::new(); 1367 program 1368 .swap_bytes(Endian::Big) 1369 .set_dst(0x01) 1370 .set_imm(0x00_00_00_10) 1371 .push(); 1372 1373 assert_eq!( 1374 program.into_bytes(), 1375 &[0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00] 1376 ); 1377 } 1378 1379 #[test] 1380 fn convert_host_to_big_endian_32bits() { 1381 let mut program = BpfCode::new(); 1382 program 1383 .swap_bytes(Endian::Big) 1384 .set_dst(0x02) 1385 .set_imm(0x00_00_00_20) 1386 .push(); 1387 1388 assert_eq!( 1389 program.into_bytes(), 1390 &[0xdc, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00] 1391 ); 1392 } 1393 1394 #[test] 1395 fn convert_host_to_big_endian_64bit() { 1396 let mut program = BpfCode::new(); 1397 program 1398 .swap_bytes(Endian::Big) 1399 .set_dst(0x03) 1400 .set_imm(0x00_00_00_40) 1401 .push(); 1402 1403 assert_eq!( 1404 program.into_bytes(), 1405 &[0xdc, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00] 1406 ); 1407 } 1408 } 1409 1410 #[cfg(test)] 1411 mod moves_instructions { 1412 #[cfg(test)] 1413 mod arch_x64 { 1414 #[cfg(test)] 1415 mod immediate { 1416 use super::super::super::super::*; 1417 1418 #[test] 1419 fn move_and_add_const_to_register() { 1420 let mut program = BpfCode::new(); 1421 program 1422 .add(Source::Imm, Arch::X64) 1423 .set_dst(0x02) 1424 .set_imm(0x01_02_03_04) 1425 .push(); 1426 1427 assert_eq!( 1428 program.into_bytes(), 1429 &[0x07, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01] 1430 ); 1431 } 1432 1433 #[test] 1434 fn move_sub_const_to_register() { 1435 let mut program = BpfCode::new(); 1436 program 1437 .sub(Source::Imm, Arch::X64) 1438 .set_dst(0x04) 1439 .set_imm(0x00_01_02_03) 1440 .push(); 1441 1442 assert_eq!( 1443 program.into_bytes(), 1444 &[0x17, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00] 1445 ); 1446 } 1447 1448 #[test] 1449 fn move_mul_const_to_register() { 1450 let mut program = BpfCode::new(); 1451 program 1452 .mul(Source::Imm, Arch::X64) 1453 .set_dst(0x05) 1454 .set_imm(0x04_03_02_01) 1455 .push(); 1456 1457 assert_eq!( 1458 program.into_bytes(), 1459 &[0x27, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04] 1460 ); 1461 } 1462 1463 #[test] 1464 fn move_div_constant_to_register() { 1465 let mut program = BpfCode::new(); 1466 program 1467 .div(Source::Imm, Arch::X64) 1468 .set_dst(0x02) 1469 .set_imm(0x00_ff_00_ff) 1470 .push(); 1471 1472 assert_eq!( 1473 program.into_bytes(), 1474 &[0x37, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00] 1475 ); 1476 } 1477 1478 #[test] 1479 fn move_bit_or_const_to_register() { 1480 let mut program = BpfCode::new(); 1481 program 1482 .bit_or(Source::Imm, Arch::X64) 1483 .set_dst(0x02) 1484 .set_imm(0x00_11_00_22) 1485 .push(); 1486 1487 assert_eq!( 1488 program.into_bytes(), 1489 &[0x47, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00] 1490 ); 1491 } 1492 1493 #[test] 1494 fn move_bit_and_const_to_register() { 1495 let mut program = BpfCode::new(); 1496 program 1497 .bit_and(Source::Imm, Arch::X64) 1498 .set_dst(0x02) 1499 .set_imm(0x11_22_33_44) 1500 .push(); 1501 1502 assert_eq!( 1503 program.into_bytes(), 1504 &[0x57, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11] 1505 ); 1506 } 1507 1508 #[test] 1509 fn move_left_shift_const_to_register() { 1510 let mut program = BpfCode::new(); 1511 program 1512 .left_shift(Source::Imm, Arch::X64) 1513 .set_dst(0x01) 1514 .push(); 1515 1516 assert_eq!( 1517 program.into_bytes(), 1518 &[0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1519 ); 1520 } 1521 1522 #[test] 1523 fn move_logical_right_shift_const_to_register() { 1524 let mut program = BpfCode::new(); 1525 program 1526 .right_shift(Source::Imm, Arch::X64) 1527 .set_dst(0x01) 1528 .push(); 1529 1530 assert_eq!( 1531 program.into_bytes(), 1532 &[0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1533 ); 1534 } 1535 1536 #[test] 1537 fn move_negate_register() { 1538 let mut program = BpfCode::new(); 1539 program.negate(Arch::X64).set_dst(0x02).push(); 1540 1541 assert_eq!( 1542 program.into_bytes(), 1543 &[0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1544 ); 1545 } 1546 1547 #[test] 1548 fn move_mod_const_to_register() { 1549 let mut program = BpfCode::new(); 1550 program.modulo(Source::Imm, Arch::X64).set_dst(0x02).push(); 1551 1552 assert_eq!( 1553 program.into_bytes(), 1554 &[0x97, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1555 ); 1556 } 1557 1558 #[test] 1559 fn move_bit_xor_const_to_register() { 1560 let mut program = BpfCode::new(); 1561 program.bit_xor(Source::Imm, Arch::X64).set_dst(0x03).push(); 1562 1563 assert_eq!( 1564 program.into_bytes(), 1565 &[0xa7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1566 ); 1567 } 1568 1569 #[test] 1570 fn move_const_to_register() { 1571 let mut program = BpfCode::new(); 1572 program 1573 .mov(Source::Imm, Arch::X64) 1574 .set_dst(0x01) 1575 .set_imm(0x00_00_00_FF) 1576 .push(); 1577 1578 assert_eq!( 1579 program.into_bytes(), 1580 &[0xb7, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00] 1581 ); 1582 } 1583 1584 #[test] 1585 fn move_signed_right_shift_const_to_register() { 1586 let mut program = BpfCode::new(); 1587 program 1588 .signed_right_shift(Source::Imm, Arch::X64) 1589 .set_dst(0x05) 1590 .push(); 1591 1592 assert_eq!( 1593 program.into_bytes(), 1594 &[0xc7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1595 ); 1596 } 1597 } 1598 1599 #[cfg(test)] 1600 mod register { 1601 use super::super::super::super::*; 1602 1603 #[test] 1604 fn move_and_add_from_register() { 1605 let mut program = BpfCode::new(); 1606 program 1607 .add(Source::Reg, Arch::X64) 1608 .set_dst(0x03) 1609 .set_src(0x02) 1610 .push(); 1611 1612 assert_eq!( 1613 program.into_bytes(), 1614 &[0x0f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1615 ); 1616 } 1617 1618 #[test] 1619 fn move_sub_from_register_to_register() { 1620 let mut program = BpfCode::new(); 1621 program 1622 .sub(Source::Reg, Arch::X64) 1623 .set_dst(0x03) 1624 .set_src(0x04) 1625 .push(); 1626 1627 assert_eq!( 1628 program.into_bytes(), 1629 &[0x1f, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1630 ); 1631 } 1632 1633 #[test] 1634 fn move_mul_from_register_to_register() { 1635 let mut program = BpfCode::new(); 1636 program 1637 .mul(Source::Reg, Arch::X64) 1638 .set_dst(0x04) 1639 .set_src(0x03) 1640 .push(); 1641 1642 assert_eq!( 1643 program.into_bytes(), 1644 &[0x2f, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1645 ); 1646 } 1647 1648 #[test] 1649 fn move_div_from_register_to_register() { 1650 let mut program = BpfCode::new(); 1651 program 1652 .div(Source::Reg, Arch::X64) 1653 .set_dst(0x01) 1654 .set_src(0x00) 1655 .push(); 1656 1657 assert_eq!( 1658 program.into_bytes(), 1659 &[0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1660 ); 1661 } 1662 1663 #[test] 1664 fn move_bit_or_from_register_to_register() { 1665 let mut program = BpfCode::new(); 1666 program 1667 .bit_or(Source::Reg, Arch::X64) 1668 .set_dst(0x03) 1669 .set_src(0x01) 1670 .push(); 1671 1672 assert_eq!( 1673 program.into_bytes(), 1674 &[0x4f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1675 ); 1676 } 1677 1678 #[test] 1679 fn move_bit_and_from_register_to_register() { 1680 let mut program = BpfCode::new(); 1681 program 1682 .bit_and(Source::Reg, Arch::X64) 1683 .set_dst(0x03) 1684 .set_src(0x02) 1685 .push(); 1686 1687 assert_eq!( 1688 program.into_bytes(), 1689 &[0x5f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1690 ); 1691 } 1692 1693 #[test] 1694 fn move_left_shift_from_register_to_register() { 1695 let mut program = BpfCode::new(); 1696 program 1697 .left_shift(Source::Reg, Arch::X64) 1698 .set_dst(0x02) 1699 .set_src(0x03) 1700 .push(); 1701 1702 assert_eq!( 1703 program.into_bytes(), 1704 &[0x6f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1705 ); 1706 } 1707 1708 #[test] 1709 fn move_logical_right_shift_from_register_to_register() { 1710 let mut program = BpfCode::new(); 1711 program 1712 .right_shift(Source::Reg, Arch::X64) 1713 .set_dst(0x02) 1714 .set_src(0x04) 1715 .push(); 1716 1717 assert_eq!( 1718 program.into_bytes(), 1719 &[0x7f, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1720 ); 1721 } 1722 1723 #[test] 1724 fn move_mod_from_register_to_register() { 1725 let mut program = BpfCode::new(); 1726 program 1727 .modulo(Source::Reg, Arch::X64) 1728 .set_dst(0x01) 1729 .set_src(0x02) 1730 .push(); 1731 1732 assert_eq!( 1733 program.into_bytes(), 1734 &[0x9f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1735 ); 1736 } 1737 1738 #[test] 1739 fn move_bit_xor_from_register_to_register() { 1740 let mut program = BpfCode::new(); 1741 program 1742 .bit_xor(Source::Reg, Arch::X64) 1743 .set_dst(0x02) 1744 .set_src(0x04) 1745 .push(); 1746 1747 assert_eq!( 1748 program.into_bytes(), 1749 &[0xaf, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1750 ); 1751 } 1752 1753 #[test] 1754 fn move_from_register_to_another_register() { 1755 let mut program = BpfCode::new(); 1756 program.mov(Source::Reg, Arch::X64).set_src(0x01).push(); 1757 1758 assert_eq!( 1759 program.into_bytes(), 1760 &[0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1761 ); 1762 } 1763 1764 #[test] 1765 fn move_signed_right_shift_from_register_to_register() { 1766 let mut program = BpfCode::new(); 1767 program 1768 .signed_right_shift(Source::Reg, Arch::X64) 1769 .set_dst(0x02) 1770 .set_src(0x03) 1771 .push(); 1772 1773 assert_eq!( 1774 program.into_bytes(), 1775 &[0xcf, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1776 ); 1777 } 1778 } 1779 } 1780 1781 #[cfg(test)] 1782 mod arch_x32 { 1783 #[cfg(test)] 1784 mod immediate { 1785 use super::super::super::super::*; 1786 1787 #[test] 1788 fn move_and_add_const_to_register() { 1789 let mut program = BpfCode::new(); 1790 program 1791 .add(Source::Imm, Arch::X32) 1792 .set_dst(0x02) 1793 .set_imm(0x01_02_03_04) 1794 .push(); 1795 1796 assert_eq!( 1797 program.into_bytes(), 1798 &[0x04, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01] 1799 ); 1800 } 1801 1802 #[test] 1803 fn move_sub_const_to_register() { 1804 let mut program = BpfCode::new(); 1805 program 1806 .sub(Source::Imm, Arch::X32) 1807 .set_dst(0x04) 1808 .set_imm(0x00_01_02_03) 1809 .push(); 1810 1811 assert_eq!( 1812 program.into_bytes(), 1813 &[0x14, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00] 1814 ); 1815 } 1816 1817 #[test] 1818 fn move_mul_const_to_register() { 1819 let mut program = BpfCode::new(); 1820 program 1821 .mul(Source::Imm, Arch::X32) 1822 .set_dst(0x05) 1823 .set_imm(0x04_03_02_01) 1824 .push(); 1825 1826 assert_eq!( 1827 program.into_bytes(), 1828 &[0x24, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04] 1829 ); 1830 } 1831 1832 #[test] 1833 fn move_div_constant_to_register() { 1834 let mut program = BpfCode::new(); 1835 program 1836 .div(Source::Imm, Arch::X32) 1837 .set_dst(0x02) 1838 .set_imm(0x00_ff_00_ff) 1839 .push(); 1840 1841 assert_eq!( 1842 program.into_bytes(), 1843 &[0x34, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00] 1844 ); 1845 } 1846 1847 #[test] 1848 fn move_bit_or_const_to_register() { 1849 let mut program = BpfCode::new(); 1850 program 1851 .bit_or(Source::Imm, Arch::X32) 1852 .set_dst(0x02) 1853 .set_imm(0x00_11_00_22) 1854 .push(); 1855 1856 assert_eq!( 1857 program.into_bytes(), 1858 &[0x44, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00] 1859 ); 1860 } 1861 1862 #[test] 1863 fn move_bit_and_const_to_register() { 1864 let mut program = BpfCode::new(); 1865 program 1866 .bit_and(Source::Imm, Arch::X32) 1867 .set_dst(0x02) 1868 .set_imm(0x11_22_33_44) 1869 .push(); 1870 1871 assert_eq!( 1872 program.into_bytes(), 1873 &[0x54, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11] 1874 ); 1875 } 1876 1877 #[test] 1878 fn move_left_shift_const_to_register() { 1879 let mut program = BpfCode::new(); 1880 program 1881 .left_shift(Source::Imm, Arch::X32) 1882 .set_dst(0x01) 1883 .push(); 1884 1885 assert_eq!( 1886 program.into_bytes(), 1887 &[0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1888 ); 1889 } 1890 1891 #[test] 1892 fn move_logical_right_shift_const_to_register() { 1893 let mut program = BpfCode::new(); 1894 program 1895 .right_shift(Source::Imm, Arch::X32) 1896 .set_dst(0x01) 1897 .push(); 1898 1899 assert_eq!( 1900 program.into_bytes(), 1901 &[0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1902 ); 1903 } 1904 1905 #[test] 1906 fn move_negate_register() { 1907 let mut program = BpfCode::new(); 1908 program.negate(Arch::X32).set_dst(0x02).push(); 1909 1910 assert_eq!( 1911 program.into_bytes(), 1912 &[0x84, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1913 ); 1914 } 1915 1916 #[test] 1917 fn move_mod_const_to_register() { 1918 let mut program = BpfCode::new(); 1919 program.modulo(Source::Imm, Arch::X32).set_dst(0x02).push(); 1920 1921 assert_eq!( 1922 program.into_bytes(), 1923 &[0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1924 ); 1925 } 1926 1927 #[test] 1928 fn move_bit_xor_const_to_register() { 1929 let mut program = BpfCode::new(); 1930 program.bit_xor(Source::Imm, Arch::X32).set_dst(0x03).push(); 1931 1932 assert_eq!( 1933 program.into_bytes(), 1934 &[0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1935 ); 1936 } 1937 1938 #[test] 1939 fn move_const_to_register() { 1940 let mut program = BpfCode::new(); 1941 program 1942 .mov(Source::Imm, Arch::X32) 1943 .set_dst(0x01) 1944 .set_imm(0x00_00_00_FF) 1945 .push(); 1946 1947 assert_eq!( 1948 program.into_bytes(), 1949 &[0xb4, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00] 1950 ); 1951 } 1952 1953 #[test] 1954 fn move_signed_right_shift_const_to_register() { 1955 let mut program = BpfCode::new(); 1956 program 1957 .signed_right_shift(Source::Imm, Arch::X32) 1958 .set_dst(0x05) 1959 .push(); 1960 1961 assert_eq!( 1962 program.into_bytes(), 1963 &[0xc4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1964 ); 1965 } 1966 } 1967 1968 #[cfg(test)] 1969 mod register { 1970 use super::super::super::super::*; 1971 1972 #[test] 1973 fn move_and_add_from_register() { 1974 let mut program = BpfCode::new(); 1975 program 1976 .add(Source::Reg, Arch::X32) 1977 .set_dst(0x03) 1978 .set_src(0x02) 1979 .push(); 1980 1981 assert_eq!( 1982 program.into_bytes(), 1983 &[0x0c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1984 ); 1985 } 1986 1987 #[test] 1988 fn move_sub_from_register_to_register() { 1989 let mut program = BpfCode::new(); 1990 program 1991 .sub(Source::Reg, Arch::X32) 1992 .set_dst(0x03) 1993 .set_src(0x04) 1994 .push(); 1995 1996 assert_eq!( 1997 program.into_bytes(), 1998 &[0x1c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 1999 ); 2000 } 2001 2002 #[test] 2003 fn move_mul_from_register_to_register() { 2004 let mut program = BpfCode::new(); 2005 program 2006 .mul(Source::Reg, Arch::X32) 2007 .set_dst(0x04) 2008 .set_src(0x03) 2009 .push(); 2010 2011 assert_eq!( 2012 program.into_bytes(), 2013 &[0x2c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2014 ); 2015 } 2016 2017 #[test] 2018 fn move_div_from_register_to_register() { 2019 let mut program = BpfCode::new(); 2020 program 2021 .div(Source::Reg, Arch::X32) 2022 .set_dst(0x01) 2023 .set_src(0x00) 2024 .push(); 2025 2026 assert_eq!( 2027 program.into_bytes(), 2028 &[0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2029 ); 2030 } 2031 2032 #[test] 2033 fn move_bit_or_from_register_to_register() { 2034 let mut program = BpfCode::new(); 2035 program 2036 .bit_or(Source::Reg, Arch::X32) 2037 .set_dst(0x03) 2038 .set_src(0x01) 2039 .push(); 2040 2041 assert_eq!( 2042 program.into_bytes(), 2043 &[0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2044 ); 2045 } 2046 2047 #[test] 2048 fn move_bit_and_from_register_to_register() { 2049 let mut program = BpfCode::new(); 2050 program 2051 .bit_and(Source::Reg, Arch::X32) 2052 .set_dst(0x03) 2053 .set_src(0x02) 2054 .push(); 2055 2056 assert_eq!( 2057 program.into_bytes(), 2058 &[0x5c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2059 ); 2060 } 2061 2062 #[test] 2063 fn move_left_shift_from_register_to_register() { 2064 let mut program = BpfCode::new(); 2065 program 2066 .left_shift(Source::Reg, Arch::X32) 2067 .set_dst(0x02) 2068 .set_src(0x03) 2069 .push(); 2070 2071 assert_eq!( 2072 program.into_bytes(), 2073 &[0x6c, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2074 ); 2075 } 2076 2077 #[test] 2078 fn move_logical_right_shift_from_register_to_register() { 2079 let mut program = BpfCode::new(); 2080 program 2081 .right_shift(Source::Reg, Arch::X32) 2082 .set_dst(0x02) 2083 .set_src(0x04) 2084 .push(); 2085 2086 assert_eq!( 2087 program.into_bytes(), 2088 &[0x7c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2089 ); 2090 } 2091 2092 #[test] 2093 fn move_mod_from_register_to_register() { 2094 let mut program = BpfCode::new(); 2095 program 2096 .modulo(Source::Reg, Arch::X32) 2097 .set_dst(0x01) 2098 .set_src(0x02) 2099 .push(); 2100 2101 assert_eq!( 2102 program.into_bytes(), 2103 &[0x9c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2104 ); 2105 } 2106 2107 #[test] 2108 fn move_bit_xor_from_register_to_register() { 2109 let mut program = BpfCode::new(); 2110 program 2111 .bit_xor(Source::Reg, Arch::X32) 2112 .set_dst(0x02) 2113 .set_src(0x04) 2114 .push(); 2115 2116 assert_eq!( 2117 program.into_bytes(), 2118 &[0xac, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2119 ); 2120 } 2121 2122 #[test] 2123 fn move_from_register_to_another_register() { 2124 let mut program = BpfCode::new(); 2125 program 2126 .mov(Source::Reg, Arch::X32) 2127 .set_dst(0x00) 2128 .set_src(0x01) 2129 .push(); 2130 2131 assert_eq!( 2132 program.into_bytes(), 2133 &[0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2134 ); 2135 } 2136 2137 #[test] 2138 fn move_signed_right_shift_from_register_to_register() { 2139 let mut program = BpfCode::new(); 2140 program 2141 .signed_right_shift(Source::Reg, Arch::X32) 2142 .set_dst(0x02) 2143 .set_src(0x03) 2144 .push(); 2145 2146 assert_eq!( 2147 program.into_bytes(), 2148 &[0xcc, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 2149 ); 2150 } 2151 } 2152 } 2153 } 2154 2155 #[cfg(test)] 2156 mod programs { 2157 use super::super::*; 2158 2159 #[test] 2160 fn example_from_assembler() { 2161 let mut program = BpfCode::new(); 2162 program 2163 .add(Source::Imm, Arch::X64) 2164 .set_dst(1) 2165 .set_imm(0x605) 2166 .push() 2167 .mov(Source::Imm, Arch::X64) 2168 .set_dst(2) 2169 .set_imm(0x32) 2170 .push() 2171 .mov(Source::Reg, Arch::X64) 2172 .set_src(0) 2173 .set_dst(1) 2174 .push() 2175 .swap_bytes(Endian::Big) 2176 .set_dst(0) 2177 .set_imm(0x10) 2178 .push() 2179 .negate(Arch::X64) 2180 .set_dst(2) 2181 .push() 2182 .exit() 2183 .push(); 2184 2185 let bytecode = program.into_bytes(); 2186 let ref_prog = &[ 2187 0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 2188 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 2189 0x10, 0x00, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 2190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2191 ]; 2192 // cargo says: "`[{integer}; 48]` cannot be formatted using `{:?}` 2193 // because it doesn't implement `std::fmt::Debug`" 2194 // So let's check in two steps. 2195 assert_eq!(bytecode[..32], ref_prog[..32]); 2196 assert_eq!(bytecode[33..], ref_prog[33..]); 2197 } 2198 } 2199 } 2200