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 the offset and size of the segment in the file. file_range(&self) -> (u64, u64)155 fn file_range(&self) -> (u64, u64); 156 157 /// Returns a reference to the file contents of the segment. 158 /// The length of this data may be different from the size of the 159 /// segment in memory. data(&self) -> &'data [u8]160 fn data(&self) -> &'data [u8]; 161 162 /// Return the segment data in the given range. data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>163 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>; 164 165 /// Returns the name of the segment. name(&self) -> Option<&str>166 fn name(&self) -> Option<&str>; 167 } 168 169 /// A section defined in an object file. 170 pub trait ObjectSection<'data> { 171 /// An iterator over the relocations for a section. 172 /// 173 /// The first field in the item tuple is the section offset 174 /// that the relocation applies to. 175 type RelocationIterator: Iterator<Item = (u64, Relocation)>; 176 177 /// Returns the section index. index(&self) -> SectionIndex178 fn index(&self) -> SectionIndex; 179 180 /// Returns the address of the section. address(&self) -> u64181 fn address(&self) -> u64; 182 183 /// Returns the size of the section in memory. size(&self) -> u64184 fn size(&self) -> u64; 185 186 /// Returns the alignment of the section in memory. align(&self) -> u64187 fn align(&self) -> u64; 188 189 /// Returns offset and size of on-disk segment (if any) file_range(&self) -> Option<(u64, u64)>190 fn file_range(&self) -> Option<(u64, u64)>; 191 192 /// Returns the raw contents of the section. 193 /// The length of this data may be different from the size of the 194 /// section in memory. 195 /// 196 /// This does not do any decompression. data(&self) -> Cow<'data, [u8]>197 fn data(&self) -> Cow<'data, [u8]>; 198 199 /// Return the raw contents of the section data in the given range. 200 /// 201 /// This does not do any decompression. data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>202 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>; 203 204 /// Returns the uncompressed contents of the section. 205 /// The length of this data may be different from the size of the 206 /// section in memory. uncompressed_data(&self) -> Cow<'data, [u8]>207 fn uncompressed_data(&self) -> Cow<'data, [u8]>; 208 209 /// Returns the name of the section. name(&self) -> Option<&str>210 fn name(&self) -> Option<&str>; 211 212 /// Returns the name of the segment for this section. segment_name(&self) -> Option<&str>213 fn segment_name(&self) -> Option<&str>; 214 215 /// Return the kind of this section. kind(&self) -> SectionKind216 fn kind(&self) -> SectionKind; 217 218 /// Get the relocations for this section. relocations(&self) -> Self::RelocationIterator219 fn relocations(&self) -> Self::RelocationIterator; 220 } 221