Pārlūkot izejas kodu

refactor: add instruction handler

Claire xyz 3 nedēļas atpakaļ
vecāks
revīzija
b04e64700d

+ 10 - 27
crates/assembler/src/instruction.rs

@@ -2,7 +2,13 @@ use crate::dynsym::RelocationType;
 use crate::lexer::{ImmediateValue, Token};
 use crate::syscall::SYSCALLS;
 use crate::errors::CompileError;
-use sbpf_common::opcode::Opcode;
+
+use sbpf_common::opcode::{
+    Opcode,
+    JUMP_OPS,
+    JUMP_IMM_OPS,
+    JUMP_REG_OPS,
+};
 
 use std::ops::Range;
 
@@ -33,32 +39,9 @@ impl Instruction {
 
     //
     pub fn is_jump(&self) -> bool {
-        matches!(
-            self.opcode,
-            Opcode::Ja
-                | Opcode::JeqImm
-                | Opcode::JgtImm
-                | Opcode::JgeImm
-                | Opcode::JltImm
-                | Opcode::JleImm
-                | Opcode::JsetImm
-                | Opcode::JneImm
-                | Opcode::JsgtImm
-                | Opcode::JsgeImm
-                | Opcode::JsltImm
-                | Opcode::JsleImm
-                | Opcode::JeqReg
-                | Opcode::JgtReg
-                | Opcode::JgeReg
-                | Opcode::JltReg
-                | Opcode::JleReg
-                | Opcode::JsetReg
-                | Opcode::JneReg
-                | Opcode::JsgtReg
-                | Opcode::JsgeReg
-                | Opcode::JsltReg
-                | Opcode::JsleReg
-        )
+        JUMP_OPS.contains(&self.opcode) 
+            || JUMP_IMM_OPS.contains(&self.opcode) 
+            || JUMP_REG_OPS.contains(&self.opcode)
     }
     //
     pub fn get_relocation_info(&self) -> (RelocationType, String) {

+ 1 - 1
crates/common/Cargo.toml

@@ -19,7 +19,7 @@ thiserror = { workspace = true }
 phf = "0.13.1"
 phf_macros = "0.13.1"
 serde = { version = "1.0.228", features = ["derive"] }
-
+once_cell = "1.21.3"
 
 [dev-dependencies]
 hex-literal = "1.0.0"

+ 335 - 0
crates/common/src/decode.rs

@@ -0,0 +1,335 @@
+use crate::errors::SBPFError;
+use crate::instruction::Instruction;
+use crate::inst_param::{
+    Register,
+    Number,
+};
+use crate::opcode::Opcode;
+use crate::syscall::SYSCALLS;
+
+// TODO: passing span for error reporting (not sure if it's necessary)
+
+#[inline]
+fn parse_bytes(bytes: &[u8]) -> Result<(Opcode, u8, u8, i16, i32), SBPFError> {
+    let opcode = Opcode::from_u8(bytes[0]).ok_or(SBPFError::BytecodeError {
+        error: format!("Invalid opcode: {:?}", bytes[0]),
+        span: 0..bytes.len(),
+        custom_label: None,
+    })?;
+    let reg = bytes[1];
+    let dst = reg & 0x0f;
+    let src = reg >> 4;
+    let off = i16::from_le_bytes([bytes[2], bytes[3]]);
+    let imm = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
+    Ok((opcode, dst, src, off, imm))
+}
+
+pub fn decode_load_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 16);
+    let (opcode, dst, src, off, imm_low) = parse_bytes(bytes)?;
+    if src != 0 || off != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {}, off: {} supposed to be zero"
+                    , opcode, src, off
+            ),
+            span: 0..16,
+            custom_label: None,
+        });
+    }
+    let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
+    let imm = ((imm_high as i64) << 32) | (imm_low as u32 as i64);
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: None,
+        imm: Some(Number::Int(imm.into())),
+        span: 0..16,
+    })
+}
+
+pub fn decode_load_memory(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has imm: {} supposed to be zero" , opcode, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: Some(Register { n: src }),
+        off: Some(off),
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_store_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if src != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {} supposed to be zero", opcode, src
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: Some(off),
+        imm: Some(Number::Int(imm.into())),
+        span: 0..8,
+    })
+}
+
+pub fn decode_store_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has imm: {} supposed to be zero", opcode, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: Some(Register { n: src }),
+        off: Some(off),
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_binary_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if src != 0 || off != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {}, off: {} supposed to be zeros"
+                    , opcode, src, off
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: None,
+        imm: Some(Number::Int(imm.into())),
+        span: 0..8,
+    })
+}
+
+pub fn decode_binary_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if off != 0 || imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has off: {}, imm: {} supposed to be zeros"
+                    , opcode, off, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: Some(Register { n: src }),
+        off: None,
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_unary(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if src != 0 || off != 0 || imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {}, off: {}, imm: {} supposed to be zeros"
+                    , opcode, src, off, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: None,
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_jump(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if  dst != 0 || src != 0 || imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has dst: {}, src: {}, imm: {} supposed to be zeros"
+                    , opcode, dst, src, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: None,
+        src: None,
+        off: Some(off),
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_jump_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if src != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {} supposed to be zero", opcode, src
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: Some(off),
+        imm: Some(Number::Int(imm.into())),
+        span: 0..8,
+    })
+}
+
+pub fn decode_jump_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has imm: {} supposed to be zero", opcode, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: Some(Register { n: src }),
+        off: Some(off),
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_call_immediate(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if SYSCALLS.get(&(imm as u32)).is_some() {
+        if dst != 0 || src != 0 || off != 0 {
+            return Err(SBPFError::BytecodeError {
+                error: format!(
+                    "{} instruction has dst: {}, src: {}, off: {} supposed to be zeros"
+                        , opcode, dst, src, off
+                ),
+                span: 0..8,
+                custom_label: None,
+            });
+        }
+    } else {
+        if dst != 0 || src != 1 || off != 0 {
+            return Err(SBPFError::BytecodeError {
+                error: format!(
+                    "{} instruction has dst: {}, src: {}, off: {} 
+                        supposed to be sixteen and zero" , opcode, dst, src, off
+                ),
+                span: 0..8,
+                custom_label: None,
+            });
+        }
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: None,
+        src: None,
+        off: None,
+        imm: Some(Number::Int(imm.into())),
+        span: 0..8,
+    })
+}
+
+pub fn decode_call_register(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    // TODO: sbpf encodes dst_reg in immediate
+    if src != 0 || off != 0 || imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction has src: {}, off: {}, imm: {} supposed to be zeros"
+                    , opcode, src, off, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: Some(Register { n: dst }),
+        src: None,
+        off: None,
+        imm: None,
+        span: 0..8,
+    })
+}
+
+pub fn decode_exit(bytes: &[u8]) -> Result<Instruction, SBPFError> {
+    assert!(bytes.len() >= 8);
+    let (opcode, dst, src, off, imm) = parse_bytes(bytes)?;
+    if dst != 0 || src != 0 || off != 0 || imm != 0 {
+        return Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction dst: {}, src: {}, off: {}, imm: {} supposed to be zero"
+                    , opcode, dst, src, off, imm
+            ),
+            span: 0..8,
+            custom_label: None,
+        });
+    }
+    Ok(Instruction {
+        opcode: opcode,
+        dst: None,
+        src: None,
+        off: None,
+        imm: None,
+        span: 0..8,
+    })
+}

