1use std::error::Error;
4use std::fmt;
5
6use symbolic_common::{Arch, AsSelf, CodeId, DebugId};
7use symbolic_ppdb::PortablePdb;
8
9use crate::base::*;
10use crate::breakpad::*;
11use crate::dwarf::*;
12use crate::elf::*;
13use crate::macho::*;
14use crate::pdb::*;
15use crate::pe::*;
16use crate::ppdb::*;
17use crate::sourcebundle::*;
18use crate::wasm::*;
19
20macro_rules! match_inner {
21 ($value:expr, $ty:tt ($pat:pat) => $expr:expr) => {
22 match $value {
23 $ty::Breakpad($pat) => $expr,
24 $ty::Elf($pat) => $expr,
25 $ty::MachO($pat) => $expr,
26 $ty::Pdb($pat) => $expr,
27 $ty::Pe($pat) => $expr,
28 $ty::SourceBundle($pat) => $expr,
29 $ty::Wasm($pat) => $expr,
30 $ty::PortablePdb($pat) => $expr,
31 }
32 };
33}
34
35macro_rules! map_inner {
36 ($value:expr, $from:tt($pat:pat) => $to:tt($expr:expr)) => {
37 match $value {
38 $from::Breakpad($pat) => $to::Breakpad($expr),
39 $from::Elf($pat) => $to::Elf($expr),
40 $from::MachO($pat) => $to::MachO($expr),
41 $from::Pdb($pat) => $to::Pdb($expr),
42 $from::Pe($pat) => $to::Pe($expr),
43 $from::SourceBundle($pat) => $to::SourceBundle($expr),
44 $from::Wasm($pat) => $to::Wasm($expr),
45 $from::PortablePdb($pat) => $to::PortablePdb($expr),
46 }
47 };
48}
49
50macro_rules! map_result {
51 ($value:expr, $from:tt($pat:pat) => $to:tt($expr:expr)) => {
52 match $value {
53 $from::Breakpad($pat) => $expr.map($to::Breakpad).map_err(ObjectError::transparent),
54 $from::Elf($pat) => $expr.map($to::Elf).map_err(ObjectError::transparent),
55 $from::MachO($pat) => $expr.map($to::MachO).map_err(ObjectError::transparent),
56 $from::Pdb($pat) => $expr.map($to::Pdb).map_err(ObjectError::transparent),
57 $from::Pe($pat) => $expr.map($to::Pe).map_err(ObjectError::transparent),
58 $from::SourceBundle($pat) => $expr
59 .map($to::SourceBundle)
60 .map_err(ObjectError::transparent),
61 $from::Wasm($pat) => $expr.map($to::Wasm).map_err(ObjectError::transparent),
62 $from::PortablePdb($pat) => $expr
63 .map($to::PortablePdb)
64 .map_err(ObjectError::transparent),
65 }
66 };
67}
68
69#[derive(Debug)]
71enum ObjectErrorRepr {
72 UnsupportedObject,
74
75 Transparent(Box<dyn Error + Send + Sync + 'static>),
77}
78
79pub struct ObjectError {
81 repr: ObjectErrorRepr,
82}
83
84impl ObjectError {
85 fn new(repr: ObjectErrorRepr) -> Self {
87 Self { repr }
88 }
89
90 fn transparent<E>(source: E) -> Self
92 where
93 E: Into<Box<dyn Error + Send + Sync>>,
94 {
95 let repr = ObjectErrorRepr::Transparent(source.into());
96 Self { repr }
97 }
98}
99
100impl fmt::Debug for ObjectError {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 match self.repr {
103 ObjectErrorRepr::Transparent(ref inner) => fmt::Debug::fmt(inner, f),
104 _ => fmt::Debug::fmt(&self.repr, f),
105 }
106 }
107}
108
109impl fmt::Display for ObjectError {
110 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 match self.repr {
112 ObjectErrorRepr::UnsupportedObject => write!(f, "unsupported object file format"),
113 ObjectErrorRepr::Transparent(ref inner) => fmt::Display::fmt(inner, f),
114 }
115 }
116}
117
118impl Error for ObjectError {
119 fn source(&self) -> Option<&(dyn Error + 'static)> {
120 match self.repr {
121 ObjectErrorRepr::UnsupportedObject => None,
122 ObjectErrorRepr::Transparent(ref inner) => inner.source(),
123 }
124 }
125}
126
127#[non_exhaustive]
129#[derive(Debug, Clone, Copy, Default)]
130pub struct ParseObjectOptions {
131 pub max_decompressed_section_size: Option<usize>,
135}
136
137pub fn peek(data: &[u8], archive: bool) -> FileFormat {
142 if data.len() < 16 {
143 return FileFormat::Unknown;
144 }
145
146 if ElfObject::test(data) {
147 FileFormat::Elf
148 } else if PeObject::test(data) {
149 FileFormat::Pe
150 } else if PdbObject::test(data) {
151 FileFormat::Pdb
152 } else if SourceBundle::test(data) {
153 FileFormat::SourceBundle
154 } else if BreakpadObject::test(data) {
155 FileFormat::Breakpad
156 } else if WasmObject::test(data) {
157 FileFormat::Wasm
158 } else if PortablePdbObject::test(data) {
159 FileFormat::PortablePdb
160 } else {
161 let magic = goblin::mach::parse_magic_and_ctx(data, 0).map(|(magic, _)| magic);
162
163 match magic {
164 Ok(goblin::mach::fat::FAT_MAGIC) => {
165 use scroll::Pread;
166 if data.pread_with::<u32>(4, scroll::BE).is_ok()
167 && archive
168 && MachArchive::test(data)
169 {
170 FileFormat::MachO
171 } else {
172 FileFormat::Unknown
173 }
174 }
175 Ok(
176 goblin::mach::header::MH_CIGAM_64
177 | goblin::mach::header::MH_CIGAM
178 | goblin::mach::header::MH_MAGIC_64
179 | goblin::mach::header::MH_MAGIC,
180 ) => FileFormat::MachO,
181 _ => FileFormat::Unknown,
182 }
183 }
184}
185
186#[allow(clippy::large_enum_variant)]
188#[derive(Debug)]
189pub enum Object<'data> {
190 Breakpad(BreakpadObject<'data>),
192 Elf(ElfObject<'data>),
194 MachO(MachObject<'data>),
196 Pdb(PdbObject<'data>),
198 Pe(PeObject<'data>),
200 SourceBundle(SourceBundle<'data>),
202 Wasm(WasmObject<'data>),
204 PortablePdb(PortablePdbObject<'data>),
206}
207
208impl<'data> Object<'data> {
209 pub fn test(data: &[u8]) -> bool {
211 Self::peek(data) != FileFormat::Unknown
212 }
213
214 pub fn peek(data: &[u8]) -> FileFormat {
216 peek(data, false)
217 }
218
219 pub fn parse(data: &'data [u8]) -> Result<Self, ObjectError> {
221 Self::parse_with_opts(data, Default::default())
222 }
223
224 pub fn parse_with_opts(
226 data: &'data [u8],
227 opts: ParseObjectOptions,
228 ) -> Result<Self, ObjectError> {
229 macro_rules! parse_object {
230 ($kind:ident, $file:ident, $data:expr) => {
231 Object::$kind($file::parse_with_opts(data, opts).map_err(ObjectError::transparent)?)
232 };
233 }
234
235 let object = match Self::peek(data) {
236 FileFormat::Breakpad => parse_object!(Breakpad, BreakpadObject, data),
237 FileFormat::Elf => parse_object!(Elf, ElfObject, data),
238 FileFormat::MachO => parse_object!(MachO, MachObject, data),
239 FileFormat::Pdb => parse_object!(Pdb, PdbObject, data),
240 FileFormat::Pe => parse_object!(Pe, PeObject, data),
241 FileFormat::SourceBundle => parse_object!(SourceBundle, SourceBundle, data),
242 FileFormat::Wasm => parse_object!(Wasm, WasmObject, data),
243 FileFormat::PortablePdb => parse_object!(PortablePdb, PortablePdbObject, data),
244 FileFormat::Unknown => {
245 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
246 }
247 };
248
249 Ok(object)
250 }
251
252 pub fn file_format(&self) -> FileFormat {
254 match *self {
255 Object::Breakpad(_) => FileFormat::Breakpad,
256 Object::Elf(_) => FileFormat::Elf,
257 Object::MachO(_) => FileFormat::MachO,
258 Object::Pdb(_) => FileFormat::Pdb,
259 Object::Pe(_) => FileFormat::Pe,
260 Object::SourceBundle(_) => FileFormat::SourceBundle,
261 Object::Wasm(_) => FileFormat::Wasm,
262 Object::PortablePdb(_) => FileFormat::PortablePdb,
263 }
264 }
265
266 pub fn code_id(&self) -> Option<CodeId> {
272 match_inner!(self, Object(ref o) => o.code_id())
273 }
274
275 pub fn debug_id(&self) -> DebugId {
280 match_inner!(self, Object(ref o) => o.debug_id())
281 }
282
283 pub fn arch(&self) -> Arch {
285 match_inner!(self, Object(ref o) => o.arch())
286 }
287
288 pub fn kind(&self) -> ObjectKind {
290 match_inner!(self, Object(ref o) => o.kind())
291 }
292
293 pub fn load_address(&self) -> u64 {
295 match_inner!(self, Object(ref o) => o.load_address())
296 }
297
298 pub fn has_symbols(&self) -> bool {
300 match_inner!(self, Object(ref o) => o.has_symbols())
301 }
302
303 pub fn symbols(&self) -> SymbolIterator<'data, '_> {
305 map_inner!(self, Object(ref o) => SymbolIterator(o.symbols()))
306 }
307
308 pub fn symbol_map(&self) -> SymbolMap<'data> {
310 match_inner!(self, Object(ref o) => o.symbol_map())
311 }
312
313 pub fn has_debug_info(&self) -> bool {
315 match_inner!(self, Object(ref o) => o.has_debug_info())
316 }
317
318 pub fn debug_session(&self) -> Result<ObjectDebugSession<'data>, ObjectError> {
332 match *self {
333 Object::Breakpad(ref o) => o
334 .debug_session()
335 .map(ObjectDebugSession::Breakpad)
336 .map_err(ObjectError::transparent),
337 Object::Elf(ref o) => o
338 .debug_session()
339 .map(ObjectDebugSession::Dwarf)
340 .map_err(ObjectError::transparent),
341 Object::MachO(ref o) => o
342 .debug_session()
343 .map(ObjectDebugSession::Dwarf)
344 .map_err(ObjectError::transparent),
345 Object::Pdb(ref o) => o
346 .debug_session()
347 .map(ObjectDebugSession::Pdb)
348 .map_err(ObjectError::transparent),
349 Object::Pe(ref o) => o
350 .debug_session()
351 .map(ObjectDebugSession::Dwarf)
352 .map_err(ObjectError::transparent),
353 Object::SourceBundle(ref o) => o
354 .debug_session()
355 .map(ObjectDebugSession::SourceBundle)
356 .map_err(ObjectError::transparent),
357 Object::Wasm(ref o) => o
358 .debug_session()
359 .map(ObjectDebugSession::Dwarf)
360 .map_err(ObjectError::transparent),
361 Object::PortablePdb(ref o) => o
362 .debug_session()
363 .map(ObjectDebugSession::PortablePdb)
364 .map_err(ObjectError::transparent),
365 }
366 }
367
368 pub fn has_unwind_info(&self) -> bool {
370 match_inner!(self, Object(ref o) => o.has_unwind_info())
371 }
372
373 pub fn has_sources(&self) -> bool {
375 match_inner!(self, Object(ref o) => o.has_sources())
376 }
377
378 pub fn is_malformed(&self) -> bool {
380 match_inner!(self, Object(ref o) => o.is_malformed())
381 }
382
383 pub fn data(&self) -> &'data [u8] {
385 match_inner!(self, Object(ref o) => o.data())
386 }
387}
388
389impl<'slf, 'data: 'slf> AsSelf<'slf> for Object<'data> {
390 type Ref = Object<'slf>;
391
392 fn as_self(&'slf self) -> &'slf Self::Ref {
393 unsafe { std::mem::transmute(self) }
394 }
395}
396
397impl<'data: 'object, 'object> ObjectLike<'data, 'object> for Object<'data> {
398 type Error = ObjectError;
399 type Session = ObjectDebugSession<'data>;
400 type SymbolIterator = SymbolIterator<'data, 'object>;
401
402 fn file_format(&self) -> FileFormat {
403 self.file_format()
404 }
405
406 fn code_id(&self) -> Option<CodeId> {
407 self.code_id()
408 }
409
410 fn debug_id(&self) -> DebugId {
411 self.debug_id()
412 }
413
414 fn arch(&self) -> Arch {
415 self.arch()
416 }
417
418 fn kind(&self) -> ObjectKind {
419 self.kind()
420 }
421
422 fn load_address(&self) -> u64 {
423 self.load_address()
424 }
425
426 fn has_symbols(&self) -> bool {
427 self.has_symbols()
428 }
429
430 fn symbol_map(&self) -> SymbolMap<'data> {
431 self.symbol_map()
432 }
433
434 fn symbols(&'object self) -> Self::SymbolIterator {
435 self.symbols()
436 }
437
438 fn has_debug_info(&self) -> bool {
439 self.has_debug_info()
440 }
441
442 fn debug_session(&self) -> Result<Self::Session, Self::Error> {
443 self.debug_session()
444 }
445
446 fn has_unwind_info(&self) -> bool {
447 self.has_unwind_info()
448 }
449
450 fn has_sources(&self) -> bool {
451 self.has_sources()
452 }
453
454 fn is_malformed(&self) -> bool {
455 self.is_malformed()
456 }
457}
458
459#[allow(clippy::large_enum_variant)]
461#[allow(missing_docs)]
462pub enum ObjectDebugSession<'d> {
463 Breakpad(BreakpadDebugSession<'d>),
464 Dwarf(DwarfDebugSession<'d>),
465 Pdb(PdbDebugSession<'d>),
466 SourceBundle(SourceBundleDebugSession<'d>),
467 PortablePdb(PortablePdbDebugSession<'d>),
468}
469
470impl ObjectDebugSession<'_> {
471 pub fn functions(&self) -> ObjectFunctionIterator<'_> {
479 match *self {
480 ObjectDebugSession::Breakpad(ref s) => ObjectFunctionIterator::Breakpad(s.functions()),
481 ObjectDebugSession::Dwarf(ref s) => ObjectFunctionIterator::Dwarf(s.functions()),
482 ObjectDebugSession::Pdb(ref s) => ObjectFunctionIterator::Pdb(s.functions()),
483 ObjectDebugSession::SourceBundle(ref s) => {
484 ObjectFunctionIterator::SourceBundle(s.functions())
485 }
486 ObjectDebugSession::PortablePdb(ref s) => {
487 ObjectFunctionIterator::PortablePdb(s.functions())
488 }
489 }
490 }
491
492 pub fn files(&self) -> ObjectFileIterator<'_> {
494 match *self {
495 ObjectDebugSession::Breakpad(ref s) => ObjectFileIterator::Breakpad(s.files()),
496 ObjectDebugSession::Dwarf(ref s) => ObjectFileIterator::Dwarf(s.files()),
497 ObjectDebugSession::Pdb(ref s) => ObjectFileIterator::Pdb(s.files()),
498 ObjectDebugSession::SourceBundle(ref s) => ObjectFileIterator::SourceBundle(s.files()),
499 ObjectDebugSession::PortablePdb(ref s) => ObjectFileIterator::PortablePdb(s.files()),
500 }
501 }
502
503 pub fn source_by_path(
506 &self,
507 path: &str,
508 ) -> Result<Option<SourceFileDescriptor<'_>>, ObjectError> {
509 match *self {
510 ObjectDebugSession::Breakpad(ref s) => {
511 s.source_by_path(path).map_err(ObjectError::transparent)
512 }
513 ObjectDebugSession::Dwarf(ref s) => {
514 s.source_by_path(path).map_err(ObjectError::transparent)
515 }
516 ObjectDebugSession::Pdb(ref s) => {
517 s.source_by_path(path).map_err(ObjectError::transparent)
518 }
519 ObjectDebugSession::SourceBundle(ref s) => {
520 s.source_by_path(path).map_err(ObjectError::transparent)
521 }
522 ObjectDebugSession::PortablePdb(ref s) => {
523 s.source_by_path(path).map_err(ObjectError::transparent)
524 }
525 }
526 }
527}
528
529impl<'session> DebugSession<'session> for ObjectDebugSession<'_> {
530 type Error = ObjectError;
531 type FunctionIterator = ObjectFunctionIterator<'session>;
532 type FileIterator = ObjectFileIterator<'session>;
533
534 fn functions(&'session self) -> Self::FunctionIterator {
535 self.functions()
536 }
537
538 fn files(&'session self) -> Self::FileIterator {
539 self.files()
540 }
541
542 fn source_by_path(&self, path: &str) -> Result<Option<SourceFileDescriptor<'_>>, Self::Error> {
543 self.source_by_path(path)
544 }
545}
546
547#[allow(missing_docs)]
549pub enum ObjectFunctionIterator<'s> {
550 Breakpad(BreakpadFunctionIterator<'s>),
551 Dwarf(DwarfFunctionIterator<'s>),
552 Pdb(PdbFunctionIterator<'s>),
553 SourceBundle(SourceBundleFunctionIterator<'s>),
554 PortablePdb(PortablePdbFunctionIterator<'s>),
555}
556
557impl<'s> Iterator for ObjectFunctionIterator<'s> {
558 type Item = Result<Function<'s>, ObjectError>;
559
560 fn next(&mut self) -> Option<Self::Item> {
561 match *self {
562 ObjectFunctionIterator::Breakpad(ref mut i) => {
563 Some(i.next()?.map_err(ObjectError::transparent))
564 }
565 ObjectFunctionIterator::Dwarf(ref mut i) => {
566 Some(i.next()?.map_err(ObjectError::transparent))
567 }
568 ObjectFunctionIterator::Pdb(ref mut i) => {
569 Some(i.next()?.map_err(ObjectError::transparent))
570 }
571 ObjectFunctionIterator::SourceBundle(ref mut i) => {
572 Some(i.next()?.map_err(ObjectError::transparent))
573 }
574 ObjectFunctionIterator::PortablePdb(ref mut i) => {
575 Some(i.next()?.map_err(ObjectError::transparent))
576 }
577 }
578 }
579}
580
581#[allow(missing_docs)]
583#[allow(clippy::large_enum_variant)]
584pub enum ObjectFileIterator<'s> {
585 Breakpad(BreakpadFileIterator<'s>),
586 Dwarf(DwarfFileIterator<'s>),
587 Pdb(PdbFileIterator<'s>),
588 SourceBundle(SourceBundleFileIterator<'s>),
589 PortablePdb(PortablePdbFileIterator<'s>),
590}
591
592impl<'s> Iterator for ObjectFileIterator<'s> {
593 type Item = Result<FileEntry<'s>, ObjectError>;
594
595 fn next(&mut self) -> Option<Self::Item> {
596 match *self {
597 ObjectFileIterator::Breakpad(ref mut i) => {
598 Some(i.next()?.map_err(ObjectError::transparent))
599 }
600 ObjectFileIterator::Dwarf(ref mut i) => {
601 Some(i.next()?.map_err(ObjectError::transparent))
602 }
603 ObjectFileIterator::Pdb(ref mut i) => Some(i.next()?.map_err(ObjectError::transparent)),
604 ObjectFileIterator::SourceBundle(ref mut i) => {
605 Some(i.next()?.map_err(ObjectError::transparent))
606 }
607 ObjectFileIterator::PortablePdb(ref mut i) => {
608 Some(i.next()?.map_err(ObjectError::transparent))
609 }
610 }
611 }
612}
613
614#[allow(missing_docs)]
616pub enum SymbolIterator<'data, 'object> {
617 Breakpad(BreakpadSymbolIterator<'data>),
618 Elf(ElfSymbolIterator<'data, 'object>),
619 MachO(MachOSymbolIterator<'data>),
620 Pdb(PdbSymbolIterator<'data, 'object>),
621 Pe(PeSymbolIterator<'data, 'object>),
622 SourceBundle(SourceBundleSymbolIterator<'data>),
623 Wasm(WasmSymbolIterator<'data, 'object>),
624 PortablePdb(PortablePdbSymbolIterator<'data>),
625}
626
627impl<'data> Iterator for SymbolIterator<'data, '_> {
628 type Item = Symbol<'data>;
629
630 fn next(&mut self) -> Option<Self::Item> {
631 match_inner!(self, SymbolIterator(ref mut iter) => iter.next())
632 }
633}
634
635impl<'data> crate::base::Parse<'data> for PortablePdb<'data> {
636 type Error = symbolic_ppdb::FormatError;
637
638 fn parse_with_opts(data: &'data [u8], _opts: ParseObjectOptions) -> Result<Self, Self::Error> {
639 Self::parse(data)
640 }
641
642 fn test(data: &'data [u8]) -> bool {
643 Self::peek(data)
644 }
645}
646
647#[derive(Debug)]
648enum ArchiveInner<'d> {
649 Breakpad(MonoArchive<'d, BreakpadObject<'d>>),
650 Elf(MonoArchive<'d, ElfObject<'d>>),
651 MachO(MachArchive<'d>),
652 Pdb(MonoArchive<'d, PdbObject<'d>>),
653 Pe(MonoArchive<'d, PeObject<'d>>),
654 SourceBundle(MonoArchive<'d, SourceBundle<'d>>),
655 Wasm(MonoArchive<'d, WasmObject<'d>>),
656 PortablePdb(MonoArchive<'d, PortablePdbObject<'d>>),
657}
658
659#[derive(Debug)]
665pub struct Archive<'d>(ArchiveInner<'d>);
666
667impl<'d> Archive<'d> {
668 pub fn test(data: &[u8]) -> bool {
670 Self::peek(data) != FileFormat::Unknown
671 }
672
673 pub fn peek(data: &[u8]) -> FileFormat {
675 peek(data, true)
676 }
677
678 pub fn parse(data: &'d [u8]) -> Result<Self, ObjectError> {
680 Self::parse_with_opts(data, Default::default())
681 }
682
683 pub fn parse_with_opts(data: &'d [u8], opts: ParseObjectOptions) -> Result<Self, ObjectError> {
685 let archive = match Self::peek(data) {
686 FileFormat::Breakpad => Archive(ArchiveInner::Breakpad(MonoArchive::new(data, opts))),
687 FileFormat::Elf => Archive(ArchiveInner::Elf(MonoArchive::new(data, opts))),
688 FileFormat::MachO => {
689 let inner = MachArchive::parse_with_opts(data, opts)
690 .map(ArchiveInner::MachO)
691 .map_err(ObjectError::transparent)?;
692 Archive(inner)
693 }
694 FileFormat::Pdb => Archive(ArchiveInner::Pdb(MonoArchive::new(data, opts))),
695 FileFormat::Pe => Archive(ArchiveInner::Pe(MonoArchive::new(data, opts))),
696 FileFormat::SourceBundle => {
697 Archive(ArchiveInner::SourceBundle(MonoArchive::new(data, opts)))
698 }
699 FileFormat::Wasm => Archive(ArchiveInner::Wasm(MonoArchive::new(data, opts))),
700 FileFormat::PortablePdb => {
701 Archive(ArchiveInner::PortablePdb(MonoArchive::new(data, opts)))
702 }
703 FileFormat::Unknown => {
704 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
705 }
706 };
707
708 Ok(archive)
709 }
710
711 pub fn file_format(&self) -> FileFormat {
713 match self.0 {
714 ArchiveInner::Breakpad(_) => FileFormat::Breakpad,
715 ArchiveInner::Elf(_) => FileFormat::Elf,
716 ArchiveInner::MachO(_) => FileFormat::MachO,
717 ArchiveInner::Pdb(_) => FileFormat::Pdb,
718 ArchiveInner::Pe(_) => FileFormat::Pe,
719 ArchiveInner::Wasm(_) => FileFormat::Wasm,
720 ArchiveInner::SourceBundle(_) => FileFormat::SourceBundle,
721 ArchiveInner::PortablePdb(_) => FileFormat::PortablePdb,
722 }
723 }
724
725 pub fn objects(&self) -> ObjectIterator<'d, '_> {
727 ObjectIterator(map_inner!(self.0, ArchiveInner(ref a) =>
728 ObjectIteratorInner(a.objects())))
729 }
730
731 pub fn object_count(&self) -> usize {
733 match_inner!(self.0, ArchiveInner(ref a) => a.object_count())
734 }
735
736 pub fn object_by_index(&self, index: usize) -> Result<Option<Object<'d>>, ObjectError> {
741 match self.0 {
742 ArchiveInner::Breakpad(ref a) => a
743 .object_by_index(index)
744 .map(|opt| opt.map(Object::Breakpad))
745 .map_err(ObjectError::transparent),
746 ArchiveInner::Elf(ref a) => a
747 .object_by_index(index)
748 .map(|opt| opt.map(Object::Elf))
749 .map_err(ObjectError::transparent),
750 ArchiveInner::MachO(ref a) => a
751 .object_by_index(index)
752 .map(|opt| opt.map(Object::MachO))
753 .map_err(ObjectError::transparent),
754 ArchiveInner::Pdb(ref a) => a
755 .object_by_index(index)
756 .map(|opt| opt.map(Object::Pdb))
757 .map_err(ObjectError::transparent),
758 ArchiveInner::Pe(ref a) => a
759 .object_by_index(index)
760 .map(|opt| opt.map(Object::Pe))
761 .map_err(ObjectError::transparent),
762 ArchiveInner::SourceBundle(ref a) => a
763 .object_by_index(index)
764 .map(|opt| opt.map(Object::SourceBundle))
765 .map_err(ObjectError::transparent),
766 ArchiveInner::Wasm(ref a) => a
767 .object_by_index(index)
768 .map(|opt| opt.map(Object::Wasm))
769 .map_err(ObjectError::transparent),
770 ArchiveInner::PortablePdb(ref a) => a
771 .object_by_index(index)
772 .map(|opt| opt.map(Object::PortablePdb))
773 .map_err(ObjectError::transparent),
774 }
775 }
776
777 pub fn is_multi(&self) -> bool {
781 match_inner!(self.0, ArchiveInner(ref a) => a.is_multi())
782 }
783}
784
785impl<'slf, 'd: 'slf> AsSelf<'slf> for Archive<'d> {
786 type Ref = Archive<'slf>;
787
788 fn as_self(&'slf self) -> &'slf Self::Ref {
789 unsafe { std::mem::transmute(self) }
790 }
791}
792
793#[allow(clippy::large_enum_variant)]
794enum ObjectIteratorInner<'d, 'a> {
795 Breakpad(MonoArchiveObjects<'d, BreakpadObject<'d>>),
796 Elf(MonoArchiveObjects<'d, ElfObject<'d>>),
797 MachO(MachObjectIterator<'d, 'a>),
798 Pdb(MonoArchiveObjects<'d, PdbObject<'d>>),
799 Pe(MonoArchiveObjects<'d, PeObject<'d>>),
800 SourceBundle(MonoArchiveObjects<'d, SourceBundle<'d>>),
801 Wasm(MonoArchiveObjects<'d, WasmObject<'d>>),
802 PortablePdb(MonoArchiveObjects<'d, PortablePdbObject<'d>>),
803}
804
805pub struct ObjectIterator<'d, 'a>(ObjectIteratorInner<'d, 'a>);
807
808impl<'d> Iterator for ObjectIterator<'d, '_> {
809 type Item = Result<Object<'d>, ObjectError>;
810
811 fn next(&mut self) -> Option<Self::Item> {
812 Some(map_result!(
813 self.0,
814 ObjectIteratorInner(ref mut iter) => Object(iter.next()?)
815 ))
816 }
817
818 fn size_hint(&self) -> (usize, Option<usize>) {
819 match_inner!(self.0, ObjectIteratorInner(ref iter) => iter.size_hint())
820 }
821}
822
823impl std::iter::FusedIterator for ObjectIterator<'_, '_> {}
824impl ExactSizeIterator for ObjectIterator<'_, '_> {}
825
826