sbpf_common/
decode.rs

1use {
2    crate::{
3        errors::SBPFError,
4        inst_param::{Number, Register},
5        instruction::Instruction,
6        opcode::Opcode,
7        syscalls::SYSCALLS,
8    },
9    either::Either,
10};
11
12// TODO: passing span for error reporting (not sure if it's necessary)
13
14#[inline]
15fn parse_bytes(bytes: &[u8]) -> Result<(Opcode, u8, u8, i16, i32), SBPFError> {
16    let opcode: Opcode = bytes[0].try_into()?;
17    let reg = bytes[1];
18    let dst = reg & 0x0f;
19    let src = reg >> 4;
20    let off = i16::from_le_bytes([bytes[2], bytes[3]]);
21    let imm = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
22    Ok((opcode, dst, src, off, imm))
23}
24
25pub fn decode_load_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
26    assert!(bytes.len() >= 16);
27    let (opcode, dst, src, off, imm_low) = parse_bytes(bytes)?;
28    if src != 0 || off != 0 {
29        return Err(SBPFError::BytecodeError {
30            error: format!(
31                "{} instruction has src: {}, off: {} supposed to be zero",
32                opcode, src, off
33            ),
34            span: 0..16,
35            custom_label: None,
36        });
37    }
38    let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
39    let imm = ((imm_high as i64) << 32) | (imm_low as u32 as i64);
40    Ok(Instruction {
41        opcode,
42        dst: Some(Register { n: dst }),
43        src: None,
44        off: None,
45        imm: Some(Either::Right(Number::Int(imm))),
46        span: 0..16,
47    })
48}
49
50pub fn decode_load_memory(bytes: &[u8]) -> Result<Instruction, SBPFError> {
51    assert!(bytes.len() >= 8);
52    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
53    if imm != 0 {
54        return Err(SBPFError::BytecodeError {
55            error: format!(
56                "{} instruction has imm: {} supposed to be zero",
57                opcode, imm
58            ),
59            span: 0..8,
60            custom_label: None,
61        });
62    }
63    Ok(Instruction {
64        opcode,
65        dst: Some(Register { n: dst }),
66        src: Some(Register { n: src }),
67        off: Some(Either::Right(off)),
68        imm: None,
69        span: 0..8,
70    })
71}
72
73pub fn decode_store_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
74    assert!(bytes.len() >= 8);
75    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
76    if src != 0 {
77        return Err(SBPFError::BytecodeError {
78            error: format!(
79                "{} instruction has src: {} supposed to be zero",
80                opcode, src
81            ),
82            span: 0..8,
83            custom_label: None,
84        });
85    }
86    Ok(Instruction {
87        opcode,
88        dst: Some(Register { n: dst }),
89        src: None,
90        off: Some(Either::Right(off)),
91        imm: Some(Either::Right(Number::Int(imm.into()))),
92        span: 0..8,
93    })
94}
95
96pub fn decode_store_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
97    assert!(bytes.len() >= 8);
98    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
99    if imm != 0 {
100        return Err(SBPFError::BytecodeError {
101            error: format!(
102                "{} instruction has imm: {} supposed to be zero",
103                opcode, imm
104            ),
105            span: 0..8,
106            custom_label: None,
107        });
108    }
109    Ok(Instruction {
110        opcode,
111        dst: Some(Register { n: dst }),
112        src: Some(Register { n: src }),
113        off: Some(Either::Right(off)),
114        imm: None,
115        span: 0..8,
116    })
117}
118
119pub fn decode_binary_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
120    assert!(bytes.len() >= 8);
121    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
122    if src != 0 || off != 0 {
123        return Err(SBPFError::BytecodeError {
124            error: format!(
125                "{} instruction has src: {}, off: {} supposed to be zeros",
126                opcode, src, off
127            ),
128            span: 0..8,
129            custom_label: None,
130        });
131    }
132    Ok(Instruction {
133        opcode,
134        dst: Some(Register { n: dst }),
135        src: None,
136        off: None,
137        imm: Some(Either::Right(Number::Int(imm.into()))),
138        span: 0..8,
139    })
140}
141
142pub fn decode_binary_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
143    assert!(bytes.len() >= 8);
144    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
145    if off != 0 || imm != 0 {
146        return Err(SBPFError::BytecodeError {
147            error: format!(
148                "{} instruction has off: {}, imm: {} supposed to be zeros",
149                opcode, off, imm
150            ),
151            span: 0..8,
152            custom_label: None,
153        });
154    }
155    Ok(Instruction {
156        opcode,
157        dst: Some(Register { n: dst }),
158        src: Some(Register { n: src }),
159        off: None,
160        imm: None,
161        span: 0..8,
162    })
163}
164
165pub fn decode_unary(bytes: &[u8]) -> Result<Instruction, SBPFError> {
166    assert!(bytes.len() >= 8);
167    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
168    if src != 0 || off != 0 || imm != 0 {
169        return Err(SBPFError::BytecodeError {
170            error: format!(
171                "{} instruction has src: {}, off: {}, imm: {} supposed to be zeros",
172                opcode, src, off, imm
173            ),
174            span: 0..8,
175            custom_label: None,
176        });
177    }
178    Ok(Instruction {
179        opcode,
180        dst: Some(Register { n: dst }),
181        src: None,
182        off: None,
183        imm: None,
184        span: 0..8,
185    })
186}
187
188pub fn decode_jump(bytes: &[u8]) -> Result<Instruction, SBPFError> {
189    assert!(bytes.len() >= 8);
190    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
191    if dst != 0 || src != 0 || imm != 0 {
192        return Err(SBPFError::BytecodeError {
193            error: format!(
194                "{} instruction has dst: {}, src: {}, imm: {} supposed to be zeros",
195                opcode, dst, src, imm
196            ),
197            span: 0..8,
198            custom_label: None,
199        });
200    }
201    Ok(Instruction {
202        opcode,
203        dst: None,
204        src: None,
205        off: Some(Either::Right(off)),
206        imm: None,
207        span: 0..8,
208    })
209}
210
211pub fn decode_jump_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
212    assert!(bytes.len() >= 8);
213    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
214    if src != 0 {
215        return Err(SBPFError::BytecodeError {
216            error: format!(
217                "{} instruction has src: {} supposed to be zero",
218                opcode, src
219            ),
220            span: 0..8,
221            custom_label: None,
222        });
223    }
224    Ok(Instruction {
225        opcode,
226        dst: Some(Register { n: dst }),
227        src: None,
228        off: Some(Either::Right(off)),
229        imm: Some(Either::Right(Number::Int(imm.into()))),
230        span: 0..8,
231    })
232}
233
234pub fn decode_jump_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
235    assert!(bytes.len() >= 8);
236    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
237    if imm != 0 {
238        return Err(SBPFError::BytecodeError {
239            error: format!(
240                "{} instruction has imm: {} supposed to be zero",
241                opcode, imm
242            ),
243            span: 0..8,
244            custom_label: None,
245        });
246    }
247    Ok(Instruction {
248        opcode,
249        dst: Some(Register { n: dst }),
250        src: Some(Register { n: src }),
251        off: Some(Either::Right(off)),
252        imm: None,
253        span: 0..8,
254    })
255}
256
257pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
258    assert!(bytes.len() >= 8);
259    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
260    let mut callimm = Some(Either::Right(Number::Int(imm.into())));
261    if let Some(syscall) = SYSCALLS.get(imm as u32) {
262        if dst != 0 || src != 0 || off != 0 {
263            return Err(SBPFError::BytecodeError {
264                error: format!(
265                    "{} instruction has dst: {}, src: {}, off: {} supposed to be zeros",
266                    opcode, dst, src, off
267                ),
268                span: 0..8,
269                custom_label: None,
270            });
271        }
272        callimm = Some(Either::Left(syscall.to_string()));
273    } else if dst != 0 || src != 1 || off != 0 {
274        return Err(SBPFError::BytecodeError {
275            error: format!(
276                "{} instruction has dst: {}, src: {}, off: {} 
277                        supposed to be sixteen and zero",
278                opcode, dst, src, off
279            ),
280            span: 0..8,
281            custom_label: None,
282        });
283    }
284    Ok(Instruction {
285        opcode,
286        dst: None,
287        src: Some(Register { n: src }),
288        off: None,
289        imm: callimm,
290        span: 0..8,
291    })
292}
293
294pub fn decode_call_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
295    assert!(bytes.len() >= 8);
296    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
297    // Handle SBPF Callx normalization
298    let (dst, imm) = if dst == 0 && imm != 0 {
299        (imm as u8, 0)
300    } else {
301        (dst, 0)
302    };
303
304    // TODO: sbpf encodes dst_reg in immediate
305    if src != 0 || off != 0 || imm != 0 {
306        return Err(SBPFError::BytecodeError {
307            error: format!(
308                "{} instruction has src: {}, off: {}, imm: {} supposed to be zeros",
309                opcode, src, off, imm
310            ),
311            span: 0..8,
312            custom_label: None,
313        });
314    }
315    Ok(Instruction {
316        opcode,
317        dst: Some(Register { n: dst }),
318        src: None,
319        off: None,
320        imm: None,
321        span: 0..8,
322    })
323}
324
325pub fn decode_exit(bytes: &[u8]) -> Result<Instruction, SBPFError> {
326    assert!(bytes.len() >= 8);
327    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
328    if dst != 0 || src != 0 || off != 0 || imm != 0 {
329        return Err(SBPFError::BytecodeError {
330            error: format!(
331                "{} instruction dst: {}, src: {}, off: {}, imm: {} supposed to be zero",
332                opcode, dst, src, off, imm
333            ),
334            span: 0..8,
335            custom_label: None,
336        });
337    }
338    Ok(Instruction {
339        opcode,
340        dst: None,
341        src: None,
342        off: None,
343        imm: None,
344        span: 0..8,
345    })
346}
347
348#[cfg(test)]
349mod tests {
350    use {
351        super::*,
352        crate::{syscalls::REGISTERED_SYSCALLS, syscalls_map::murmur3_32},
353    };
354
355    #[test]
356    fn test_decode_load_immediate_valid() {
357        // lddw r1, 0x123456789abcdef0
358        let mut bytes = vec![0x18, 0x01, 0x00, 0x00, 0xf0, 0xde, 0xbc, 0x9a];
359        bytes.extend_from_slice(&[0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12]);
360
361        let result = decode_load_immediate(&bytes).unwrap();
362        assert_eq!(result.opcode, Opcode::Lddw);
363        assert_eq!(result.dst.unwrap().n, 1);
364        assert!(result.src.is_none());
365        assert!(result.off.is_none());
366        assert_eq!(result.span, 0..16);
367    }
368
369    #[test]
370    fn test_decode_load_immediate_error_nonzero_src() {
371        let mut bytes = vec![0x18, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
372        bytes.extend_from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
373
374        let result = decode_load_immediate(&bytes);
375        assert!(result.is_err());
376    }
377
378    #[test]
379    fn test_decode_load_immediate_error_nonzero_off() {
380        let mut bytes = vec![0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
381        bytes.extend_from_slice(&[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
382
383        let result = decode_load_immediate(&bytes);
384        assert!(result.is_err());
385    }
386
387    #[test]
388    fn test_decode_load_memory_valid() {
389        // ldxw r2, [r3+10]
390        let bytes = vec![0x61, 0x32, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
391
392        let result = decode_load_memory(&bytes).unwrap();
393        assert_eq!(result.opcode, Opcode::Ldxw);
394        assert_eq!(result.dst.unwrap().n, 2);
395        assert_eq!(result.src.unwrap().n, 3);
396        assert_eq!(result.span, 0..8);
397    }
398
399    #[test]
400    fn test_decode_load_memory_error_nonzero_imm() {
401        let bytes = vec![0x61, 0x32, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00];
402
403        let result = decode_load_memory(&bytes);
404        assert!(result.is_err());
405    }
406
407    #[test]
408    fn test_decode_store_immediate_valid() {
409        // stw [r1+4], 100
410        let bytes = vec![0x62, 0x01, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00];
411
412        let result = decode_store_immediate(&bytes).unwrap();
413        assert_eq!(result.opcode, Opcode::Stw);
414        assert_eq!(result.dst.unwrap().n, 1);
415        assert!(result.src.is_none());
416        assert_eq!(result.span, 0..8);
417    }
418
419    #[test]
420    fn test_decode_store_immediate_error_nonzero_src() {
421        let bytes = vec![0x62, 0x11, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00];
422
423        let result = decode_store_immediate(&bytes);
424        assert!(result.is_err());
425    }
426
427    #[test]
428    fn test_decode_store_register_valid() {
429        // stxw [r1+4], r2
430        let bytes = vec![0x63, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00];
431
432        let result = decode_store_register(&bytes).unwrap();
433        assert_eq!(result.opcode, Opcode::Stxw);
434        assert_eq!(result.dst.unwrap().n, 1);
435        assert_eq!(result.src.unwrap().n, 2);
436        assert_eq!(result.span, 0..8);
437    }
438
439    #[test]
440    fn test_decode_store_register_error_nonzero_imm() {
441        let bytes = vec![0x63, 0x21, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00];
442
443        let result = decode_store_register(&bytes);
444        assert!(result.is_err());
445    }
446
447    #[test]
448    fn test_decode_binary_immediate_valid() {
449        // add32 r1, 100
450        let bytes = vec![0x04, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00];
451
452        let result = decode_binary_immediate(&bytes).unwrap();
453        assert_eq!(result.opcode, Opcode::Add32Imm);
454        assert_eq!(result.dst.unwrap().n, 1);
455        assert!(result.src.is_none());
456        assert!(result.off.is_none());
457        assert_eq!(result.span, 0..8);
458    }
459
460    #[test]
461    fn test_decode_binary_immediate_error_nonzero_src() {
462        let bytes = vec![0x04, 0x11, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00];
463
464        let result = decode_binary_immediate(&bytes);
465        assert!(result.is_err());
466    }
467
468    #[test]
469    fn test_decode_binary_immediate_error_nonzero_off() {
470        let bytes = vec![0x04, 0x01, 0x01, 0x00, 0x64, 0x00, 0x00, 0x00];
471
472        let result = decode_binary_immediate(&bytes);
473        assert!(result.is_err());
474    }
475
476    #[test]
477    fn test_decode_binary_register_valid() {
478        // add32 r1, r2
479        let bytes = vec![0x0c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
480
481        let result = decode_binary_register(&bytes).unwrap();
482        assert_eq!(result.opcode, Opcode::Add32Reg);
483        assert_eq!(result.dst.unwrap().n, 1);
484        assert_eq!(result.src.unwrap().n, 2);
485        assert!(result.off.is_none());
486        assert!(result.imm.is_none());
487        assert_eq!(result.span, 0..8);
488    }
489
490    #[test]
491    fn test_decode_binary_register_error_nonzero_off() {
492        let bytes = vec![0x0c, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
493
494        let result = decode_binary_register(&bytes);
495        assert!(result.is_err());
496    }
497
498    #[test]
499    fn test_decode_binary_register_error_nonzero_imm() {
500        let bytes = vec![0x0c, 0x21, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
501
502        let result = decode_binary_register(&bytes);
503        assert!(result.is_err());
504    }
505
506    #[test]
507    fn test_decode_unary_valid() {
508        // neg64 r1
509        let bytes = vec![0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
510
511        let result = decode_unary(&bytes).unwrap();
512        assert_eq!(result.opcode, Opcode::Neg64);
513        assert_eq!(result.dst.unwrap().n, 1);
514        assert!(result.src.is_none());
515        assert!(result.off.is_none());
516        assert!(result.imm.is_none());
517        assert_eq!(result.span, 0..8);
518    }
519
520    #[test]
521    fn test_decode_unary_error_nonzero_src() {
522        let bytes = vec![0x87, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
523
524        let result = decode_unary(&bytes);
525        assert!(result.is_err());
526    }
527
528    #[test]
529    fn test_decode_unary_error_nonzero_off() {
530        let bytes = vec![0x87, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
531
532        let result = decode_unary(&bytes);
533        assert!(result.is_err());
534    }
535
536    #[test]
537    fn test_decode_unary_error_nonzero_imm() {
538        let bytes = vec![0x87, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
539
540        let result = decode_unary(&bytes);
541        assert!(result.is_err());
542    }
543
544    #[test]
545    fn test_decode_jump_valid() {
546        // ja +10
547        let bytes = vec![0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
548
549        let result = decode_jump(&bytes).unwrap();
550        assert_eq!(result.opcode, Opcode::Ja);
551        assert!(result.dst.is_none());
552        assert!(result.src.is_none());
553        assert!(result.imm.is_none());
554        assert_eq!(result.span, 0..8);
555    }
556
557    #[test]
558    fn test_decode_jump_error_nonzero_dst() {
559        let bytes = vec![0x05, 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
560
561        let result = decode_jump(&bytes);
562        assert!(result.is_err());
563    }
564
565    #[test]
566    fn test_decode_jump_error_nonzero_src() {
567        let bytes = vec![0x05, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
568
569        let result = decode_jump(&bytes);
570        assert!(result.is_err());
571    }
572
573    #[test]
574    fn test_decode_jump_error_nonzero_imm() {
575        let bytes = vec![0x05, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00];
576
577        let result = decode_jump(&bytes);
578        assert!(result.is_err());
579    }
580
581    #[test]
582    fn test_decode_jump_immediate_valid() {
583        // jeq r1, 100, +10
584        let bytes = vec![0x15, 0x01, 0x0a, 0x00, 0x64, 0x00, 0x00, 0x00];
585
586        let result = decode_jump_immediate(&bytes).unwrap();
587        assert_eq!(result.opcode, Opcode::JeqImm);
588        assert_eq!(result.dst.unwrap().n, 1);
589        assert!(result.src.is_none());
590        assert_eq!(result.span, 0..8);
591    }
592
593    #[test]
594    fn test_decode_jump_immediate_error_nonzero_src() {
595        let bytes = vec![0x15, 0x11, 0x0a, 0x00, 0x64, 0x00, 0x00, 0x00];
596
597        let result = decode_jump_immediate(&bytes);
598        assert!(result.is_err());
599    }
600
601    #[test]
602    fn test_decode_jump_register_valid() {
603        // jeq r1, r2, +10
604        let bytes = vec![0x1d, 0x21, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
605
606        let result = decode_jump_register(&bytes).unwrap();
607        assert_eq!(result.opcode, Opcode::JeqReg);
608        assert_eq!(result.dst.unwrap().n, 1);
609        assert_eq!(result.src.unwrap().n, 2);
610        assert_eq!(result.span, 0..8);
611    }
612
613    #[test]
614    fn test_decode_jump_register_error_nonzero_imm() {
615        let bytes = vec![0x1d, 0x21, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00];
616
617        let result = decode_jump_register(&bytes);
618        assert!(result.is_err());
619    }
620
621    #[test]
622    fn test_decode_call_immediate_valid_regular() {
623        // call 100 (non-syscall) - src must be 1
624        let bytes = vec![0x85, 0x10, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00];
625
626        let result = decode_call_immediate(&bytes).unwrap();
627        assert_eq!(result.opcode, Opcode::Call);
628        assert!(result.dst.is_none());
629        assert_eq!(result.src.unwrap().n, 1);
630        assert_eq!(result.span, 0..8);
631    }
632
633    #[test]
634    fn test_decode_call_immediate_error_invalid_regular() {
635        // Invalid: dst != 0 for non-syscall
636        let bytes = vec![0x85, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00];
637
638        let result = decode_call_immediate(&bytes);
639        assert!(result.is_err());
640    }
641
642    #[test]
643    fn test_decode_call_immediate_valid_syscall() {
644        let syscall_name = REGISTERED_SYSCALLS[0];
645        let syscall_hash = murmur3_32(syscall_name);
646        let hash_bytes = syscall_hash.to_le_bytes();
647
648        // Build call instruction with syscall hash and all zeros for dst, src, off
649        let bytes = vec![
650            0x85,
651            0x00,
652            0x00,
653            0x00,
654            hash_bytes[0],
655            hash_bytes[1],
656            hash_bytes[2],
657            hash_bytes[3],
658        ];
659
660        let result = decode_call_immediate(&bytes).unwrap();
661        assert_eq!(result.opcode, Opcode::Call);
662        assert!(result.dst.is_none());
663        assert_eq!(result.src.unwrap().n, 0);
664    }
665
666    #[test]
667    fn test_decode_call_immediate_syscall_error_nonzero_dst() {
668        let syscall_hash = murmur3_32(REGISTERED_SYSCALLS[0]);
669        let hash_bytes = syscall_hash.to_le_bytes();
670
671        let bytes = vec![
672            0x85,
673            0x01,
674            0x00,
675            0x00,
676            hash_bytes[0],
677            hash_bytes[1],
678            hash_bytes[2],
679            hash_bytes[3],
680        ];
681
682        let result = decode_call_immediate(&bytes);
683        assert!(result.is_err());
684    }
685
686    #[test]
687    fn test_decode_call_immediate_syscall_error_nonzero_src() {
688        let syscall_hash = murmur3_32(REGISTERED_SYSCALLS[0]);
689        let hash_bytes = syscall_hash.to_le_bytes();
690
691        let bytes = vec![
692            0x85,
693            0x10,
694            0x00,
695            0x00,
696            hash_bytes[0],
697            hash_bytes[1],
698            hash_bytes[2],
699            hash_bytes[3],
700        ];
701
702        let result = decode_call_immediate(&bytes);
703        assert!(result.is_err());
704    }
705
706    #[test]
707    fn test_decode_call_immediate_syscall_error_nonzero_off() {
708        let syscall_hash = murmur3_32(REGISTERED_SYSCALLS[0]);
709        let hash_bytes = syscall_hash.to_le_bytes();
710
711        let bytes = vec![
712            0x85,
713            0x00,
714            0x01,
715            0x00,
716            hash_bytes[0],
717            hash_bytes[1],
718            hash_bytes[2],
719            hash_bytes[3],
720        ];
721        let result = decode_call_immediate(&bytes);
722        assert!(result.is_err());
723    }
724
725    #[test]
726    fn test_decode_call_register_valid() {
727        // callx r1
728        let bytes = vec![0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
729
730        let result = decode_call_register(&bytes).unwrap();
731        assert_eq!(result.opcode, Opcode::Callx);
732        assert_eq!(result.dst.unwrap().n, 1);
733        assert!(result.src.is_none());
734        assert!(result.off.is_none());
735        assert!(result.imm.is_none());
736        assert_eq!(result.span, 0..8);
737    }
738
739    #[test]
740    fn test_decode_call_register_normalized() {
741        // callx with dst in imm (sBPF normalization)
742        let bytes = vec![0x8d, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00];
743        let result = decode_call_register(&bytes).unwrap();
744        assert_eq!(result.dst.unwrap().n, 5);
745    }
746
747    #[test]
748    fn test_decode_call_register_error_nonzero_src() {
749        let bytes = vec![0x8d, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
750
751        let result = decode_call_register(&bytes);
752        assert!(result.is_err());
753    }
754
755    #[test]
756    fn test_decode_call_register_error_nonzero_off() {
757        let bytes = vec![0x8d, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
758
759        let result = decode_call_register(&bytes);
760        assert!(result.is_err());
761    }
762
763    #[test]
764    fn test_decode_exit_valid() {
765        // exit
766        let bytes = vec![0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
767
768        let result = decode_exit(&bytes).unwrap();
769        assert_eq!(result.opcode, Opcode::Exit);
770        assert!(result.dst.is_none());
771        assert!(result.src.is_none());
772        assert!(result.off.is_none());
773        assert!(result.imm.is_none());
774        assert_eq!(result.span, 0..8);
775    }
776
777    #[test]
778    fn test_decode_exit_error_nonzero_dst() {
779        let bytes = vec![0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
780
781        let result = decode_exit(&bytes);
782        assert!(result.is_err());
783    }
784
785    #[test]
786    fn test_decode_exit_error_nonzero_src() {
787        let bytes = vec![0x95, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
788
789        let result = decode_exit(&bytes);
790        assert!(result.is_err());
791    }
792
793    #[test]
794    fn test_decode_exit_error_nonzero_off() {
795        let bytes = vec![0x95, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00];
796
797        let result = decode_exit(&bytes);
798        assert!(result.is_err());
799    }
800
801    #[test]
802    fn test_decode_exit_error_nonzero_imm() {
803        let bytes = vec![0x95, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00];
804
805        let result = decode_exit(&bytes);
806        assert!(result.is_err());
807    }
808
809    #[test]
810    fn test_all_load_memory_opcodes() {
811        let opcodes = vec![
812            (0x71, Opcode::Ldxb),
813            (0x69, Opcode::Ldxh),
814            (0x61, Opcode::Ldxw),
815            (0x79, Opcode::Ldxdw),
816        ];
817
818        for (byte, expected_opcode) in opcodes {
819            let bytes = vec![byte, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00];
820            let result = decode_load_memory(&bytes).unwrap();
821            assert_eq!(result.opcode, expected_opcode);
822        }
823    }
824
825    #[test]
826    fn test_all_store_immediate_opcodes() {
827        let opcodes = vec![
828            (0x72, Opcode::Stb),
829            (0x6a, Opcode::Sth),
830            (0x62, Opcode::Stw),
831            (0x7a, Opcode::Stdw),
832        ];
833
834        for (byte, expected_opcode) in opcodes {
835            let bytes = vec![byte, 0x01, 0x04, 0x00, 0x64, 0x00, 0x00, 0x00];
836            let result = decode_store_immediate(&bytes).unwrap();
837            assert_eq!(result.opcode, expected_opcode);
838        }
839    }
840
841    #[test]
842    fn test_all_store_register_opcodes() {
843        let opcodes = vec![
844            (0x73, Opcode::Stxb),
845            (0x6b, Opcode::Stxh),
846            (0x63, Opcode::Stxw),
847            (0x7b, Opcode::Stxdw),
848        ];
849
850        for (byte, expected_opcode) in opcodes {
851            let bytes = vec![byte, 0x21, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00];
852            let result = decode_store_register(&bytes).unwrap();
853            assert_eq!(result.opcode, expected_opcode);
854        }
855    }
856
857    #[test]
858    fn test_decode_alu64_operations() {
859        let ops = vec![
860            (0x07, Opcode::Add64Imm),
861            (0x0f, Opcode::Add64Reg),
862            (0x17, Opcode::Sub64Imm),
863            (0x1f, Opcode::Sub64Reg),
864        ];
865
866        for (byte, expected_opcode) in ops {
867            let mut bytes = vec![byte, 0x01, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00];
868
869            if byte & 0x08 == 0 {
870                // Immediate
871                let result = decode_binary_immediate(&bytes).unwrap();
872                assert_eq!(result.opcode, expected_opcode);
873            } else {
874                // Register
875                bytes[4] = 0x00; // imm must be 0 for reg ops
876                bytes[1] = 0x21; // add src
877                let result = decode_binary_register(&bytes).unwrap();
878                assert_eq!(result.opcode, expected_opcode);
879            }
880        }
881    }
882
883    #[test]
884    fn test_decode_neg32() {
885        let bytes = vec![0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
886
887        let result = decode_unary(&bytes).unwrap();
888        assert_eq!(result.opcode, Opcode::Neg32);
889        assert_eq!(result.dst.unwrap().n, 1);
890    }
891
892    #[test]
893    fn test_decode_various_jump_immediates() {
894        let jumps = vec![
895            (0x15, Opcode::JeqImm),
896            (0x25, Opcode::JgtImm),
897            (0x35, Opcode::JgeImm),
898        ];
899
900        for (byte, expected_opcode) in jumps {
901            let bytes = vec![byte, 0x01, 0x0a, 0x00, 0x64, 0x00, 0x00, 0x00];
902            let result = decode_jump_immediate(&bytes).unwrap();
903            assert_eq!(result.opcode, expected_opcode);
904        }
905    }
906
907    #[test]
908    fn test_decode_various_jump_registers() {
909        let jumps = vec![
910            (0x1d, Opcode::JeqReg),
911            (0x2d, Opcode::JgtReg),
912            (0x3d, Opcode::JgeReg),
913        ];
914
915        for (byte, expected_opcode) in jumps {
916            let bytes = vec![byte, 0x21, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00];
917            let result = decode_jump_register(&bytes).unwrap();
918            assert_eq!(result.opcode, expected_opcode);
919        }
920    }
921}