binfmt/
fmt.rs

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        // Binary Formats are unique and singleton
66    }
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        // SAFETY: Hecking NLL not being powerful enough
183        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}