+ 101 - 0
crates/common/src/inst_handler.rs

@@ -0,0 +1,101 @@
+use crate::decode::{
+    decode_load_immediate,
+    decode_load_memory,
+    decode_store_immediate,
+    decode_store_register,
+    decode_binary_immediate,
+    decode_binary_register,
+    decode_unary,
+    decode_jump,
+    decode_jump_immediate,
+    decode_jump_register,
+    decode_call_immediate,
+    decode_call_register,
+    decode_exit,
+};
+use crate::errors::SBPFError;
+use crate::instruction::Instruction;
+use crate::opcode::{
+    Opcode,
+    OperationType,
+    LOAD_IMM_OPS,
+    LOAD_MEMORY_OPS,
+    STORE_IMM_OPS,
+    STORE_REG_OPS,
+    BIN_IMM_OPS,
+    BIN_REG_OPS,
+    UNARY_OPS,
+    JUMP_OPS,
+    JUMP_IMM_OPS,
+    JUMP_REG_OPS,
+    CALL_IMM_OPS,
+    CALL_REG_OPS,
+    EXIT_OPS,
+};
+
+type DecodeFn = fn(&[u8]) -> Result<Instruction, SBPFError>;
+
+pub struct InstructionHandler {
+    pub decode: DecodeFn,
+}
+
+use once_cell::sync::Lazy;
+use std::collections::HashMap;
+
+pub static OPCODE_TO_HANDLER: 
+    Lazy<HashMap<Opcode, InstructionHandler>> = Lazy::new(|| {
+    //
+    let mut map = HashMap::new();
+
+    fn register_group(map: &mut HashMap<Opcode, InstructionHandler>
+                    , ops: &[Opcode]
+                    , decode: DecodeFn) {
+        for &op in ops {
+            map.insert(op, InstructionHandler { decode });
+        }
+    }
+    
+    register_group(&mut map, LOAD_IMM_OPS, decode_load_immediate);
+    register_group(&mut map, LOAD_MEMORY_OPS, decode_load_memory);
+    register_group(&mut map, STORE_IMM_OPS, decode_store_immediate);
+    register_group(&mut map, STORE_REG_OPS, decode_store_register);
+    register_group(&mut map, BIN_IMM_OPS, decode_binary_immediate);
+    register_group(&mut map, BIN_REG_OPS, decode_binary_register);
+    register_group(&mut map, UNARY_OPS, decode_unary);
+    register_group(&mut map, JUMP_OPS, decode_jump);
+    register_group(&mut map, JUMP_IMM_OPS, decode_jump_immediate);
+    register_group(&mut map, JUMP_REG_OPS, decode_jump_register);
+    register_group(&mut map, CALL_IMM_OPS, decode_call_immediate);
+    register_group(&mut map, CALL_REG_OPS, decode_call_register);
+    register_group(&mut map, EXIT_OPS, decode_exit);
+
+    map
+});
+
+pub static OPCODE_TO_TYPE: Lazy<HashMap<Opcode, OperationType>> = Lazy::new(|| {
+    let mut map = HashMap::new();
+
+    fn register_group(map: &mut HashMap<Opcode, OperationType>
+                    , ops: &[Opcode]
+                    , op_type: OperationType) {
+        for &op in ops {
+            map.insert(op, op_type);
+        }
+    }
+    
+    register_group(&mut map, LOAD_IMM_OPS, OperationType::LoadImmediate);
+    register_group(&mut map, LOAD_MEMORY_OPS, OperationType::LoadMemory);
+    register_group(&mut map, STORE_IMM_OPS, OperationType::StoreImmediate);
+    register_group(&mut map, STORE_REG_OPS, OperationType::StoreRegister);
+    register_group(&mut map, BIN_IMM_OPS, OperationType::BinaryImmediate);
+    register_group(&mut map, BIN_REG_OPS, OperationType::BinaryRegister);
+    register_group(&mut map, UNARY_OPS, OperationType::Unary);
+    register_group(&mut map, JUMP_OPS, OperationType::Jump);
+    register_group(&mut map, JUMP_IMM_OPS, OperationType::JumpImmediate);
+    register_group(&mut map, JUMP_REG_OPS, OperationType::JumpRegister);
+    register_group(&mut map, CALL_IMM_OPS, OperationType::CallImmediate);
+    register_group(&mut map, CALL_REG_OPS, OperationType::CallRegister);
+    register_group(&mut map, EXIT_OPS, OperationType::Exit);
+
+    map
+});

