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