1 use alloc::borrow::Cow;
2 use alloc::vec::Vec;
3 
4 use crate::read::{
5     self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export,
6     FileFlags, Import, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, SectionKind,
7     SymbolFlags, SymbolIndex, 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 section named `section_name`, if such a section exists.
73     ///
74     /// If `section_name` starts with a '.' then it is treated as a system section name,
75     /// and is compared using the conventions specific to the object file format. This
76     /// includes:
77     /// - if ".debug_str_offsets" is requested for a Mach-O object file, then the actual
78     /// section name that is searched for is "__debug_str_offs".
79     /// - if ".debug_info" is requested for an ELF object file, then
80     /// ".zdebug_info" may be returned (and similarly for other debug sections).
81     ///
82     /// For some object files, multiple segments may contain sections with the same
83     /// name. In this case, the first matching section will be used.
84     ///
85     /// This method skips over sections with invalid names.
section_by_name(&'file self, section_name: &str) -> Option<Self::Section>86     fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;
87 
88     /// Get the section at the given index.
89     ///
90     /// The meaning of the index depends on the object file.
91     ///
92     /// For some object files, this requires iterating through all sections.
93     ///
94     /// Returns an error if the index is invalid.
section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>95     fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>;
96 
97     /// Get an iterator over the sections in the file.
sections(&'file self) -> Self::SectionIterator98     fn sections(&'file self) -> Self::SectionIterator;
99 
100     /// Get an iterator over the COMDAT section groups in the file.
comdats(&'file self) -> Self::ComdatIterator101     fn comdats(&'file self) -> Self::ComdatIterator;
102 
103     /// Get the symbol table, if any.
symbol_table(&'file self) -> Option<Self::SymbolTable>104     fn symbol_table(&'file self) -> Option<Self::SymbolTable>;
105 
106     /// Get the debugging symbol at the given index.
107     ///
108     /// The meaning of the index depends on the object file.
109     ///
110     /// Returns an error if the index is invalid.
symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>111     fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>;
112 
113     /// Get an iterator over the debugging symbols in the file.
114     ///
115     /// This may skip over symbols that are malformed or unsupported.
116     ///
117     /// For Mach-O files, this does not include STAB entries.
symbols(&'file self) -> Self::SymbolIterator118     fn symbols(&'file self) -> Self::SymbolIterator;
119 
120     /// Get the dynamic linking symbol table, if any.
121     ///
122     /// Only ELF has a separate dynamic linking symbol table.
dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>123     fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>;
124 
125     /// Get an iterator over the dynamic linking symbols in the file.
126     ///
127     /// This may skip over symbols that are malformed or unsupported.
128     ///
129     /// Only ELF has separate dynamic linking symbols.
130     /// Other file formats will return an empty iterator.
dynamic_symbols(&'file self) -> Self::SymbolIterator131     fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
132 
133     /// Get the dynamic relocations for this file.
134     ///
135     /// Symbol indices in these relocations refer to the dynamic symbol table.
136     ///
137     /// Only ELF has dynamic relocations.
dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>138     fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>;
139 
140     /// Construct a map from addresses to symbol names.
141     ///
142     /// The map will only contain defined text and data symbols.
143     /// The dynamic symbol table will only be used if there are no debugging symbols.
symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>>144     fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> {
145         let mut symbols = Vec::new();
146         if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) {
147             for symbol in table.symbols() {
148                 if !symbol.is_definition() {
149                     continue;
150                 }
151                 if let Ok(name) = symbol.name() {
152                     symbols.push(SymbolMapName::new(symbol.address(), name));
153                 }
154             }
155         }
156         SymbolMap::new(symbols)
157     }
158 
159     /// Construct a map from addresses to symbol names and object file names.
160     ///
161     /// This is derived from Mach-O STAB entries.
object_map(&'file self) -> ObjectMap<'data>162     fn object_map(&'file self) -> ObjectMap<'data> {
163         ObjectMap::default()
164     }
165 
166     /// Get the imported symbols.
imports(&self) -> Result<Vec<Import<'data>>>167     fn imports(&self) -> Result<Vec<Import<'data>>>;
168 
169     /// Get the exported symbols.
exports(&self) -> Result<Vec<Export<'data>>>170     fn exports(&self) -> Result<Vec<Export<'data>>>;
171 
172     /// Return true if the file contains debug information sections, false if not.
has_debug_symbols(&self) -> bool173     fn has_debug_symbols(&self) -> bool;
174 
175     /// The UUID from a Mach-O `LC_UUID` load command.
176     #[inline]
mach_uuid(&self) -> Result<Option<[u8; 16]>>177     fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
178         Ok(None)
179     }
180 
181     /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
182     #[inline]
build_id(&self) -> Result<Option<&'data [u8]>>183     fn build_id(&self) -> Result<Option<&'data [u8]>> {
184         Ok(None)
185     }
186 
187     /// The filename and CRC from a `.gnu_debuglink` section.
188     #[inline]
gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>189     fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
190         Ok(None)
191     }
192 
193     /// The filename and build ID from a `.gnu_debugaltlink` section.
194     #[inline]
gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>>195     fn gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>> {
196         Ok(None)
197     }
198 
199     /// The filename and GUID from the PE CodeView section
200     #[inline]
pdb_info(&self) -> Result<Option<CodeView>>201     fn pdb_info(&self) -> Result<Option<CodeView>> {
202         Ok(None)
203     }
204 
205     /// Get the base address used for relative virtual addresses.
206     ///
207     /// Currently this is only non-zero for PE.
relative_address_base(&'file self) -> u64208     fn relative_address_base(&'file self) -> u64;
209 
210     /// Get the virtual address of the entry point of the binary
entry(&'file self) -> u64211     fn entry(&'file self) -> u64;
212 
213     /// File flags that are specific to each file format.
flags(&self) -> FileFlags214     fn flags(&self) -> FileFlags;
215 }
216 
217 /// A loadable segment defined in an object file.
218 ///
219 /// For ELF, this is a program header with type `PT_LOAD`.
220 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
221 pub trait ObjectSegment<'data>: read::private::Sealed {
222     /// Returns the virtual address of the segment.
address(&self) -> u64223     fn address(&self) -> u64;
224 
225     /// Returns the size of the segment in memory.
size(&self) -> u64226     fn size(&self) -> u64;
227 
228     /// Returns the alignment of the segment in memory.
align(&self) -> u64229     fn align(&self) -> u64;
230 
231     /// Returns the offset and size of the segment in the file.
file_range(&self) -> (u64, u64)232     fn file_range(&self) -> (u64, u64);
233 
234     /// Returns a reference to the file contents of the segment.
235     ///
236     /// The length of this data may be different from the size of the
237     /// segment in memory.
data(&self) -> Result<&'data [u8]>238     fn data(&self) -> Result<&'data [u8]>;
239 
240     /// Return the segment data in the given range.
241     ///
242     /// Returns `Ok(None)` if the segment does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>243     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
244 
245     /// Returns the name of the segment.
name(&self) -> Result<Option<&str>>246     fn name(&self) -> Result<Option<&str>>;
247 }
248 
249 /// A section defined in an object file.
250 pub trait ObjectSection<'data>: read::private::Sealed {
251     /// An iterator over the relocations for a section.
252     ///
253     /// The first field in the item tuple is the section offset
254     /// that the relocation applies to.
255     type RelocationIterator: Iterator<Item = (u64, Relocation)>;
256 
257     /// Returns the section index.
index(&self) -> SectionIndex258     fn index(&self) -> SectionIndex;
259 
260     /// Returns the address of the section.
address(&self) -> u64261     fn address(&self) -> u64;
262 
263     /// Returns the size of the section in memory.
size(&self) -> u64264     fn size(&self) -> u64;
265 
266     /// Returns the alignment of the section in memory.
align(&self) -> u64267     fn align(&self) -> u64;
268 
269     /// Returns offset and size of on-disk segment (if any).
file_range(&self) -> Option<(u64, u64)>270     fn file_range(&self) -> Option<(u64, u64)>;
271 
272     /// Returns the raw contents of the section.
273     ///
274     /// The length of this data may be different from the size of the
275     /// section in memory.
276     ///
277     /// This does not do any decompression.
data(&self) -> Result<&'data [u8]>278     fn data(&self) -> Result<&'data [u8]>;
279 
280     /// Return the raw contents of the section data in the given range.
281     ///
282     /// This does not do any decompression.
283     ///
284     /// Returns `Ok(None)` if the section does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>285     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
286 
287     /// Returns the potentially compressed file range of the section,
288     /// along with information about the compression.
compressed_file_range(&self) -> Result<CompressedFileRange>289     fn compressed_file_range(&self) -> Result<CompressedFileRange>;
290 
291     /// Returns the potentially compressed contents of the section,
292     /// along with information about the compression.
compressed_data(&self) -> Result<CompressedData<'data>>293     fn compressed_data(&self) -> Result<CompressedData<'data>>;
294 
295     /// Returns the uncompressed contents of the section.
296     ///
297     /// The length of this data may be different from the size of the
298     /// section in memory.
299     ///
300     /// If no compression is detected, then returns the data unchanged.
301     /// Returns `Err` if decompression fails.
uncompressed_data(&self) -> Result<Cow<'data, [u8]>>302     fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
303         self.compressed_data()?.decompress()
304     }
305 
306     /// Returns the name of the section.
name(&self) -> Result<&str>307     fn name(&self) -> Result<&str>;
308 
309     /// Returns the name of the segment for this section.
segment_name(&self) -> Result<Option<&str>>310     fn segment_name(&self) -> Result<Option<&str>>;
311 
312     /// Return the kind of this section.
kind(&self) -> SectionKind313     fn kind(&self) -> SectionKind;
314 
315     /// Get the relocations for this section.
relocations(&self) -> Self::RelocationIterator316     fn relocations(&self) -> Self::RelocationIterator;
317 
318     /// Section flags that are specific to each file format.
flags(&self) -> SectionFlags319     fn flags(&self) -> SectionFlags;
320 }
321 
322 /// A COMDAT section group defined in an object file.
323 pub trait ObjectComdat<'data>: read::private::Sealed {
324     /// An iterator over the sections in the object file.
325     type SectionIterator: Iterator<Item = SectionIndex>;
326 
327     /// Returns the COMDAT selection kind.
kind(&self) -> ComdatKind328     fn kind(&self) -> ComdatKind;
329 
330     /// Returns the index of the symbol used for the name of COMDAT section group.
symbol(&self) -> SymbolIndex331     fn symbol(&self) -> SymbolIndex;
332 
333     /// Returns the name of the COMDAT section group.
name(&self) -> Result<&str>334     fn name(&self) -> Result<&str>;
335 
336     /// Get the sections in this section group.
sections(&self) -> Self::SectionIterator337     fn sections(&self) -> Self::SectionIterator;
338 }
339 
340 /// A symbol table.
341 pub trait ObjectSymbolTable<'data>: read::private::Sealed {
342     /// A symbol table entry.
343     type Symbol: ObjectSymbol<'data>;
344 
345     /// An iterator over the symbols in a symbol table.
346     type SymbolIterator: Iterator<Item = Self::Symbol>;
347 
348     /// Get an iterator over the symbols in the table.
349     ///
350     /// This may skip over symbols that are malformed or unsupported.
symbols(&self) -> Self::SymbolIterator351     fn symbols(&self) -> Self::SymbolIterator;
352 
353     /// Get the symbol at the given index.
354     ///
355     /// The meaning of the index depends on the object file.
356     ///
357     /// Returns an error if the index is invalid.
symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>358     fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>;
359 }
360 
361 /// A symbol table entry.
362 pub trait ObjectSymbol<'data>: read::private::Sealed {
363     /// The index of the symbol.
index(&self) -> SymbolIndex364     fn index(&self) -> SymbolIndex;
365 
366     /// The name of the symbol.
name(&self) -> Result<&'data str>367     fn name(&self) -> Result<&'data str>;
368 
369     /// The address of the symbol. May be zero if the address is unknown.
address(&self) -> u64370     fn address(&self) -> u64;
371 
372     /// The size of the symbol. May be zero if the size is unknown.
size(&self) -> u64373     fn size(&self) -> u64;
374 
375     /// Return the kind of this symbol.
kind(&self) -> SymbolKind376     fn kind(&self) -> SymbolKind;
377 
378     /// Returns the section where the symbol is defined.
section(&self) -> SymbolSection379     fn section(&self) -> SymbolSection;
380 
381     /// Returns the section index for the section containing this symbol.
382     ///
383     /// May return `None` if the symbol is not defined in a section.
section_index(&self) -> Option<SectionIndex>384     fn section_index(&self) -> Option<SectionIndex> {
385         self.section().index()
386     }
387 
388     /// Return true if the symbol is undefined.
is_undefined(&self) -> bool389     fn is_undefined(&self) -> bool;
390 
391     /// Return true if the symbol is a definition of a function or data object
392     /// that has a known address.
is_definition(&self) -> bool393     fn is_definition(&self) -> bool;
394 
395     /// Return true if the symbol is common data.
396     ///
397     /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
is_common(&self) -> bool398     fn is_common(&self) -> bool;
399 
400     /// Return true if the symbol is weak.
is_weak(&self) -> bool401     fn is_weak(&self) -> bool;
402 
403     /// Returns the symbol scope.
scope(&self) -> SymbolScope404     fn scope(&self) -> SymbolScope;
405 
406     /// Return true if the symbol visible outside of the compilation unit.
407     ///
408     /// This treats `SymbolScope::Unknown` as global.
is_global(&self) -> bool409     fn is_global(&self) -> bool;
410 
411     /// Return true if the symbol is only visible within the compilation unit.
is_local(&self) -> bool412     fn is_local(&self) -> bool;
413 
414     /// Symbol flags that are specific to each file format.
flags(&self) -> SymbolFlags<SectionIndex>415     fn flags(&self) -> SymbolFlags<SectionIndex>;
416 }
417 
418 /// An iterator for files that don't have dynamic relocations.
419 #[derive(Debug)]
420 pub struct NoDynamicRelocationIterator;
421 
422 impl Iterator for NoDynamicRelocationIterator {
423     type Item = (u64, Relocation);
424 
425     #[inline]
next(&mut self) -> Option<Self::Item>426     fn next(&mut self) -> Option<Self::Item> {
427         None
428     }
429 }
430