+ 82 - 0
crates/common/src/inst_param.rs

@@ -0,0 +1,82 @@
+
+use core::fmt;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
+pub struct Register {
+    pub n: u8,
+}
+
+impl fmt::Display for Register {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "r{}", self.n)
+    }
+}
+
+pub enum OperandValue {
+    Number(Number),
+    Ident(String),
+}
+
+#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
+pub enum Number {
+    Int(i64),
+    Addr(i64),
+}
+
+impl fmt::Display for Number {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Number::Int(i) => write!(f, "{}", i),
+            Number::Addr(a) => write!(f, "{}", a),
+        }
+    }
+}
+
+impl std::ops::Add for Number {
+    type Output = Number;
+    fn add(self, other: Self) -> Number {
+        match (self, other) {
+            (Number::Int(a), Number::Int(b)) => Number::Int(a + b),
+            (Number::Addr(a), Number::Addr(b)) => Number::Addr(a + b),
+            (Number::Int(a), Number::Addr(b)) => Number::Addr(a + b),
+            (Number::Addr(a), Number::Int(b)) => Number::Addr(a + b),
+        }
+    }
+}
+
+impl std::ops::Sub for Number {
+    type Output = Number;
+    fn sub(self, other: Self) -> Number {
+        match (self, other) {
+            (Number::Int(a), Number::Int(b)) => Number::Int(a - b),
+            (Number::Addr(a), Number::Addr(b)) => Number::Addr(a - b),
+            (Number::Int(a), Number::Addr(b)) => Number::Addr(a - b),
+            (Number::Addr(a), Number::Int(b)) => Number::Addr(a - b),
+        }
+    }
+}
+
+impl std::ops::Mul for Number {
+    type Output = Number;
+    fn mul(self, other: Self) -> Number {
+        match (self, other) {
+            (Number::Int(a), Number::Int(b)) => Number::Int(a * b),
+            (Number::Addr(a), Number::Addr(b)) => Number::Addr(a * b),
+            (Number::Int(a), Number::Addr(b)) => Number::Addr(a * b),
+            (Number::Addr(a), Number::Int(b)) => Number::Addr(a * b),
+        }
+    }
+}
+
+impl std::ops::Div for Number {
+    type Output = Number;
+    fn div(self, other: Self) -> Number {
+        match (self, other) {
+            (Number::Int(a), Number::Int(b)) => Number::Int(a / b),
+            (Number::Addr(a), Number::Addr(b)) => Number::Addr(a / b),
+            (Number::Int(a), Number::Addr(b)) => Number::Addr(a / b),
+            (Number::Addr(a), Number::Int(b)) => Number::Addr(a / b),
+        }
+    }
+}

