1 use alloc::borrow::Cow;
2 
3 use crate::read::{
4     self, Architecture, CompressedData, FileFlags, Relocation, Result, SectionFlags, SectionIndex,
5     SectionKind, Symbol, SymbolIndex, SymbolMap,
6 };
7 use crate::Endianness;
8 
9 /// An object file.
10 pub trait Object<'data, 'file>: read::private::Sealed {
11     /// A segment in the object file.
12     type Segment: ObjectSegment<'data>;
13 
14     /// An iterator over the segments in the object file.
15     type SegmentIterator: Iterator<Item = Self::Segment>;
16 
17     /// A section in the object file.
18     type Section: ObjectSection<'data>;
19 
20     /// An iterator over the sections in the object file.
21     type SectionIterator: Iterator<Item = Self::Section>;
22 
23     /// An iterator over the symbols in the object file.
24     type SymbolIterator: Iterator<Item = (SymbolIndex, Symbol<'data>)>;
25 
26     /// Get the architecture type of the file.
architecture(&self) -> Architecture27     fn architecture(&self) -> Architecture;
28 
29     /// Get the endianness of the file.
30     #[inline]
endianness(&self) -> Endianness31     fn endianness(&self) -> Endianness {
32         if self.is_little_endian() {
33             Endianness::Little
34         } else {
35             Endianness::Big
36         }
37     }
38 
39     /// Return true if the file is little endian, false if it is big endian.
is_little_endian(&self) -> bool40     fn is_little_endian(&self) -> bool;
41 
42     /// Return true if the file can contain 64-bit addresses.
is_64(&self) -> bool43     fn is_64(&self) -> bool;
44 
45     /// Get an iterator over the segments in the file.
segments(&'file self) -> Self::SegmentIterator46     fn segments(&'file self) -> Self::SegmentIterator;
47 
48     /// Get the entry point address of the binary
entry(&'file self) -> u6449     fn entry(&'file self) -> u64;
50 
51     /// Get the section named `section_name`, if such a section exists.
52     ///
53     /// If `section_name` starts with a '.' then it is treated as a system section name,
54     /// and is compared using the conventions specific to the object file format. This
55     /// includes:
56     /// - if ".text" is requested for a Mach-O object file, then the actual
57     /// section name that is searched for is "__text".
58     /// - if ".debug_info" is requested for an ELF object file, then
59     /// ".zdebug_info" may be returned (and similarly for other debug sections).
60     ///
61     /// For some object files, multiple segments may contain sections with the same
62     /// name. In this case, the first matching section will be used.
63     ///
64     /// This method skips over sections with invalid names.
section_by_name(&'file self, section_name: &str) -> Option<Self::Section>65     fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>;
66 
67     /// Get the section at the given index.
68     ///
69     /// The meaning of the index depends on the object file.
70     ///
71     /// For some object files, this requires iterating through all sections.
72     ///
73     /// Returns an error if the index is invalid.
section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>74     fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>;
75 
76     /// Get an iterator over the sections in the file.
sections(&'file self) -> Self::SectionIterator77     fn sections(&'file self) -> Self::SectionIterator;
78 
79     /// Get the debugging symbol at the given index.
80     ///
81     /// The meaning of the index depends on the object file.
82     ///
83     /// Returns an error if the index is invalid.
symbol_by_index(&self, index: SymbolIndex) -> Result<Symbol<'data>>84     fn symbol_by_index(&self, index: SymbolIndex) -> Result<Symbol<'data>>;
85 
86     /// Get an iterator over the debugging symbols in the file.
87     ///
88     /// This may skip over symbols that are malformed or unsupported.
symbols(&'file self) -> Self::SymbolIterator89     fn symbols(&'file self) -> Self::SymbolIterator;
90 
91     /// Get the data for the given symbol.
92     ///
93     /// This may iterate over segments.
94     ///
95     /// Returns `Ok(None)` for undefined symbols or if the data could not be found.
symbol_data(&'file self, symbol: &Symbol<'data>) -> Result<Option<&'data [u8]>>96     fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Result<Option<&'data [u8]>> {
97         if symbol.is_undefined() {
98             return Ok(None);
99         }
100         let address = symbol.address();
101         let size = symbol.size();
102         if let Some(index) = symbol.section_index() {
103             let section = self.section_by_index(index)?;
104             section.data_range(address, size)
105         } else {
106             for segment in self.segments() {
107                 if let Some(data) = segment.data_range(address, size)? {
108                     return Ok(Some(data));
109                 }
110             }
111             Ok(None)
112         }
113     }
114 
115     /// Get an iterator over the dynamic linking symbols in the file.
116     ///
117     /// This may skip over symbols that are malformed or unsupported.
dynamic_symbols(&'file self) -> Self::SymbolIterator118     fn dynamic_symbols(&'file self) -> Self::SymbolIterator;
119 
120     /// Construct a map from addresses to symbols.
symbol_map(&self) -> SymbolMap<'data>121     fn symbol_map(&self) -> SymbolMap<'data>;
122 
123     /// Return true if the file contains debug information sections, false if not.
has_debug_symbols(&self) -> bool124     fn has_debug_symbols(&self) -> bool;
125 
126     /// The UUID from a Mach-O `LC_UUID` load command.
127     #[inline]
mach_uuid(&self) -> Result<Option<[u8; 16]>>128     fn mach_uuid(&self) -> Result<Option<[u8; 16]>> {
129         Ok(None)
130     }
131 
132     /// The build ID from an ELF `NT_GNU_BUILD_ID` note.
133     #[inline]
build_id(&self) -> Result<Option<&'data [u8]>>134     fn build_id(&self) -> Result<Option<&'data [u8]>> {
135         Ok(None)
136     }
137 
138     /// The filename and CRC from a `.gnu_debuglink` section.
139     #[inline]
gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>140     fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> {
141         Ok(None)
142     }
143 
144     /// File flags that are specific to each file format.
flags(&self) -> FileFlags145     fn flags(&self) -> FileFlags;
146 }
147 
148 /// A loadable segment defined in an object file.
149 ///
150 /// For ELF, this is a program header with type `PT_LOAD`.
151 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`.
152 pub trait ObjectSegment<'data>: read::private::Sealed {
153     /// Returns the virtual address of the segment.
address(&self) -> u64154     fn address(&self) -> u64;
155 
156     /// Returns the size of the segment in memory.
size(&self) -> u64157     fn size(&self) -> u64;
158 
159     /// Returns the alignment of the segment in memory.
align(&self) -> u64160     fn align(&self) -> u64;
161 
162     /// Returns the offset and size of the segment in the file.
file_range(&self) -> (u64, u64)163     fn file_range(&self) -> (u64, u64);
164 
165     /// Returns a reference to the file contents of the segment.
166     ///
167     /// The length of this data may be different from the size of the
168     /// segment in memory.
data(&self) -> Result<&'data [u8]>169     fn data(&self) -> Result<&'data [u8]>;
170 
171     /// Return the segment data in the given range.
172     ///
173     /// Returns `Ok(None)` if the segment does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>174     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
175 
176     /// Returns the name of the segment.
name(&self) -> Result<Option<&str>>177     fn name(&self) -> Result<Option<&str>>;
178 }
179 
180 /// A section defined in an object file.
181 pub trait ObjectSection<'data>: read::private::Sealed {
182     /// An iterator over the relocations for a section.
183     ///
184     /// The first field in the item tuple is the section offset
185     /// that the relocation applies to.
186     type RelocationIterator: Iterator<Item = (u64, Relocation)>;
187 
188     /// Returns the section index.
index(&self) -> SectionIndex189     fn index(&self) -> SectionIndex;
190 
191     /// Returns the address of the section.
address(&self) -> u64192     fn address(&self) -> u64;
193 
194     /// Returns the size of the section in memory.
size(&self) -> u64195     fn size(&self) -> u64;
196 
197     /// Returns the alignment of the section in memory.
align(&self) -> u64198     fn align(&self) -> u64;
199 
200     /// Returns offset and size of on-disk segment (if any).
file_range(&self) -> Option<(u64, u64)>201     fn file_range(&self) -> Option<(u64, u64)>;
202 
203     /// Returns the raw contents of the section.
204     ///
205     /// The length of this data may be different from the size of the
206     /// section in memory.
207     ///
208     /// This does not do any decompression.
data(&self) -> Result<&'data [u8]>209     fn data(&self) -> Result<&'data [u8]>;
210 
211     /// Return the raw contents of the section data in the given range.
212     ///
213     /// This does not do any decompression.
214     ///
215     /// Returns `Ok(None)` if the section does not contain the given range.
data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>216     fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>;
217 
218     /// Returns the potentially compressed contents of the section,
219     /// along with information about the compression.
compressed_data(&self) -> Result<CompressedData<'data>>220     fn compressed_data(&self) -> Result<CompressedData<'data>>;
221 
222     /// Returns the uncompressed contents of the section.
223     ///
224     /// The length of this data may be different from the size of the
225     /// section in memory.
226     ///
227     /// If no compression is detected, then returns the data unchanged.
228     /// Returns `Err` if decompression fails.
uncompressed_data(&self) -> Result<Cow<'data, [u8]>>229     fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> {
230         self.compressed_data()?.decompress()
231     }
232 
233     /// Returns the name of the section.
name(&self) -> Result<&str>234     fn name(&self) -> Result<&str>;
235 
236     /// Returns the name of the segment for this section.
segment_name(&self) -> Result<Option<&str>>237     fn segment_name(&self) -> Result<Option<&str>>;
238 
239     /// Return the kind of this section.
kind(&self) -> SectionKind240     fn kind(&self) -> SectionKind;
241 
242     /// Get the relocations for this section.
relocations(&self) -> Self::RelocationIterator243     fn relocations(&self) -> Self::RelocationIterator;
244 
245     /// Section flags that are specific to each file format.
flags(&self) -> SectionFlags246     fn flags(&self) -> SectionFlags;
247 }
248