1use crate::{errors::SBPFError, inst_param::Number, instruction::Instruction};
2
3pub fn validate_load_immediate(inst: &Instruction) -> Result<(), SBPFError> {
4 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
5 (Some(_dst), None, None, Some(_imm)) => Ok(()),
6 _ => Err(SBPFError::BytecodeError {
7 error: format!(
8 "{} instruction requires destination register and immediate value",
9 inst.opcode
10 ),
11 span: inst.span.clone(),
12 custom_label: None,
13 }),
14 }
15}
16
17pub fn validate_load_memory(inst: &Instruction) -> Result<(), SBPFError> {
18 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
19 (Some(_dst), Some(_src), Some(_off), None) => Ok(()),
20 _ => Err(SBPFError::BytecodeError {
21 error: format!(
22 "{} instruction requires destination register, source register, and offset",
23 inst.opcode
24 ),
25 span: inst.span.clone(),
26 custom_label: None,
27 }),
28 }
29}
30
31pub fn validate_store_immediate(inst: &Instruction) -> Result<(), SBPFError> {
32 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
33 (Some(_dst), None, Some(_off), Some(_imm)) => Ok(()),
34 _ => Err(SBPFError::BytecodeError {
35 error: format!(
36 "{} instruction requires destination register, offset, and immediate value",
37 inst.opcode
38 ),
39 span: inst.span.clone(),
40 custom_label: None,
41 }),
42 }
43}
44
45pub fn validate_store_register(inst: &Instruction) -> Result<(), SBPFError> {
46 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
47 (Some(_dst), Some(_src), Some(_off), None) => Ok(()),
48 _ => Err(SBPFError::BytecodeError {
49 error: format!(
50 "{} instruction requires destination register, source register, and offset",
51 inst.opcode
52 ),
53 span: inst.span.clone(),
54 custom_label: None,
55 }),
56 }
57}
58
59pub fn validate_unary(inst: &Instruction) -> Result<(), SBPFError> {
60 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
61 (Some(_dst), None, None, None) => Ok(()),
62 _ => Err(SBPFError::BytecodeError {
63 error: format!(
64 "{} instruction requires destination register only",
65 inst.opcode
66 ),
67 span: inst.span.clone(),
68 custom_label: None,
69 }),
70 }
71}
72
73pub fn validate_endian(inst: &Instruction) -> Result<(), SBPFError> {
74 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
75 (Some(_dst), None, None, Some(imm)) => {
76 let valid_bits = matches!(
77 imm,
78 either::Either::Right(Number::Int(bits)) if *bits == 16 || *bits == 32 || *bits == 64
79 );
80
81 if valid_bits {
82 Ok(())
83 } else {
84 Err(SBPFError::BytecodeError {
85 error: format!(
86 "{} instruction requires immediate value of 16, 32, or 64",
87 inst.opcode
88 ),
89 span: inst.span.clone(),
90 custom_label: None,
91 })
92 }
93 }
94 _ => Err(SBPFError::BytecodeError {
95 error: format!(
96 "{} instruction requires destination register and immediate value",
97 inst.opcode
98 ),
99 span: inst.span.clone(),
100 custom_label: None,
101 }),
102 }
103}
104
105pub fn validate_binary_immediate(inst: &Instruction) -> Result<(), SBPFError> {
106 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
107 (Some(_dst), None, None, Some(_imm)) => Ok(()),
108 _ => Err(SBPFError::BytecodeError {
109 error: format!(
110 "{} instruction requires destination register and immediate value",
111 inst.opcode
112 ),
113 span: inst.span.clone(),
114 custom_label: None,
115 }),
116 }
117}
118
119pub fn validate_binary_register(inst: &Instruction) -> Result<(), SBPFError> {
120 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
121 (Some(_dst), Some(_src), None, None) => Ok(()),
122 _ => Err(SBPFError::BytecodeError {
123 error: format!(
124 "{} instruction requires destination register and source register",
125 inst.opcode
126 ),
127 span: inst.span.clone(),
128 custom_label: None,
129 }),
130 }
131}
132
133pub fn validate_jump(inst: &Instruction) -> Result<(), SBPFError> {
134 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
135 (None, None, Some(_off), None) => Ok(()),
136 _ => Err(SBPFError::BytecodeError {
137 error: format!("{} instruction requires offset only", inst.opcode),
138 span: inst.span.clone(),
139 custom_label: None,
140 }),
141 }
142}
143
144pub fn validate_jump_immediate(inst: &Instruction) -> Result<(), SBPFError> {
145 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
146 (Some(_dst), None, Some(_off), Some(_imm)) => Ok(()),
147 _ => Err(SBPFError::BytecodeError {
148 error: format!(
149 "{} instruction requires destination register, offset and immediate value",
150 inst.opcode
151 ),
152 span: inst.span.clone(),
153 custom_label: None,
154 }),
155 }
156}
157
158pub fn validate_jump_register(inst: &Instruction) -> Result<(), SBPFError> {
159 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
160 (Some(_dst), Some(_src), Some(_off), None) => Ok(()),
161 _ => Err(SBPFError::BytecodeError {
162 error: format!(
163 "{} instruction requires destination register, source register, and offset",
164 inst.opcode
165 ),
166 span: inst.span.clone(),
167 custom_label: None,
168 }),
169 }
170}
171
172pub fn validate_call_immediate(inst: &Instruction) -> Result<(), SBPFError> {
173 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
174 (None, Some(_src), None, Some(_imm)) => Ok(()),
175 _ => Err(SBPFError::BytecodeError {
176 error: format!(
177 "{} instruction requires source register and immediate value",
178 inst.opcode
179 ),
180 span: inst.span.clone(),
181 custom_label: None,
182 }),
183 }
184}
185
186pub fn validate_call_register(inst: &Instruction) -> Result<(), SBPFError> {
187 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
188 (Some(_dst), None, None, None) => Ok(()),
189 _ => Err(SBPFError::BytecodeError {
190 error: format!(
191 "{} instruction requires destination register only",
192 inst.opcode
193 ),
194 span: inst.span.clone(),
195 custom_label: None,
196 }),
197 }
198}
199
200pub fn validate_exit(inst: &Instruction) -> Result<(), SBPFError> {
201 match (&inst.dst, &inst.src, &inst.off, &inst.imm) {
202 (None, None, None, None) => Ok(()),
203 _ => Err(SBPFError::BytecodeError {
204 error: format!("{} instruction requires no operands", inst.opcode),
205 span: inst.span.clone(),
206 custom_label: None,
207 }),
208 }
209}
210
211#[cfg(test)]
212mod tests {
213 use {
214 super::*,
215 crate::{
216 inst_param::{Number, Register},
217 instruction::Instruction,
218 opcode::Opcode,
219 },
220 either::Either,
221 };
222
223 #[test]
224 fn test_validate_load_immediate_valid() {
225 let valid_inst = Instruction {
226 opcode: Opcode::Lddw,
227 dst: Some(Register { n: 0 }),
228 src: None,
229 off: None,
230 imm: Some(Either::Right(Number::Int(42))),
231 span: 0..8,
232 };
233 assert!(validate_load_immediate(&valid_inst).is_ok());
234 }
235
236 #[test]
237 fn test_validate_load_immediate_missing_dst() {
238 let inst = Instruction {
239 opcode: Opcode::Lddw,
240 dst: None,
241 src: None,
242 off: None,
243 imm: Some(Either::Right(Number::Int(42))),
244 span: 0..8,
245 };
246 let result = validate_load_immediate(&inst);
247 assert!(result.is_err());
248 if let Err(SBPFError::BytecodeError { error, .. }) = result {
249 assert_eq!(
250 error,
251 format!(
252 "{} instruction requires destination register and immediate value",
253 Opcode::Lddw
254 )
255 );
256 }
257 }
258
259 #[test]
260 fn test_validate_load_immediate_missing_imm() {
261 let inst = Instruction {
262 opcode: Opcode::Lddw,
263 dst: Some(Register { n: 0 }),
264 src: None,
265 off: None,
266 imm: None,
267 span: 0..8,
268 };
269 let result = validate_load_immediate(&inst);
270 assert!(result.is_err());
271 if let Err(SBPFError::BytecodeError { error, .. }) = result {
272 assert_eq!(
273 error,
274 format!(
275 "{} instruction requires destination register and immediate value",
276 Opcode::Lddw
277 )
278 );
279 }
280 }
281
282 #[test]
283 fn test_validate_load_immediate_has_src() {
284 let inst = Instruction {
285 opcode: Opcode::Lddw,
286 dst: Some(Register { n: 0 }),
287 src: Some(Register { n: 1 }),
288 off: None,
289 imm: Some(Either::Right(Number::Int(42))),
290 span: 0..8,
291 };
292 let result = validate_load_immediate(&inst);
293 assert!(result.is_err());
294 if let Err(SBPFError::BytecodeError { error, .. }) = result {
295 assert_eq!(
296 error,
297 format!(
298 "{} instruction requires destination register and immediate value",
299 Opcode::Lddw
300 )
301 );
302 }
303 }
304
305 #[test]
306 fn test_validate_load_immediate_has_offset() {
307 let inst = Instruction {
308 opcode: Opcode::Lddw,
309 dst: Some(Register { n: 0 }),
310 src: None,
311 off: Some(Either::Right(10)),
312 imm: Some(Either::Right(Number::Int(42))),
313 span: 0..8,
314 };
315 let result = validate_load_immediate(&inst);
316 assert!(result.is_err());
317 if let Err(SBPFError::BytecodeError { error, .. }) = result {
318 assert_eq!(
319 error,
320 format!(
321 "{} instruction requires destination register and immediate value",
322 Opcode::Lddw
323 )
324 );
325 }
326 }
327
328 #[test]
329 fn test_validate_load_memory_valid() {
330 let valid_inst = Instruction {
331 opcode: Opcode::Ldxw,
332 dst: Some(Register { n: 0 }),
333 src: Some(Register { n: 1 }),
334 off: Some(Either::Right(8)),
335 imm: None,
336 span: 0..8,
337 };
338 assert!(validate_load_memory(&valid_inst).is_ok());
339 }
340
341 #[test]
342 fn test_validate_load_memory_missing_dst() {
343 let inst = Instruction {
344 opcode: Opcode::Ldxw,
345 dst: None,
346 src: Some(Register { n: 1 }),
347 off: Some(Either::Right(8)),
348 imm: None,
349 span: 0..8,
350 };
351 let result = validate_load_memory(&inst);
352 assert!(result.is_err());
353 if let Err(SBPFError::BytecodeError { error, .. }) = result {
354 assert_eq!(
355 error,
356 format!(
357 "{} instruction requires destination register, source register, and offset",
358 Opcode::Ldxw
359 )
360 );
361 }
362 }
363
364 #[test]
365 fn test_validate_load_memory_has_imm() {
366 let inst = Instruction {
367 opcode: Opcode::Ldxw,
368 dst: Some(Register { n: 0 }),
369 src: Some(Register { n: 1 }),
370 off: Some(Either::Right(8)),
371 imm: Some(Either::Right(Number::Int(42))),
372 span: 0..8,
373 };
374 let result = validate_load_memory(&inst);
375 assert!(result.is_err());
376 if let Err(SBPFError::BytecodeError { error, .. }) = result {
377 assert_eq!(
378 error,
379 format!(
380 "{} instruction requires destination register, source register, and offset",
381 Opcode::Ldxw
382 )
383 );
384 }
385 }
386
387 #[test]
388 fn test_validate_load_memory_missing_src() {
389 let inst = Instruction {
390 opcode: Opcode::Ldxw,
391 dst: Some(Register { n: 0 }),
392 src: None,
393 off: Some(Either::Right(8)),
394 imm: None,
395 span: 0..8,
396 };
397 let result = validate_load_memory(&inst);
398 assert!(result.is_err());
399 if let Err(SBPFError::BytecodeError { error, .. }) = result {
400 assert_eq!(
401 error,
402 format!(
403 "{} instruction requires destination register, source register, and offset",
404 Opcode::Ldxw
405 )
406 );
407 }
408 }
409
410 #[test]
411 fn test_validate_store_immediate_valid() {
412 let valid_inst = Instruction {
413 opcode: Opcode::Stw,
414 dst: Some(Register { n: 0 }),
415 src: None,
416 off: Some(Either::Right(8)),
417 imm: Some(Either::Right(Number::Int(42))),
418 span: 0..8,
419 };
420 assert!(validate_store_immediate(&valid_inst).is_ok());
421 }
422
423 #[test]
424 fn test_validate_store_immediate_missing_imm() {
425 let inst = Instruction {
426 opcode: Opcode::Stw,
427 dst: Some(Register { n: 0 }),
428 src: None,
429 off: Some(Either::Right(8)),
430 imm: None,
431 span: 0..8,
432 };
433 let result = validate_store_immediate(&inst);
434 assert!(result.is_err());
435 if let Err(SBPFError::BytecodeError { error, .. }) = result {
436 assert_eq!(
437 error,
438 format!(
439 "{} instruction requires destination register, offset, and immediate value",
440 Opcode::Stw
441 )
442 );
443 }
444 }
445
446 #[test]
447 fn test_validate_store_immediate_has_src() {
448 let inst = Instruction {
449 opcode: Opcode::Stw,
450 dst: Some(Register { n: 0 }),
451 src: Some(Register { n: 1 }),
452 off: Some(Either::Right(8)),
453 imm: Some(Either::Right(Number::Int(42))),
454 span: 0..8,
455 };
456 let result = validate_store_immediate(&inst);
457 assert!(result.is_err());
458 if let Err(SBPFError::BytecodeError { error, .. }) = result {
459 assert_eq!(
460 error,
461 format!(
462 "{} instruction requires destination register, offset, and immediate value",
463 Opcode::Stw
464 )
465 );
466 }
467 }
468
469 #[test]
470 fn test_validate_store_register_valid() {
471 let valid_inst = Instruction {
472 opcode: Opcode::Stxw,
473 dst: Some(Register { n: 0 }),
474 src: Some(Register { n: 1 }),
475 off: Some(Either::Right(8)),
476 imm: None,
477 span: 0..8,
478 };
479 assert!(validate_store_register(&valid_inst).is_ok());
480 }
481
482 #[test]
483 fn test_validate_store_register_missing_src() {
484 let inst = Instruction {
485 opcode: Opcode::Stxw,
486 dst: Some(Register { n: 0 }),
487 src: None,
488 off: Some(Either::Right(8)),
489 imm: None,
490 span: 0..8,
491 };
492 let result = validate_store_register(&inst);
493 assert!(result.is_err());
494 if let Err(SBPFError::BytecodeError { error, .. }) = result {
495 assert_eq!(
496 error,
497 format!(
498 "{} instruction requires destination register, source register, and offset",
499 Opcode::Stxw
500 )
501 );
502 }
503 }
504
505 #[test]
506 fn test_validate_store_register_has_imm() {
507 let inst = Instruction {
508 opcode: Opcode::Stxw,
509 dst: Some(Register { n: 0 }),
510 src: Some(Register { n: 1 }),
511 off: Some(Either::Right(8)),
512 imm: Some(Either::Right(Number::Int(42))),
513 span: 0..8,
514 };
515 let result = validate_store_register(&inst);
516 assert!(result.is_err());
517 if let Err(SBPFError::BytecodeError { error, .. }) = result {
518 assert_eq!(
519 error,
520 format!(
521 "{} instruction requires destination register, source register, and offset",
522 Opcode::Stxw
523 )
524 );
525 }
526 }
527
528 #[test]
529 fn test_validate_unary_valid() {
530 let valid_inst = Instruction {
531 opcode: Opcode::Neg64,
532 dst: Some(Register { n: 0 }),
533 src: None,
534 off: None,
535 imm: None,
536 span: 0..8,
537 };
538 assert!(validate_unary(&valid_inst).is_ok());
539 }
540
541 #[test]
542 fn test_validate_unary_missing_dst() {
543 let inst = Instruction {
544 opcode: Opcode::Neg64,
545 dst: None,
546 src: None,
547 off: None,
548 imm: None,
549 span: 0..8,
550 };
551 let result = validate_unary(&inst);
552 assert!(result.is_err());
553 if let Err(SBPFError::BytecodeError { error, .. }) = result {
554 assert_eq!(
555 error,
556 format!(
557 "{} instruction requires destination register only",
558 Opcode::Neg64
559 )
560 );
561 }
562 }
563
564 #[test]
565 fn test_validate_unary_has_src() {
566 let inst = Instruction {
567 opcode: Opcode::Neg64,
568 dst: Some(Register { n: 0 }),
569 src: Some(Register { n: 1 }),
570 off: None,
571 imm: None,
572 span: 0..8,
573 };
574 let result = validate_unary(&inst);
575 assert!(result.is_err());
576 if let Err(SBPFError::BytecodeError { error, .. }) = result {
577 assert_eq!(
578 error,
579 format!(
580 "{} instruction requires destination register only",
581 Opcode::Neg64
582 )
583 );
584 }
585 }
586
587 #[test]
588 fn test_validate_unary_has_offset() {
589 let inst = Instruction {
590 opcode: Opcode::Neg64,
591 dst: Some(Register { n: 0 }),
592 src: None,
593 off: Some(Either::Right(10)),
594 imm: None,
595 span: 0..8,
596 };
597 let result = validate_unary(&inst);
598 assert!(result.is_err());
599 if let Err(SBPFError::BytecodeError { error, .. }) = result {
600 assert_eq!(
601 error,
602 format!(
603 "{} instruction requires destination register only",
604 Opcode::Neg64
605 )
606 );
607 }
608 }
609
610 #[test]
611 fn test_validate_unary_has_imm() {
612 let inst = Instruction {
613 opcode: Opcode::Neg64,
614 dst: Some(Register { n: 0 }),
615 src: None,
616 off: None,
617 imm: Some(Either::Right(Number::Int(42))),
618 span: 0..8,
619 };
620 let result = validate_unary(&inst);
621 assert!(result.is_err());
622 if let Err(SBPFError::BytecodeError { error, .. }) = result {
623 assert_eq!(
624 error,
625 format!(
626 "{} instruction requires destination register only",
627 Opcode::Neg64
628 )
629 );
630 }
631 }
632
633 #[test]
634 fn test_validate_endian_valid() {
635 let valid_inst = Instruction {
636 opcode: Opcode::Le,
637 dst: Some(Register { n: 0 }),
638 src: None,
639 off: None,
640 imm: Some(Either::Right(Number::Int(32))),
641 span: 0..8,
642 };
643 assert!(validate_endian(&valid_inst).is_ok());
644 }
645
646 #[test]
647 fn test_validate_endian_invalid_width() {
648 let inst = Instruction {
649 opcode: Opcode::Be,
650 dst: Some(Register { n: 0 }),
651 src: None,
652 off: None,
653 imm: Some(Either::Right(Number::Int(8))),
654 span: 0..8,
655 };
656 let result = validate_endian(&inst);
657 assert!(result.is_err());
658 if let Err(SBPFError::BytecodeError { error, .. }) = result {
659 assert_eq!(
660 error,
661 format!(
662 "{} instruction requires immediate value of 16, 32, or 64",
663 Opcode::Be
664 )
665 );
666 }
667 }
668
669 #[test]
670 fn test_validate_endian_missing_imm() {
671 let inst = Instruction {
672 opcode: Opcode::Le,
673 dst: Some(Register { n: 0 }),
674 src: None,
675 off: None,
676 imm: None,
677 span: 0..8,
678 };
679 let result = validate_endian(&inst);
680 assert!(result.is_err());
681 if let Err(SBPFError::BytecodeError { error, .. }) = result {
682 assert_eq!(
683 error,
684 format!(
685 "{} instruction requires destination register and immediate value",
686 Opcode::Le
687 )
688 );
689 }
690 }
691
692 #[test]
693 fn test_validate_endian_has_src() {
694 let inst = Instruction {
695 opcode: Opcode::Le,
696 dst: Some(Register { n: 0 }),
697 src: Some(Register { n: 1 }),
698 off: None,
699 imm: Some(Either::Right(Number::Int(16))),
700 span: 0..8,
701 };
702 let result = validate_endian(&inst);
703 assert!(result.is_err());
704 if let Err(SBPFError::BytecodeError { error, .. }) = result {
705 assert_eq!(
706 error,
707 format!(
708 "{} instruction requires destination register and immediate value",
709 Opcode::Le
710 )
711 );
712 }
713 }
714
715 #[test]
716 fn test_validate_endian_has_offset() {
717 let inst = Instruction {
718 opcode: Opcode::Be,
719 dst: Some(Register { n: 0 }),
720 src: None,
721 off: Some(Either::Right(10)),
722 imm: Some(Either::Right(Number::Int(64))),
723 span: 0..8,
724 };
725 let result = validate_endian(&inst);
726 assert!(result.is_err());
727 if let Err(SBPFError::BytecodeError { error, .. }) = result {
728 assert_eq!(
729 error,
730 format!(
731 "{} instruction requires destination register and immediate value",
732 Opcode::Be
733 )
734 );
735 }
736 }
737
738 #[test]
739 fn test_validate_binary_immediate_valid() {
740 let valid_inst = Instruction {
741 opcode: Opcode::Add64Imm,
742 dst: Some(Register { n: 0 }),
743 src: None,
744 off: None,
745 imm: Some(Either::Right(Number::Int(42))),
746 span: 0..8,
747 };
748 assert!(validate_binary_immediate(&valid_inst).is_ok());
749 }
750
751 #[test]
752 fn test_validate_binary_immediate_missing_dst() {
753 let inst = Instruction {
754 opcode: Opcode::Add64Imm,
755 dst: None,
756 src: None,
757 off: None,
758 imm: Some(Either::Right(Number::Int(42))),
759 span: 0..8,
760 };
761 let result = validate_binary_immediate(&inst);
762 assert!(result.is_err());
763 if let Err(SBPFError::BytecodeError { error, .. }) = result {
764 assert_eq!(
765 error,
766 format!(
767 "{} instruction requires destination register and immediate value",
768 Opcode::Add64Imm
769 )
770 );
771 }
772 }
773
774 #[test]
775 fn test_validate_binary_immediate_missing_imm() {
776 let inst = Instruction {
777 opcode: Opcode::Add64Imm,
778 dst: Some(Register { n: 0 }),
779 src: None,
780 off: None,
781 imm: None,
782 span: 0..8,
783 };
784 let result = validate_binary_immediate(&inst);
785 assert!(result.is_err());
786 if let Err(SBPFError::BytecodeError { error, .. }) = result {
787 assert_eq!(
788 error,
789 format!(
790 "{} instruction requires destination register and immediate value",
791 Opcode::Add64Imm
792 )
793 );
794 }
795 }
796
797 #[test]
798 fn test_validate_binary_immediate_has_src() {
799 let inst = Instruction {
800 opcode: Opcode::Add64Imm,
801 dst: Some(Register { n: 0 }),
802 src: Some(Register { n: 1 }),
803 off: None,
804 imm: Some(Either::Right(Number::Int(42))),
805 span: 0..8,
806 };
807 let result = validate_binary_immediate(&inst);
808 assert!(result.is_err());
809 if let Err(SBPFError::BytecodeError { error, .. }) = result {
810 assert_eq!(
811 error,
812 format!(
813 "{} instruction requires destination register and immediate value",
814 Opcode::Add64Imm
815 )
816 );
817 }
818 }
819
820 #[test]
821 fn test_validate_binary_immediate_has_offset() {
822 let inst = Instruction {
823 opcode: Opcode::Add64Imm,
824 dst: Some(Register { n: 0 }),
825 src: None,
826 off: Some(Either::Right(10)),
827 imm: Some(Either::Right(Number::Int(16))),
828 span: 0..8,
829 };
830 let result = validate_binary_immediate(&inst);
831 assert!(result.is_err());
832 if let Err(SBPFError::BytecodeError { error, .. }) = result {
833 assert_eq!(
834 error,
835 format!(
836 "{} instruction requires destination register and immediate value",
837 Opcode::Add64Imm
838 )
839 );
840 }
841 }
842
843 #[test]
844 fn test_validate_binary_register_valid() {
845 let valid_inst = Instruction {
846 opcode: Opcode::Add64Reg,
847 dst: Some(Register { n: 0 }),
848 src: Some(Register { n: 1 }),
849 off: None,
850 imm: None,
851 span: 0..8,
852 };
853 assert!(validate_binary_register(&valid_inst).is_ok());
854 }
855
856 #[test]
857 fn test_validate_binary_register_missing_dst() {
858 let inst = Instruction {
859 opcode: Opcode::Add64Reg,
860 dst: None,
861 src: Some(Register { n: 1 }),
862 off: None,
863 imm: None,
864 span: 0..8,
865 };
866 let result = validate_binary_register(&inst);
867 assert!(result.is_err());
868 if let Err(SBPFError::BytecodeError { error, .. }) = result {
869 assert_eq!(
870 error,
871 format!(
872 "{} instruction requires destination register and source register",
873 Opcode::Add64Reg
874 )
875 );
876 }
877 }
878
879 #[test]
880 fn test_validate_binary_register_missing_src() {
881 let inst = Instruction {
882 opcode: Opcode::Add64Reg,
883 dst: Some(Register { n: 0 }),
884 src: None,
885 off: None,
886 imm: None,
887 span: 0..8,
888 };
889 let result = validate_binary_register(&inst);
890 assert!(result.is_err());
891 if let Err(SBPFError::BytecodeError { error, .. }) = result {
892 assert_eq!(
893 error,
894 format!(
895 "{} instruction requires destination register and source register",
896 Opcode::Add64Reg
897 )
898 );
899 }
900 }
901
902 #[test]
903 fn test_validate_binary_register_has_offset() {
904 let inst = Instruction {
905 opcode: Opcode::Add64Reg,
906 dst: Some(Register { n: 0 }),
907 src: Some(Register { n: 1 }),
908 off: Some(Either::Right(10)),
909 imm: None,
910 span: 0..8,
911 };
912 let result = validate_binary_register(&inst);
913 assert!(result.is_err());
914 if let Err(SBPFError::BytecodeError { error, .. }) = result {
915 assert_eq!(
916 error,
917 format!(
918 "{} instruction requires destination register and source register",
919 Opcode::Add64Reg
920 )
921 );
922 }
923 }
924
925 #[test]
926 fn test_validate_binary_register_has_imm() {
927 let inst = Instruction {
928 opcode: Opcode::Add64Reg,
929 dst: Some(Register { n: 0 }),
930 src: Some(Register { n: 1 }),
931 off: None,
932 imm: Some(Either::Right(Number::Int(42))),
933 span: 0..8,
934 };
935 let result = validate_binary_register(&inst);
936 assert!(result.is_err());
937 if let Err(SBPFError::BytecodeError { error, .. }) = result {
938 assert_eq!(
939 error,
940 format!(
941 "{} instruction requires destination register and source register",
942 Opcode::Add64Reg
943 )
944 );
945 }
946 }
947
948 #[test]
949 fn test_validate_jump_valid() {
950 let valid_inst = Instruction {
951 opcode: Opcode::Ja,
952 dst: None,
953 src: None,
954 off: Some(Either::Right(10)),
955 imm: None,
956 span: 0..8,
957 };
958 assert!(validate_jump(&valid_inst).is_ok());
959 }
960
961 #[test]
962 fn test_validate_jump_valid_has_dst() {
963 let inst = Instruction {
964 opcode: Opcode::Ja,
965 dst: Some(Register { n: 0 }),
966 src: None,
967 off: Some(Either::Right(10)),
968 imm: None,
969 span: 0..8,
970 };
971 let result = validate_jump(&inst);
972 assert!(result.is_err());
973 if let Err(SBPFError::BytecodeError { error, .. }) = result {
974 assert_eq!(
975 error,
976 format!("{} instruction requires offset only", Opcode::Ja)
977 );
978 }
979 }
980
981 #[test]
982 fn test_validate_jump_has_src() {
983 let inst = Instruction {
984 opcode: Opcode::Ja,
985 dst: None,
986 src: Some(Register { n: 1 }),
987 off: Some(Either::Right(10)),
988 imm: None,
989 span: 0..8,
990 };
991 let result = validate_jump(&inst);
992 assert!(result.is_err());
993 if let Err(SBPFError::BytecodeError { error, .. }) = result {
994 assert_eq!(
995 error,
996 format!("{} instruction requires offset only", Opcode::Ja)
997 );
998 }
999 }
1000
1001 #[test]
1002 fn test_validate_jump_has_imm() {
1003 let inst = Instruction {
1004 opcode: Opcode::Ja,
1005 dst: None,
1006 src: None,
1007 off: Some(Either::Right(10)),
1008 imm: Some(Either::Right(Number::Int(42))),
1009 span: 0..8,
1010 };
1011 let result = validate_jump(&inst);
1012 assert!(result.is_err());
1013 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1014 assert_eq!(
1015 error,
1016 format!("{} instruction requires offset only", Opcode::Ja)
1017 );
1018 }
1019 }
1020
1021 #[test]
1022 fn test_validate_jump_immediate_valid() {
1023 let valid_inst = Instruction {
1024 opcode: Opcode::JeqImm,
1025 dst: Some(Register { n: 0 }),
1026 src: None,
1027 off: Some(Either::Right(10)),
1028 imm: Some(Either::Right(Number::Int(42))),
1029 span: 0..8,
1030 };
1031 assert!(validate_jump_immediate(&valid_inst).is_ok());
1032 }
1033
1034 #[test]
1035 fn test_validate_jump_immediate_missing_dst() {
1036 let inst = Instruction {
1037 opcode: Opcode::JeqImm,
1038 dst: None,
1039 src: None,
1040 off: Some(Either::Right(10)),
1041 imm: Some(Either::Right(Number::Int(42))),
1042 span: 0..8,
1043 };
1044 let result = validate_jump_immediate(&inst);
1045 assert!(result.is_err());
1046 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1047 assert_eq!(
1048 error,
1049 format!(
1050 "{} instruction requires destination register, offset and immediate value",
1051 Opcode::JeqImm
1052 )
1053 );
1054 }
1055 }
1056
1057 #[test]
1058 fn test_validate_jump_immediate_missing_imm() {
1059 let inst = Instruction {
1060 opcode: Opcode::JeqImm,
1061 dst: Some(Register { n: 0 }),
1062 src: None,
1063 off: Some(Either::Right(10)),
1064 imm: None,
1065 span: 0..8,
1066 };
1067 let result = validate_jump_immediate(&inst);
1068 assert!(result.is_err());
1069 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1070 assert_eq!(
1071 error,
1072 format!(
1073 "{} instruction requires destination register, offset and immediate value",
1074 Opcode::JeqImm
1075 )
1076 );
1077 }
1078 }
1079
1080 #[test]
1081 fn test_validate_jump_register_valid() {
1082 let valid_inst = Instruction {
1083 opcode: Opcode::JeqReg,
1084 dst: Some(Register { n: 0 }),
1085 src: Some(Register { n: 1 }),
1086 off: Some(Either::Right(10)),
1087 imm: None,
1088 span: 0..8,
1089 };
1090 assert!(validate_jump_register(&valid_inst).is_ok());
1091 }
1092
1093 #[test]
1094 fn test_validate_jump_register_missing_dst() {
1095 let inst = Instruction {
1096 opcode: Opcode::JeqReg,
1097 dst: None,
1098 src: Some(Register { n: 1 }),
1099 off: Some(Either::Right(10)),
1100 imm: None,
1101 span: 0..8,
1102 };
1103 let result = validate_jump_register(&inst);
1104 assert!(result.is_err());
1105 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1106 assert_eq!(
1107 error,
1108 format!(
1109 "{} instruction requires destination register, source register, and offset",
1110 Opcode::JeqReg
1111 )
1112 );
1113 }
1114 }
1115
1116 #[test]
1117 fn test_validate_jump_register_missing_src() {
1118 let inst = Instruction {
1119 opcode: Opcode::JeqReg,
1120 dst: Some(Register { n: 0 }),
1121 src: None,
1122 off: Some(Either::Right(10)),
1123 imm: None,
1124 span: 0..8,
1125 };
1126 let result = validate_jump_register(&inst);
1127 assert!(result.is_err());
1128 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1129 assert_eq!(
1130 error,
1131 format!(
1132 "{} instruction requires destination register, source register, and offset",
1133 Opcode::JeqReg
1134 )
1135 );
1136 }
1137 }
1138
1139 #[test]
1140 fn test_validate_jump_register_missing_offset() {
1141 let inst = Instruction {
1142 opcode: Opcode::JeqReg,
1143 dst: Some(Register { n: 0 }),
1144 src: Some(Register { n: 1 }),
1145 off: None,
1146 imm: None,
1147 span: 0..8,
1148 };
1149 let result = validate_jump_register(&inst);
1150 assert!(result.is_err());
1151 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1152 assert_eq!(
1153 error,
1154 format!(
1155 "{} instruction requires destination register, source register, and offset",
1156 Opcode::JeqReg
1157 )
1158 );
1159 }
1160 }
1161
1162 #[test]
1163 fn test_validate_jump_register_has_imm() {
1164 let inst = Instruction {
1165 opcode: Opcode::JeqReg,
1166 dst: Some(Register { n: 0 }),
1167 src: Some(Register { n: 1 }),
1168 off: Some(Either::Right(10)),
1169 imm: Some(Either::Right(Number::Int(42))),
1170 span: 0..8,
1171 };
1172 let result = validate_jump_register(&inst);
1173 assert!(result.is_err());
1174 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1175 assert_eq!(
1176 error,
1177 format!(
1178 "{} instruction requires destination register, source register, and offset",
1179 Opcode::JeqReg
1180 )
1181 );
1182 }
1183 }
1184
1185 #[test]
1186 fn test_validate_call_immediate_valid() {
1187 let valid_inst = Instruction {
1188 opcode: Opcode::Call,
1189 dst: None,
1190 src: Some(Register { n: 1 }),
1191 off: None,
1192 imm: Some(Either::Right(Number::Int(100))),
1193 span: 0..8,
1194 };
1195 assert!(validate_call_immediate(&valid_inst).is_ok());
1196 }
1197
1198 #[test]
1199 fn test_validate_call_immediate_missing_imm() {
1200 let inst = Instruction {
1201 opcode: Opcode::Call,
1202 dst: None,
1203 src: None,
1204 off: None,
1205 imm: None,
1206 span: 0..8,
1207 };
1208 let result = validate_call_immediate(&inst);
1209 assert!(result.is_err());
1210 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1211 assert_eq!(
1212 error,
1213 format!(
1214 "{} instruction requires source register and immediate value",
1215 Opcode::Call
1216 )
1217 );
1218 }
1219 }
1220
1221 #[test]
1222 fn test_validate_call_immediate_has_dst() {
1223 let inst = Instruction {
1224 opcode: Opcode::Call,
1225 dst: Some(Register { n: 0 }),
1226 src: None,
1227 off: None,
1228 imm: Some(Either::Right(Number::Int(100))),
1229 span: 0..8,
1230 };
1231 let result = validate_call_immediate(&inst);
1232 assert!(result.is_err());
1233 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1234 assert_eq!(
1235 error,
1236 format!(
1237 "{} instruction requires source register and immediate value",
1238 Opcode::Call
1239 )
1240 );
1241 }
1242 }
1243
1244 #[test]
1245 fn test_validate_call_immediate_has_offset() {
1246 let inst = Instruction {
1247 opcode: Opcode::Call,
1248 dst: None,
1249 src: None,
1250 off: Some(Either::Right(10)),
1251 imm: Some(Either::Right(Number::Int(100))),
1252 span: 0..8,
1253 };
1254 let result = validate_call_immediate(&inst);
1255 assert!(result.is_err());
1256 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1257 assert_eq!(
1258 error,
1259 format!(
1260 "{} instruction requires source register and immediate value",
1261 Opcode::Call
1262 )
1263 );
1264 }
1265 }
1266
1267 #[test]
1268 fn test_validate_call_register_valid() {
1269 let valid_inst = Instruction {
1270 opcode: Opcode::Callx,
1271 dst: Some(Register { n: 1 }),
1272 src: None,
1273 off: None,
1274 imm: None,
1275 span: 0..8,
1276 };
1277 assert!(validate_call_register(&valid_inst).is_ok());
1278 }
1279
1280 #[test]
1281 fn test_validate_call_register_missing_dst() {
1282 let inst = Instruction {
1283 opcode: Opcode::Callx,
1284 dst: None,
1285 src: None,
1286 off: None,
1287 imm: None,
1288 span: 0..8,
1289 };
1290 let result = validate_call_register(&inst);
1291 assert!(result.is_err());
1292 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1293 assert_eq!(
1294 error,
1295 format!(
1296 "{} instruction requires destination register only",
1297 Opcode::Callx
1298 )
1299 );
1300 }
1301 }
1302
1303 #[test]
1304 fn test_validate_call_register_has_src() {
1305 let inst = Instruction {
1306 opcode: Opcode::Callx,
1307 dst: Some(Register { n: 0 }),
1308 src: Some(Register { n: 1 }),
1309 off: None,
1310 imm: None,
1311 span: 0..8,
1312 };
1313 let result = validate_call_register(&inst);
1314 assert!(result.is_err());
1315 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1316 assert_eq!(
1317 error,
1318 format!(
1319 "{} instruction requires destination register only",
1320 Opcode::Callx
1321 )
1322 );
1323 }
1324 }
1325
1326 #[test]
1327 fn test_validate_call_register_has_offset() {
1328 let inst = Instruction {
1329 opcode: Opcode::Callx,
1330 dst: Some(Register { n: 1 }),
1331 src: None,
1332 off: Some(Either::Right(10)),
1333 imm: None,
1334 span: 0..8,
1335 };
1336 let result = validate_call_register(&inst);
1337 assert!(result.is_err());
1338 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1339 assert_eq!(
1340 error,
1341 format!(
1342 "{} instruction requires destination register only",
1343 Opcode::Callx
1344 )
1345 );
1346 }
1347 }
1348
1349 #[test]
1350 fn test_validate_call_register_has_imm() {
1351 let inst = Instruction {
1352 opcode: Opcode::Callx,
1353 dst: Some(Register { n: 1 }),
1354 src: None,
1355 off: None,
1356 imm: Some(Either::Right(Number::Int(100))),
1357 span: 0..8,
1358 };
1359 let result = validate_call_register(&inst);
1360 assert!(result.is_err());
1361 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1362 assert_eq!(
1363 error,
1364 format!(
1365 "{} instruction requires destination register only",
1366 Opcode::Callx
1367 )
1368 );
1369 }
1370 }
1371
1372 #[test]
1373 fn test_validate_exit_valid() {
1374 let valid_inst = Instruction {
1375 opcode: Opcode::Exit,
1376 dst: None,
1377 src: None,
1378 off: None,
1379 imm: None,
1380 span: 0..8,
1381 };
1382 assert!(validate_exit(&valid_inst).is_ok());
1383 }
1384
1385 #[test]
1386 fn test_validate_exit_has_dst() {
1387 let inst = Instruction {
1388 opcode: Opcode::Exit,
1389 dst: Some(Register { n: 0 }),
1390 src: None,
1391 off: None,
1392 imm: None,
1393 span: 0..8,
1394 };
1395 let result = validate_exit(&inst);
1396 assert!(result.is_err());
1397 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1398 assert_eq!(
1399 error,
1400 format!("{} instruction requires no operands", Opcode::Exit)
1401 );
1402 }
1403 }
1404
1405 #[test]
1406 fn test_validate_exit_has_src() {
1407 let inst = Instruction {
1408 opcode: Opcode::Exit,
1409 dst: None,
1410 src: Some(Register { n: 1 }),
1411 off: None,
1412 imm: None,
1413 span: 0..8,
1414 };
1415 let result = validate_exit(&inst);
1416 assert!(result.is_err());
1417 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1418 assert_eq!(
1419 error,
1420 format!("{} instruction requires no operands", Opcode::Exit)
1421 );
1422 }
1423 }
1424
1425 #[test]
1426 fn test_validate_exit_has_offset() {
1427 let inst = Instruction {
1428 opcode: Opcode::Exit,
1429 dst: None,
1430 src: None,
1431 off: Some(Either::Right(10)),
1432 imm: None,
1433 span: 0..8,
1434 };
1435 let result = validate_exit(&inst);
1436 assert!(result.is_err());
1437 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1438 assert_eq!(
1439 error,
1440 format!("{} instruction requires no operands", Opcode::Exit)
1441 );
1442 }
1443 }
1444
1445 #[test]
1446 fn test_validate_exit_has_imm() {
1447 let inst = Instruction {
1448 opcode: Opcode::Exit,
1449 dst: None,
1450 src: None,
1451 off: None,
1452 imm: Some(Either::Right(Number::Int(0))),
1453 span: 0..8,
1454 };
1455 let result = validate_exit(&inst);
1456 assert!(result.is_err());
1457 if let Err(SBPFError::BytecodeError { error, .. }) = result {
1458 assert_eq!(
1459 error,
1460 format!("{} instruction requires no operands", Opcode::Exit)
1461 );
1462 }
1463 }
1464}