1use std::{
2 any::Any,
3 collections::{hash_map::Values, HashMap},
4 io::{self, Read, Write},
5 slice::{Iter, IterMut},
6};
7
8use crate::{
9 howto::{HowTo, Reloc, RelocCode},
10 sym::{Symbol, SymbolKind, SymbolType},
11 traits::ReadSeek,
12};
13
14use arch_ops::{
15 disasm::OpcodePrinter,
16 traits::{Address, InsnWrite},
17};
18
19#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
20pub enum CallbackError {
21 InvalidType,
22 NotAccepted,
23}
24
25pub trait Binfmt {
26 fn relnum_to_howto(&self, relnum: u32) -> Option<&dyn HowTo>;
27 fn code_to_howto(&self, code: RelocCode) -> Option<&dyn HowTo>;
28
29 fn name(&self) -> &'static str;
30 fn create_file(&self, ty: FileType) -> BinaryFile;
31 fn ident_file(&self, file: &mut (dyn Read + '_)) -> io::Result<bool>;
32 fn file_priority(&self) -> i32 {
33 0
34 }
35 fn read_file(&self, file: &mut (dyn ReadSeek + '_)) -> io::Result<Option<BinaryFile>>;
36 fn write_file(&self, file: &mut (dyn Write + '_), bfile: &BinaryFile) -> io::Result<()>;
37
38 fn has_sections(&self) -> bool;
39
40 fn disassembler(&self) -> Option<&dyn OpcodePrinter> {
41 None
42 }
43
44 fn create_section(&self, _section: &mut Section) -> Result<(), CallbackError> {
45 Ok(())
46 }
47 fn create_symbol(&self, _sym: &mut Symbol) -> Result<(), CallbackError> {
48 Ok(())
49 }
50 fn create_reloc(&self, _reloc: &mut Reloc) -> Result<(), CallbackError> {
51 Ok(())
52 }
53 fn before_relocate(&self, _reloc: &mut Reloc, _symbol: &Symbol) {}
54}
55
56impl core::fmt::Debug for dyn Binfmt {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 f.write_str(self.name())
59 }
60}
61
62impl core::cmp::PartialEq for dyn Binfmt {
63 fn eq(&self, rhs: &Self) -> bool {
64 core::ptr::eq(self as *const _ as *const u8, rhs as *const _ as *const u8)
65 }
67}
68
69impl core::cmp::Eq for dyn Binfmt {}
70
71impl core::hash::Hash for dyn Binfmt {
72 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
73 core::ptr::hash(self as *const _ as *const u8, state)
74 }
75}
76
77#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
78pub enum FileType {
79 Exec,
80 Relocatable,
81 SharedObject,
82 FormatSpecific(u32),
83}
84
85pub struct BinaryFile<'a> {
86 sections: Option<Vec<Section>>,
87 symbols: Option<HashMap<String, Symbol>>,
88 relocs: Option<Vec<Reloc>>,
89 fmt: &'a dyn Binfmt,
90 data: Box<dyn Any>,
91 ty: FileType,
92}
93
94impl<'a> BinaryFile<'a> {
95 pub fn create(fmt: &'a dyn Binfmt, data: Box<dyn Any>, ty: FileType) -> Self {
96 Self {
97 sections: None,
98 symbols: None,
99 relocs: None,
100 fmt,
101 data,
102 ty,
103 }
104 }
105
106 pub fn file_type(&self) -> &FileType {
107 &self.ty
108 }
109
110 pub fn data(&self) -> &dyn Any {
111 &*self.data
112 }
113
114 pub fn data_mut(&mut self) -> &mut dyn Any {
115 &mut *self.data
116 }
117
118 pub fn add_section(&mut self, mut sect: Section) -> Result<u32, Section> {
119 if self.sections.is_none() {
120 if !self.fmt.has_sections() {
121 return Err(sect);
122 }
123 self.sections = Some(Vec::new());
124 }
125 let sections = self.sections.as_mut().unwrap();
126 let num = sections.len();
127 if num >= (u32::max_value() as usize) {
128 panic!("Too many sections created in a binary file");
129 }
130 if self.fmt.create_section(&mut sect).is_err() {
131 return Err(sect);
132 }
133 sections.push(sect);
134 Ok(num as u32)
135 }
136
137 pub fn sections(&self) -> Sections<'_> {
138 Sections(self.sections.as_ref().map(|x| x.iter()))
139 }
140
141 pub fn sections_mut(&mut self) -> SectionsMut<'_> {
142 SectionsMut(self.sections.as_mut().map(|x| x.iter_mut()))
143 }
144
145 pub fn get_section(&self, secno: u32) -> Option<&Section> {
146 self.sections
147 .as_ref()
148 .and_then(|sect| sect.get(secno as usize))
149 }
150
151 pub fn remove_section(&mut self, x: u32) -> Option<Section> {
152 self.sections
153 .as_mut()
154 .filter(|v| (x as usize) < v.len())
155 .map(|v| v.remove(x as usize))
156 }
157
158 pub fn add_symbols<I: IntoIterator<Item = Symbol>>(
159 &mut self,
160 syms: I,
161 ) -> Result<(), CallbackError> {
162 if self.symbols.is_none() {
163 self.symbols = Some(HashMap::new());
164 }
165
166 let symtab = self.symbols.as_mut().unwrap();
167
168 for mut sym in syms {
169 self.fmt.create_symbol(&mut sym)?;
170 symtab.insert(sym.name().to_string(), sym);
171 }
172
173 Ok(())
174 }
175
176 pub fn get_or_create_symbol(&mut self, name: &str) -> Result<&mut Symbol, CallbackError> {
177 if self.symbols.is_none() {
178 self.symbols = Some(HashMap::new());
179 }
180
181 let symtab = self.symbols.as_mut().unwrap();
182 if let Some(x) = unsafe { &mut *(symtab as *mut HashMap<String, Symbol>) }.get_mut(name) {
184 return Ok(x);
185 }
186 {
187 let mut sym = Symbol::new(
188 name.to_string(),
189 None,
190 None,
191 SymbolType::Null,
192 SymbolKind::Local,
193 );
194 self.fmt.create_symbol(&mut sym)?;
195 symtab.insert(name.to_string(), sym);
196 Ok(symtab.get_mut(name).unwrap())
197 }
198 }
199
200 pub fn insert_symbol(&mut self, mut sym: Symbol) -> Result<(), Symbol> {
201 if self.symbols.is_none() {
202 self.symbols = Some(HashMap::new());
203 }
204
205 let symbols = self.symbols.as_mut().unwrap();
206 if self.fmt.create_symbol(&mut sym).is_err() {
207 Err(sym)
208 } else {
209 let name = sym.name().to_string();
210 symbols.insert(name, sym);
211 Ok(())
212 }
213 }
214
215 pub fn symbols(&self) -> Symbols {
216 Symbols(self.symbols.as_ref().map(|x| x.values()))
217 }
218
219 pub fn remove_symbol(&mut self, name: &str) -> Option<Symbol> {
220 self.symbols.as_mut().and_then(|x| x.remove(name))
221 }
222
223 pub fn create_reloc(&mut self, mut reloc: Reloc) -> Result<(), Reloc> {
224 if self.relocs.is_none() {
225 self.relocs = Some(Vec::new());
226 }
227
228 let relocs = self.relocs.as_mut().unwrap();
229 if self.fmt.create_reloc(&mut reloc).is_err() {
230 Err(reloc)
231 } else {
232 relocs.push(reloc);
233 Ok(())
234 }
235 }
236
237 pub fn relocs(&self) -> Relocs {
238 Relocs(self.relocs.as_ref().map(|x| x.iter()))
239 }
240
241 pub fn remove_reloc(&mut self, x: usize) -> Option<Reloc> {
242 self.relocs
243 .as_mut()
244 .filter(|v| x < v.len())
245 .map(|v| v.remove(x))
246 }
247
248 pub fn fmt(&self) -> &'a (dyn Binfmt + 'a) {
249 self.fmt
250 }
251}
252
253pub struct Sections<'a>(Option<Iter<'a, Section>>);
254
255impl<'a> Iterator for Sections<'a> {
256 type Item = &'a Section;
257
258 fn next(&mut self) -> Option<Self::Item> {
259 self.0.as_mut().and_then(|x| x.next())
260 }
261}
262
263pub struct SectionsMut<'a>(Option<IterMut<'a, Section>>);
264
265impl<'a> Iterator for SectionsMut<'a> {
266 type Item = &'a mut Section;
267
268 fn next(&mut self) -> Option<Self::Item> {
269 self.0.as_mut().and_then(|x| x.next())
270 }
271}
272
273pub struct Symbols<'a>(Option<Values<'a, String, Symbol>>);
274
275impl<'a> Iterator for Symbols<'a> {
276 type Item = &'a Symbol;
277
278 fn next(&mut self) -> Option<Self::Item> {
279 self.0.as_mut().and_then(|x| x.next())
280 }
281}
282
283pub struct Relocs<'a>(Option<Iter<'a, Reloc>>);
284
285impl<'a> Iterator for Relocs<'a> {
286 type Item = &'a Reloc;
287
288 fn next(&mut self) -> Option<Self::Item> {
289 self.0.as_mut().and_then(|x| x.next())
290 }
291}
292
293#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
294#[non_exhaustive]
295pub enum HashTableType {
296 Elf,
297 Gnu,
298}
299
300#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
301#[non_exhaustive]
302pub enum SectionType {
303 NoBits,
304 ProgBits,
305 SymbolTable,
306 SymbolHashTable(HashTableType),
307 StringTable,
308 Dynamic,
309 ProcedureLinkageTable,
310 GlobalOffsetTable,
311 RelocationTable,
312 RelocationAddendTable,
313 FormatSpecific(u32),
314}
315
316impl Default for SectionType {
317 fn default() -> SectionType {
318 SectionType::NoBits
319 }
320}
321
322#[derive(Clone, Debug, Hash, Default)]
323pub struct Section {
324 pub name: String,
325 pub align: usize,
326 pub ty: SectionType,
327 pub content: Vec<u8>,
328 pub tail_size: usize,
329 pub relocs: Vec<Reloc>,
330 pub info: u64,
331 pub link: u64,
332 #[doc(hidden)]
333 pub __private: (),
334}
335
336impl InsnWrite for Section {
337 fn write_addr(&mut self, size: usize, addr: Address, rel: bool) -> std::io::Result<()> {
338 match (addr, rel) {
339 (Address::Abs(_), true) => todo!(),
340 (Address::Abs(val), false) => {
341 let bytes = val.to_le_bytes();
342 self.content.extend_from_slice(&bytes[..(size / 8)]);
343 Ok(())
344 }
345 (Address::Disp(disp), true) => {
346 let bytes = disp.to_le_bytes();
347 self.content.extend_from_slice(&bytes[..(size / 8)]);
348 Ok(())
349 }
350 (Address::Disp(_), false) => todo!(),
351 (Address::Symbol { name, disp }, true) => {
352 let bytes = disp.to_le_bytes();
353 let code = RelocCode::Rel { addr_width: size };
354 let offset = self.content.len() as u64;
355 self.content.extend_from_slice(&bytes[..(size / 8)]);
356 self.relocs.push(Reloc {
357 code,
358 symbol: name,
359 addend: Some(disp - ((size / 8) as i64)),
360 offset,
361 });
362 Ok(())
363 }
364 (Address::Symbol { name, disp }, false) => {
365 let bytes = disp.to_le_bytes();
366 let code = RelocCode::Abs { addr_width: size };
367 let offset = self.content.len() as u64;
368 self.content.extend_from_slice(&bytes[..(size / 8)]);
369 self.relocs.push(Reloc {
370 code,
371 symbol: name,
372 addend: Some(disp),
373 offset,
374 });
375 Ok(())
376 }
377 (Address::PltSym { name }, true) => {
378 let bytes = 0u64.to_le_bytes();
379 let code = RelocCode::RelPlt { addr_width: size };
380 let offset = self.content.len() as u64;
381 self.content.extend_from_slice(&bytes[..(size / 8)]);
382 self.relocs.push(Reloc {
383 code,
384 symbol: name,
385 addend: Some(-((size / 8) as i64)),
386 offset,
387 });
388 Ok(())
389 }
390 (Address::PltSym { name: _ }, false) => todo!(),
391 }
392 }
393
394 fn offset(&self) -> usize {
395 self.content.len()
396 }
397
398 fn write_reloc(&mut self, reloc: Reloc) -> io::Result<()> {
399 self.relocs.push(reloc);
400 Ok(())
401 }
402 fn write_zeroes(&mut self, count: usize) -> std::io::Result<()> {
403 self.tail_size += count;
404 Ok(())
405 }
406}
407
408impl Write for Section {
409 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
410 if self.tail_size == 0 {
411 arch_ops::traits::default_write_zeroes(&mut self.content, self.tail_size)?;
412 self.tail_size = 0;
413 }
414 self.content.write(buf)
415 }
416
417 fn flush(&mut self) -> io::Result<()> {
418 self.content.flush()
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use crate::traits::ReadSeek;
425
426 use super::{Binfmt, FileType};
427
428 pub struct TestBinfmt;
429
430 impl super::Binfmt for TestBinfmt {
431 fn relnum_to_howto(&self, _: u32) -> Option<&dyn crate::howto::HowTo> {
432 None
433 }
434
435 fn code_to_howto(&self, _: crate::howto::RelocCode) -> Option<&dyn crate::howto::HowTo> {
436 None
437 }
438
439 fn name(&self) -> &'static str {
440 "test"
441 }
442
443 fn create_file(&self, ty: super::FileType) -> super::BinaryFile {
444 super::BinaryFile::create(self, Box::new(()), ty)
445 }
446
447 fn read_file(
448 &self,
449 _: &mut (dyn ReadSeek + '_),
450 ) -> std::io::Result<Option<super::BinaryFile>> {
451 Err(std::io::Error::new(
452 std::io::ErrorKind::Unsupported,
453 "Can't Read/write Test Binfmts",
454 ))
455 }
456
457 fn write_file(
458 &self,
459 _: &mut (dyn std::io::Write + '_),
460 _: &super::BinaryFile,
461 ) -> std::io::Result<()> {
462 Err(std::io::Error::new(
463 std::io::ErrorKind::Unsupported,
464 "Can't Read/write Test Binfmts",
465 ))
466 }
467
468 fn has_sections(&self) -> bool {
469 true
470 }
471
472 fn ident_file(&self, _: &mut (dyn std::io::Read + '_)) -> std::io::Result<bool> {
473 Ok(false)
474 }
475 }
476 #[test]
477 pub fn test_data_type() {
478 let fmt = TestBinfmt.create_file(FileType::Exec);
479 fmt.data().downcast_ref::<()>();
480 }
481}