Skip to main content

object/read/
traits.rs

1use alloc::borrow::Cow;
2use alloc::vec::Vec;
3
4use crate::endian::Endianness;
5use crate::read::{
6    self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export,
7    FileFlags, Import, ObjectKind, ObjectMap, Permissions, Relocation, RelocationMap, Result,
8    SectionFlags, SectionIndex, SectionKind, SegmentFlags, SubArchitecture, SymbolFlags,
9    SymbolIndex, SymbolKind, SymbolMap, SymbolMapBuilder, SymbolMapName, SymbolScope,
10    SymbolSection,
11};
12
13/// An object file.
14///
15/// This is the primary trait for the unified read API.
16pub trait Object<'data>: read::private::Sealed {
17    /// A loadable segment in the object file.
18    type Segment<'file>: ObjectSegment<'data>
19    where
20        Self: 'file,
21        'data: 'file;
22
23    /// An iterator for the loadable segments in the object file.
24    type SegmentIterator<'file>: Iterator<Item = Self::Segment<'file>>
25    where
26        Self: 'file,
27        'data: 'file;
28
29    /// A section in the object file.
30    type Section<'file>: ObjectSection<'data>
31    where
32        Self: 'file,
33        'data: 'file;
34
35    /// An iterator for the sections in the object file.
36    type SectionIterator<'file>: Iterator<Item = Self::Section<'file>>
37    where
38        Self: 'file,
39        'data: 'file;
40
41    /// A COMDAT section group in the object file.
42    type Comdat<'file>: ObjectComdat<'data>
43    where
44        Self: 'file,
45        'data: 'file;
46
47    /// An iterator for the COMDAT section groups in the object file.
48    type ComdatIterator<'file>: Iterator<Item = Self::Comdat<'file>>
49    where
50        Self: 'file,
51        'data: 'file;
52
53    /// A symbol in the object file.
54    type Symbol<'file>: ObjectSymbol<'data>
55    where
56        Self: 'file,
57        'data: 'file;
58
59    /// An iterator for symbols in the object file.
60    type SymbolIterator<'file>: Iterator<Item = Self::Symbol<'file>>
61    where
62        Self: 'file,
63        'data: 'file;
64
65    /// A symbol table in the object file.
66    type SymbolTable<'file>: ObjectSymbolTable<
67        'data,
68        Symbol = Self::Symbol<'file>,
69        SymbolIterator = Self::SymbolIterator<'file>,
70    >
71    where
72        Self: 'file,
73        'data: 'file;
74
75    /// An iterator for the dynamic relocations in the file.
76    ///
77    /// The first field in the item tuple is the address
78    /// that the relocation applies to.
79    type DynamicRelocationIterator<'file>: Iterator<Item = (u64, Relocation)>
80    where
81        Self: 'file,
82        'data: 'file;
83
84    /// Get the architecture type of the file.
85    fn architecture(&self) -> Architecture;
86
87    /// Get the sub-architecture type of the file if known.
88    ///
89    /// A value of `None` has a range of meanings: the file supports all
90    /// sub-architectures, the file does not explicitly specify a
91    /// sub-architecture, or the sub-architecture is currently unrecognized.
92    fn sub_architecture(&self) -> Option<SubArchitecture> {
93        None
94    }
95
96    /// Get the endianness of the file.
97    #[inline]
98    fn endianness(&self) -> Endianness {
99        if self.is_little_endian() {
100            Endianness::Little
101        } else {
102            Endianness::Big
103        }
104    }
105
106    /// Return true if the file is little endian, false if it is big endian.
107    fn is_little_endian(&self) -> bool;
108
109    /// Return true if the file can contain 64-bit addresses.
110    fn is_64(&self) -> bool;
111
112    /// Return the kind of this object.
113    fn kind(&self) -> ObjectKind;
114
115    /// Get an iterator for the loadable segments in the file.
116    ///
117    /// For ELF, this is program headers with type [`PT_LOAD`](crate::elf::PT_LOAD).
118    /// For Mach-O, this is load commands with type [`LC_SEGMENT`](crate::macho::LC_SEGMENT)
119    /// or [`LC_SEGMENT_64`](crate::macho::LC_SEGMENT_64).
120    /// For PE, this is all sections.
121    fn segments(&self) -> Self::SegmentIterator<'_>;
122
123    /// Get the section named `section_name`, if such a section exists.
124    ///
125    /// If `section_name` starts with a '.' then it is treated as a system
126    /// section name, and is compared using the conventions specific to the
127    /// object file format. This includes:
128    /// - if ".debug_str_offsets" is requested for a Mach-O object file, then
129    ///   the actual section name that is searched for is "__debug_str_offs".
130    /// - if ".debug_info" is requested for an ELF object file, then
131    ///   ".zdebug_info" may be returned (and similarly for other debug
132    ///   sections). Similarly, if ".debug_info" is requested for a Mach-O
133    ///   object file, then "__zdebug_info" may be returned.
134    ///
135    /// For some object files, multiple segments may contain sections with the
136    /// same name. In this case, the first matching section will be used.
137    ///
138    /// This method skips over sections with invalid names.
139    fn section_by_name(&self, section_name: &str) -> Option<Self::Section<'_>> {
140        self.section_by_name_bytes(section_name.as_bytes())
141    }
142
143    /// Like [`Self::section_by_name`], but allows names that are not UTF-8.
144    fn section_by_name_bytes<'file>(
145        &'file self,
146        section_name: &[u8],
147    ) -> Option<Self::Section<'file>>;
148
149    /// Get the section at the given index.
150    ///
151    /// The meaning of the index depends on the object file.
152    ///
153    /// For some object files, this requires iterating through all sections.
154    ///
155    /// Returns an error if the index is invalid.
156    fn section_by_index(&self, index: SectionIndex) -> Result<Self::Section<'_>>;
157
158    /// Get an iterator for the sections in the file.
159    fn sections(&self) -> Self::SectionIterator<'_>;
160
161    /// Get an iterator for the COMDAT section groups in the file.
162    fn comdats(&self) -> Self::ComdatIterator<'_>;
163
164    /// Get the debugging symbol table, if any.
165    fn symbol_table(&self) -> Option<Self::SymbolTable<'_>>;
166
167    /// Get the debugging symbol at the given index.
168    ///
169    /// The meaning of the index depends on the object file.
170    ///
171    /// Returns an error if the index is invalid.
172    fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol<'_>>;
173
174    /// Get an iterator for the debugging symbols in the file.
175    ///
176    /// This may skip over symbols that are malformed or unsupported.
177    ///
178    /// For Mach-O files, this does not include STAB entries.
179    fn symbols(&self) -> Self::SymbolIterator<'_>;
180
181    /// Get the symbol named `symbol_name`, if the symbol exists.
182    fn symbol_by_name<'file>(&'file self, symbol_name: &str) -> Option<Self::Symbol<'file>> {
183        self.symbol_by_name_bytes(symbol_name.as_bytes())
184    }
185
186    /// Like [`Self::symbol_by_name`], but allows names that are not UTF-8.
187    fn symbol_by_name_bytes<'file>(&'file self, symbol_name: &[u8]) -> Option<Self::Symbol<'file>> {
188        self.symbols()
189            .find(|sym| sym.name_bytes() == Ok(symbol_name))
190    }
191
192    /// Get the dynamic linking symbol table, if any.
193    ///
194    /// Only ELF has a separate dynamic linking symbol table.
195    /// Consider using [`Self::exports`] or [`Self::imports`] instead.
196    fn dynamic_symbol_table(&self) -> Option<Self::SymbolTable<'_>>;
197
198    /// Get an iterator for the dynamic linking symbols in the file.
199    ///
200    /// This may skip over symbols that are malformed or unsupported.
201    ///
202    /// Only ELF has dynamic linking symbols.
203    /// Other file formats will return an empty iterator.
204    /// Consider using [`Self::exports`] or [`Self::imports`] instead.
205    fn dynamic_symbols(&self) -> Self::SymbolIterator<'_>;
206
207    /// Get the dynamic relocations for this file.
208    ///
209    /// Symbol indices in these relocations refer to the dynamic symbol table.
210    ///
211    /// Only ELF has dynamic relocations.
212    fn dynamic_relocations(&self) -> Option<Self::DynamicRelocationIterator<'_>>;
213
214    /// Construct a map from addresses to symbol names.
215    ///
216    /// See [`SymbolMapBuilder::build`] for details of the map contents.
217    fn symbol_map(&self) -> SymbolMap<SymbolMapName<'data>> {
218        SymbolMapBuilder::new().build(self)
219    }
220
221    /// Construct a map from addresses to symbol names and object file names.
222    ///
223    /// This is derived from Mach-O STAB entries.
224    fn object_map(&self) -> ObjectMap<'data> {
225        ObjectMap::default()
226    }
227
228    /// Get the imported symbols.
229    fn imports(&self) -> Result<Vec<Import<'data>>>;
230
231    /// Get the exported symbols that expose both a name and an address.
232    ///
233    /// Some file formats may provide other kinds of symbols that can be retrieved using
234    /// the low level API.
235    fn exports(&self) -> Result<Vec<Export<'data>>>;
236
237    /// Return true if the file contains DWARF debug information sections, false if not.
238    fn has_debug_symbols(&self) -> bool;
239
240    /// The UUID from a Mach-O [`LC_UUID`](crate::macho::LC_UUID) load command.
241    #[inline]
242    fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
243        Ok(None)
244    }
245
246    /// The build ID from an ELF [`NT_GNU_BUILD_ID`](crate::elf::NT_GNU_BUILD_ID) note.
247    #[inline]
248    fn build_id(&self) -> Result<Option<&'data [u8]>> {
249        Ok(None)
250    }
251
252    /// The filename and CRC from a `.gnu_debuglink` section.
253    #[inline]
254    fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
255        Ok(None)
256    }
257
258    /// The filename and build ID from a `.gnu_debugaltlink` section.
259    #[inline]
260    fn gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>> {
261        Ok(None)
262    }
263
264    /// The filename and GUID from the PE CodeView section.
265    #[inline]
266    fn pdb_info(&self) -> Result<Option<CodeView<'_>>> {
267        Ok(None)
268    }
269
270    /// Get the base address used for relative virtual addresses.
271    ///
272    /// Currently this is only non-zero for PE.
273    fn relative_address_base(&self) -> u64;
274
275    /// Get the virtual address of the entry point of the binary.
276    fn entry(&self) -> u64;
277
278    /// File flags that are specific to each file format.
279    fn flags(&self) -> FileFlags;
280}
281
282/// A loadable segment in an [`Object`].
283///
284/// This trait is part of the unified read API.
285pub trait ObjectSegment<'data>: read::private::Sealed {
286    /// Returns the virtual address of the segment.
287    fn address(&self) -> u64;
288
289    /// Returns the size of the segment in memory.
290    fn size(&self) -> u64;
291
292    /// Returns the alignment of the segment in memory.
293    fn align(&self) -> u64;
294
295    /// Returns the offset and size of the segment in the file.
296    fn file_range(&self) -> (u64, u64);
297
298    /// Returns a reference to the file contents of the segment.
299    ///
300    /// The length of this data may be different from the size of the
301    /// segment in memory.
302    fn data(&self) -> Result<&'data [u8]>;
303
304    /// Return the segment data in the given range.
305    ///
306    /// Returns `Ok(None)` if the segment does not contain the given range.
307    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
308
309    /// Returns the name of the segment.
310    fn name_bytes(&self) -> Result<Option<&[u8]>>;
311
312    /// Returns the name of the segment.
313    ///
314    /// Returns an error if the name is not UTF-8.
315    fn name(&self) -> Result<Option<&str>>;
316
317    /// Return the flags of segment.
318    fn flags(&self) -> SegmentFlags;
319
320    /// Return the permissions of the segment.
321    fn permissions(&self) -> Permissions;
322}
323
324/// A section in an [`Object`].
325///
326/// This trait is part of the unified read API.
327pub trait ObjectSection<'data>: read::private::Sealed {
328    /// An iterator for the relocations for a section.
329    ///
330    /// The first field in the item tuple is the section offset
331    /// that the relocation applies to.
332    type RelocationIterator: Iterator<Item = (u64, Relocation)>;
333
334    /// Returns the section index.
335    fn index(&self) -> SectionIndex;
336
337    /// Returns the address of the section.
338    fn address(&self) -> u64;
339
340    /// Returns the size of the section in memory.
341    fn size(&self) -> u64;
342
343    /// Returns the alignment of the section in memory.
344    fn align(&self) -> u64;
345
346    /// Returns offset and size of on-disk segment (if any).
347    fn file_range(&self) -> Option<(u64, u64)>;
348
349    /// Returns the raw contents of the section.
350    ///
351    /// The length of this data may be different from the size of the
352    /// section in memory.
353    ///
354    /// This does not do any decompression.
355    fn data(&self) -> Result<&'data [u8]>;
356
357    /// Return the raw contents of the section data in the given range.
358    ///
359    /// This does not do any decompression.
360    ///
361    /// Returns `Ok(None)` if the section does not contain the given range.
362    fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
363
364    /// Returns the potentially compressed file range of the section,
365    /// along with information about the compression.
366    fn compressed_file_range(&self) -> Result<CompressedFileRange>;
367
368    /// Returns the potentially compressed contents of the section,
369    /// along with information about the compression.
370    fn compressed_data(&self) -> Result<CompressedData<'data>>;
371
372    /// Returns the uncompressed contents of the section.
373    ///
374    /// The length of this data may be different from the size of the
375    /// section in memory.
376    ///
377    /// If no compression is detected, then returns the data unchanged.
378    /// Returns `Err` if decompression fails.
379    fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
380        self.compressed_data()?.decompress()
381    }
382
383    /// Returns the name of the section.
384    fn name_bytes(&self) -> Result<&'data [u8]>;
385
386    /// Returns the name of the section.
387    ///
388    /// Returns an error if the name is not UTF-8.
389    fn name(&self) -> Result<&'data str>;
390
391    /// Returns the name of the segment for this section.
392    fn segment_name_bytes(&self) -> Result<Option<&[u8]>>;
393
394    /// Returns the name of the segment for this section.
395    ///
396    /// Returns an error if the name is not UTF-8.
397    fn segment_name(&self) -> Result<Option<&str>>;
398
399    /// Return the kind of this section.
400    fn kind(&self) -> SectionKind;
401
402    /// Get the relocations for this section.
403    fn relocations(&self) -> Self::RelocationIterator;
404
405    /// Construct a relocation map for this section.
406    fn relocation_map(&self) -> Result<RelocationMap>;
407
408    /// Section flags that are specific to each file format.
409    fn flags(&self) -> SectionFlags;
410}
411
412/// A COMDAT section group in an [`Object`].
413///
414/// This trait is part of the unified read API.
415pub trait ObjectComdat<'data>: read::private::Sealed {
416    /// An iterator for the sections in the section group.
417    type SectionIterator: Iterator<Item = SectionIndex>;
418
419    /// Returns the COMDAT selection kind.
420    fn kind(&self) -> ComdatKind;
421
422    /// Returns the index of the symbol used for the name of COMDAT section group.
423    fn symbol(&self) -> SymbolIndex;
424
425    /// Returns the name of the COMDAT section group.
426    fn name_bytes(&self) -> Result<&'data [u8]>;
427
428    /// Returns the name of the COMDAT section group.
429    ///
430    /// Returns an error if the name is not UTF-8.
431    fn name(&self) -> Result<&'data str>;
432
433    /// Get the sections in this section group.
434    fn sections(&self) -> Self::SectionIterator;
435}
436
437/// A symbol table in an [`Object`].
438///
439/// This trait is part of the unified read API.
440pub trait ObjectSymbolTable<'data>: read::private::Sealed {
441    /// A symbol table entry.
442    type Symbol: ObjectSymbol<'data>;
443
444    /// An iterator for the symbols in a symbol table.
445    type SymbolIterator: Iterator<Item = Self::Symbol>;
446
447    /// Get an iterator for the symbols in the table.
448    ///
449    /// This may skip over symbols that are malformed or unsupported.
450    fn symbols(&self) -> Self::SymbolIterator;
451
452    /// Get the symbol at the given index.
453    ///
454    /// The meaning of the index depends on the object file.
455    ///
456    /// Returns an error if the index is invalid.
457    fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>;
458}
459
460/// A symbol table entry in an [`Object`].
461///
462/// This trait is part of the unified read API.
463pub trait ObjectSymbol<'data>: read::private::Sealed {
464    /// The index of the symbol.
465    fn index(&self) -> SymbolIndex;
466
467    /// The name of the symbol.
468    fn name_bytes(&self) -> Result<&'data [u8]>;
469
470    /// The name of the symbol.
471    ///
472    /// Returns an error if the name is not UTF-8.
473    fn name(&self) -> Result<&'data str>;
474
475    /// The address of the symbol. May be zero if the address is unknown.
476    fn address(&self) -> u64;
477
478    /// The size of the symbol. May be zero if the size is unknown.
479    fn size(&self) -> u64;
480
481    /// Return the kind of this symbol.
482    fn kind(&self) -> SymbolKind;
483
484    /// Returns the section where the symbol is defined.
485    fn section(&self) -> SymbolSection;
486
487    /// Returns the section index for the section containing this symbol.
488    ///
489    /// May return `None` if the symbol is not defined in a section.
490    fn section_index(&self) -> Option<SectionIndex> {
491        self.section().index()
492    }
493
494    /// Return true if the symbol is undefined.
495    fn is_undefined(&self) -> bool;
496
497    /// Return true if the symbol is a definition of a function or data object
498    /// that has a known address.
499    ///
500    /// This is primarily used to implement [`Object::symbol_map`].
501    fn is_definition(&self) -> bool;
502
503    /// Return true if the symbol is common data.
504    ///
505    /// Note: does not check for [`SymbolSection::Section`] with [`SectionKind::Common`].
506    fn is_common(&self) -> bool;
507
508    /// Return true if the symbol is weak.
509    fn is_weak(&self) -> bool;
510
511    /// Returns the symbol scope.
512    fn scope(&self) -> SymbolScope;
513
514    /// Return true if the symbol visible outside of the compilation unit.
515    ///
516    /// This treats [`SymbolScope::Unknown`] as global.
517    fn is_global(&self) -> bool;
518
519    /// Return true if the symbol is only visible within the compilation unit.
520    fn is_local(&self) -> bool;
521
522    /// Symbol flags that are specific to each file format.
523    fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex>;
524}
525
526/// An iterator for files that don't have dynamic relocations.
527#[derive(Debug)]
528pub struct NoDynamicRelocationIterator;
529
530impl Iterator for NoDynamicRelocationIterator {
531    type Item = (u64, Relocation);
532
533    #[inline]
534    fn next(&mut self) -> Option<Self::Item> {
535        None
536    }
537}