1 use alloc::borrow::Cow; 2 use alloc::vec::Vec; 3 4 use crate::read::{ 5 self, Architecture, ComdatKind, CompressedData, Export, FileFlags, Import, ObjectMap, 6 Relocation, Result, SectionFlags, SectionIndex, SectionKind, SymbolFlags, SymbolIndex, 7 SymbolKind, SymbolMap, 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 /// An iterator over dynamic relocations in the file. 45 /// 46 /// The first field in the item tuple is the address 47 /// that the relocation applies to. 48 type DynamicRelocationIterator: Iterator<Item = (u64, Relocation)>; 49 50 /// Get the architecture type of the file. architecture(&self) -> Architecture51 fn architecture(&self) -> Architecture; 52 53 /// Get the endianness of the file. 54 #[inline] endianness(&self) -> Endianness55 fn endianness(&self) -> Endianness { 56 if self.is_little_endian() { 57 Endianness::Little 58 } else { 59 Endianness::Big 60 } 61 } 62 63 /// Return true if the file is little endian, false if it is big endian. is_little_endian(&self) -> bool64 fn is_little_endian(&self) -> bool; 65 66 /// Return true if the file can contain 64-bit addresses. is_64(&self) -> bool67 fn is_64(&self) -> bool; 68 69 /// Get an iterator over the segments in the file. segments(&'file self) -> Self::SegmentIterator70 fn segments(&'file self) -> Self::SegmentIterator; 71 72 /// Get the entry point address of the binary entry(&'file self) -> u6473 fn entry(&'file self) -> u64; 74 75 /// Get the section named `section_name`, if such a section exists. 76 /// 77 /// If `section_name` starts with a '.' then it is treated as a system section name, 78 /// and is compared using the conventions specific to the object file format. This 79 /// includes: 80 /// - if ".text" is requested for a Mach-O object file, then the actual 81 /// section name that is searched for is "__text". 82 /// - if ".debug_info" is requested for an ELF object file, then 83 /// ".zdebug_info" may be returned (and similarly for other debug sections). 84 /// 85 /// For some object files, multiple segments may contain sections with the same 86 /// name. In this case, the first matching section will be used. 87 /// 88 /// This method skips over sections with invalid names. section_by_name(&'file self, section_name: &str) -> Option<Self::Section>89 fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>; 90 91 /// Get the section at the given index. 92 /// 93 /// The meaning of the index depends on the object file. 94 /// 95 /// For some object files, this requires iterating through all sections. 96 /// 97 /// Returns an error if the index is invalid. section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>98 fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>; 99 100 /// Get an iterator over the sections in the file. sections(&'file self) -> Self::SectionIterator101 fn sections(&'file self) -> Self::SectionIterator; 102 103 /// Get an iterator over the COMDAT section groups in the file. comdats(&'file self) -> Self::ComdatIterator104 fn comdats(&'file self) -> Self::ComdatIterator; 105 106 /// Get the symbol table, if any. symbol_table(&'file self) -> Option<Self::SymbolTable>107 fn symbol_table(&'file self) -> Option<Self::SymbolTable>; 108 109 /// Get the debugging symbol at the given index. 110 /// 111 /// The meaning of the index depends on the object file. 112 /// 113 /// Returns an error if the index is invalid. symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>114 fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>; 115 116 /// Get an iterator over the debugging symbols in the file. 117 /// 118 /// This may skip over symbols that are malformed or unsupported. 119 /// 120 /// For Mach-O files, this does not include STAB entries. symbols(&'file self) -> Self::SymbolIterator121 fn symbols(&'file self) -> Self::SymbolIterator; 122 123 /// Get the dynamic linking symbol table, if any. 124 /// 125 /// Only ELF has a separate dynamic linking symbol table. dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>126 fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>; 127 128 /// Get an iterator over the dynamic linking symbols in the file. 129 /// 130 /// This may skip over symbols that are malformed or unsupported. 131 /// 132 /// Only ELF has separate dynamic linking symbols. 133 /// Other file formats will return an empty iterator. dynamic_symbols(&'file self) -> Self::SymbolIterator134 fn dynamic_symbols(&'file self) -> Self::SymbolIterator; 135 136 /// Get the dynamic relocations for this file. 137 /// 138 /// Symbol indices in these relocations refer to the dynamic symbol table. 139 /// 140 /// Only ELF has dynamic relocations. dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>141 fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>; 142 143 /// Construct a map from addresses to symbol names. 144 /// 145 /// The map will only contain defined text and data symbols. 146 /// The dynamic symbol table will only be used if there are no debugging symbols. symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>>147 fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> { 148 let mut symbols = Vec::new(); 149 if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) { 150 for symbol in table.symbols() { 151 if !symbol.is_definition() { 152 continue; 153 } 154 if let Ok(name) = symbol.name() { 155 symbols.push(SymbolMapName::new(symbol.address(), name)); 156 } 157 } 158 } 159 SymbolMap::new(symbols) 160 } 161 162 /// Construct a map from addresses to symbol names and object file names. 163 /// 164 /// This is derived from Mach-O STAB entries. object_map(&'file self) -> ObjectMap<'data>165 fn object_map(&'file self) -> ObjectMap<'data> { 166 ObjectMap::default() 167 } 168 169 /// Get the imported symbols. imports(&self) -> Result<Vec<Import<'data>>>170 fn imports(&self) -> Result<Vec<Import<'data>>>; 171 172 /// Get the exported symbols. exports(&self) -> Result<Vec<Export<'data>>>173 fn exports(&self) -> Result<Vec<Export<'data>>>; 174 175 /// Return true if the file contains debug information sections, false if not. has_debug_symbols(&self) -> bool176 fn has_debug_symbols(&self) -> bool; 177 178 /// The UUID from a Mach-O `LC_UUID` load command. 179 #[inline] mach_uuid(&self) -> Result<Option<[u8; 16]>>180 fn mach_uuid(&self) -> Result<Option<[u8; 16]>> { 181 Ok(None) 182 } 183 184 /// The build ID from an ELF `NT_GNU_BUILD_ID` note. 185 #[inline] build_id(&self) -> Result<Option<&'data [u8]>>186 fn build_id(&self) -> Result<Option<&'data [u8]>> { 187 Ok(None) 188 } 189 190 /// The filename and CRC from a `.gnu_debuglink` section. 191 #[inline] gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>192 fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> { 193 Ok(None) 194 } 195 196 /// File flags that are specific to each file format. flags(&self) -> FileFlags197 fn flags(&self) -> FileFlags; 198 } 199 200 /// A loadable segment defined in an object file. 201 /// 202 /// For ELF, this is a program header with type `PT_LOAD`. 203 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`. 204 pub trait ObjectSegment<'data>: read::private::Sealed { 205 /// Returns the virtual address of the segment. address(&self) -> u64206 fn address(&self) -> u64; 207 208 /// Returns the size of the segment in memory. size(&self) -> u64209 fn size(&self) -> u64; 210 211 /// Returns the alignment of the segment in memory. align(&self) -> u64212 fn align(&self) -> u64; 213 214 /// Returns the offset and size of the segment in the file. file_range(&self) -> (u64, u64)215 fn file_range(&self) -> (u64, u64); 216 217 /// Returns a reference to the file contents of the segment. 218 /// 219 /// The length of this data may be different from the size of the 220 /// segment in memory. data(&self) -> Result<&'data [u8]>221 fn data(&self) -> Result<&'data [u8]>; 222 223 /// Return the segment data in the given range. 224 /// 225 /// Returns `Ok(None)` if the segment does not contain the given range. data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>226 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>; 227 228 /// Returns the name of the segment. name(&self) -> Result<Option<&str>>229 fn name(&self) -> Result<Option<&str>>; 230 } 231 232 /// A section defined in an object file. 233 pub trait ObjectSection<'data>: read::private::Sealed { 234 /// An iterator over the relocations for a section. 235 /// 236 /// The first field in the item tuple is the section offset 237 /// that the relocation applies to. 238 type RelocationIterator: Iterator<Item = (u64, Relocation)>; 239 240 /// Returns the section index. index(&self) -> SectionIndex241 fn index(&self) -> SectionIndex; 242 243 /// Returns the address of the section. address(&self) -> u64244 fn address(&self) -> u64; 245 246 /// Returns the size of the section in memory. size(&self) -> u64247 fn size(&self) -> u64; 248 249 /// Returns the alignment of the section in memory. align(&self) -> u64250 fn align(&self) -> u64; 251 252 /// Returns offset and size of on-disk segment (if any). file_range(&self) -> Option<(u64, u64)>253 fn file_range(&self) -> Option<(u64, u64)>; 254 255 /// Returns the raw contents of the section. 256 /// 257 /// The length of this data may be different from the size of the 258 /// section in memory. 259 /// 260 /// This does not do any decompression. data(&self) -> Result<&'data [u8]>261 fn data(&self) -> Result<&'data [u8]>; 262 263 /// Return the raw contents of the section data in the given range. 264 /// 265 /// This does not do any decompression. 266 /// 267 /// Returns `Ok(None)` if the section does not contain the given range. data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>268 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>; 269 270 /// Returns the potentially compressed contents of the section, 271 /// along with information about the compression. compressed_data(&self) -> Result<CompressedData<'data>>272 fn compressed_data(&self) -> Result<CompressedData<'data>>; 273 274 /// Returns the uncompressed contents of the section. 275 /// 276 /// The length of this data may be different from the size of the 277 /// section in memory. 278 /// 279 /// If no compression is detected, then returns the data unchanged. 280 /// Returns `Err` if decompression fails. uncompressed_data(&self) -> Result<Cow<'data, [u8]>>281 fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> { 282 self.compressed_data()?.decompress() 283 } 284 285 /// Returns the name of the section. name(&self) -> Result<&str>286 fn name(&self) -> Result<&str>; 287 288 /// Returns the name of the segment for this section. segment_name(&self) -> Result<Option<&str>>289 fn segment_name(&self) -> Result<Option<&str>>; 290 291 /// Return the kind of this section. kind(&self) -> SectionKind292 fn kind(&self) -> SectionKind; 293 294 /// Get the relocations for this section. relocations(&self) -> Self::RelocationIterator295 fn relocations(&self) -> Self::RelocationIterator; 296 297 /// Section flags that are specific to each file format. flags(&self) -> SectionFlags298 fn flags(&self) -> SectionFlags; 299 } 300 301 /// A COMDAT section group defined in an object file. 302 pub trait ObjectComdat<'data>: read::private::Sealed { 303 /// An iterator over the sections in the object file. 304 type SectionIterator: Iterator<Item = SectionIndex>; 305 306 /// Returns the COMDAT selection kind. kind(&self) -> ComdatKind307 fn kind(&self) -> ComdatKind; 308 309 /// Returns the index of the symbol used for the name of COMDAT section group. symbol(&self) -> SymbolIndex310 fn symbol(&self) -> SymbolIndex; 311 312 /// Returns the name of the COMDAT section group. name(&self) -> Result<&str>313 fn name(&self) -> Result<&str>; 314 315 /// Get the sections in this section group. sections(&self) -> Self::SectionIterator316 fn sections(&self) -> Self::SectionIterator; 317 } 318 319 /// A symbol table. 320 pub trait ObjectSymbolTable<'data>: read::private::Sealed { 321 /// A symbol table entry. 322 type Symbol: ObjectSymbol<'data>; 323 324 /// An iterator over the symbols in a symbol table. 325 type SymbolIterator: Iterator<Item = Self::Symbol>; 326 327 /// Get an iterator over the symbols in the table. 328 /// 329 /// This may skip over symbols that are malformed or unsupported. symbols(&self) -> Self::SymbolIterator330 fn symbols(&self) -> Self::SymbolIterator; 331 332 /// Get the symbol at the given index. 333 /// 334 /// The meaning of the index depends on the object file. 335 /// 336 /// Returns an error if the index is invalid. symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>337 fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>; 338 } 339 340 /// A symbol table entry. 341 pub trait ObjectSymbol<'data>: read::private::Sealed { 342 /// The index of the symbol. index(&self) -> SymbolIndex343 fn index(&self) -> SymbolIndex; 344 345 /// The name of the symbol. name(&self) -> Result<&'data str>346 fn name(&self) -> Result<&'data str>; 347 348 /// The address of the symbol. May be zero if the address is unknown. address(&self) -> u64349 fn address(&self) -> u64; 350 351 /// The size of the symbol. May be zero if the size is unknown. size(&self) -> u64352 fn size(&self) -> u64; 353 354 /// Return the kind of this symbol. kind(&self) -> SymbolKind355 fn kind(&self) -> SymbolKind; 356 357 /// Returns the section where the symbol is defined. section(&self) -> SymbolSection358 fn section(&self) -> SymbolSection; 359 360 /// Returns the section index for the section containing this symbol. 361 /// 362 /// May return `None` if the symbol is not defined in a section. section_index(&self) -> Option<SectionIndex>363 fn section_index(&self) -> Option<SectionIndex> { 364 self.section().index() 365 } 366 367 /// Return true if the symbol is undefined. is_undefined(&self) -> bool368 fn is_undefined(&self) -> bool; 369 370 /// Return true if the symbol is a definition of a function or data object 371 /// that has a known address. is_definition(&self) -> bool372 fn is_definition(&self) -> bool; 373 374 /// Return true if the symbol is common data. 375 /// 376 /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. is_common(&self) -> bool377 fn is_common(&self) -> bool; 378 379 /// Return true if the symbol is weak. is_weak(&self) -> bool380 fn is_weak(&self) -> bool; 381 382 /// Returns the symbol scope. scope(&self) -> SymbolScope383 fn scope(&self) -> SymbolScope; 384 385 /// Return true if the symbol visible outside of the compilation unit. 386 /// 387 /// This treats `SymbolScope::Unknown` as global. is_global(&self) -> bool388 fn is_global(&self) -> bool; 389 390 /// Return true if the symbol is only visible within the compilation unit. is_local(&self) -> bool391 fn is_local(&self) -> bool; 392 393 /// Symbol flags that are specific to each file format. flags(&self) -> SymbolFlags<SectionIndex>394 fn flags(&self) -> SymbolFlags<SectionIndex>; 395 } 396 397 /// An iterator for files that don't have dynamic relocations. 398 #[derive(Debug)] 399 pub struct NoDynamicRelocationIterator; 400 401 impl Iterator for NoDynamicRelocationIterator { 402 type Item = (u64, Relocation); 403 404 #[inline] next(&mut self) -> Option<Self::Item>405 fn next(&mut self) -> Option<Self::Item> { 406 None 407 } 408 } 409