1 use alloc::borrow::Cow;
2 use alloc::vec::Vec;
3 
4 use crate::read::{
5     self, Architecture, ComdatKind, CompressedData, FileFlags, ObjectMap, Relocation, Result,
6     SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, SymbolKind, SymbolMap,
7     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     /// Get the architecture type of the file.
architecture(&self) -> Architecture45     fn architecture(&self) -> Architecture;
46 
47     /// Get the endianness of the file.
48     #[inline]
endianness(&self) -> Endianness49     fn endianness(&self) -> Endianness {
50         if self.is_little_endian() {
51             Endianness::Little
52         } else {
53             Endianness::Big
54         }
55     }
56 
57     /// Return true if the file is little endian, false if it is big endian.
is_little_endian(&self) -> bool58     fn is_little_endian(&self) -> bool;
59 
60     /// Return true if the file can contain 64-bit addresses.
is_64(&self) -> bool61     fn is_64(&self) -> bool;
62 
63     /// Get an iterator over the segments in the file.
segments(&'file self) -> Self::SegmentIterator64     fn segments(&'file self) -> Self::SegmentIterator;
65 
66     /// Get the entry point address of the binary
entry(&'file self) -> u6467     fn entry(&'file self) -> u64;
68 
69     /// Get the section named `section_name`, if such a section exists.
70     ///
71     /// If `section_name` starts with a '.' then it is treated as a system section name,
72     /// and is compared using the conventions specific to the object file format. This
73     /// includes:
74     /// - if ".text" is requested for a Mach-O object file, then the actual
75     /// section name that is searched for is "__text".
76     /// - if ".debug_info" is requested for an ELF object file, then
77     /// ".zdebug_info" may be returned (and similarly for other debug sections).
78     ///
79     /// For some object files, multiple segments may contain sections with the same
80     /// name. In this case, the first matching section will be used.
81     ///
82     /// This method skips over sections with invalid names.
section_by_name(&'file self, section_name: &str) -> Option<Self::Section>83     fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;
84 
85     /// Get the section at the given index.
86     ///
87     /// The meaning of the index depends on the object file.
88     ///
89     /// For some object files, this requires iterating through all sections.
90     ///
91     /// Returns an error if the index is invalid.
section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>92     fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>;
93 
94     /// Get an iterator over the sections in the file.
sections(&'file self) -> Self::SectionIterator95     fn sections(&'file self) -> Self::SectionIterator;
96 
97     /// Get an iterator over the COMDAT section groups in the file.
comdats(&'file self) -> Self::ComdatIterator98     fn comdats(&'file self) -> Self::ComdatIterator;
99 
100     /// Get the symbol table, if any.
symbol_table(&'file self) -> Option<Self::SymbolTable>101     fn symbol_table(&'file self) -> Option<Self::SymbolTable>;
102 
103     /// Get the debugging symbol at the given index.
104     ///
105     /// The meaning of the index depends on the object file.
106     ///
107     /// Returns an error if the index is invalid.
symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>108     fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>;
109 
110     /// Get an iterator over the debugging symbols in the file.
111     ///
112     /// This may skip over symbols that are malformed or unsupported.
113     ///
114     /// For Mach-O files, this does not include STAB entries.
symbols(&'file self) -> Self::SymbolIterator115     fn symbols(&'file self) -> Self::SymbolIterator;
116 
117     /// Get the dynamic linking symbol table, if any.
118     ///
119     /// Only ELF has a separate dynamic linking symbol table.
dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>120     fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>;
121 
122     /// Get an iterator over the dynamic linking symbols in the file.
123     ///
124     /// This may skip over symbols that are malformed or unsupported.
dynamic_symbols(&'file self) -> Self::SymbolIterator125     fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
126 
127     /// Construct a map from addresses to symbol names.
128     ///
129     /// The map will only contain defined text and data symbols.
130     /// The dynamic symbol table will only be used if there are no debugging symbols.
symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>>131     fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> {
132         let mut symbols = Vec::new();
133         if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) {
134             for symbol in table.symbols() {
135                 if !symbol.is_definition() {
136                     continue;
137                 }
138                 if let Ok(name) = symbol.name() {
139                     symbols.push(SymbolMapName::new(symbol.address(), name));
140                 }
141             }
142         }
143         SymbolMap::new(symbols)
144     }
145 
146     /// Construct a map from addresses to symbol names and object file names.
147     ///
148     /// This is derived from Mach-O STAB entries.
object_map(&'file self) -> ObjectMap<'data>149     fn object_map(&'file self) -> ObjectMap<'data> {
150         ObjectMap::default()
151     }
152 
153     /// Return true if the file contains debug information sections, false if not.
has_debug_symbols(&self) -> bool154     fn has_debug_symbols(&self) -> bool;
155 
156     /// The UUID from a Mach-O `LC_UUID` load command.
157     #[inline]
mach_uuid(&self) -> Result<Option<[u8; 16]>>158     fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
159         Ok(None)
160     }
161 
162     /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
163     #[inline]
build_id(&self) -> Result<Option<&'data [u8]>>164     fn build_id(&self) -> Result<Option<&'data [u8]>> {
165         Ok(None)
166     }
167 
168     /// The filename and CRC from a `.gnu_debuglink` section.
169     #[inline]
gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>170     fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
171         Ok(None)
172     }
173 
174     /// File flags that are specific to each file format.
flags(&self) -> FileFlags175     fn flags(&self) -> FileFlags;
176 }
177 
178 /// A loadable segment defined in an object file.
179 ///
180 /// For ELF, this is a program header with type `PT_LOAD`.
181 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
182 pub trait ObjectSegment<'data>: read::private::Sealed {
183     /// Returns the virtual address of the segment.
address(&self) -> u64184     fn address(&self) -> u64;
185 
186     /// Returns the size of the segment in memory.
size(&self) -> u64187     fn size(&self) -> u64;
188 
189     /// Returns the alignment of the segment in memory.
align(&self) -> u64190     fn align(&self) -> u64;
191 
192     /// Returns the offset and size of the segment in the file.
file_range(&self) -> (u64, u64)193     fn file_range(&self) -> (u64, u64);
194 
195     /// Returns a reference to the file contents of the segment.
196     ///
197     /// The length of this data may be different from the size of the
198     /// segment in memory.
data(&self) -> Result<&'data [u8]>199     fn data(&self) -> Result<&'data [u8]>;
200 
201     /// Return the segment data in the given range.
202     ///
203     /// Returns `Ok(None)` if the segment does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>204     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
205 
206     /// Returns the name of the segment.
name(&self) -> Result<Option<&str>>207     fn name(&self) -> Result<Option<&str>>;
208 }
209 
210 /// A section defined in an object file.
211 pub trait ObjectSection<'data>: read::private::Sealed {
212     /// An iterator over the relocations for a section.
213     ///
214     /// The first field in the item tuple is the section offset
215     /// that the relocation applies to.
216     type RelocationIterator: Iterator<Item = (u64, Relocation)>;
217 
218     /// Returns the section index.
index(&self) -> SectionIndex219     fn index(&self) -> SectionIndex;
220 
221     /// Returns the address of the section.
address(&self) -> u64222     fn address(&self) -> u64;
223 
224     /// Returns the size of the section in memory.
size(&self) -> u64225     fn size(&self) -> u64;
226 
227     /// Returns the alignment of the section in memory.
align(&self) -> u64228     fn align(&self) -> u64;
229 
230     /// Returns offset and size of on-disk segment (if any).
file_range(&self) -> Option<(u64, u64)>231     fn file_range(&self) -> Option<(u64, u64)>;
232 
233     /// Returns the raw contents of the section.
234     ///
235     /// The length of this data may be different from the size of the
236     /// section in memory.
237     ///
238     /// This does not do any decompression.
data(&self) -> Result<&'data [u8]>239     fn data(&self) -> Result<&'data [u8]>;
240 
241     /// Return the raw contents of the section data in the given range.
242     ///
243     /// This does not do any decompression.
244     ///
245     /// Returns `Ok(None)` if the section does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>246     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
247 
248     /// Returns the potentially compressed contents of the section,
249     /// along with information about the compression.
compressed_data(&self) -> Result<CompressedData<'data>>250     fn compressed_data(&self) -> Result<CompressedData<'data>>;
251 
252     /// Returns the uncompressed contents of the section.
253     ///
254     /// The length of this data may be different from the size of the
255     /// section in memory.
256     ///
257     /// If no compression is detected, then returns the data unchanged.
258     /// Returns `Err` if decompression fails.
uncompressed_data(&self) -> Result<Cow<'data, [u8]>>259     fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
260         self.compressed_data()?.decompress()
261     }
262 
263     /// Returns the name of the section.
name(&self) -> Result<&str>264     fn name(&self) -> Result<&str>;
265 
266     /// Returns the name of the segment for this section.
segment_name(&self) -> Result<Option<&str>>267     fn segment_name(&self) -> Result<Option<&str>>;
268 
269     /// Return the kind of this section.
kind(&self) -> SectionKind270     fn kind(&self) -> SectionKind;
271 
272     /// Get the relocations for this section.
relocations(&self) -> Self::RelocationIterator273     fn relocations(&self) -> Self::RelocationIterator;
274 
275     /// Section flags that are specific to each file format.
flags(&self) -> SectionFlags276     fn flags(&self) -> SectionFlags;
277 }
278 
279 /// A COMDAT section group defined in an object file.
280 pub trait ObjectComdat<'data>: read::private::Sealed {
281     /// An iterator over the sections in the object file.
282     type SectionIterator: Iterator<Item = SectionIndex>;
283 
284     /// Returns the COMDAT selection kind.
kind(&self) -> ComdatKind285     fn kind(&self) -> ComdatKind;
286 
287     /// Returns the index of the symbol used for the name of COMDAT section group.
symbol(&self) -> SymbolIndex288     fn symbol(&self) -> SymbolIndex;
289 
290     /// Returns the name of the COMDAT section group.
name(&self) -> Result<&str>291     fn name(&self) -> Result<&str>;
292 
293     /// Get the sections in this section group.
sections(&self) -> Self::SectionIterator294     fn sections(&self) -> Self::SectionIterator;
295 }
296 
297 /// A symbol table.
298 pub trait ObjectSymbolTable<'data>: read::private::Sealed {
299     /// A symbol table entry.
300     type Symbol: ObjectSymbol<'data>;
301 
302     /// An iterator over the symbols in a symbol table.
303     type SymbolIterator: Iterator<Item = Self::Symbol>;
304 
305     /// Get an iterator over the symbols in the table.
306     ///
307     /// This may skip over symbols that are malformed or unsupported.
symbols(&self) -> Self::SymbolIterator308     fn symbols(&self) -> Self::SymbolIterator;
309 
310     /// Get the symbol at the given index.
311     ///
312     /// The meaning of the index depends on the object file.
313     ///
314     /// Returns an error if the index is invalid.
symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>315     fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>;
316 }
317 
318 /// A symbol table entry.
319 pub trait ObjectSymbol<'data>: read::private::Sealed {
320     /// The index of the symbol.
index(&self) -> SymbolIndex321     fn index(&self) -> SymbolIndex;
322 
323     /// The name of the symbol.
name(&self) -> Result<&'data str>324     fn name(&self) -> Result<&'data str>;
325 
326     /// The address of the symbol. May be zero if the address is unknown.
address(&self) -> u64327     fn address(&self) -> u64;
328 
329     /// The size of the symbol. May be zero if the size is unknown.
size(&self) -> u64330     fn size(&self) -> u64;
331 
332     /// Return the kind of this symbol.
kind(&self) -> SymbolKind333     fn kind(&self) -> SymbolKind;
334 
335     /// Returns the section where the symbol is defined.
section(&self) -> SymbolSection336     fn section(&self) -> SymbolSection;
337 
338     /// Returns the section index for the section containing this symbol.
339     ///
340     /// May return `None` if the symbol is not defined in a section.
section_index(&self) -> Option<SectionIndex>341     fn section_index(&self) -> Option<SectionIndex> {
342         self.section().index()
343     }
344 
345     /// Return true if the symbol is undefined.
is_undefined(&self) -> bool346     fn is_undefined(&self) -> bool;
347 
348     /// Return true if the symbol is a definition of a function or data object
349     /// that has a known address.
is_definition(&self) -> bool350     fn is_definition(&self) -> bool;
351 
352     /// Return true if the symbol is common data.
353     ///
354     /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`.
is_common(&self) -> bool355     fn is_common(&self) -> bool;
356 
357     /// Return true if the symbol is weak.
is_weak(&self) -> bool358     fn is_weak(&self) -> bool;
359 
360     /// Returns the symbol scope.
scope(&self) -> SymbolScope361     fn scope(&self) -> SymbolScope;
362 
363     /// Return true if the symbol visible outside of the compilation unit.
364     ///
365     /// This treats `SymbolScope::Unknown` as global.
is_global(&self) -> bool366     fn is_global(&self) -> bool;
367 
368     /// Return true if the symbol is only visible within the compilation unit.
is_local(&self) -> bool369     fn is_local(&self) -> bool;
370 
371     /// Symbol flags that are specific to each file format.
flags(&self) -> SymbolFlags<SectionIndex>372     fn flags(&self) -> SymbolFlags<SectionIndex>;
373 }
374