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 OpCode::Lddw => format!("{} r{}, {}", self.op, self.dst, self.imm),
66 OpCode::Ldxb |
69 OpCode::Ldxh |
70 OpCode::Ldxw |
71 OpCode::Ldxdw => format!("{} r{}, {}", self.op, self.dst, self.src_off()),
72 OpCode::Stb |
74 OpCode::Sth |
75 OpCode::Stw |
76 OpCode::Stdw => format!("{} {}, {}", self.op, self.dst_off(), self.imm),
77 OpCode::Stxb |
80 OpCode::Stxh |
81 OpCode::Stxw |
82 OpCode::Stxdw => format!("{} {}, r{}", self.op, self.dst_off(), self.src),
83 OpCode::Neg32 | OpCode::Neg64 => format!("{} r{}", self.op, self.dst),
86 OpCode::Le |
91 OpCode::Be => format!("{}{}", self.op_imm_bits()?, self.dst), 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 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 OpCode::Ja => format!("{} {}", self.op, self.off_str()),
170
171 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 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 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}