sbpf_disassembler/
instructions.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{errors::DisassemblerError, opcodes::OpCode};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
6pub struct Ix {
7    pub op: OpCode,
8    pub dst: u8,
9    pub src: u8,
10    pub off: i16,
11    pub imm: i64,
12}
13
14impl Ix {
15    pub fn off_str(&self) -> String {
16        match self.off.is_negative() {
17            true => self.off.to_string(),
18            false => format!("+{}", self.off),
19        }
20    }
21
22    pub fn dst_off(&self) -> String {
23        format!("[r{}{}]", self.dst, self.off_str())
24    }
25
26    pub fn src_off(&self) -> String {
27        format!("[r{}{}]", self.src, self.off_str())
28    }
29
30    pub fn op_imm_bits(&self) -> Result<String, DisassemblerError> {
31        Ok(match self.imm {
32            16 => format!("{}16", self.op),
33            32 => format!("{}32", self.op),
34            64 => format!("{}64", self.op),
35            _ => return Err(DisassemblerError::InvalidImmediate),
36        })
37    }
38}
39
40impl Ix {
41    pub fn from_bytes(b: &[u8]) -> Result<Self, DisassemblerError> {
42        if b.len() < 8 {
43            return Err(DisassemblerError::InvalidDataLength);
44        }
45
46        let op = OpCode::try_from(b[0])?;
47        let reg = b[1];
48        let src = reg >> 4;
49        let dst = reg & 0x0f;
50        let off = i16::from_le_bytes([b[2], b[3]]);
51
52        let imm = match op {
53            OpCode::Lddw => {
54                if b.len() < 16 {
55                    return Err(DisassemblerError::InvalidDataLength);
56                }
57                let mut imm_bytes = [0u8; 8];
58                imm_bytes[0..4].copy_from_slice(&b[4..8]);
59
60                if u32::from_le_bytes([b[8], b[9], b[10], b[11]]) != 0 {
61                    return Err(DisassemblerError::InvalidImmediate);
62                }
63
64                imm_bytes[4..8].copy_from_slice(&b[12..16]);
65                i64::from_le_bytes(imm_bytes)
66            }
67            _ => i32::from_le_bytes([b[4], b[5], b[6], b[7]]) as i64,
68        };
69
70        Ok(Ix {
71            op,
72            src,
73            dst,
74            off,
75            imm,
76        })
77    }
78
79    pub fn to_bytes(&self) -> Vec<u8> {
80        let mut b = vec![self.op.clone() as u8, self.src << 4 | self.dst];
81        b.extend_from_slice(&self.off.to_le_bytes());
82        b.extend_from_slice(&self.imm.to_le_bytes()[..4]);
83        if self.op == OpCode::Lddw {
84            b.extend_from_slice(&[0; 4]);
85            b.extend_from_slice(&self.imm.to_le_bytes()[4..]);
86        }
87        b
88    }
89
90    pub fn to_asm(&self) -> Result<String, DisassemblerError> {
91        Ok(match self.op {
92            // lddw - (load double word) takes up two instructions. The 64 bit value
93            // is made up of two halves with the upper half being the immediate
94            // of the lddw value and the lower half being the immediate of the
95            // following instruction
96            OpCode::Lddw => format!("{} r{}, {}", self.op, self.dst, self.imm),
97            // ldx - (load x) store a 8/16/32/64 bit (byte/half/word/double word)
98            // value in a register
99            OpCode::Ldxb |
100            OpCode::Ldxh |
101            OpCode::Ldxw |
102            OpCode::Ldxdw => format!("{} r{}, {}", self.op, self.dst, self.src_off()),
103            // stb - these instructions are deprecated
104            OpCode::Stb |
105            OpCode::Sth |
106            OpCode::Stw |
107            OpCode::Stdw => format!("{} {}, {}", self.op, self.dst_off(), self.imm),
108            // stx - store a 8/16/32/64 bit value from a source register into the offset
109            // of the destination register
110            OpCode::Stxb |
111            OpCode::Stxh |
112            OpCode::Stxw |
113            OpCode::Stxdw => format!("{} {}, r{}", self.op, self.dst_off(), self.src),
114            // Math
115            OpCode::Neg32 | // Deprecated in SBFv2
116            OpCode::Neg64 => format!("{} r{}", self.op, self.dst),
117            // LE and BE OpCodes act a little differently to others. In assembly form, they are
118            // notated as be16, be32 and b64. In byte form, the bit length of the operation is 
119            // determined by the immedate value of its parent instruction, 0x10, 0x20 and 0x40
120            // accordingly (the hex of 16/32/64)
121            OpCode::Le |
122            OpCode::Be => format!("{}{}", self.op_imm_bits()?, self.dst), // Docs for this seem wrong //DC01000010000000 DC01000020000000 DC01000040000000
123            // Immedate
124            OpCode::Add32Imm |
125            OpCode::Sub32Imm |
126            OpCode::Mul32Imm |
127            OpCode::Div32Imm |
128            OpCode::Or32Imm |
129            OpCode::And32Imm |
130            OpCode::Lsh32Imm |
131            OpCode::Rsh32Imm |
132            OpCode::Mod32Imm |
133            OpCode::Xor32Imm |
134            OpCode::Arsh32Imm |
135            OpCode::Mov32Imm |
136            OpCode::Lmul32Imm |
137            OpCode::Udiv32Imm |
138            OpCode::Urem32Imm |
139            OpCode::Sdiv32Imm |
140            OpCode::Srem32Imm |
141            OpCode::Add64Imm |
142            OpCode::Sub64Imm |
143            OpCode::Mul64Imm |
144            OpCode::Div64Imm |
145            OpCode::Or64Imm |
146            OpCode::And64Imm |
147            OpCode::Lsh64Imm |
148            OpCode::Rsh64Imm |
149            OpCode::Mod64Imm |
150            OpCode::Xor64Imm |
151            OpCode::Mov64Imm |
152            OpCode::Arsh64Imm |
153            OpCode::Hor64Imm |
154            OpCode::Lmul64Imm |
155            OpCode::Uhmul64Imm |
156            OpCode::Udiv64Imm |
157            OpCode::Urem64Imm |
158            OpCode::Shmul64Imm |
159            OpCode::Sdiv64Imm |
160            OpCode::Srem64Imm => format!("{} r{}, {}", self.op, self.dst, self.imm),
161            // Register
162            OpCode::Add32Reg |
163            OpCode::Sub32Reg |
164            OpCode::Mul32Reg |
165            OpCode::Div32Reg |
166            OpCode::Or32Reg |
167            OpCode::And32Reg |
168            OpCode::Lsh32Reg |
169            OpCode::Rsh32Reg |
170            OpCode::Mod32Reg |
171            OpCode::Xor32Reg |
172            OpCode::Mov32Reg |
173            OpCode::Arsh32Reg |
174            OpCode::Lmul32Reg |
175            OpCode::Udiv32Reg |
176            OpCode::Urem32Reg |
177            OpCode::Sdiv32Reg |
178            OpCode::Srem32Reg |
179            OpCode::Add64Reg |
180            OpCode::Sub64Reg |
181            OpCode::Mul64Reg |
182            OpCode::Div64Reg |
183            OpCode::Or64Reg |
184            OpCode::And64Reg |
185            OpCode::Lsh64Reg |
186            OpCode::Rsh64Reg |
187            OpCode::Mod64Reg |
188            OpCode::Xor64Reg |
189            OpCode::Mov64Reg |
190            OpCode::Arsh64Reg |
191            OpCode::Lmul64Reg |
192            OpCode::Uhmul64Reg |
193            OpCode::Udiv64Reg |
194            OpCode::Urem64Reg |
195            OpCode::Shmul64Reg |
196            OpCode::Sdiv64Reg |
197            OpCode::Srem64Reg => format!("{} r{}, r{}", self.op, self.dst, self.src),
198
199            // Jumps
200            OpCode::Ja => format!("{} {}", self.op, self.off_str()),
201
202            // Immediates
203            OpCode::JeqImm |
204            OpCode::JgtImm |
205            OpCode::JgeImm |
206            OpCode::JltImm |
207            OpCode::JleImm |
208            OpCode::JsetImm |
209            OpCode::JneImm |
210            OpCode::JsgtImm |
211            OpCode::JsgeImm |
212            OpCode::JsltImm |
213            OpCode::JsleImm => format!("{} r{}, {}, {}", self.op, self.dst, self.imm, self.off_str()),
214            // Registers
215            OpCode::JeqReg |
216            OpCode::JgtReg |
217            OpCode::JgeReg |
218            OpCode::JltReg |
219            OpCode::JleReg |
220            OpCode::JsetReg |
221            OpCode::JneReg |
222            OpCode::JsgtReg |
223            OpCode::JsgeReg |
224            OpCode::JsltReg |
225            OpCode::JsleReg => format!("{} r{}, r{}, {}", self.op, self.dst, self.src, self.off_str()),
226
227
228            // Calls
229            OpCode::Call => format!("call {}", self.imm),
230            OpCode::Callx => format!("call r{}", self.src),
231            OpCode::Exit => format!("{}", self.op),
232        })
233    }
234}
235
236#[cfg(test)]
237mod test {
238    use hex_literal::hex;
239
240    use crate::instructions::Ix;
241
242    #[test]
243    fn serialize_e2e() {
244        let b = hex!("9700000000000000");
245        let i = Ix::from_bytes(&b).unwrap();
246        assert_eq!(i.to_bytes(), &b);
247    }
248
249    #[test]
250    fn serialize_e2e_lddw() {
251        let b = hex!("18010000000000000000000000000000");
252        let i = Ix::from_bytes(&b).unwrap();
253        assert_eq!(i.to_bytes(), &b);
254    }
255}