1use {
2 crate::{
3 errors::SBPFError,
4 inst_handler::{OPCODE_TO_HANDLER, OPCODE_TO_TYPE},
5 inst_param::{Number, Register},
6 opcode::{Opcode, OperationType},
7 },
8 core::ops::Range,
9 either::Either,
10 serde::{Deserialize, Serialize},
11};
12
13#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub struct Instruction {
15 pub opcode: Opcode,
16 pub dst: Option<Register>,
17 pub src: Option<Register>,
18 pub off: Option<Either<String, i16>>,
19 pub imm: Option<Either<String, Number>>,
20 pub span: Range<usize>,
21}
22
23impl Instruction {
24 pub fn get_size(&self) -> u64 {
25 match self.opcode {
26 Opcode::Lddw => 16,
27 _ => 8,
28 }
29 }
30
31 fn get_opcode_type(&self) -> OperationType {
32 *OPCODE_TO_TYPE.get(&self.opcode).unwrap()
33 }
34
35 pub fn is_jump(&self) -> bool {
36 matches!(
37 self.get_opcode_type(),
38 OperationType::Jump | OperationType::JumpImmediate | OperationType::JumpRegister
39 )
40 }
41
42 pub fn needs_relocation(&self) -> bool {
43 match self.opcode {
44 Opcode::Call | Opcode::Lddw => {
45 matches!(&self.imm, Some(Either::Left(_identifier)))
46 }
47 _ => false,
48 }
49 }
50
51 pub fn op_imm_bits(&self) -> Result<String, SBPFError> {
53 match &self.imm {
54 Some(Either::Right(Number::Int(imm))) => match *imm {
55 16 => Ok(format!("{}16", self.opcode)),
56 32 => Ok(format!("{}32", self.opcode)),
57 64 => Ok(format!("{}64", self.opcode)),
58 _ => Err(SBPFError::BytecodeError {
59 error: format!(
60 "Invalid immediate value: {:?} for opcode: {:?}",
61 self.imm, self.opcode
62 ),
63 span: self.span.clone(),
64 custom_label: None,
65 }),
66 },
67 _ => Err(SBPFError::BytecodeError {
68 error: format!("Expected immediate value for opcode: {:?}", self.opcode),
69 span: self.span.clone(),
70 custom_label: None,
71 }),
72 }
73 }
74
75 pub fn from_bytes(bytes: &[u8]) -> Result<Self, SBPFError> {
76 let opcode: Opcode = bytes[0].try_into()?;
77 if let Some(handler) = OPCODE_TO_HANDLER.get(&opcode) {
78 (handler.decode)(bytes)
79 } else {
80 Err(SBPFError::BytecodeError {
81 error: format!("no decode handler for opcode {}", opcode),
82 span: 0..1,
83 custom_label: Some("Invalid opcode".to_string()),
84 })
85 }
86 }
87
88 pub fn from_bytes_sbpf_v2(bytes: &[u8]) -> Result<Self, SBPFError> {
89 let mut processed_bytes = bytes.to_vec();
91
92 match processed_bytes[0] {
93 0x8C => processed_bytes[0] = 0x61, 0x8F => processed_bytes[0] = 0x63, 0x2C => processed_bytes[0] = 0x71, 0x3C => processed_bytes[0] = 0x69, 0x9C => processed_bytes[0] = 0x79, 0x27 => processed_bytes[0] = 0x72, 0x2F => processed_bytes[0] = 0x73, 0x37 => processed_bytes[0] = 0x6A, 0x3F => processed_bytes[0] = 0x6B, 0x87 => processed_bytes[0] = 0x62, 0x97 => processed_bytes[0] = 0x7A, 0x9F => processed_bytes[0] = 0x7B, 0x21 => {
109 if let Some(lddw_2) = processed_bytes.get(8)
110 && lddw_2 == &0xf7
111 {
112 processed_bytes[0] = 0x18;
113 processed_bytes[8..12].clone_from_slice(&[0u8; 4]);
114 }
115 }
116 0x8D => processed_bytes[1] >>= 4,
118 _ => (),
120 }
121
122 Self::from_bytes(&processed_bytes)
123 }
124
125 pub fn to_bytes(&self) -> Result<Vec<u8>, SBPFError> {
126 let dst_val = self.dst.as_ref().map(|r| r.n).unwrap_or(0);
127 let src_val = if self.opcode == Opcode::Call {
128 1
129 } else {
130 self.src.as_ref().map(|r| r.n).unwrap_or(0)
131 };
132 let off_val = match &self.off {
133 Some(Either::Left(ident)) => {
134 unreachable!("Identifier '{}' should have been resolved earlier", ident)
135 }
136 Some(Either::Right(off)) => *off,
137 None => 0,
138 };
139 let imm_val = match &self.imm {
140 Some(Either::Left(ident)) => {
141 if self.opcode == Opcode::Call {
142 -1i64 } else {
144 unreachable!("Identifier '{}' should have been resolved earlier", ident)
145 }
146 }
147 Some(Either::Right(Number::Int(imm))) | Some(Either::Right(Number::Addr(imm))) => *imm,
148 None => 0,
149 };
150 let (dst_val, imm_val) = match self.opcode {
152 Opcode::Callx => (0, dst_val as i64), _ => (dst_val, imm_val),
154 };
155
156 let mut b = vec![self.opcode.into(), src_val << 4 | dst_val];
157 b.extend_from_slice(&off_val.to_le_bytes());
158 b.extend_from_slice(&(imm_val as i32).to_le_bytes());
159 if self.opcode == Opcode::Lddw {
160 b.extend_from_slice(&[0; 4]);
161 b.extend_from_slice(&((imm_val >> 32) as i32).to_le_bytes());
162 }
163 Ok(b)
164 }
165
166 pub fn to_asm(&self) -> Result<String, SBPFError> {
167 if let Some(handler) = OPCODE_TO_HANDLER.get(&self.opcode) {
168 match (handler.validate)(self) {
169 Ok(()) => {
170 let mut asm = if self.opcode == Opcode::Le || self.opcode == Opcode::Be {
171 self.op_imm_bits()?
172 } else {
173 format!("{}", self.opcode)
174 };
175 let mut param = vec![];
176
177 fn off_str(off: &Either<String, i16>) -> String {
178 match off {
179 Either::Left(ident) => ident.clone(),
180 Either::Right(offset) => {
181 if offset.is_negative() {
182 offset.to_string()
183 } else {
184 format!("+{}", offset)
185 }
186 }
187 }
188 }
189
190 fn mem_off(r: &Register, off: &Either<String, i16>) -> String {
191 format!("[r{}{}]", r.n, off_str(off))
192 }
193
194 if self.get_opcode_type() == OperationType::LoadMemory {
195 param.push(format!("r{}", self.dst.as_ref().unwrap().n));
196 param.push(mem_off(
197 self.src.as_ref().unwrap(),
198 self.off.as_ref().unwrap(),
199 ));
200 } else if self.get_opcode_type() == OperationType::StoreImmediate {
201 param.push(mem_off(
202 self.dst.as_ref().unwrap(),
203 self.off.as_ref().unwrap(),
204 ));
205 param.push(format!("{}", self.imm.as_ref().unwrap()));
206 } else if self.get_opcode_type() == OperationType::StoreRegister {
207 param.push(mem_off(
208 self.dst.as_ref().unwrap(),
209 self.off.as_ref().unwrap(),
210 ));
211 param.push(format!("r{}", self.src.as_ref().unwrap().n));
212 } else {
213 if let Some(dst) = &self.dst {
214 param.push(format!("r{}", dst.n));
215 }
216 if let Some(src) = &self.src {
217 let is_syscall = self.opcode == Opcode::Call
219 && matches!(&self.imm, Some(Either::Left(_)));
220 if !is_syscall {
221 param.push(format!("r{}", src.n));
222 }
223 }
224 if let Some(imm) = &self.imm
225 && self.opcode != Opcode::Le
226 && self.opcode != Opcode::Be
227 {
228 param.push(format!("{}", imm));
229 }
230 if let Some(off) = &self.off {
231 param.push(off_str(off).to_string());
232 }
233 }
234 if !param.is_empty() {
235 asm.push(' ');
236 asm.push_str(¶m.join(", "));
237 }
238 Ok(asm)
239 }
240 Err(e) => Err(e),
241 }
242 } else {
243 Err(SBPFError::BytecodeError {
244 error: format!("no validate handler for opcode {}", self.opcode),
245 span: self.span.clone(),
246 custom_label: None,
247 })
248 }
249 }
250}
251
252#[cfg(test)]
253mod test {
254 use {
255 crate::{
256 inst_param::{Number, Register},
257 instruction::Instruction,
258 opcode::Opcode,
259 },
260 either::Either,
261 hex_literal::hex,
262 };
263
264 #[test]
265 fn serialize_e2e() {
266 let b = hex!("9700000000000000");
267 let i = Instruction::from_bytes(&b).unwrap();
268 assert_eq!(i.to_bytes().unwrap(), &b);
269 assert_eq!(i.to_asm().unwrap(), "mod64 r0, 0");
270 }
271
272 #[test]
273 fn serialize_e2e_lddw() {
274 let b = hex!("18010000000000000000000000000000");
275 let i = Instruction::from_bytes(&b).unwrap();
276 assert_eq!(i.to_bytes().unwrap(), &b);
277 assert_eq!(i.to_asm().unwrap(), "lddw r1, 0");
278 }
279
280 #[test]
281 fn serialize_e2e_add64_imm() {
282 let b = hex!("0701000000000000");
283 let i = Instruction::from_bytes(&b).unwrap();
284 assert_eq!(i.to_bytes().unwrap(), &b);
285 assert_eq!(i.to_asm().unwrap(), "add64 r1, 0");
286 }
287
288 #[test]
289 fn serialize_e2e_add64_reg() {
290 let b = hex!("0f12000000000000");
291 let i = Instruction::from_bytes(&b).unwrap();
292 assert_eq!(i.to_bytes().unwrap(), &b);
293 assert_eq!(i.to_asm().unwrap(), "add64 r2, r1");
294 }
295
296 #[test]
297 fn serialize_e2e_ja() {
298 let b = hex!("05000a0000000000");
299 let i = Instruction::from_bytes(&b).unwrap();
300 assert_eq!(i.to_bytes().unwrap(), &b);
301 assert_eq!(i.to_asm().unwrap(), "ja +10");
302 }
303
304 #[test]
305 fn serialize_e2e_jeq_imm() {
306 let b = hex!("15030a0001000000");
307 let i = Instruction::from_bytes(&b).unwrap();
308 assert_eq!(i.to_bytes().unwrap(), &b);
309 assert_eq!(i.to_asm().unwrap(), "jeq r3, 1, +10");
310 }
311
312 #[test]
313 fn serialize_e2e_jeq_reg() {
314 let b = hex!("1d210a0000000000");
315 let i = Instruction::from_bytes(&b).unwrap();
316 assert_eq!(i.to_bytes().unwrap(), &b);
317 assert_eq!(i.to_asm().unwrap(), "jeq r1, r2, +10");
318 }
319
320 #[test]
321 fn serialize_e2e_ldxw() {
322 let b = hex!("6112000000000000");
323 let i = Instruction::from_bytes(&b).unwrap();
324 assert_eq!(i.to_bytes().unwrap(), &b);
325 assert_eq!(i.to_asm().unwrap(), "ldxw r2, [r1+0]");
326 }
327
328 #[test]
329 fn serialize_e2e_stxw() {
330 let b = hex!("6312000000000000");
331 let i = Instruction::from_bytes(&b).unwrap();
332 assert_eq!(i.to_bytes().unwrap(), &b);
333 assert_eq!(i.to_asm().unwrap(), "stxw [r2+0], r1");
334 }
335
336 #[test]
337 fn serialize_e2e_stb() {
338 let b = hex!("7200000000000000");
339 let i = Instruction::from_bytes(&b).unwrap();
340 assert_eq!(i.opcode, Opcode::Stb);
341 assert!(i.src.is_none());
342 assert_eq!(i.to_bytes().unwrap(), &b);
343 assert_eq!(i.to_asm().unwrap(), "stb [r0+0], 0");
344 }
345
346 #[test]
347 fn serialize_e2e_sth() {
348 let b = hex!("6a01040034120000");
349 let i = Instruction::from_bytes(&b).unwrap();
350 assert_eq!(i.opcode, Opcode::Sth);
351 assert!(i.src.is_none());
352 assert_eq!(i.to_bytes().unwrap(), &b);
353 assert_eq!(i.to_asm().unwrap(), "sth [r1+4], 4660");
354 }
355
356 #[test]
357 fn serialize_e2e_stw() {
358 let b = hex!("6201080064000000");
359 let i = Instruction::from_bytes(&b).unwrap();
360 assert_eq!(i.opcode, Opcode::Stw);
361 assert!(i.src.is_none());
362 assert_eq!(i.to_bytes().unwrap(), &b);
363 assert_eq!(i.to_asm().unwrap(), "stw [r1+8], 100");
364 }
365
366 #[test]
367 fn serialize_e2e_stdw() {
368 let b = hex!("7a021000efbeadde");
369 let i = Instruction::from_bytes(&b).unwrap();
370 assert_eq!(i.opcode, Opcode::Stdw);
371 assert!(i.src.is_none());
372 assert_eq!(i.to_bytes().unwrap(), &b);
373 assert_eq!(i.to_asm().unwrap(), "stdw [r2+16], -559038737");
374 }
375
376 #[test]
377 fn serialize_e2e_le16() {
378 let b = hex!("d401000010000000");
379 let i = Instruction::from_bytes(&b).unwrap();
380 assert_eq!(i.opcode, Opcode::Le);
381 assert_eq!(i.to_bytes().unwrap(), &b);
382 assert_eq!(i.to_asm().unwrap(), "le16 r1");
383 }
384
385 #[test]
386 fn serialize_e2e_le32() {
387 let b = hex!("d401000020000000");
388 let i = Instruction::from_bytes(&b).unwrap();
389 assert_eq!(i.opcode, Opcode::Le);
390 assert_eq!(i.to_bytes().unwrap(), &b);
391 assert_eq!(i.to_asm().unwrap(), "le32 r1");
392 }
393
394 #[test]
395 fn serialize_e2e_le64() {
396 let b = hex!("d403000040000000");
397 let i = Instruction::from_bytes(&b).unwrap();
398 assert_eq!(i.opcode, Opcode::Le);
399 assert_eq!(i.to_bytes().unwrap(), &b);
400 assert_eq!(i.to_asm().unwrap(), "le64 r3");
401 }
402
403 #[test]
404 fn serialize_e2e_be16() {
405 let b = hex!("dc01000010000000");
406 let i = Instruction::from_bytes(&b).unwrap();
407 assert_eq!(i.opcode, Opcode::Be);
408 assert_eq!(i.to_bytes().unwrap(), &b);
409 assert_eq!(i.to_asm().unwrap(), "be16 r1");
410 }
411
412 #[test]
413 fn serialize_e2e_be32() {
414 let b = hex!("dc02000020000000");
415 let i = Instruction::from_bytes(&b).unwrap();
416 assert_eq!(i.opcode, Opcode::Be);
417 assert_eq!(i.to_bytes().unwrap(), &b);
418 assert_eq!(i.to_asm().unwrap(), "be32 r2");
419 }
420
421 #[test]
422 fn serialize_e2e_be64() {
423 let b = hex!("dc03000040000000");
424 let i = Instruction::from_bytes(&b).unwrap();
425 assert_eq!(i.opcode, Opcode::Be);
426 assert_eq!(i.to_bytes().unwrap(), &b);
427 assert_eq!(i.to_asm().unwrap(), "be64 r3");
428 }
429
430 #[test]
431 fn serialize_e2e_neg64() {
432 let b = hex!("8700000000000000");
433 let i = Instruction::from_bytes(&b).unwrap();
434 assert_eq!(i.to_bytes().unwrap(), &b);
435 assert_eq!(i.to_asm().unwrap(), "neg64 r0");
436 }
437
438 #[test]
439 fn test_instruction_size() {
440 let exit = Instruction::from_bytes(&hex!("9500000000000000")).unwrap();
441 assert_eq!(exit.get_size(), 8);
442
443 let lddw = Instruction::from_bytes(&hex!("18010000000000000000000000000000")).unwrap();
444 assert_eq!(lddw.get_size(), 16);
445 }
446
447 #[test]
448 fn test_is_jump() {
449 let ja = Instruction::from_bytes(&hex!("0500000000000000")).unwrap();
450 assert!(ja.is_jump());
451
452 let jeq_imm = Instruction::from_bytes(&hex!("1502000000000000")).unwrap();
453 assert!(jeq_imm.is_jump());
454
455 let jeq_reg = Instruction::from_bytes(&hex!("1d12000000000000")).unwrap();
456 assert!(jeq_reg.is_jump());
457
458 let exit = Instruction::from_bytes(&hex!("9500000000000000")).unwrap();
459 assert!(!exit.is_jump());
460
461 let add64 = Instruction::from_bytes(&hex!("0701000000000000")).unwrap();
462 assert!(!add64.is_jump());
463 }
464
465 #[test]
466 fn test_invalid_opcode() {
467 let result = Instruction::from_bytes(&hex!("ff00000000000000"));
468 assert!(result.is_err());
469 }
470
471 #[test]
472 fn test_unsupported_opcode() {
473 let add32 = Instruction::from_bytes(&hex!("1300000000000000"));
474 assert!(add32.is_err());
475 }
476
477 #[test]
478 fn test_op_imm_bits_16() {
479 let inst = Instruction {
480 opcode: Opcode::Le,
481 dst: Some(Register { n: 1 }),
482 src: None,
483 off: None,
484 imm: Some(Either::Right(Number::Int(16))),
485 span: 0..8,
486 };
487 assert_eq!(inst.op_imm_bits().unwrap(), "le16");
488 }
489
490 #[test]
491 fn test_op_imm_bits_32() {
492 let inst = Instruction {
493 opcode: Opcode::Le,
494 dst: Some(Register { n: 1 }),
495 src: None,
496 off: None,
497 imm: Some(Either::Right(Number::Int(32))),
498 span: 0..8,
499 };
500 assert_eq!(inst.op_imm_bits().unwrap(), "le32");
501 }
502
503 #[test]
504 fn test_op_imm_bits_64() {
505 let inst = Instruction {
506 opcode: Opcode::Be,
507 dst: Some(Register { n: 1 }),
508 src: None,
509 off: None,
510 imm: Some(Either::Right(Number::Int(64))),
511 span: 0..8,
512 };
513 assert_eq!(inst.op_imm_bits().unwrap(), "be64");
514 }
515
516 #[test]
517 fn test_op_imm_bits_invalid() {
518 let inst = Instruction {
519 opcode: Opcode::Le,
520 dst: Some(Register { n: 1 }),
521 src: None,
522 off: None,
523 imm: Some(Either::Right(Number::Int(8))),
524 span: 0..8,
525 };
526 assert!(inst.op_imm_bits().is_err());
527 }
528
529 #[test]
530 fn test_op_imm_bits_no_imm() {
531 let inst = Instruction {
532 opcode: Opcode::Le,
533 dst: Some(Register { n: 1 }),
534 src: None,
535 off: None,
536 imm: None,
537 span: 0..8,
538 };
539 assert!(inst.op_imm_bits().is_err());
540 }
541
542 #[test]
543 fn test_to_bytes_callx() {
544 let inst = Instruction {
546 opcode: Opcode::Callx,
547 dst: Some(Register { n: 5 }),
548 src: None,
549 off: None,
550 imm: None,
551 span: 0..8,
552 };
553 let bytes = inst.to_bytes().unwrap();
554 assert_eq!(bytes[0], 0x8d);
555 assert_eq!(bytes[4], 5);
556 }
557
558 #[test]
559 fn test_to_bytes_call_with_identifier() {
560 let inst = Instruction {
561 opcode: Opcode::Call,
562 dst: None,
563 src: Some(Register { n: 1 }),
564 off: None,
565 imm: Some(Either::Left("function".to_string())),
566 span: 0..8,
567 };
568 let bytes = inst.to_bytes().unwrap();
569 assert_eq!(
571 i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
572 -1
573 );
574 }
575
576 #[test]
577 fn test_to_asm_with_imm_addr() {
578 let inst = Instruction {
580 opcode: Opcode::Add64Imm,
581 dst: Some(Register { n: 1 }),
582 src: None,
583 off: None,
584 imm: Some(Either::Right(Number::Addr(100))),
585 span: 0..8,
586 };
587 let bytes = inst.to_bytes().unwrap();
588 assert_eq!(bytes[0], 0x07); assert_eq!(
590 i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
591 100
592 );
593 }
594
595 #[test]
596 fn test_from_bytes_sbpf_v2() {
597 let test_cases = vec![
599 (hex!("8c12000000000000"), Opcode::Ldxw, "v2: 0x8C -> ldxw"),
601 (hex!("8f12000000000000"), Opcode::Stxw, "v2: 0x8F -> stxw"),
602 (
604 hex!("2c12000000000000"),
605 Opcode::Ldxb,
606 "v2: 0x2C (mul32 reg) -> ldxb",
607 ),
608 (
609 hex!("3c12000000000000"),
610 Opcode::Ldxh,
611 "v2: 0x3C (div32 reg) -> ldxh",
612 ),
613 (
614 hex!("9c12000000000000"),
615 Opcode::Ldxdw,
616 "v2: 0x9C (mod32 reg) -> ldxdw",
617 ),
618 (
619 hex!("2701040064000000"),
620 Opcode::Stb,
621 "v2: 0x27 (mul64 imm) -> stb",
622 ),
623 (
624 hex!("2f12040000000000"),
625 Opcode::Stxb,
626 "v2: 0x2F (mul64 reg) -> stxb",
627 ),
628 (
629 hex!("3701040064000000"),
630 Opcode::Sth,
631 "v2: 0x37 (div64 imm) -> sth",
632 ),
633 (
634 hex!("3f12040000000000"),
635 Opcode::Stxh,
636 "v2: 0x3F (div64 reg) -> stxh",
637 ),
638 (
639 hex!("8701040064000000"),
640 Opcode::Stw,
641 "v2: 0x87 (neg64) -> stw",
642 ),
643 (
644 hex!("9701040064000000"),
645 Opcode::Stdw,
646 "v2: 0x97 (mod64 imm) -> stdw",
647 ),
648 (
649 hex!("9f12040000000000"),
650 Opcode::Stxdw,
651 "v2: 0x9F (mod64 reg) -> stxdw",
652 ),
653 ];
654
655 for (bytes, expected_opcode, description) in test_cases {
656 let inst = Instruction::from_bytes_sbpf_v2(&bytes).unwrap();
657 assert_eq!(inst.opcode, expected_opcode, "{}", description);
658 }
659
660 let callx_bytes = hex!("8d50000000000000");
662 let callx_inst = Instruction::from_bytes_sbpf_v2(&callx_bytes).unwrap();
663 assert_eq!(callx_inst.opcode, Opcode::Callx);
664 assert_eq!(callx_inst.dst.unwrap().n, 5);
665
666 let mut lddw_bytes = vec![0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
668 lddw_bytes.extend_from_slice(&[0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
669 let lddw_inst = Instruction::from_bytes_sbpf_v2(&lddw_bytes).unwrap();
670 assert_eq!(lddw_inst.opcode, Opcode::Lddw);
671 }
672}