Browse Source

Merge pull request #54 from bidhan-a/fix/inst-handler-encode

update to_asm to use inst_handler
Claire Fan 3 weeks ago
parent
commit
c4406833ca

+ 164 - 0
crates/common/src/encode.rs

@@ -0,0 +1,164 @@
+use crate::{errors::SBPFError, instruction::Instruction, opcode::Opcode};
+
+pub fn encode_load_immediate(inst: &Instruction) -> Result<String, SBPFError> {
+    match (&inst.dst, &inst.imm) {
+        (Some(dst), Some(imm)) => Ok(format!("{} r{}, {}", inst.opcode, dst.n, imm)),
+        _ => Err(SBPFError::BytecodeError {
+            error: "Lddw instruction missing destination register or immediate value".to_string(),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_load_memory(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.dst {
+        Some(dst) => Ok(format!("{} r{}, {}", inst.opcode, dst.n, inst.src_off())),
+        None => Err(SBPFError::BytecodeError {
+            error: format!("{} instruction missing destination register", inst.opcode),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_store_immediate(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.imm {
+        Some(imm) => Ok(format!("{} {}, {}", inst.opcode, inst.dst_off(), imm)),
+        None => Err(SBPFError::BytecodeError {
+            error: format!("{} instruction missing immediate value", inst.opcode),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_store_register(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.src {
+        Some(src) => Ok(format!("{} {}, r{}", inst.opcode, inst.dst_off(), src.n)),
+        None => Err(SBPFError::BytecodeError {
+            error: format!("{} instruction missing source register", inst.opcode),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_unary(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.dst {
+        Some(dst) => Ok(format!("{} r{}", inst.opcode, dst.n)),
+        None => Err(SBPFError::BytecodeError {
+            error: format!("{} instruction missing destination register", inst.opcode),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_binary_immediate(inst: &Instruction) -> Result<String, SBPFError> {
+    match inst.opcode {
+        Opcode::Le | Opcode::Be => match &inst.dst {
+            Some(dst) => Ok(format!("{}{}", inst.op_imm_bits()?, dst.n)),
+            None => Err(SBPFError::BytecodeError {
+                error: format!("{} instruction missing destination register", inst.opcode),
+                span: inst.span.clone(),
+                custom_label: None,
+            }),
+        },
+        _ => match (&inst.dst, &inst.imm) {
+            (Some(dst), Some(imm)) => Ok(format!("{} r{}, {}", inst.opcode, dst.n, imm)),
+            _ => Err(SBPFError::BytecodeError {
+                error: format!(
+                    "{} instruction missing destination register or immediate value",
+                    inst.opcode
+                ),
+                span: inst.span.clone(),
+                custom_label: None,
+            }),
+        },
+    }
+}
+
+pub fn encode_binary_register(inst: &Instruction) -> Result<String, SBPFError> {
+    match (&inst.dst, &inst.src) {
+        (Some(dst), Some(src)) => Ok(format!("{} r{}, r{}", inst.opcode, dst.n, src.n)),
+        _ => Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction missing destination or source register",
+                inst.opcode
+            ),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_jump(inst: &Instruction) -> Result<String, SBPFError> {
+    Ok(format!("{} {}", inst.opcode, inst.off_str()))
+}
+
+pub fn encode_jump_immediate(inst: &Instruction) -> Result<String, SBPFError> {
+    match (&inst.dst, &inst.imm) {
+        (Some(dst), Some(imm)) => Ok(format!(
+            "{} r{}, {}, {}",
+            inst.opcode,
+            dst.n,
+            imm,
+            inst.off_str()
+        )),
+        _ => Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction missing destination register or immediate value",
+                inst.opcode
+            ),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_jump_register(inst: &Instruction) -> Result<String, SBPFError> {
+    match (&inst.dst, &inst.src) {
+        (Some(dst), Some(src)) => Ok(format!(
+            "{} r{}, r{}, {}",
+            inst.opcode,
+            dst.n,
+            src.n,
+            inst.off_str()
+        )),
+        _ => Err(SBPFError::BytecodeError {
+            error: format!(
+                "{} instruction missing destination or source register",
+                inst.opcode
+            ),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_call_immediate(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.imm {
+        Some(imm) => Ok(format!("call {}", imm)),
+        None => Err(SBPFError::BytecodeError {
+            error: "Call instruction missing immediate value".to_string(),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_call_register(inst: &Instruction) -> Result<String, SBPFError> {
+    match &inst.src {
+        Some(src) => Ok(format!("call r{}", src.n)),
+        None => Err(SBPFError::BytecodeError {
+            error: "Callx instruction missing source register".to_string(),
+            span: inst.span.clone(),
+            custom_label: None,
+        }),
+    }
+}
+
+pub fn encode_exit(inst: &Instruction) -> Result<String, SBPFError> {
+    Ok(format!("{}", inst.opcode))
+}

+ 73 - 14
crates/common/src/inst_handler.rs

@@ -5,6 +5,12 @@ use crate::{
         decode_jump_register, decode_load_immediate, decode_load_memory, decode_store_immediate,
         decode_jump_register, decode_load_immediate, decode_load_memory, decode_store_immediate,
         decode_store_register, decode_unary,
         decode_store_register, decode_unary,
     },
     },
+    encode::{
+        encode_binary_immediate, encode_binary_register, encode_call_immediate,
+        encode_call_register, encode_exit, encode_jump, encode_jump_immediate,
+        encode_jump_register, encode_load_immediate, encode_load_memory, encode_store_immediate,
+        encode_store_register, encode_unary,
+    },
     errors::SBPFError,
     errors::SBPFError,
     instruction::Instruction,
     instruction::Instruction,
     opcode::{
     opcode::{
@@ -15,9 +21,11 @@ use crate::{
 };
 };
 
 
 type DecodeFn = fn(&[u8]) -> Result<Instruction, SBPFError>;
 type DecodeFn = fn(&[u8]) -> Result<Instruction, SBPFError>;
+type EncodeFn = fn(&Instruction) -> Result<String, SBPFError>;
 
 
 pub struct InstructionHandler {
 pub struct InstructionHandler {
     pub decode: DecodeFn,
     pub decode: DecodeFn,
+    pub encode: EncodeFn,
 }
 }
 
 
 use {once_cell::sync::Lazy, std::collections::HashMap};
 use {once_cell::sync::Lazy, std::collections::HashMap};
@@ -30,25 +38,76 @@ pub static OPCODE_TO_HANDLER: Lazy<HashMap<Opcode, InstructionHandler>> = Lazy::
         map: &mut HashMap<Opcode, InstructionHandler>,
         map: &mut HashMap<Opcode, InstructionHandler>,
         ops: &[Opcode],
         ops: &[Opcode],
         decode: DecodeFn,
         decode: DecodeFn,
+        encode: EncodeFn,
     ) {
     ) {
         for &op in ops {
         for &op in ops {
-            map.insert(op, InstructionHandler { decode });
+            map.insert(op, InstructionHandler { decode, encode });
         }
         }
     }
     }
 
 
-    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);
+    register_group(
+        &mut map,
+        LOAD_IMM_OPS,
+        decode_load_immediate,
+        encode_load_immediate,
+    );
+    register_group(
+        &mut map,
+        LOAD_MEMORY_OPS,
+        decode_load_memory,
+        encode_load_memory,
+    );
+    register_group(
+        &mut map,
+        STORE_IMM_OPS,
+        decode_store_immediate,
+        encode_store_immediate,
+    );
+    register_group(
+        &mut map,
+        STORE_REG_OPS,
+        decode_store_register,
+        encode_store_register,
+    );
+    register_group(
+        &mut map,
+        BIN_IMM_OPS,
+        decode_binary_immediate,
+        encode_binary_immediate,
+    );
+    register_group(
+        &mut map,
+        BIN_REG_OPS,
+        decode_binary_register,
+        encode_binary_register,
+    );
+    register_group(&mut map, UNARY_OPS, decode_unary, encode_unary);
+    register_group(&mut map, JUMP_OPS, decode_jump, encode_jump);
+    register_group(
+        &mut map,
+        JUMP_IMM_OPS,
+        decode_jump_immediate,
+        encode_jump_immediate,
+    );
+    register_group(
+        &mut map,
+        JUMP_REG_OPS,
+        decode_jump_register,
+        encode_jump_register,
+    );
+    register_group(
+        &mut map,
+        CALL_IMM_OPS,
+        decode_call_immediate,
+        encode_call_immediate,
+    );
+    register_group(
+        &mut map,
+        CALL_REG_OPS,
+        decode_call_register,
+        encode_call_register,
+    );
+    register_group(&mut map, EXIT_OPS, decode_exit, encode_exit);
 
 
     map
     map
 });
 });

+ 9 - 250
crates/common/src/instruction.rs

@@ -121,256 +121,15 @@ impl Instruction {
     }
     }
 
 
     pub fn to_asm(&self) -> Result<String, SBPFError> {
     pub fn to_asm(&self) -> Result<String, SBPFError> {
-        Ok(match self.opcode {
-            // lddw - (load double word) takes up two instructions. The 64 bit value
-            // is made up of two halves with the upper half being the immediate
-            // of the lddw value and the lower half being the immediate of the
-            // following instruction
-            Opcode::Lddw => {
-                match (&self.dst, &self.imm) {
-                    (Some(dst), Some(imm)) => format!("{} r{}, {}", self.opcode, dst.n, imm),
-                    _ => return Err(SBPFError::BytecodeError {
-                        error: "Lddw instruction missing destination register or immediate value".to_string(),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // ldx - (load x) store a 8/16/32/64 bit (byte/half/word/double word)
-            // value in a register
-            Opcode::Ldxb |
-            Opcode::Ldxh |
-            Opcode::Ldxw |
-            Opcode::Ldxdw => {
-                match &self.dst {
-                    Some(dst) => format!("{} r{}, {}", self.opcode, dst.n, self.src_off()),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // stb - these instructions are deprecated
-            Opcode::Stb |
-            Opcode::Sth |
-            Opcode::Stw |
-            Opcode::Stdw => {
-                match &self.imm {
-                    Some(imm) => format!("{} {}, {}", self.opcode, self.dst_off(), imm),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing immediate value", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // stx - store a 8/16/32/64 bit value from a source register into the offset
-            // of the destination register
-            Opcode::Stxb |
-            Opcode::Stxh |
-            Opcode::Stxw |
-            Opcode::Stxdw => {
-                match &self.src {
-                    Some(src) => format!("{} {}, r{}", self.opcode, self.dst_off(), src.n),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing source register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // Math
-            Opcode::Neg32 | // Deprecated in SBFv2
-            Opcode::Neg64 => {
-                match &self.dst {
-                    Some(dst) => format!("{} r{}", self.opcode, dst.n),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // LE and BE OpCodes act a little differently to others. In assembly form, they are
-            // notated as be16, be32 and b64. In byte form, the bit length of the operation is 
-            // determined by the immedate value of its parent instruction, 0x10, 0x20 and 0x40
-            // accordingly (the hex of 16/32/64)
-            Opcode::Le |
-            Opcode::Be => {
-                match &self.dst {
-                    Some(dst) => format!("{}{}", self.op_imm_bits()?, dst.n),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            }, // Docs for this seem wrong //DC01000010000000 DC01000020000000 DC01000040000000
-            // Immedate
-            Opcode::Add32Imm |
-            Opcode::Sub32Imm |
-            Opcode::Mul32Imm |
-            Opcode::Div32Imm |
-            Opcode::Or32Imm |
-            Opcode::And32Imm |
-            Opcode::Lsh32Imm |
-            Opcode::Rsh32Imm |
-            Opcode::Mod32Imm |
-            Opcode::Xor32Imm |
-            Opcode::Arsh32Imm |
-            Opcode::Mov32Imm |
-            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 => {
-                match (&self.dst, &self.imm) {
-                    (Some(dst), Some(imm)) => format!("{} r{}, {}", self.opcode, dst.n, imm),
-                    _ => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination register or immediate value", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // Register
-            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 => {
-                match (&self.dst, &self.src) {
-                    (Some(dst), Some(src)) => format!("{} r{}, r{}", self.opcode, dst.n, src.n),
-                    _ => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination or source register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-
-            // Jumps
-            Opcode::Ja => format!("{} {}", self.opcode, self.off_str()),
-
-            // Immediates
-            Opcode::JeqImm |
-            Opcode::JgtImm |
-            Opcode::JgeImm |
-            Opcode::JltImm |
-            Opcode::JleImm |
-            Opcode::JsetImm |
-            Opcode::JneImm |
-            Opcode::JsgtImm |
-            Opcode::JsgeImm |
-            Opcode::JsltImm |
-            Opcode::JsleImm => {
-                match (&self.dst, &self.imm) {
-                    (Some(dst), Some(imm)) => format!("{} r{}, {}, {}", self.opcode, dst.n, imm, self.off_str()),
-                    _ => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination register or immediate value", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            // Registers
-            Opcode::JeqReg |
-            Opcode::JgtReg |
-            Opcode::JgeReg |
-            Opcode::JltReg |
-            Opcode::JleReg |
-            Opcode::JsetReg |
-            Opcode::JneReg |
-            Opcode::JsgtReg |
-            Opcode::JsgeReg |
-            Opcode::JsltReg |
-            Opcode::JsleReg => {
-                match (&self.dst, &self.src) {
-                    (Some(dst), Some(src)) => format!("{} r{}, r{}, {}", self.opcode, dst.n, src.n, self.off_str()),
-                    _ => return Err(SBPFError::BytecodeError {
-                        error: format!("{} instruction missing destination or source register", self.opcode),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-
-
-            // Calls
-            Opcode::Call => {
-                match &self.imm {
-                    Some(imm) => format!("call {}", imm),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: "Call instruction missing immediate value".to_string(),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            Opcode::Callx => {
-                match &self.src {
-                    Some(src) => format!("call r{}", src.n),
-                    None => return Err(SBPFError::BytecodeError {
-                        error: "Callx instruction missing source register".to_string(),
-                        span: self.span.clone(),
-                        custom_label: None,
-                    }),
-                }
-            },
-            Opcode::Exit => format!("{}", self.opcode),
-        })
+        if let Some(handler) = OPCODE_TO_HANDLER.get(&self.opcode) {
+            (handler.encode)(self)
+        } else {
+            Err(SBPFError::BytecodeError {
+                error: format!("no encode handler for opcode {}", self.opcode),
+                span: self.span.clone(),
+                custom_label: None,
+            })
+        }
     }
     }
 }
 }
 
 

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

@@ -1,4 +1,5 @@
 pub mod decode;
 pub mod decode;
+pub mod encode;
 pub mod errors;
 pub mod errors;
 pub mod inst_handler;
 pub mod inst_handler;
 pub mod inst_param;
 pub mod inst_param;