|
@@ -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,
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|