+ 27 - 390
crates/common/src/instruction.rs

@@ -1,36 +1,15 @@
 use crate::errors::SBPFError;
-use crate::opcode::Opcode;
-use crate::syscall::SYSCALLS;
 
-use core::fmt;
-use core::ops::Range;
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub struct Register {
-    pub n: u8,
-}
+use crate::inst_param::{
+    Register,
+    Number
+};
 
-impl fmt::Display for Register {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "r{}", self.n)
-    }
-}
-
-#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
-pub enum Number {
-    Int(i64),
-    Addr(i64),
-}
+use crate::opcode::{Opcode, OperationType};
+use crate::inst_handler::{OPCODE_TO_HANDLER, OPCODE_TO_TYPE};
 
-impl fmt::Display for Number {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Number::Int(i) => write!(f, "{}", i),
-            Number::Addr(a) => write!(f, "{}", a),
-        }
-    }
-}
+use core::ops::Range;
+use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
 pub struct Instruction {
@@ -49,33 +28,17 @@ impl Instruction {
             _ => 8,
         }
     }
-
+    
+    fn get_opcode_type(&self) -> OperationType {
+        *OPCODE_TO_TYPE.get(&self.opcode).unwrap()
+    }
+    
     pub fn is_jump(&self) -> bool {
         matches!(
-            self.opcode,
-            Opcode::Ja
-                | Opcode::JeqImm
-                | Opcode::JgtImm
-                | Opcode::JgeImm
-                | Opcode::JltImm
-                | Opcode::JleImm
-                | Opcode::JsetImm
-                | Opcode::JneImm
-                | Opcode::JsgtImm
-                | Opcode::JsgeImm
-                | Opcode::JsltImm
-                | Opcode::JsleImm
-                | Opcode::JeqReg
-                | Opcode::JgtReg
-                | Opcode::JgeReg
-                | Opcode::JltReg
-                | Opcode::JleReg
-                | Opcode::JsetReg
-                | Opcode::JneReg
-                | Opcode::JsgtReg
-                | Opcode::JsgeReg
-                | Opcode::JsltReg
-                | Opcode::JsleReg
+            self.get_opcode_type(),
+            OperationType::Jump 
+                | OperationType::JumpImmediate 
+                | OperationType::JumpRegister
         )
     }
 
@@ -105,7 +68,7 @@ impl Instruction {
             None => format!("[r0{}]", self.off_str()),
         }
     }
