1 use alloc::borrow::Cow; 2 use alloc::vec::Vec; 3 4 use crate::read::{ 5 self, Architecture, CodeView, ComdatKind, CompressedData, CompressedFileRange, Export, 6 FileFlags, Import, ObjectMap, Relocation, Result, SectionFlags, SectionIndex, SectionKind, 7 SymbolFlags, SymbolIndex, 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 section named `section_name`, if such a section exists. 73 /// 74 /// If `section_name` starts with a '.' then it is treated as a system section name, 75 /// and is compared using the conventions specific to the object file format. This 76 /// includes: 77 /// - if ".debug_str_offsets" is requested for a Mach-O object file, then the actual 78 /// section name that is searched for is "__debug_str_offs". 79 /// - if ".debug_info" is requested for an ELF object file, then 80 /// ".zdebug_info" may be returned (and similarly for other debug sections). 81 /// 82 /// For some object files, multiple segments may contain sections with the same 83 /// name. In this case, the first matching section will be used. 84 /// 85 /// This method skips over sections with invalid names. section_by_name(&'file self, section_name: &str) -> Option<Self::Section>86 fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>; 87 88 /// Get the section at the given index. 89 /// 90 /// The meaning of the index depends on the object file. 91 /// 92 /// For some object files, this requires iterating through all sections. 93 /// 94 /// Returns an error if the index is invalid. section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>95 fn section_by_index(&'file self, index: SectionIndex) -> Result<Self::Section>; 96 97 /// Get an iterator over the sections in the file. sections(&'file self) -> Self::SectionIterator98 fn sections(&'file self) -> Self::SectionIterator; 99 100 /// Get an iterator over the COMDAT section groups in the file. comdats(&'file self) -> Self::ComdatIterator101 fn comdats(&'file self) -> Self::ComdatIterator; 102 103 /// Get the symbol table, if any. symbol_table(&'file self) -> Option<Self::SymbolTable>104 fn symbol_table(&'file self) -> Option<Self::SymbolTable>; 105 106 /// Get the debugging symbol at the given index. 107 /// 108 /// The meaning of the index depends on the object file. 109 /// 110 /// Returns an error if the index is invalid. symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>111 fn symbol_by_index(&'file self, index: SymbolIndex) -> Result<Self::Symbol>; 112 113 /// Get an iterator over the debugging symbols in the file. 114 /// 115 /// This may skip over symbols that are malformed or unsupported. 116 /// 117 /// For Mach-O files, this does not include STAB entries. symbols(&'file self) -> Self::SymbolIterator118 fn symbols(&'file self) -> Self::SymbolIterator; 119 120 /// Get the dynamic linking symbol table, if any. 121 /// 122 /// Only ELF has a separate dynamic linking symbol table. dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>123 fn dynamic_symbol_table(&'file self) -> Option<Self::SymbolTable>; 124 125 /// Get an iterator over the dynamic linking symbols in the file. 126 /// 127 /// This may skip over symbols that are malformed or unsupported. 128 /// 129 /// Only ELF has separate dynamic linking symbols. 130 /// Other file formats will return an empty iterator. dynamic_symbols(&'file self) -> Self::SymbolIterator131 fn dynamic_symbols(&'file self) -> Self::SymbolIterator; 132 133 /// Get the dynamic relocations for this file. 134 /// 135 /// Symbol indices in these relocations refer to the dynamic symbol table. 136 /// 137 /// Only ELF has dynamic relocations. dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>138 fn dynamic_relocations(&'file self) -> Option<Self::DynamicRelocationIterator>; 139 140 /// Construct a map from addresses to symbol names. 141 /// 142 /// The map will only contain defined text and data symbols. 143 /// The dynamic symbol table will only be used if there are no debugging symbols. symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>>144 fn symbol_map(&'file self) -> SymbolMap<SymbolMapName<'data>> { 145 let mut symbols = Vec::new(); 146 if let Some(table) = self.symbol_table().or_else(|| self.dynamic_symbol_table()) { 147 for symbol in table.symbols() { 148 if !symbol.is_definition() { 149 continue; 150 } 151 if let Ok(name) = symbol.name() { 152 symbols.push(SymbolMapName::new(symbol.address(), name)); 153 } 154 } 155 } 156 SymbolMap::new(symbols) 157 } 158 159 /// Construct a map from addresses to symbol names and object file names. 160 /// 161 /// This is derived from Mach-O STAB entries. object_map(&'file self) -> ObjectMap<'data>162 fn object_map(&'file self) -> ObjectMap<'data> { 163 ObjectMap::default() 164 } 165 166 /// Get the imported symbols. imports(&self) -> Result<Vec<Import<'data>>>167 fn imports(&self) -> Result<Vec<Import<'data>>>; 168 169 /// Get the exported symbols. exports(&self) -> Result<Vec<Export<'data>>>170 fn exports(&self) -> Result<Vec<Export<'data>>>; 171 172 /// Return true if the file contains debug information sections, false if not. has_debug_symbols(&self) -> bool173 fn has_debug_symbols(&self) -> bool; 174 175 /// The UUID from a Mach-O `LC_UUID` load command. 176 #[inline] mach_uuid(&self) -> Result<Option<[u8; 16]>>177 fn mach_uuid(&self) -> Result<Option<[u8; 16]>> { 178 Ok(None) 179 } 180 181 /// The build ID from an ELF `NT_GNU_BUILD_ID` note. 182 #[inline] build_id(&self) -> Result<Option<&'data [u8]>>183 fn build_id(&self) -> Result<Option<&'data [u8]>> { 184 Ok(None) 185 } 186 187 /// The filename and CRC from a `.gnu_debuglink` section. 188 #[inline] gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>>189 fn gnu_debuglink(&self) -> Result<Option<(&'data [u8], u32)>> { 190 Ok(None) 191 } 192 193 /// The filename and build ID from a `.gnu_debugaltlink` section. 194 #[inline] gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>>195 fn gnu_debugaltlink(&self) -> Result<Option<(&'data [u8], &'data [u8])>> { 196 Ok(None) 197 } 198 199 /// The filename and GUID from the PE CodeView section 200 #[inline] pdb_info(&self) -> Result<Option<CodeView>>201 fn pdb_info(&self) -> Result<Option<CodeView>> { 202 Ok(None) 203 } 204 205 /// Get the base address used for relative virtual addresses. 206 /// 207 /// Currently this is only non-zero for PE. relative_address_base(&'file self) -> u64208 fn relative_address_base(&'file self) -> u64; 209 210 /// Get the virtual address of the entry point of the binary entry(&'file self) -> u64211 fn entry(&'file self) -> u64; 212 213 /// File flags that are specific to each file format. flags(&self) -> FileFlags214 fn flags(&self) -> FileFlags; 215 } 216 217 /// A loadable segment defined in an object file. 218 /// 219 /// For ELF, this is a program header with type `PT_LOAD`. 220 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`. 221 pub trait ObjectSegment<'data>: read::private::Sealed { 222 /// Returns the virtual address of the segment. address(&self) -> u64223 fn address(&self) -> u64; 224 225 /// Returns the size of the segment in memory. size(&self) -> u64226 fn size(&self) -> u64; 227 228 /// Returns the alignment of the segment in memory. align(&self) -> u64229 fn align(&self) -> u64; 230 231 /// Returns the offset and size of the segment in the file. file_range(&self) -> (u64, u64)232 fn file_range(&self) -> (u64, u64); 233 234 /// Returns a reference to the file contents of the segment. 235 /// 236 /// The length of this data may be different from the size of the 237 /// segment in memory. data(&self) -> Result<&'data [u8]>238 fn data(&self) -> Result<&'data [u8]>; 239 240 /// Return the segment data in the given range. 241 /// 242 /// Returns `Ok(None)` if the segment does not contain the given range. data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>243 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>; 244 245 /// Returns the name of the segment. name(&self) -> Result<Option<&str>>246 fn name(&self) -> Result<Option<&str>>; 247 } 248 249 /// A section defined in an object file. 250 pub trait ObjectSection<'data>: read::private::Sealed { 251 /// An iterator over the relocations for a section. 252 /// 253 /// The first field in the item tuple is the section offset 254 /// that the relocation applies to. 255 type RelocationIterator: Iterator<Item = (u64, Relocation)>; 256 257 /// Returns the section index. index(&self) -> SectionIndex258 fn index(&self) -> SectionIndex; 259 260 /// Returns the address of the section. address(&self) -> u64261 fn address(&self) -> u64; 262 263 /// Returns the size of the section in memory. size(&self) -> u64264 fn size(&self) -> u64; 265 266 /// Returns the alignment of the section in memory. align(&self) -> u64267 fn align(&self) -> u64; 268 269 /// Returns offset and size of on-disk segment (if any). file_range(&self) -> Option<(u64, u64)>270 fn file_range(&self) -> Option<(u64, u64)>; 271 272 /// Returns the raw contents of the section. 273 /// 274 /// The length of this data may be different from the size of the 275 /// section in memory. 276 /// 277 /// This does not do any decompression. data(&self) -> Result<&'data [u8]>278 fn data(&self) -> Result<&'data [u8]>; 279 280 /// Return the raw contents of the section data in the given range. 281 /// 282 /// This does not do any decompression. 283 /// 284 /// Returns `Ok(None)` if the section does not contain the given range. data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>285 fn data_range(&self, address: u64, size: u64) -> Result<Option<&'data [u8]>>; 286 287 /// Returns the potentially compressed file range of the section, 288 /// along with information about the compression. compressed_file_range(&self) -> Result<CompressedFileRange>289 fn compressed_file_range(&self) -> Result<CompressedFileRange>; 290 291 /// Returns the potentially compressed contents of the section, 292 /// along with information about the compression. compressed_data(&self) -> Result<CompressedData<'data>>293 fn compressed_data(&self) -> Result<CompressedData<'data>>; 294 295 /// Returns the uncompressed contents of the section. 296 /// 297 /// The length of this data may be different from the size of the 298 /// section in memory. 299 /// 300 /// If no compression is detected, then returns the data unchanged. 301 /// Returns `Err` if decompression fails. uncompressed_data(&self) -> Result<Cow<'data, [u8]>>302 fn uncompressed_data(&self) -> Result<Cow<'data, [u8]>> { 303 self.compressed_data()?.decompress() 304 } 305 306 /// Returns the name of the section. name(&self) -> Result<&str>307 fn name(&self) -> Result<&str>; 308 309 /// Returns the name of the segment for this section. segment_name(&self) -> Result<Option<&str>>310 fn segment_name(&self) -> Result<Option<&str>>; 311 312 /// Return the kind of this section. kind(&self) -> SectionKind313 fn kind(&self) -> SectionKind; 314 315 /// Get the relocations for this section. relocations(&self) -> Self::RelocationIterator316 fn relocations(&self) -> Self::RelocationIterator; 317 318 /// Section flags that are specific to each file format. flags(&self) -> SectionFlags319 fn flags(&self) -> SectionFlags; 320 } 321 322 /// A COMDAT section group defined in an object file. 323 pub trait ObjectComdat<'data>: read::private::Sealed { 324 /// An iterator over the sections in the object file. 325 type SectionIterator: Iterator<Item = SectionIndex>; 326 327 /// Returns the COMDAT selection kind. kind(&self) -> ComdatKind328 fn kind(&self) -> ComdatKind; 329 330 /// Returns the index of the symbol used for the name of COMDAT section group. symbol(&self) -> SymbolIndex331 fn symbol(&self) -> SymbolIndex; 332 333 /// Returns the name of the COMDAT section group. name(&self) -> Result<&str>334 fn name(&self) -> Result<&str>; 335 336 /// Get the sections in this section group. sections(&self) -> Self::SectionIterator337 fn sections(&self) -> Self::SectionIterator; 338 } 339 340 /// A symbol table. 341 pub trait ObjectSymbolTable<'data>: read::private::Sealed { 342 /// A symbol table entry. 343 type Symbol: ObjectSymbol<'data>; 344 345 /// An iterator over the symbols in a symbol table. 346 type SymbolIterator: Iterator<Item = Self::Symbol>; 347 348 /// Get an iterator over the symbols in the table. 349 /// 350 /// This may skip over symbols that are malformed or unsupported. symbols(&self) -> Self::SymbolIterator351 fn symbols(&self) -> Self::SymbolIterator; 352 353 /// Get the symbol at the given index. 354 /// 355 /// The meaning of the index depends on the object file. 356 /// 357 /// Returns an error if the index is invalid. symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>358 fn symbol_by_index(&self, index: SymbolIndex) -> Result<Self::Symbol>; 359 } 360 361 /// A symbol table entry. 362 pub trait ObjectSymbol<'data>: read::private::Sealed { 363 /// The index of the symbol. index(&self) -> SymbolIndex364 fn index(&self) -> SymbolIndex; 365 366 /// The name of the symbol. name(&self) -> Result<&'data str>367 fn name(&self) -> Result<&'data str>; 368 369 /// The address of the symbol. May be zero if the address is unknown. address(&self) -> u64370 fn address(&self) -> u64; 371 372 /// The size of the symbol. May be zero if the size is unknown. size(&self) -> u64373 fn size(&self) -> u64; 374 375 /// Return the kind of this symbol. kind(&self) -> SymbolKind376 fn kind(&self) -> SymbolKind; 377 378 /// Returns the section where the symbol is defined. section(&self) -> SymbolSection379 fn section(&self) -> SymbolSection; 380 381 /// Returns the section index for the section containing this symbol. 382 /// 383 /// May return `None` if the symbol is not defined in a section. section_index(&self) -> Option<SectionIndex>384 fn section_index(&self) -> Option<SectionIndex> { 385 self.section().index() 386 } 387 388 /// Return true if the symbol is undefined. is_undefined(&self) -> bool389 fn is_undefined(&self) -> bool; 390 391 /// Return true if the symbol is a definition of a function or data object 392 /// that has a known address. is_definition(&self) -> bool393 fn is_definition(&self) -> bool; 394 395 /// Return true if the symbol is common data. 396 /// 397 /// Note: does not check for `SymbolSection::Section` with `SectionKind::Common`. is_common(&self) -> bool398 fn is_common(&self) -> bool; 399 400 /// Return true if the symbol is weak. is_weak(&self) -> bool401 fn is_weak(&self) -> bool; 402 403 /// Returns the symbol scope. scope(&self) -> SymbolScope404 fn scope(&self) -> SymbolScope; 405 406 /// Return true if the symbol visible outside of the compilation unit. 407 /// 408 /// This treats `SymbolScope::Unknown` as global. is_global(&self) -> bool409 fn is_global(&self) -> bool; 410 411 /// Return true if the symbol is only visible within the compilation unit. is_local(&self) -> bool412 fn is_local(&self) -> bool; 413 414 /// Symbol flags that are specific to each file format. flags(&self) -> SymbolFlags<SectionIndex>415 fn flags(&self) -> SymbolFlags<SectionIndex>; 416 } 417 418 /// An iterator for files that don't have dynamic relocations. 419 #[derive(Debug)] 420 pub struct NoDynamicRelocationIterator; 421 422 impl Iterator for NoDynamicRelocationIterator { 423 type Item = (u64, Relocation); 424 425 #[inline] next(&mut self) -> Option<Self::Item>426 fn next(&mut self) -> Option<Self::Item> { 427 None 428 } 429 } 430