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