1 use crate::alloc::borrow::Cow; 2 use crate::alloc::fmt; 3 use target_lexicon::{Architecture, BinaryFormat}; 4 use uuid::Uuid; 5 6 #[cfg(feature = "wasm")] 7 use crate::read::wasm; 8 use crate::read::{coff, elf, macho, pe}; 9 use crate::read::{ 10 Object, ObjectSection, ObjectSegment, Relocation, SectionIndex, SectionKind, Symbol, 11 SymbolIndex, SymbolMap, 12 }; 13 14 /// Evaluate an expression on the contents of a file format enum. 15 /// 16 /// This is a hack to avoid virtual calls. 17 macro_rules! with_inner { 18 ($inner:expr, $enum:ident, | $var:ident | $body:expr) => { 19 match $inner { 20 $enum::Coff(ref $var) => $body, 21 $enum::Elf(ref $var) => $body, 22 $enum::MachO(ref $var) => $body, 23 $enum::Pe(ref $var) => $body, 24 #[cfg(feature = "wasm")] 25 $enum::Wasm(ref $var) => $body, 26 } 27 }; 28 } 29 30 macro_rules! with_inner_mut { 31 ($inner:expr, $enum:ident, | $var:ident | $body:expr) => { 32 match $inner { 33 $enum::Coff(ref mut $var) => $body, 34 $enum::Elf(ref mut $var) => $body, 35 $enum::MachO(ref mut $var) => $body, 36 $enum::Pe(ref mut $var) => $body, 37 #[cfg(feature = "wasm")] 38 $enum::Wasm(ref mut $var) => $body, 39 } 40 }; 41 } 42 43 /// Like `with_inner!`, but wraps the result in another enum. 44 macro_rules! map_inner { 45 ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => { 46 match $inner { 47 $from::Coff(ref $var) => $to::Coff($body), 48 $from::Elf(ref $var) => $to::Elf($body), 49 $from::MachO(ref $var) => $to::MachO($body), 50 $from::Pe(ref $var) => $to::Pe($body), 51 #[cfg(feature = "wasm")] 52 $from::Wasm(ref $var) => $to::Wasm($body), 53 } 54 }; 55 } 56 57 /// Like `map_inner!`, but the result is a Result or Option. 58 macro_rules! map_inner_option { 59 ($inner:expr, $from:ident, $to:ident, | $var:ident | $body:expr) => { 60 match $inner { 61 $from::Coff(ref $var) => $body.map($to::Coff), 62 $from::Elf(ref $var) => $body.map($to::Elf), 63 $from::MachO(ref $var) => $body.map($to::MachO), 64 $from::Pe(ref $var) => $body.map($to::Pe), 65 #[cfg(feature = "wasm")] 66 $from::Wasm(ref $var) => $body.map($to::Wasm), 67 } 68 }; 69 } 70 71 /// Call `next` for a file format iterator. 72 macro_rules! next_inner { 73 ($inner:expr, $from:ident, $to:ident) => { 74 match $inner { 75 $from::Coff(ref mut iter) => iter.next().map($to::Coff), 76 $from::Elf(ref mut iter) => iter.next().map($to::Elf), 77 $from::MachO(ref mut iter) => iter.next().map($to::MachO), 78 $from::Pe(ref mut iter) => iter.next().map($to::Pe), 79 #[cfg(feature = "wasm")] 80 $from::Wasm(ref mut iter) => iter.next().map($to::Wasm), 81 } 82 }; 83 } 84 85 /// An object file. 86 /// 87 /// Most functionality is provided by the `Object` trait implementation. 88 #[derive(Debug)] 89 pub struct File<'data> { 90 inner: FileInternal<'data>, 91 } 92 93 #[allow(clippy::large_enum_variant)] 94 #[derive(Debug)] 95 enum FileInternal<'data> { 96 Coff(coff::CoffFile<'data>), 97 Elf(elf::ElfFile<'data>), 98 MachO(macho::MachOFile<'data>), 99 Pe(pe::PeFile<'data>), 100 #[cfg(feature = "wasm")] 101 Wasm(wasm::WasmFile), 102 } 103 104 impl<'data> File<'data> { 105 /// Parse the raw file data. parse(data: &'data [u8]) -> Result<Self, &'static str>106 pub fn parse(data: &'data [u8]) -> Result<Self, &'static str> { 107 if data.len() < 16 { 108 return Err("File too short"); 109 } 110 111 let inner = match [data[0], data[1], data[2], data[3]] { 112 // ELF 113 [0x7f, b'E', b'L', b'F'] => FileInternal::Elf(elf::ElfFile::parse(data)?), 114 // 32-bit Mach-O 115 [0xfe, 0xed, 0xfa, 0xce] 116 | [0xce, 0xfa, 0xed, 0xfe] 117 // 64-bit Mach-O 118 | [0xfe, 0xed, 0xfa, 0xcf] 119 | [0xcf, 0xfa, 0xed, 0xfe] => FileInternal::MachO(macho::MachOFile::parse(data)?), 120 // WASM 121 #[cfg(feature = "wasm")] 122 [0x00, b'a', b's', b'm'] => FileInternal::Wasm(wasm::WasmFile::parse(data)?), 123 // MS-DOS, assume stub for Windows PE 124 [b'M', b'Z', _, _] => FileInternal::Pe(pe::PeFile::parse(data)?), 125 // TODO: more COFF machines 126 // COFF x86 127 [0x4c, 0x01, _, _] 128 // COFF x86-64 129 | [0x64, 0x86, _, _] => FileInternal::Coff(coff::CoffFile::parse(data)?), 130 _ => return Err("Unknown file magic"), 131 }; 132 Ok(File { inner }) 133 } 134 135 /// Return the file format. format(&self) -> BinaryFormat136 pub fn format(&self) -> BinaryFormat { 137 match self.inner { 138 FileInternal::Elf(_) => BinaryFormat::Elf, 139 FileInternal::MachO(_) => BinaryFormat::Macho, 140 FileInternal::Coff(_) | FileInternal::Pe(_) => BinaryFormat::Coff, 141 #[cfg(feature = "wasm")] 142 FileInternal::Wasm(_) => BinaryFormat::Wasm, 143 } 144 } 145 } 146 147 impl<'data, 'file> Object<'data, 'file> for File<'data> 148 where 149 'data: 'file, 150 { 151 type Segment = Segment<'data, 'file>; 152 type SegmentIterator = SegmentIterator<'data, 'file>; 153 type Section = Section<'data, 'file>; 154 type SectionIterator = SectionIterator<'data, 'file>; 155 type SymbolIterator = SymbolIterator<'data, 'file>; 156 architecture(&self) -> Architecture157 fn architecture(&self) -> Architecture { 158 with_inner!(self.inner, FileInternal, |x| x.architecture()) 159 } 160 is_little_endian(&self) -> bool161 fn is_little_endian(&self) -> bool { 162 with_inner!(self.inner, FileInternal, |x| x.is_little_endian()) 163 } 164 is_64(&self) -> bool165 fn is_64(&self) -> bool { 166 with_inner!(self.inner, FileInternal, |x| x.is_64()) 167 } 168 segments(&'file self) -> SegmentIterator<'data, 'file>169 fn segments(&'file self) -> SegmentIterator<'data, 'file> { 170 SegmentIterator { 171 inner: map_inner!(self.inner, FileInternal, SegmentIteratorInternal, |x| x 172 .segments()), 173 } 174 } 175 section_by_name(&'file self, section_name: &str) -> Option<Section<'data, 'file>>176 fn section_by_name(&'file self, section_name: &str) -> Option<Section<'data, 'file>> { 177 map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x 178 .section_by_name(section_name)) 179 .map(|inner| Section { inner }) 180 } 181 section_by_index(&'file self, index: SectionIndex) -> Option<Section<'data, 'file>>182 fn section_by_index(&'file self, index: SectionIndex) -> Option<Section<'data, 'file>> { 183 map_inner_option!(self.inner, FileInternal, SectionInternal, |x| x 184 .section_by_index(index)) 185 .map(|inner| Section { inner }) 186 } 187 section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>>188 fn section_data_by_name(&self, section_name: &str) -> Option<Cow<'data, [u8]>> { 189 with_inner!(self.inner, FileInternal, |x| x 190 .section_data_by_name(section_name)) 191 } 192 sections(&'file self) -> SectionIterator<'data, 'file>193 fn sections(&'file self) -> SectionIterator<'data, 'file> { 194 SectionIterator { 195 inner: map_inner!(self.inner, FileInternal, SectionIteratorInternal, |x| x 196 .sections()), 197 } 198 } 199 symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>>200 fn symbol_by_index(&self, index: SymbolIndex) -> Option<Symbol<'data>> { 201 with_inner!(self.inner, FileInternal, |x| x.symbol_by_index(index)) 202 } 203 symbols(&'file self) -> SymbolIterator<'data, 'file>204 fn symbols(&'file self) -> SymbolIterator<'data, 'file> { 205 SymbolIterator { 206 inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x 207 .symbols()), 208 } 209 } 210 dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file>211 fn dynamic_symbols(&'file self) -> SymbolIterator<'data, 'file> { 212 SymbolIterator { 213 inner: map_inner!(self.inner, FileInternal, SymbolIteratorInternal, |x| x 214 .dynamic_symbols()), 215 } 216 } 217 symbol_map(&self) -> SymbolMap<'data>218 fn symbol_map(&self) -> SymbolMap<'data> { 219 with_inner!(self.inner, FileInternal, |x| x.symbol_map()) 220 } 221 has_debug_symbols(&self) -> bool222 fn has_debug_symbols(&self) -> bool { 223 with_inner!(self.inner, FileInternal, |x| x.has_debug_symbols()) 224 } 225 226 #[inline] mach_uuid(&self) -> Option<Uuid>227 fn mach_uuid(&self) -> Option<Uuid> { 228 with_inner!(self.inner, FileInternal, |x| x.mach_uuid()) 229 } 230 231 #[inline] build_id(&self) -> Option<&'data [u8]>232 fn build_id(&self) -> Option<&'data [u8]> { 233 with_inner!(self.inner, FileInternal, |x| x.build_id()) 234 } 235 236 #[inline] gnu_debuglink(&self) -> Option<(&'data [u8], u32)>237 fn gnu_debuglink(&self) -> Option<(&'data [u8], u32)> { 238 with_inner!(self.inner, FileInternal, |x| x.gnu_debuglink()) 239 } 240 entry(&self) -> u64241 fn entry(&self) -> u64 { 242 with_inner!(self.inner, FileInternal, |x| x.entry()) 243 } 244 } 245 246 /// An iterator over the segments of a `File`. 247 #[derive(Debug)] 248 pub struct SegmentIterator<'data, 'file> 249 where 250 'data: 'file, 251 { 252 inner: SegmentIteratorInternal<'data, 'file>, 253 } 254 255 #[derive(Debug)] 256 enum SegmentIteratorInternal<'data, 'file> 257 where 258 'data: 'file, 259 { 260 Coff(coff::CoffSegmentIterator<'data, 'file>), 261 Elf(elf::ElfSegmentIterator<'data, 'file>), 262 MachO(macho::MachOSegmentIterator<'data, 'file>), 263 Pe(pe::PeSegmentIterator<'data, 'file>), 264 #[cfg(feature = "wasm")] 265 Wasm(wasm::WasmSegmentIterator<'file>), 266 } 267 268 impl<'data, 'file> Iterator for SegmentIterator<'data, 'file> { 269 type Item = Segment<'data, 'file>; 270 next(&mut self) -> Option<Self::Item>271 fn next(&mut self) -> Option<Self::Item> { 272 next_inner!(self.inner, SegmentIteratorInternal, SegmentInternal) 273 .map(|inner| Segment { inner }) 274 } 275 } 276 277 /// A segment of a `File`. 278 pub struct Segment<'data, 'file> 279 where 280 'data: 'file, 281 { 282 inner: SegmentInternal<'data, 'file>, 283 } 284 285 #[derive(Debug)] 286 enum SegmentInternal<'data, 'file> 287 where 288 'data: 'file, 289 { 290 Coff(coff::CoffSegment<'data, 'file>), 291 Elf(elf::ElfSegment<'data, 'file>), 292 MachO(macho::MachOSegment<'data, 'file>), 293 Pe(pe::PeSegment<'data, 'file>), 294 #[cfg(feature = "wasm")] 295 Wasm(wasm::WasmSegment<'file>), 296 } 297 298 impl<'data, 'file> fmt::Debug for Segment<'data, 'file> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 300 // It's painful to do much better than this 301 f.debug_struct("Segment") 302 .field("name", &self.name().unwrap_or("<unnamed>")) 303 .field("address", &self.address()) 304 .field("size", &self.data().len()) 305 .finish() 306 } 307 } 308 309 impl<'data, 'file> ObjectSegment<'data> for Segment<'data, 'file> { address(&self) -> u64310 fn address(&self) -> u64 { 311 with_inner!(self.inner, SegmentInternal, |x| x.address()) 312 } 313 size(&self) -> u64314 fn size(&self) -> u64 { 315 with_inner!(self.inner, SegmentInternal, |x| x.size()) 316 } 317 align(&self) -> u64318 fn align(&self) -> u64 { 319 with_inner!(self.inner, SegmentInternal, |x| x.align()) 320 } 321 file_range(&self) -> (u64, u64)322 fn file_range(&self) -> (u64, u64) { 323 with_inner!(self.inner, SegmentInternal, |x| x.file_range()) 324 } 325 data(&self) -> &'data [u8]326 fn data(&self) -> &'data [u8] { 327 with_inner!(self.inner, SegmentInternal, |x| x.data()) 328 } 329 data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>330 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> { 331 with_inner!(self.inner, SegmentInternal, |x| x.data_range(address, size)) 332 } 333 name(&self) -> Option<&str>334 fn name(&self) -> Option<&str> { 335 with_inner!(self.inner, SegmentInternal, |x| x.name()) 336 } 337 } 338 339 /// An iterator of the sections of a `File`. 340 #[derive(Debug)] 341 pub struct SectionIterator<'data, 'file> 342 where 343 'data: 'file, 344 { 345 inner: SectionIteratorInternal<'data, 'file>, 346 } 347 348 // we wrap our enums in a struct so that they are kept private. 349 #[derive(Debug)] 350 enum SectionIteratorInternal<'data, 'file> 351 where 352 'data: 'file, 353 { 354 Coff(coff::CoffSectionIterator<'data, 'file>), 355 Elf(elf::ElfSectionIterator<'data, 'file>), 356 MachO(macho::MachOSectionIterator<'data, 'file>), 357 Pe(pe::PeSectionIterator<'data, 'file>), 358 #[cfg(feature = "wasm")] 359 Wasm(wasm::WasmSectionIterator<'file>), 360 } 361 362 impl<'data, 'file> Iterator for SectionIterator<'data, 'file> { 363 type Item = Section<'data, 'file>; 364 next(&mut self) -> Option<Self::Item>365 fn next(&mut self) -> Option<Self::Item> { 366 next_inner!(self.inner, SectionIteratorInternal, SectionInternal) 367 .map(|inner| Section { inner }) 368 } 369 } 370 371 /// A Section of a File 372 pub struct Section<'data, 'file> 373 where 374 'data: 'file, 375 { 376 inner: SectionInternal<'data, 'file>, 377 } 378 379 enum SectionInternal<'data, 'file> 380 where 381 'data: 'file, 382 { 383 Coff(coff::CoffSection<'data, 'file>), 384 Elf(elf::ElfSection<'data, 'file>), 385 MachO(macho::MachOSection<'data, 'file>), 386 Pe(pe::PeSection<'data, 'file>), 387 #[cfg(feature = "wasm")] 388 Wasm(wasm::WasmSection<'file>), 389 } 390 391 impl<'data, 'file> fmt::Debug for Section<'data, 'file> { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result392 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 393 // It's painful to do much better than this 394 let mut s = f.debug_struct("Section"); 395 if let Some(segment) = self.segment_name() { 396 s.field("segment", &segment); 397 } 398 s.field("name", &self.name().unwrap_or("<invalid name>")) 399 .field("address", &self.address()) 400 .field("size", &self.data().len()) 401 .field("kind", &self.kind()) 402 .finish() 403 } 404 } 405 406 impl<'data, 'file> ObjectSection<'data> for Section<'data, 'file> { 407 type RelocationIterator = RelocationIterator<'data, 'file>; 408 index(&self) -> SectionIndex409 fn index(&self) -> SectionIndex { 410 with_inner!(self.inner, SectionInternal, |x| x.index()) 411 } 412 address(&self) -> u64413 fn address(&self) -> u64 { 414 with_inner!(self.inner, SectionInternal, |x| x.address()) 415 } 416 size(&self) -> u64417 fn size(&self) -> u64 { 418 with_inner!(self.inner, SectionInternal, |x| x.size()) 419 } 420 align(&self) -> u64421 fn align(&self) -> u64 { 422 with_inner!(self.inner, SectionInternal, |x| x.align()) 423 } 424 file_range(&self) -> Option<(u64, u64)>425 fn file_range(&self) -> Option<(u64, u64)> { 426 with_inner!(self.inner, SectionInternal, |x| x.file_range()) 427 } 428 data(&self) -> Cow<'data, [u8]>429 fn data(&self) -> Cow<'data, [u8]> { 430 with_inner!(self.inner, SectionInternal, |x| x.data()) 431 } 432 data_range(&self, address: u64, size: u64) -> Option<&'data [u8]>433 fn data_range(&self, address: u64, size: u64) -> Option<&'data [u8]> { 434 with_inner!(self.inner, SectionInternal, |x| x.data_range(address, size)) 435 } 436 uncompressed_data(&self) -> Cow<'data, [u8]>437 fn uncompressed_data(&self) -> Cow<'data, [u8]> { 438 with_inner!(self.inner, SectionInternal, |x| x.uncompressed_data()) 439 } 440 name(&self) -> Option<&str>441 fn name(&self) -> Option<&str> { 442 with_inner!(self.inner, SectionInternal, |x| x.name()) 443 } 444 segment_name(&self) -> Option<&str>445 fn segment_name(&self) -> Option<&str> { 446 with_inner!(self.inner, SectionInternal, |x| x.segment_name()) 447 } 448 kind(&self) -> SectionKind449 fn kind(&self) -> SectionKind { 450 with_inner!(self.inner, SectionInternal, |x| x.kind()) 451 } 452 relocations(&self) -> RelocationIterator<'data, 'file>453 fn relocations(&self) -> RelocationIterator<'data, 'file> { 454 RelocationIterator { 455 inner: map_inner!( 456 self.inner, 457 SectionInternal, 458 RelocationIteratorInternal, 459 |x| x.relocations() 460 ), 461 } 462 } 463 } 464 465 /// An iterator over symbol table entries. 466 #[derive(Debug)] 467 pub struct SymbolIterator<'data, 'file> 468 where 469 'data: 'file, 470 { 471 inner: SymbolIteratorInternal<'data, 'file>, 472 } 473 474 #[derive(Debug)] 475 enum SymbolIteratorInternal<'data, 'file> 476 where 477 'data: 'file, 478 { 479 Coff(coff::CoffSymbolIterator<'data, 'file>), 480 Elf(elf::ElfSymbolIterator<'data, 'file>), 481 MachO(macho::MachOSymbolIterator<'data, 'file>), 482 Pe(pe::PeSymbolIterator<'data, 'file>), 483 #[cfg(feature = "wasm")] 484 Wasm(wasm::WasmSymbolIterator<'file>), 485 } 486 487 impl<'data, 'file> Iterator for SymbolIterator<'data, 'file> { 488 type Item = (SymbolIndex, Symbol<'data>); 489 next(&mut self) -> Option<Self::Item>490 fn next(&mut self) -> Option<Self::Item> { 491 with_inner_mut!(self.inner, SymbolIteratorInternal, |x| x.next()) 492 } 493 } 494 495 /// An iterator over relocation entries 496 #[derive(Debug)] 497 pub struct RelocationIterator<'data, 'file> 498 where 499 'data: 'file, 500 { 501 inner: RelocationIteratorInternal<'data, 'file>, 502 } 503 504 #[derive(Debug)] 505 enum RelocationIteratorInternal<'data, 'file> 506 where 507 'data: 'file, 508 { 509 Coff(coff::CoffRelocationIterator<'data, 'file>), 510 Elf(elf::ElfRelocationIterator<'data, 'file>), 511 MachO(macho::MachORelocationIterator<'data, 'file>), 512 Pe(pe::PeRelocationIterator), 513 #[cfg(feature = "wasm")] 514 Wasm(wasm::WasmRelocationIterator), 515 } 516 517 impl<'data, 'file> Iterator for RelocationIterator<'data, 'file> { 518 type Item = (u64, Relocation); 519 next(&mut self) -> Option<Self::Item>520 fn next(&mut self) -> Option<Self::Item> { 521 with_inner_mut!(self.inner, RelocationIteratorInternal, |x| x.next()) 522 } 523 } 524