-
+    // only used for be/le
     pub fn op_imm_bits(&self) -> Result<String, SBPFError> {
         match &self.imm {
             Some(Number::Int(imm)) => match *imm {
@@ -130,342 +93,16 @@ impl Instruction {
     }
 
     pub fn from_bytes(bytes: &[u8]) -> Result<Self, SBPFError> {
-        let span = 0..bytes.len();
-
-        let opcode = Opcode::from_u8(bytes[0]).ok_or(SBPFError::BytecodeError {
-            error: format!("Invalid opcode: {:?}", bytes[0]),
-            span: span.clone(),
-            custom_label: None,
-        })?;
-        let reg = bytes[1];
-        let src = reg >> 4;
-        let dst = reg & 0x0f;
-        let off = i16::from_le_bytes([bytes[2], bytes[3]]);
-        let imm = match opcode {
-            Opcode::Lddw => {
-                let imm_low = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
-                let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
-
-                ((imm_high as i64) << 32) | (imm_low as u32 as i64)
-            }
-            _ => i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as i64,
-        };
-
-        let mut out_dst: Option<Register> = None;
-        let mut out_src: Option<Register> = None;
-        let mut out_off: Option<i16> = None;
-        let mut out_imm: Option<Number> = None;
-
-        match opcode {
-            Opcode::Lddw => {
-                if src != 0 || off != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Lddw instruction expects src and off to be 0, but got src: {}, off: {}",
-                            src, off
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_imm = Some(Number::Int(imm));
-            }
-
-            Opcode::Call => {
-                if SYSCALLS.get(&(imm as u32)).is_some() {
-                    if reg != 0 || off != 0 {
-                        return Err(SBPFError::BytecodeError {
-                            error: format!(
-                                "Call instruction with syscall expects reg and off to be 0, but got reg: {}, off: {}",
-                                reg, off
-                            ),
-                            span: span.clone(),
-                            custom_label: None,
-                        });
-                    }
-                    out_imm = Some(Number::Int(imm));
-                } else {
-                    if reg != 16 || off != 0 {
-                        return Err(SBPFError::BytecodeError {
-                            error: format!(
-                                "Call instruction with immediate expects reg to be 16 and off to be 0, but got reg: {}, off: {}",
-                                reg, off
-                            ),
-                            span: span.clone(),
-                            custom_label: None,
-                        });
-                    }
-                    out_imm = Some(Number::Int(imm));
-                }
-            }
-
-            Opcode::Callx => {
-                if src != 0 || off != 0 || imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Callx instruction expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}",
-                            src, off, imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                // callx destination register is encoded in the dst field
-                out_dst = Some(Register { n: dst });
-            }
-
-            Opcode::Ja => {
-                if reg != 0 || imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Ja instruction expects reg and imm to be 0, but got reg: {}, imm: {}",
-                            reg, imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_off = Some(off);
-            }
-
-            Opcode::JeqImm
-            | Opcode::JgtImm
-            | Opcode::JgeImm
-            | Opcode::JltImm
-            | Opcode::JleImm
-            | Opcode::JsetImm
-            | Opcode::JneImm
-            | Opcode::JsgtImm
-            | Opcode::JsgeImm
-            | Opcode::JsltImm
-            | Opcode::JsleImm => {
-                if src != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Jump instruction with immediate expects src to be 0, but got src: {}",
-                            src
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_imm = Some(Number::Int(imm));
-                out_off = Some(off);
-            }
-
-            Opcode::JeqReg
-            | Opcode::JgtReg
-            | Opcode::JgeReg
-            | Opcode::JltReg
-            | Opcode::JleReg
-            | Opcode::JsetReg
-            | Opcode::JneReg
-            | Opcode::JsgtReg
-            | Opcode::JsgeReg
-            | Opcode::JsltReg
-            | Opcode::JsleReg => {
-                if imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Jump instruction with register expects imm to be 0, but got imm: {}",
-                            imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_src = Some(Register { n: src });
-                out_off = Some(off);
-            }
-
-            // Arithmetic instructions with immediate values
-            Opcode::Add32Imm
-            | Opcode::Sub32Imm
-            | Opcode::Mul32Imm
-            | Opcode::Div32Imm
-            | Opcode::Or32Imm
-            | Opcode::And32Imm
-            | Opcode::Lsh32Imm
-            | Opcode::Rsh32Imm
-            | Opcode::Mod32Imm
-            | Opcode::Xor32Imm
-            | Opcode::Mov32Imm
-            | Opcode::Arsh32Imm
-            | Opcode::Lmul32Imm
-            | Opcode::Udiv32Imm
-            | Opcode::Urem32Imm
-            | Opcode::Sdiv32Imm
-            | Opcode::Srem32Imm
-            | Opcode::Add64Imm
-            | Opcode::Sub64Imm
-            | Opcode::Mul64Imm
-            | Opcode::Div64Imm
-            | Opcode::Or64Imm
-            | Opcode::And64Imm
-            | Opcode::Lsh64Imm
-            | Opcode::Rsh64Imm
-            | Opcode::Mod64Imm
-            | Opcode::Xor64Imm
-            | Opcode::Mov64Imm
-            | Opcode::Arsh64Imm
-            | Opcode::Hor64Imm
-            | Opcode::Lmul64Imm
-            | Opcode::Uhmul64Imm
-            | Opcode::Udiv64Imm
-            | Opcode::Urem64Imm
-            | Opcode::Shmul64Imm
-            | Opcode::Sdiv64Imm
-            | Opcode::Srem64Imm
-            | Opcode::Be
-            | Opcode::Le => {
-                if src != 0 || off != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Arithmetic instruction with immediate expects src and off to be 0, but got src: {}, off: {}",
-                            src, off
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_imm = Some(Number::Int(imm));
-            }
-
-            // Arithmetic instructions with register operands
-            Opcode::Add32Reg
-            | Opcode::Sub32Reg
-            | Opcode::Mul32Reg
-            | Opcode::Div32Reg
-            | Opcode::Or32Reg
-            | Opcode::And32Reg
-            | Opcode::Lsh32Reg
-            | Opcode::Rsh32Reg
-            | Opcode::Mod32Reg
-            | Opcode::Xor32Reg
-            | Opcode::Mov32Reg
-            | Opcode::Arsh32Reg
-            | Opcode::Lmul32Reg
-            | Opcode::Udiv32Reg
-            | Opcode::Urem32Reg
-            | Opcode::Sdiv32Reg
-            | Opcode::Srem32Reg
-            | Opcode::Add64Reg
-            | Opcode::Sub64Reg
-            | Opcode::Mul64Reg
-            | Opcode::Div64Reg
-            | Opcode::Or64Reg
-            | Opcode::And64Reg
-            | Opcode::Lsh64Reg
-            | Opcode::Rsh64Reg
-            | Opcode::Mod64Reg
-            | Opcode::Xor64Reg
-            | Opcode::Mov64Reg
-            | Opcode::Arsh64Reg
-            | Opcode::Lmul64Reg
-            | Opcode::Uhmul64Reg
-            | Opcode::Udiv64Reg
-            | Opcode::Urem64Reg
-            | Opcode::Shmul64Reg
-            | Opcode::Sdiv64Reg
-            | Opcode::Srem64Reg => {
-                if off != 0 || imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Arithmetic instruction with register expects off and imm to be 0, but got off: {}, imm: {}",
-                            off, imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_src = Some(Register { n: src });
-            }
-
-            Opcode::Ldxw | Opcode::Ldxh | Opcode::Ldxb | Opcode::Ldxdw => {
-                if imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Load instruction expects imm to be 0, but got imm: {}",
-                            imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_src = Some(Register { n: src });
-                out_off = Some(off);
-            }
-
-            Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
-                if src != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Store instruction expects src to be 0, but got src: {}",
-                            src
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_off = Some(off);
-                out_imm = Some(Number::Int(imm));
-            }
-
-            Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
-                if imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Store instruction with register expects imm to be 0, but got imm: {}",
-                            imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-                out_src = Some(Register { n: src });
-                out_off = Some(off);
-            }
-
-            // Unary operations
-            Opcode::Neg32 | Opcode::Neg64 | Opcode::Exit => {
-                if src != 0 || off != 0 || imm != 0 {
-                    return Err(SBPFError::BytecodeError {
-                        error: format!(
-                            "Unary operation expects src, off, and imm to be 0, but got src: {}, off: {}, imm: {}",
-                            src, off, imm
-                        ),
-                        span: span.clone(),
-                        custom_label: None,
-                    });
-                }
-                out_dst = Some(Register { n: dst });
-            }
-
-            _ => {
-                return Err(SBPFError::BytecodeError {
-                    error: format!("Unsupported opcode: {:?}", opcode),
-                    span: span.clone(),
-                    custom_label: None,
-                });
-            }
+        let opcode = Opcode::from_u8(bytes[0]).unwrap();
+        if let Some(handler) = OPCODE_TO_HANDLER.get(&opcode) {
+            (handler.decode)(bytes)
+        } else {
+            Err(SBPFError::BytecodeError {
+                error: format!("no decode handler for opcode {}", opcode),
+                span: 0..1,
+                custom_label: Some("Invalid opcode".to_string()),
+            })
         }
-
-        Ok(Instruction {
-            opcode,
-            dst: out_dst,
-            src: out_src,
-            off: out_off,
-            imm: out_imm,
-            span,
-        })
     }
 
     pub fn to_bytes(&self) -> Vec<u8> {

+ 3 - 0
crates/common/src/lib.rs

@@ -1,4 +1,7 @@
+pub mod decode;
 pub mod errors;
+pub mod inst_handler;
+pub mod inst_param;
 pub mod instruction;
 pub mod opcode;
 pub mod syscall;

+ 147 - 1
crates/common/src/opcode.rs

@@ -4,7 +4,153 @@ use core::str::FromStr;
 use num_derive::FromPrimitive;
 use serde::{Deserialize, Serialize};
 
-#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive, Serialize, Deserialize)]
+#[derive(Debug, Clone, Copy)]
+pub enum OperationType {
+    LoadImmediate,
+    LoadMemory,
+    StoreImmediate,
+    StoreRegister,
+    BinaryImmediate,
+    BinaryRegister,
+    Unary,
+    Jump,
+    JumpImmediate,
+    JumpRegister,
+    CallImmediate,
+    CallRegister,
+    Exit,
+}
+
+pub const LOAD_IMM_OPS: &[Opcode] = &[Opcode::Lddw];    // OperationType::LoadImmediate
+
+pub const LOAD_MEMORY_OPS: &[Opcode] = &[Opcode::Ldxb   // OperationType::LoadMemory
+                                , Opcode::Ldxh
+                                , Opcode::Ldxw
+                                , Opcode::Ldxdw];
+
+pub const STORE_IMM_OPS: &[Opcode] = &[Opcode::Stb      // OperationType::StoreImmediate
+                                , Opcode::Sth
+                                , Opcode::Stw
+                                , Opcode::Stdw]; 
+
+pub const STORE_REG_OPS: &[Opcode] = &[Opcode::Stxb     // OperationType::StoreRegister
+                                , Opcode::Stxh
+                                , Opcode::Stxw
+                                , Opcode::Stxdw];
+
+pub const BIN_IMM_OPS: &[Opcode] = &[Opcode::Add32Imm   // OperationType::BinaryImmediate
+                                , Opcode::Sub32Imm
+                                , Opcode::Mul32Imm
+                                , Opcode::Div32Imm
+                                , Opcode::Or32Imm
+                                , Opcode::And32Imm
+                                , Opcode::Lsh32Imm
+                                , Opcode::Rsh32Imm
+                                , Opcode::Mod32Imm
+                                , Opcode::Xor32Imm
+                                , Opcode::Mov32Imm
+                                , Opcode::Arsh32Imm
+                                , Opcode::Lmul32Imm
+                                , Opcode::Udiv32Imm
+                                , Opcode::Urem32Imm
+                                , Opcode::Sdiv32Imm
+                                , Opcode::Srem32Imm
+                                , Opcode::Le
+                                , Opcode::Be
+                                , Opcode::Add64Imm
+                                , Opcode::Sub64Imm
+                                , Opcode::Mul64Imm
+                                , Opcode::Div64Imm
+                                , Opcode::Or64Imm
+                                , Opcode::And64Imm
+                                , Opcode::Lsh64Imm
+                                , Opcode::Rsh64Imm
+                                , Opcode::Mod64Imm
+                                , Opcode::Xor64Imm
+                                , Opcode::Mov64Imm
+                                , Opcode::Arsh64Imm
+                                , Opcode::Hor64Imm
+                                , Opcode::Lmul64Imm
+                                , Opcode::Uhmul64Imm
+                                , Opcode::Udiv64Imm
+                                , Opcode::Urem64Imm
+                                , Opcode::Shmul64Imm
+                                , Opcode::Sdiv64Imm
+                                , Opcode::Srem64Imm];
+
+pub const BIN_REG_OPS: &[Opcode] = &[Opcode::Add32Reg   // OperationType::BinaryRegister
+                                , Opcode::Sub32Reg
+                                , Opcode::Mul32Reg
+                                , Opcode::Div32Reg
+                                , Opcode::Or32Reg
+                                , Opcode::And32Reg
+                                , Opcode::Lsh32Reg
+                                , Opcode::Rsh32Reg
+                                , Opcode::Mod32Reg
+                                , Opcode::Xor32Reg
+                                , Opcode::Mov32Reg
+                                , Opcode::Arsh32Reg
+                                , Opcode::Lmul32Reg
+                                , Opcode::Udiv32Reg 
+                                , Opcode::Urem32Reg
+                                , Opcode::Sdiv32Reg
+                                , Opcode::Srem32Reg
+                                , Opcode::Add64Reg
+                                , Opcode::Sub64Reg
+                                , Opcode::Mul64Reg
+                                , Opcode::Div64Reg
+                                , Opcode::Or64Reg
+                                , Opcode::And64Reg
+                                , Opcode::Lsh64Reg
+                                , Opcode::Rsh64Reg
+                                , Opcode::Mod64Reg
+                                , Opcode::Xor64Reg
+                                , Opcode::Mov64Reg
+                                , Opcode::Arsh64Reg
+                                , Opcode::Lmul64Reg
+                                , Opcode::Uhmul64Reg
+                                , Opcode::Udiv64Reg
+                                , Opcode::Urem64Reg
+                                , Opcode::Shmul64Reg
+                                , Opcode::Sdiv64Reg
+                                , Opcode::Srem64Reg];
+
+pub const UNARY_OPS: &[Opcode] = &[Opcode::Neg32        // OperationType::Unary
+                                , Opcode::Neg64];
+
+pub const JUMP_OPS: &[Opcode] = &[Opcode::Ja];          // OperationType::Jump
+
+pub const JUMP_IMM_OPS: &[Opcode] = &[Opcode::JeqImm    // OperationType::JumpImmediate
+                                , Opcode::JgtImm
+                                , Opcode::JgeImm
+                                , Opcode::JltImm
+                                , Opcode::JleImm
+                                , Opcode::JsetImm
+                                , Opcode::JneImm
+                                , Opcode::JsgtImm
+                                , Opcode::JsgeImm
+                                , Opcode::JsltImm
+                                , Opcode::JsleImm];
+
+pub const JUMP_REG_OPS: &[Opcode] = &[Opcode::JeqReg    // OperationType::JumpRegister
+                                , Opcode::JgtReg
+                                , Opcode::JgeReg
+                                , Opcode::JltReg
+                                , Opcode::JleReg
+                                , Opcode::JsetReg
+                                , Opcode::JneReg
+                                , Opcode::JsgtReg
+                                , Opcode::JsgeReg
+                                , Opcode::JsltReg
+                                , Opcode::JsleReg];
+
+pub const CALL_IMM_OPS: &[Opcode] = &[Opcode::Call];    // OperationType::CallImmediate
+
+pub const CALL_REG_OPS: &[Opcode] = &[Opcode::Callx];   // OperationType::CallRegister
+
+pub const EXIT_OPS: &[Opcode] = &[Opcode::Exit];        // OperationType::Exit
+//
+#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, FromPrimitive, Serialize, Deserialize)]
 #[repr(u8)]
 pub enum Opcode {
     Lddw,

+ 7 - 3
crates/disassembler/src/section_header_entry.rs

@@ -75,7 +75,11 @@ impl SectionHeaderEntry {
 #[cfg(test)]
 mod test {
     use crate::section_header_entry::SectionHeaderEntry;
-    use sbpf_common::instruction::{Instruction, Number, Register};
+    use sbpf_common::inst_param::{
+        Number,
+        Register
+    };
+    use sbpf_common::instruction::Instruction;
     use sbpf_common::opcode::Opcode;
 
     #[test]
@@ -94,11 +98,11 @@ mod test {
                 src: None,
                 off: None,
                 imm: Some(Number::Int(0)),
-                span: 0..24,
+                span: 0..16,
             },
             Instruction {
                 opcode: Opcode::Exit,
-                dst: Some(Register { n: 0 }),
+                dst: None,
                 src: None,
                 off: None,
                 imm: None,