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