1use {
2 either::Either,
3 sbpf_common::{instruction::Instruction, opcode::Opcode},
4 std::collections::BTreeMap,
5};
6
7#[derive(Debug)]
8pub struct DynamicSymbol {
9 name: u32, info: u8, other: u8, shndx: u16, value: u64, size: u64, }
16
17impl DynamicSymbol {
18 pub fn new(name: u32, info: u8, other: u8, shndx: u16, value: u64, size: u64) -> Self {
19 Self {
20 name,
21 info,
22 other,
23 shndx,
24 value,
25 size,
26 }
27 }
28
29 pub fn bytecode(&self) -> Vec<u8> {
30 let mut bytes = Vec::new();
31 bytes.extend(self.name.to_le_bytes());
32 bytes.push(self.info);
33 bytes.push(self.other);
34 bytes.extend(self.shndx.to_le_bytes());
35 bytes.extend(self.value.to_le_bytes());
36 bytes.extend(self.size.to_le_bytes());
37 bytes
38 }
39
40 pub fn get_name(&self) -> u32 {
41 self.name
42 }
43}
44
45#[derive(Debug, Clone, PartialEq)]
46pub enum SymbolKind {
47 EntryPoint,
48 CallTarget,
49}
50
51#[derive(Debug, Default)]
52pub struct DynamicSymbolMap {
53 symbols: BTreeMap<String, Vec<(SymbolKind, u64)>>,
54}
55
56impl DynamicSymbolMap {
57 pub fn new() -> Self {
58 Self::default()
59 }
60
61 pub fn copy(&self) -> Self {
62 Self {
63 symbols: self.symbols.clone(),
64 }
65 }
66
67 pub fn add_symbol(&mut self, name: String, kind: SymbolKind, offset: u64) {
68 self.symbols.entry(name).or_default().push((kind, offset));
69 }
70
71 pub fn add_entry_point(&mut self, name: String, offset: u64) {
72 self.add_symbol(name, SymbolKind::EntryPoint, offset);
73 }
74
75 pub fn add_call_target(&mut self, name: String, offset: u64) {
76 self.add_symbol(name, SymbolKind::CallTarget, offset);
77 }
78
79 pub fn get_entry_points(&self) -> Vec<(String, u64)> {
80 self.get_symbols_by_kind(SymbolKind::EntryPoint)
81 }
82
83 pub fn get_call_targets(&self) -> Vec<(String, u64)> {
84 self.get_symbols_by_kind(SymbolKind::CallTarget)
85 }
86
87 fn get_symbols_by_kind(&self, kind: SymbolKind) -> Vec<(String, u64)> {
88 self.symbols
89 .iter()
90 .filter(|(_, symbols)| symbols.iter().any(|(k, _)| *k == kind))
91 .map(|(name, symbols)| {
92 (
93 name.clone(),
94 symbols.iter().find(|(k, _)| *k == kind).unwrap().1,
95 )
96 })
97 .collect()
98 }
99
100 pub fn get_symbol(&self, name: &str) -> Option<&Vec<(SymbolKind, u64)>> {
101 self.symbols.get(name)
102 }
103
104 pub fn get_symbols(&self) -> &BTreeMap<String, Vec<(SymbolKind, u64)>> {
105 &self.symbols
106 }
107}
108
109#[derive(Debug, Clone, Copy, PartialEq)]
110#[repr(u64)]
111pub enum RelocationType {
112 RSbf64Relative = 0x08,
113 RSbfSyscall = 0x0a,
114}
115
116pub fn get_relocation_info(inst: &Instruction) -> (RelocationType, String) {
117 match inst.opcode {
118 Opcode::Lddw => match &inst.imm {
119 Some(Either::Left(identifier)) => (RelocationType::RSbf64Relative, identifier.clone()),
120 _ => panic!("Expected label operand"),
121 },
122 _ => {
123 if let Some(Either::Left(identifier)) = &inst.imm {
124 (RelocationType::RSbfSyscall, identifier.clone())
125 } else {
126 panic!("Expected label operand")
127 }
128 }
129 }
130}
131
132#[derive(Debug, Clone, PartialEq)]
133pub struct RelDyn {
134 offset: u64,
135 rel_type: u64,
136 dynstr_offset: u64,
137}
138
139impl RelDyn {
140 pub fn new(offset: u64, rel_type: u64, dynstr_offset: u64) -> Self {
141 Self {
142 offset,
143 rel_type,
144 dynstr_offset,
145 }
146 }
147
148 pub fn bytecode(&self) -> Vec<u8> {
149 let mut bytes = Vec::new();
150 bytes.extend(self.offset.to_le_bytes());
151
152 if self.rel_type == 0x08 {
153 bytes.extend(self.rel_type.to_le_bytes());
155 } else if self.rel_type == 0x0a {
156 bytes.extend((self.rel_type as u32).to_le_bytes());
158 bytes.extend((self.dynstr_offset as u32).to_le_bytes());
160 }
161
162 bytes
163 }
164}
165
166#[derive(Debug, Default)]
167pub struct RelDynMap {
168 rel_dyns: BTreeMap<u64, Vec<(RelocationType, String)>>,
169}
170
171impl RelDynMap {
172 pub fn new() -> Self {
173 Self::default()
174 }
175
176 pub fn add_rel_dyn(&mut self, offset: u64, rel_type: RelocationType, name: String) {
177 self.rel_dyns
178 .entry(offset)
179 .or_default()
180 .push((rel_type, name));
181 }
182
183 pub fn get_rel_dyns(&self) -> Vec<(u64, RelocationType, String)> {
184 self.rel_dyns
185 .iter()
186 .flat_map(|(offset, rel_types)| {
187 rel_types
188 .iter()
189 .map(move |(rel_type, name)| (*offset, *rel_type, name.clone()))
190 })
191 .collect()
192 }
193
194 pub fn copy(&self) -> Self {
195 Self {
196 rel_dyns: self.rel_dyns.clone(),
197 }
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use {super::*, sbpf_common::inst_param::Register};
204
205 #[test]
206 fn test_dynamic_symbol_get_name() {
207 let sym = DynamicSymbol::new(42, 0x12, 0, 1, 0, 0);
208 assert_eq!(sym.get_name(), 42);
209 }
210
211 #[test]
212 fn test_dynamic_symbol_map_new() {
213 let map = DynamicSymbolMap::new();
214 assert!(map.symbols.is_empty());
215 }
216
217 #[test]
218 fn test_dynamic_symbol_map_add_entry_point() {
219 let mut map = DynamicSymbolMap::new();
220 map.add_entry_point("entrypoint".to_string(), 0x120);
221
222 let entry_points = map.get_entry_points();
223 assert_eq!(entry_points.len(), 1);
224 assert_eq!(entry_points[0].0, "entrypoint");
225 assert_eq!(entry_points[0].1, 0x120);
226 }
227
228 #[test]
229 fn test_dynamic_symbol_map_add_call_target() {
230 let mut map = DynamicSymbolMap::new();
231 map.add_call_target("function".to_string(), 0x200);
232
233 let call_targets = map.get_call_targets();
234 assert_eq!(call_targets.len(), 1);
235 assert_eq!(call_targets[0].0, "function");
236 assert_eq!(call_targets[0].1, 0x200);
237 }
238
239 #[test]
240 fn test_dynamic_symbol_map_get_symbol() {
241 let mut map = DynamicSymbolMap::new();
242 map.add_symbol("test".to_string(), SymbolKind::CallTarget, 100);
243
244 let sym = map.get_symbol("test");
245 assert!(sym.is_some());
246 assert_eq!(sym.unwrap().len(), 1);
247
248 let not_found = map.get_symbol("nonexistent");
249 assert!(not_found.is_none());
250 }
251
252 #[test]
253 fn test_dynamic_symbol_map_get_symbols() {
254 let mut map = DynamicSymbolMap::new();
255 map.add_symbol("func1".to_string(), SymbolKind::CallTarget, 100);
256 map.add_symbol("func2".to_string(), SymbolKind::EntryPoint, 200);
257
258 let symbols = map.get_symbols();
259 assert_eq!(symbols.len(), 2);
260 assert!(symbols.contains_key("func1"));
261 assert!(symbols.contains_key("func2"));
262 }
263
264 #[test]
265 fn test_dynamic_symbol_map_copy() {
266 let mut map = DynamicSymbolMap::new();
267 map.add_entry_point("main".to_string(), 0);
268
269 let copy = map.copy();
270 assert_eq!(copy.symbols.len(), 1);
271 assert!(copy.get_symbol("main").is_some());
272 }
273
274 #[test]
275 fn test_get_relocation_info_lddw() {
276 let inst = Instruction {
277 opcode: Opcode::Lddw,
278 dst: Some(Register { n: 1 }),
279 src: None,
280 off: None,
281 imm: Some(Either::Left("my_data".to_string())),
282 span: 0..10,
283 };
284
285 let (rel_type, name) = get_relocation_info(&inst);
286 assert_eq!(rel_type, RelocationType::RSbf64Relative);
287 assert_eq!(name, "my_data");
288 }
289
290 #[test]
291 fn test_get_relocation_info_call() {
292 let inst = Instruction {
293 opcode: Opcode::Call,
294 dst: None,
295 src: Some(Register { n: 1 }),
296 off: None,
297 imm: Some(Either::Left("my_function".to_string())),
298 span: 0..10,
299 };
300
301 let (rel_type, name) = get_relocation_info(&inst);
302 assert_eq!(rel_type, RelocationType::RSbfSyscall);
303 assert_eq!(name, "my_function");
304 }
305
306 #[test]
307 fn test_rel_dyn_map_add_and_get() {
308 let mut map = RelDynMap::new();
309 map.add_rel_dyn(0x100, RelocationType::RSbf64Relative, "data".to_string());
310 map.add_rel_dyn(0x200, RelocationType::RSbfSyscall, "func".to_string());
311
312 let rel_dyns = map.get_rel_dyns();
313 assert_eq!(rel_dyns.len(), 2);
314 }
315
316 #[test]
317 fn test_rel_dyn_map_copy() {
318 let mut map = RelDynMap::new();
319 map.add_rel_dyn(0x100, RelocationType::RSbf64Relative, "test".to_string());
320
321 let copy = map.copy();
322 assert_eq!(copy.rel_dyns.len(), 1);
323 }
324}