sbpf_disassembler/
instructions.rs

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