1 use alloc::borrow::Cow;
2 use alloc::vec::Vec;
3 
4 use crate::read::{
5     self, Architecture, ComdatKind, CompressedData, Export, FileFlags, Import, ObjectMap,
6     Relocation, Result, SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex,
7     SymbolKind, SymbolMap, SymbolMapName, SymbolScope, SymbolSection,
8 };
9 use crate::Endianness;
10 
11 /// An object file.
12 pub trait Object<'data: 'file, 'file>: read::private::Sealed {
13     /// A segment in the object file.
14     type Segment: ObjectSegment<'data>;
15 
16     /// An iterator over the segments in the object file.
17     type SegmentIterator: Iterator<Item = Self::Segment>;
18 
19     /// A section in the object file.
20     type Section: ObjectSection<'data>;
21 
22     /// An iterator over the sections in the object file.
23     type SectionIterator: Iterator<Item = Self::Section>;
24 
25     /// A COMDAT section group in the object file.
26     type Comdat: ObjectComdat<'data>;
27 
28     /// An iterator over the COMDAT section groups in the object file.
29     type ComdatIterator: Iterator<Item = Self::Comdat>;
30 
31     /// A symbol in the object file.
32     type Symbol: ObjectSymbol<'data>;
33 
34     /// An iterator over symbols in the object file.
35     type SymbolIterator: Iterator<Item = Self::Symbol>;
36 
37     /// A symbol table in the object file.
38     type SymbolTable: ObjectSymbolTable<
39         'data,
40         Symbol = Self::Symbol,
41         SymbolIterator = Self::SymbolIterator,
42     >;
43 
44     /// An iterator over dynamic relocations in the file.
45     ///
46     /// The first field in the item tuple is the address
47     /// that the relocation applies to.
48     type DynamicRelocationIterator: Iterator<Item = (u64, Relocation)>;
49 
50     /// Get the architecture type of the file.
architecture(&self) -> Architecture51     fn architecture(&self) -> Architecture;
52 
53     /// Get the endianness of the file.
54     #[inline]
endianness(&self) -> Endianness55     fn endianness(&self) -> Endianness {
56         if self.is_little_endian() {
57             Endianness::Little
58         } else {
59             Endianness::Big
60         }
61     }
62 
63     /// Return true if the file is little endian, false if it is big endian.
is_little_endian(&self) -> bool64     fn is_little_endian(&self) -> bool;
65 
66     /// Return true if the file can contain 64-bit addresses.
is_64(&self) -> bool67     fn is_64(&self) -> bool;
68 
69     /// Get an iterator over the segments in the file.
segments(&'file self) -> Self::SegmentIterator70     fn segments(&'file self) -> Self::SegmentIterator;
71 
72     /// Get the entry point address of the binary
entry(&'file self) -> u6473     fn entry(&'file self) -> u64;
74 
75     /// Get the section named `section_name`, if such a section exists.
76     ///
77     /// If `section_name` starts with a '.' then it is treated as a system section name,
78     /// and is compared using the conventions specific to the object file format. This
79     /// includes:
80     /// - if ".text" is requested for a Mach-O object file, then the actual
81     /// section name that is searched for is "__text".
82     /// - if ".debug_info" is requested for an ELF object file, then
83     /// ".zdebug_info" may be returned (and similarly for other debug sections).
84     ///
85     /// For some object files, multiple segments may contain sections with the same
86     /// name. In this case, the first matching section will be used.
87     ///
88     /// This method skips over sections with invalid names.
section_by_name(&'file self, section_name: &str) -> Option<Self::Section>89     fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;
90 
91     /// Get the section at the given index.
92     ///
93     /// The meaning of the index depends on the object file.
94     ///
95     /// For some object files, this requires iterating through all sections.
96     ///
97     /// Returns an error if the index is invalid.
section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>98     fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>;
99 
100     /// Get an iterator over the sections in the file.
sections(&'file self) -> Self::SectionIterator101     fn sections(&'file self) -> Self::SectionIterator;
102 
103     /// Get an iterator over the COMDAT section groups in the file.
comdats(&'file self) -> Self::ComdatIterator104     fn comdats(&'file self) -> Self::ComdatIterator;
105 
106     /// Get the symbol table, if any.
symbol_table(&'file self) -> Option<Self::SymbolTable>107     fn symbol_table(&'file self) -> Option<Self::SymbolTable>;
108 
109     /// Get the debugging symbol at the given index.
110     ///
111     /// The meaning of the index depends on the object file.
112     ///
113     /// Returns an error if the index is invalid.
symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>114     fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>;
115 
116     /// Get an iterator over the debugging symbols in the file.
117     ///
118     /// This may skip over symbols that are malformed or unsupported.
119     ///
120     /// For Mach-O files, this does not include STAB entries.
symbols(&'file self) -> Self::SymbolIterator121     fn symbols(&'file self) -> Self::SymbolIterator;
122 
123     /// Get the dynamic linking symbol table, if any.
124     ///
125     /// Only ELF has a separate dynamic linking symbol table.
dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>126     fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>;
127 
128     /// Get an iterator over the dynamic linking symbols in the file.
129     ///
130     /// This may skip over symbols that are malformed or unsupported.
131     ///
132     /// Only ELF has separate dynamic linking symbols.
133     /// Other file formats will return an empty iterator.
dynamic_symbols(&'file self) -> Self::SymbolIterator134     fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
135 
136     /// Get the dynamic relocations for this file.
137     ///
138     /// Symbol indices in these relocations refer to the dynamic symbol table.
139     ///
140     /// Only ELF has dynamic relocations.
dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>141     fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>;
142 
143     /// Construct a map from addresses to symbol names.
144     ///
145     /// The map will only contain defined text and data symbols.
146     /// The dynamic symbol table will only be used if there are no debugging symbols.
symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>>147     fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> {
148         let mut symbols = Vec::new();
149         if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) {
150             for symbol in table.symbols() {
151                 if !symbol.is_definition() {
152                     continue;
153                 }
154                 if let Ok(name) = symbol.name() {
155                     symbols.push(SymbolMapName::new(symbol.address(), name));
156                 }
157             }
158         }
159         SymbolMap::new(symbols)
160     }
161 
162     /// Construct a map from addresses to symbol names and object file names.
163     ///
164     /// This is derived from Mach-O STAB entries.
object_map(&'file self) -> ObjectMap<'data>165     fn object_map(&'file self) -> ObjectMap<'data> {
166         ObjectMap::default()
167     }
168 
169     /// Get the imported symbols.
imports(&self) -> Result<Vec<Import<'data>>>170     fn imports(&self) -> Result<Vec<Import<'data>>>;
171 
172     /// Get the exported symbols.
exports(&self) -> Result<Vec<Export<'data>>>173     fn exports(&self) -> Result<Vec<Export<'data>>>;
174 
175     /// Return true if the file contains debug information sections, false if not.
has_debug_symbols(&self) -> bool176     fn has_debug_symbols(&self) -> bool;
177 
178     /// The UUID from a Mach-O `LC_UUID` load command.
179     #[inline]
mach_uuid(&self) -> Result<Option<[u8; 16]>>180     fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
181         Ok(None)
182     }
183 
184     /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
185     #[inline]
build_id(&self) -> Result<Option<&'data [u8]>>186     fn build_id(&self) -> Result<Option<&'data [u8]>> {
187         Ok(None)
188     }
189 
190     /// The filename and CRC from a `.gnu_debuglink` section.
191     #[inline]
gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>192     fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
193         Ok(None)
194     }
195 
196     /// File flags that are specific to each file format.
flags(&self) -> FileFlags197     fn flags(&self) -> FileFlags;
198 }
199 
200 /// A loadable segment defined in an object file.
201 ///
202 /// For ELF, this is a program header with type `PT_LOAD`.
203 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
204 pub trait ObjectSegment<'data>: read::private::Sealed {
205     /// Returns the virtual address of the segment.
address(&self) -> u64206     fn address(&self) -> u64;
207 
208     /// Returns the size of the segment in memory.
size(&self) -> u64209     fn size(&self) -> u64;
210 
211     /// Returns the alignment of the segment in memory.
align(&self) -> u64212     fn align(&self) -> u64;
213 
214     /// Returns the offset and size of the segment in the file.
file_range(&self) -> (u64, u64)215     fn file_range(&self) -> (u64, u64);
216 
217     /// Returns a reference to the file contents of the segment.
218     ///
219     /// The length of this data may be different from the size of the
220     /// segment in memory.
data(&self) -> Result<&'data [u8]>221     fn data(&self) -> Result<&'data [u8]>;
222 
223     /// Return the segment data in the given range.
224     ///
225     /// Returns `Ok(None)` if the segment does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>226     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
227 
228     /// Returns the name of the segment.
name(&self) -> Result<Option<&str>>229     fn name(&self) -> Result<Option<&str>>;
230 }
231 
232 /// A section defined in an object file.
233 pub trait ObjectSection<'data>: read::private::Sealed {
234     /// An iterator over the relocations for a section.
235     ///
236     /// The first field in the item tuple is the section offset
237     /// that the relocation applies to.
238     type RelocationIterator: Iterator<Item = (u64, Relocation)>;
239 
240     /// Returns the section index.
index(&self) -> SectionIndex241     fn index(&self) -> SectionIndex;
242 
243     /// Returns the address of the section.
address(&self) -> u64244     fn address(&self) -> u64;
245 
246     /// Returns the size of the section in memory.
size(&self) -> u64247     fn size(&self) -> u64;
248 
249     /// Returns the alignment of the section in memory.
align(&self) -> u64250     fn align(&self) -> u64;
251 
252     /// Returns offset and size of on-disk segment (if any).
file_range(&self) -> Option<(u64, u64)>253     fn file_range(&self) -> Option<(u64, u64)>;
254 
255     /// Returns the raw contents of the section.
256     ///
257     /// The length of this data may be different from the size of the
258     /// section in memory.
259     ///
260     /// This does not do any decompression.
data(&self) -> Result<&'data [u8]>261     fn data(&self) -> Result<&'data [u8]>;
262 
263     /// Return the raw contents of the section data in the given range.
264     ///
265     /// This does not do any decompression.
266     ///
267     /// Returns `Ok(None)` if the section does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>268     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
269 
270     /// Returns the potentially compressed contents of the section,
271     /// along with information about the compression.
compressed_data(&self) -> Result<CompressedData<'data>>272     fn compressed_data(&self) -> Result<CompressedData<'data>>;
273 
274     /// Returns the uncompressed contents of the section.
275     ///
276     /// The length of this data may be different from the size of the
277     /// section in memory.
278     ///
279     /// If no compression is detected, then returns the data unchanged.
280     /// Returns `Err` if decompression fails.
uncompressed_data(&self) -> Result<Cow<'data, [u8]>>281     fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
282         self.compressed_data()?.decompress()
283     }
284 
285     /// Returns the name of the section.
name(&self) -> Result<&str>286     fn name(&self) -> Result<&str>;
287 
288     /// Returns the name of the segment for this section.
segment_name(&self) -> Result<Option<&str>>289     fn segment_name(&self) -> Result<Option<&str>>;
290 
291     /// Return the kind of this section.
kind(&self) -> SectionKind292     fn kind(&self) -> SectionKind;
293 
294     /// Get the relocations for this section.
relocations(&self) -> Self::RelocationIterator295     fn relocations(&self) -> Self::RelocationIterator;
296 
297     /// Section flags that are specific to each file format.
flags(&self) -> SectionFlags298     fn flags(&self) -> SectionFlags;
299 }
300 
301 /// A COMDAT section group defined in an object file.
302 pub trait ObjectComdat<'data>: read::private::Sealed {
303     /// An iterator over the sections in the object file.
304     type SectionIterator: Iterator<Item = SectionIndex>;
305 
306     /// Returns the COMDAT selection kind.
kind(&self) -> ComdatKind307     fn kind(&self) -> ComdatKind;
308 
309     /// Returns the index of the symbol used for the name of COMDAT section group.
symbol(&self) -> SymbolIndex310     fn symbol(&self) -> SymbolIndex;
311 
312     /// Returns the name of the COMDAT section group.
name(&self) -> Result<&str>313     fn name(&self) -> Result<&str>;
314 
315     /// Get the sections in this section group.
sections(&self) -> Self::SectionIterator316     fn sections(&self) -> Self::SectionIterator;
317 }
318 
319 /// A symbol table.
320 pub trait ObjectSymbolTable<'data>: read::private::Sealed {
321     /// A symbol table entry.
322     type Symbol: ObjectSymbol<'data>;
323 
324     /// An iterator over the symbols in a symbol table.
325     type SymbolIterator: Iterator<Item = Self::Symbol>;
326 
327     /// Get an iterator over the symbols in the table.
328     ///
329     /// This may skip over symbols that are malformed or unsupported.
symbols(&self) -> Self::SymbolIterator330     fn symbols(&self) -> Self::SymbolIterator;
331 
332     /// Get the symbol at the given index.
333     ///
334     /// The meaning of the index depends on the object file.
335     ///
336     /// Returns an error if the index is invalid.
symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>337     fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>;
338 }
339 
340 /// A symbol table entry.
341 pub trait ObjectSymbol<'data>: read::private::Sealed {
342     /// The index of the symbol.
index(&self) -> SymbolIndex343     fn index(&self) -> SymbolIndex;
344 
345     /// The name of the symbol.
name(&self) -> Result<&'data str>346     fn name(&self) -> Result<&'data str>;
347 
348     /// The address of the symbol. May be zero if the address is unknown.
address(&self) -> u64349     fn address(&self) -> u64;
350 
351     /// The size of the symbol. May be zero if the size is unknown.
size(&self) -> u64352     fn size(&self) -> u64;
353 
354     /// Return the kind of this symbol.
kind(&self) -> SymbolKind355     fn kind(&self) -> SymbolKind;
356 
357     /// Returns the section where the symbol is defined.
section(&self) -> SymbolSection358     fn section(&self) -> SymbolSection;
359 
360     /// Returns the section index for the section containing this symbol.
361     ///
362     /// May return `None` if the symbol is not defined in a section.
section_index(&self) -> Option<SectionIndex>363     fn section_index(&self) -> Option<SectionIndex> {
364         self.section().index()
365     }
366 
367     /// Return true if the symbol is undefined.
is_undefined(&self) -> bool368     fn is_undefined(&self) -> bool;
369 
370     /// Return true if the symbol is a definition of a function or data object
371     /// that has a known address.
is_definition(&self) -> bool372     fn is_definition(&self) -> bool;
373 
374     /// Return true if the symbol is common data.
375     ///
376     /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
is_common(&self) -> bool377     fn is_common(&self) -> bool;
378 
379     /// Return true if the symbol is weak.
is_weak(&self) -> bool380     fn is_weak(&self) -> bool;
381 
382     /// Returns the symbol scope.
scope(&self) -> SymbolScope383     fn scope(&self) -> SymbolScope;
384 
385     /// Return true if the symbol visible outside of the compilation unit.
386     ///
387     /// This treats `SymbolScope::Unknown` as global.
is_global(&self) -> bool388     fn is_global(&self) -> bool;
389 
390     /// Return true if the symbol is only visible within the compilation unit.
is_local(&self) -> bool391     fn is_local(&self) -> bool;
392 
393     /// Symbol flags that are specific to each file format.
flags(&self) -> SymbolFlags<SectionIndex>394     fn flags(&self) -> SymbolFlags<SectionIndex>;
395 }
396 
397 /// An iterator for files that don't have dynamic relocations.
398 #[derive(Debug)]
399 pub struct NoDynamicRelocationIterator;
400 
401 impl Iterator for NoDynamicRelocationIterator {
402     type Item = (u64, Relocation);
403 
404     #[inline]
next(&mut self) -> Option<Self::Item>405     fn next(&mut self) -> Option<Self::Item> {
406         None
407     }
408 }
409