1 use crate::alloc::borrow::Cow; 2 use crate::{Relocation, SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolMap}; 3 use target_lexicon::{Architecture, Endianness}; 4 use uuid::Uuid; 5 6 /// An object file. 7 pub trait Object<'data, 'file> { 8 /// A segment in the object file. 9 type Segment: ObjectSegment<'data>; 10 11 /// An iterator over the segments in the object file. 12 type SegmentIterator: Iterator<Item = Self::Segment>; 13 14 /// A section in the object file. 15 type Section: ObjectSection<'data>; 16 17 /// An iterator over the sections in the object file. 18 type SectionIterator: Iterator<Item = Self::Section>; 19 20 /// An iterator over the symbols in the object file. 21 type SymbolIterator: Iterator<Item = (SymbolIndex, Symbol<'data>)>; 22 23 /// Get the architecture type of the file. architecture(&self) -> Architecture24 fn architecture(&self) -> Architecture; 25 26 /// Get the endianness of the file. 27 #[inline] endianness(&self) -> Endianness28 fn endianness(&self) -> Endianness { 29 if self.is_little_endian() { 30 Endianness::Little 31 } else { 32 Endianness::Big 33 } 34 } 35 36 /// Return true if the file is little endian, false if it is big endian. is_little_endian(&self) -> bool37 fn is_little_endian(&self) -> bool; 38 39 /// Return true if the file can contain 64-bit addresses. is_64(&self) -> bool40 fn is_64(&self) -> bool; 41 42 /// Get an iterator over the segments in the file. segments(&'file self) -> Self::SegmentIterator43 fn segments(&'file self) -> Self::SegmentIterator; 44 45 /// Get the entry point address of the binary entry(&'file self) -> u6446 fn entry(&'file self) -> u64; 47 48 /// Get the section named `section_name`, if such a section exists. 49 /// 50 /// If `section_name` starts with a '.' then it is treated as a system section name, 51 /// and is compared using the conventions specific to the object file format. This 52 /// includes: 53 /// - if ".text" is requested for a Mach-O object file, then the actual 54 /// section name that is searched for is "__text". 55 /// - if ".debug_info" is requested for an ELF object file, then 56 /// ".zdebug_info" may be returned (and similarly for other debug sections). 57 /// 58 /// For some object files, multiple segments may contain sections with the same 59 /// name. In this case, the first matching section will be used. section_by_name(&'file self, section_name: &str) -> Option<Self::Section>60 fn section_by_name(&'file self, section_name: &str) -> Option<Self::Section>; 61 62 /// Get the section at the given index. 63 /// 64 /// The meaning of the index depends on the object file. 65 /// 66 /// For some object files, this requires iterating through all sections. section_by_index(&'file self, index: SectionIndex) -> Option<Self::Section>67 fn section_by_index(&'file self, index: SectionIndex) -> Option<Self::Section>; 68 69 /// Get the contents of the section named `section_name`, if such 70 /// a section exists. 71 /// 72 /// The `section_name` is interpreted according to `Self::section_by_name`. 73 /// 74 /// This may decompress section data. section_data_by_name(&'file self, section_name: &str) -> Option<Cow<'data, [u8]>>75 fn section_data_by_name(&'file self, section_name: &str) -> Option<Cow<'data, [u8]>> { 76 self.section_by_name(section_name) 77 .map(|section| section.uncompressed_data()) 78 } 79 80 /// Get an iterator over the sections in the file. sections(&'file self) -> Self::SectionIterator81 fn sections(&'file self) -> Self::SectionIterator; 82 83 /// Get the debugging symbol at the given index. 84 /// 85 /// This is similar to `self.symbols().nth(index)`, except that 86 /// the index will take into account malformed or unsupported symbols. symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>87 fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>; 88 89 /// Get an iterator over the debugging symbols in the file. 90 /// 91 /// This may skip over symbols that are malformed or unsupported. symbols(&'file self) -> Self::SymbolIterator92 fn symbols(&'file self) -> Self::SymbolIterator; 93 94 /// Get the data for the given symbol. symbol_data(&'file self, symbol: &Symbol<'data>) -> Option<&'data [u8]>95 fn symbol_data(&'file self, symbol: &Symbol<'data>) -> Option<&'data [u8]> { 96 if symbol.is_undefined() { 97 return None; 98 } 99 let address = symbol.address(); 100 let size = symbol.size(); 101 if let Some(index) = symbol.section_index() { 102 self.section_by_index(index) 103 .and_then(|section| section.data_range(address, size)) 104 } else { 105 self.segments() 106 .find_map(|segment| segment.data_range(address, size)) 107 } 108 } 109 110 /// Get an iterator over the dynamic linking symbols in the file. 111 /// 112 /// This may skip over symbols that are malformed or unsupported. dynamic_symbols(&'file self) -> Self::SymbolIterator113 fn dynamic_symbols(&'file self) -> Self::SymbolIterator; 114 115 /// Construct a map from addresses to symbols. symbol_map(&self) -> SymbolMap<'data>116 fn symbol_map(&self) -> SymbolMap<'data>; 117 118 /// Return true if the file contains debug information sections, false if not. has_debug_symbols(&self) -> bool119 fn has_debug_symbols(&self) -> bool; 120 121 /// The UUID from a Mach-O `LC_UUID` load command. 122 #[inline] mach_uuid(&self) -> Option<Uuid>123 fn mach_uuid(&self) -> Option<Uuid> { 124 None 125 } 126 127 /// The build ID from an ELF `NT_GNU_BUILD_ID` note. 128 #[inline] build_id(&self) -> Option<&'data [u8]>129 fn build_id(&self) -> Option<&'data [u8]> { 130 None 131 } 132 133 /// The filename and CRC from a `.gnu_debuglink` section. 134 #[inline] gnu_debuglink(&self) -> Option<(&'data [u8], u32)>135 fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> { 136 None 137 } 138 } 139 140 /// A loadable segment defined in an object file. 141 /// 142 /// For ELF, this is a program header with type `PT_LOAD`. 143 /// For Mach-O, this is a load command with type `LC_SEGMENT` or `LC_SEGMENT_64`. 144 pub trait ObjectSegment<'data> { 145 /// Returns the virtual address of the segment. address(&self) -> u64146 fn address(&self) -> u64; 147 148 /// Returns the size of the segment in memory. size(&self) -> u64149 fn size(&self) -> u64; 150 151 /// Returns the alignment of the segment in memory. align(&self) -> u64152 fn align(&self) -> u64; 153 154 /// Returns a reference to the file contents of the segment. 155 /// The length of this data may be different from the size of the 156 /// segment in memory. data(&self) -> &'data [u8]157 fn data(&self) -> &'data [u8]; 158 159 /// Return the segment data in the given range. data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>160 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>; 161 162 /// Returns the name of the segment. name(&self) -> Option<&str>163 fn name(&self) -> Option<&str>; 164 } 165 166 /// A section defined in an object file. 167 pub trait ObjectSection<'data> { 168 /// An iterator over the relocations for a section. 169 /// 170 /// The first field in the item tuple is the section offset 171 /// that the relocation applies to. 172 type RelocationIterator: Iterator<Item = (u64, Relocation)>; 173 174 /// Returns the section index. index(&self) -> SectionIndex175 fn index(&self) -> SectionIndex; 176 177 /// Returns the address of the section. address(&self) -> u64178 fn address(&self) -> u64; 179 180 /// Returns the size of the section in memory. size(&self) -> u64181 fn size(&self) -> u64; 182 183 /// Returns the alignment of the section in memory. align(&self) -> u64184 fn align(&self) -> u64; 185 186 /// Returns the raw contents of the section. 187 /// The length of this data may be different from the size of the 188 /// section in memory. 189 /// 190 /// This does not do any decompression. data(&self) -> Cow<'data, [u8]>191 fn data(&self) -> Cow<'data, [u8]>; 192 193 /// Return the raw contents of the section data in the given range. 194 /// 195 /// This does not do any decompression. data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>196 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>; 197 198 /// Returns the uncompressed contents of the section. 199 /// The length of this data may be different from the size of the 200 /// section in memory. uncompressed_data(&self) -> Cow<'data, [u8]>201 fn uncompressed_data(&self) -> Cow<'data, [u8]>; 202 203 /// Returns the name of the section. name(&self) -> Option<&str>204 fn name(&self) -> Option<&str>; 205 206 /// Returns the name of the segment for this section. segment_name(&self) -> Option<&str>207 fn segment_name(&self) -> Option<&str>; 208 209 /// Return the kind of this section. kind(&self) -> SectionKind210 fn kind(&self) -> SectionKind; 211 212 /// Get the relocations for this section. relocations(&self) -> Self::RelocationIterator213 fn relocations(&self) -> Self::RelocationIterator; 214 } 215