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 pub max_decompressed_embedded_source_size: Option<usize>,
140}
141
142pub fn peek(data: &[u8], archive: bool) -> FileFormat {
147 if data.len() < 16 {
148 return FileFormat::Unknown;
149 }
150
151 if ElfObject::test(data) {
152 FileFormat::Elf
153 } else if PeObject::test(data) {
154 FileFormat::Pe
155 } else if PdbObject::test(data) {
156 FileFormat::Pdb
157 } else if SourceBundle::test(data) {
158 FileFormat::SourceBundle
159 } else if BreakpadObject::test(data) {
160 FileFormat::Breakpad
161 } else if WasmObject::test(data) {
162 FileFormat::Wasm
163 } else if PortablePdbObject::test(data) {
164 FileFormat::PortablePdb
165 } else {
166 let magic = goblin::mach::parse_magic_and_ctx(data, 0).map(|(magic, _)| magic);
167
168 match magic {
169 Ok(goblin::mach::fat::FAT_MAGIC) => {
170 use scroll::Pread;
171 if data.pread_with::<u32>(4, scroll::BE).is_ok()
172 && archive
173 && MachArchive::test(data)
174 {
175 FileFormat::MachO
176 } else {
177 FileFormat::Unknown
178 }
179 }
180 Ok(
181 goblin::mach::header::MH_CIGAM_64
182 | goblin::mach::header::MH_CIGAM
183 | goblin::mach::header::MH_MAGIC_64
184 | goblin::mach::header::MH_MAGIC,
185 ) => FileFormat::MachO,
186 _ => FileFormat::Unknown,
187 }
188 }
189}
190
191#[allow(clippy::large_enum_variant)]
193#[derive(Debug)]
194pub enum Object<'data> {
195 Breakpad(BreakpadObject<'data>),
197 Elf(ElfObject<'data>),
199 MachO(MachObject<'data>),
201 Pdb(PdbObject<'data>),
203 Pe(PeObject<'data>),
205 SourceBundle(SourceBundle<'data>),
207 Wasm(WasmObject<'data>),
209 PortablePdb(PortablePdbObject<'data>),
211}
212
213impl<'data> Object<'data> {
214 pub fn test(data: &[u8]) -> bool {
216 Self::peek(data) != FileFormat::Unknown
217 }
218
219 pub fn peek(data: &[u8]) -> FileFormat {
221 peek(data, false)
222 }
223
224 pub fn parse(data: &'data [u8]) -> Result<Self, ObjectError> {
226 Self::parse_with_opts(data, Default::default())
227 }
228
229 pub fn parse_with_opts(
231 data: &'data [u8],
232 opts: ParseObjectOptions,
233 ) -> Result<Self, ObjectError> {
234 macro_rules! parse_object {
235 ($kind:ident, $file:ident, $data:expr) => {
236 Object::$kind($file::parse_with_opts(data, opts).map_err(ObjectError::transparent)?)
237 };
238 }
239
240 let object = match Self::peek(data) {
241 FileFormat::Breakpad => parse_object!(Breakpad, BreakpadObject, data),
242 FileFormat::Elf => parse_object!(Elf, ElfObject, data),
243 FileFormat::MachO => parse_object!(MachO, MachObject, data),
244 FileFormat::Pdb => parse_object!(Pdb, PdbObject, data),
245 FileFormat::Pe => parse_object!(Pe, PeObject, data),
246 FileFormat::SourceBundle => parse_object!(SourceBundle, SourceBundle, data),
247 FileFormat::Wasm => parse_object!(Wasm, WasmObject, data),
248 FileFormat::PortablePdb => parse_object!(PortablePdb, PortablePdbObject, data),
249 FileFormat::Unknown => {
250 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
251 }
252 };
253
254 Ok(object)
255 }
256
257 pub fn file_format(&self) -> FileFormat {
259 match *self {
260 Object::Breakpad(_) => FileFormat::Breakpad,
261 Object::Elf(_) => FileFormat::Elf,
262 Object::MachO(_) => FileFormat::MachO,
263 Object::Pdb(_) => FileFormat::Pdb,
264 Object::Pe(_) => FileFormat::Pe,
265 Object::SourceBundle(_) => FileFormat::SourceBundle,
266 Object::Wasm(_) => FileFormat::Wasm,
267 Object::PortablePdb(_) => FileFormat::PortablePdb,
268 }
269 }
270
271 pub fn code_id(&self) -> Option<CodeId> {
277 match_inner!(self, Object(ref o) => o.code_id())
278 }
279
280 pub fn debug_id(&self) -> DebugId {
285 match_inner!(self, Object(ref o) => o.debug_id())
286 }
287
288 pub fn arch(&self) -> Arch {
290 match_inner!(self, Object(ref o) => o.arch())
291 }
292
293 pub fn kind(&self) -> ObjectKind {
295 match_inner!(self, Object(ref o) => o.kind())
296 }
297
298 pub fn load_address(&self) -> u64 {
300 match_inner!(self, Object(ref o) => o.load_address())
301 }
302
303 pub fn has_symbols(&self) -> bool {
305 match_inner!(self, Object(ref o) => o.has_symbols())
306 }
307
308 pub fn symbols(&self) -> SymbolIterator<'data, '_> {
310 map_inner!(self, Object(ref o) => SymbolIterator(o.symbols()))
311 }
312
313 pub fn symbol_map(&self) -> SymbolMap<'data> {
315 match_inner!(self, Object(ref o) => o.symbol_map())
316 }
317
318 pub fn has_debug_info(&self) -> bool {
320 match_inner!(self, Object(ref o) => o.has_debug_info())
321 }
322
323 pub fn debug_session(&self) -> Result<ObjectDebugSession<'data>, ObjectError> {
337 match *self {
338 Object::Breakpad(ref o) => o
339 .debug_session()
340 .map(ObjectDebugSession::Breakpad)
341 .map_err(ObjectError::transparent),
342 Object::Elf(ref o) => o
343 .debug_session()
344 .map(ObjectDebugSession::Dwarf)
345 .map_err(ObjectError::transparent),
346 Object::MachO(ref o) => o
347 .debug_session()
348 .map(ObjectDebugSession::Dwarf)
349 .map_err(ObjectError::transparent),
350 Object::Pdb(ref o) => o
351 .debug_session()
352 .map(ObjectDebugSession::Pdb)
353 .map_err(ObjectError::transparent),
354 Object::Pe(ref o) => o
355 .debug_session()
356 .map(ObjectDebugSession::Dwarf)
357 .map_err(ObjectError::transparent),
358 Object::SourceBundle(ref o) => o
359 .debug_session()
360 .map(ObjectDebugSession::SourceBundle)
361 .map_err(ObjectError::transparent),
362 Object::Wasm(ref o) => o
363 .debug_session()
364 .map(ObjectDebugSession::Dwarf)
365 .map_err(ObjectError::transparent),
366 Object::PortablePdb(ref o) => o
367 .debug_session()
368 .map(ObjectDebugSession::PortablePdb)
369 .map_err(ObjectError::transparent),
370 }
371 }
372
373 pub fn has_unwind_info(&self) -> bool {
375 match_inner!(self, Object(ref o) => o.has_unwind_info())
376 }
377
378 pub fn has_sources(&self) -> bool {
380 match_inner!(self, Object(ref o) => o.has_sources())
381 }
382
383 pub fn is_malformed(&self) -> bool {
385 match_inner!(self, Object(ref o) => o.is_malformed())
386 }
387
388 pub fn data(&self) -> &'data [u8] {
390 match_inner!(self, Object(ref o) => o.data())
391 }
392}
393
394impl<'slf, 'data: 'slf> AsSelf<'slf> for Object<'data> {
395 type Ref = Object<'slf>;
396
397 fn as_self(&'slf self) -> &'slf Self::Ref {
398 unsafe { std::mem::transmute(self) }
399 }
400}
401
402impl<'slf, 'data: 'slf> AsSelf<'slf> for ObjectDebugSession<'data> {
403 type Ref = ObjectDebugSession<'slf>;
404
405 fn as_self(&'slf self) -> &'slf Self::Ref {
406 unsafe { std::mem::transmute(self) }
407 }
408}
409
410impl<'data: 'object, 'object> ObjectLike<'data, 'object> for Object<'data> {
411 type Error = ObjectError;
412 type Session = ObjectDebugSession<'data>;
413 type SymbolIterator = SymbolIterator<'data, 'object>;
414
415 fn file_format(&self) -> FileFormat {
416 self.file_format()
417 }
418
419 fn code_id(&self) -> Option<CodeId> {
420 self.code_id()
421 }
422
423 fn debug_id(&self) -> DebugId {
424 self.debug_id()
425 }
426
427 fn arch(&self) -> Arch {
428 self.arch()
429 }
430
431 fn kind(&self) -> ObjectKind {
432 self.kind()
433 }
434
435 fn load_address(&self) -> u64 {
436 self.load_address()
437 }
438
439 fn has_symbols(&self) -> bool {
440 self.has_symbols()
441 }
442
443 fn symbol_map(&self) -> SymbolMap<'data> {
444 self.symbol_map()
445 }
446
447 fn symbols(&'object self) -> Self::SymbolIterator {
448 self.symbols()
449 }
450
451 fn has_debug_info(&self) -> bool {
452 self.has_debug_info()
453 }
454
455 fn debug_session(&self) -> Result<Self::Session, Self::Error> {
456 self.debug_session()
457 }
458
459 fn has_unwind_info(&self) -> bool {
460 self.has_unwind_info()
461 }
462
463 fn has_sources(&self) -> bool {
464 self.has_sources()
465 }
466
467 fn is_malformed(&self) -> bool {
468 self.is_malformed()
469 }
470}
471
472#[allow(clippy::large_enum_variant)]
474#[allow(missing_docs)]
475pub enum ObjectDebugSession<'d> {
476 Breakpad(BreakpadDebugSession<'d>),
477 Dwarf(DwarfDebugSession<'d>),
478 Pdb(PdbDebugSession<'d>),
479 SourceBundle(SourceBundleDebugSession<'d>),
480 PortablePdb(PortablePdbDebugSession<'d>),
481}
482
483impl ObjectDebugSession<'_> {
484 pub fn functions(&self) -> ObjectFunctionIterator<'_> {
492 match *self {
493 ObjectDebugSession::Breakpad(ref s) => ObjectFunctionIterator::Breakpad(s.functions()),
494 ObjectDebugSession::Dwarf(ref s) => ObjectFunctionIterator::Dwarf(s.functions()),
495 ObjectDebugSession::Pdb(ref s) => ObjectFunctionIterator::Pdb(s.functions()),
496 ObjectDebugSession::SourceBundle(ref s) => {
497 ObjectFunctionIterator::SourceBundle(s.functions())
498 }
499 ObjectDebugSession::PortablePdb(ref s) => {
500 ObjectFunctionIterator::PortablePdb(s.functions())
501 }
502 }
503 }
504
505 pub fn files(&self) -> ObjectFileIterator<'_> {
507 match *self {
508 ObjectDebugSession::Breakpad(ref s) => ObjectFileIterator::Breakpad(s.files()),
509 ObjectDebugSession::Dwarf(ref s) => ObjectFileIterator::Dwarf(s.files()),
510 ObjectDebugSession::Pdb(ref s) => ObjectFileIterator::Pdb(s.files()),
511 ObjectDebugSession::SourceBundle(ref s) => ObjectFileIterator::SourceBundle(s.files()),
512 ObjectDebugSession::PortablePdb(ref s) => ObjectFileIterator::PortablePdb(s.files()),
513 }
514 }
515
516 pub fn source_by_path(
519 &self,
520 path: &str,
521 ) -> Result<Option<SourceFileDescriptor<'_>>, ObjectError> {
522 match *self {
523 ObjectDebugSession::Breakpad(ref s) => {
524 s.source_by_path(path).map_err(ObjectError::transparent)
525 }
526 ObjectDebugSession::Dwarf(ref s) => {
527 s.source_by_path(path).map_err(ObjectError::transparent)
528 }
529 ObjectDebugSession::Pdb(ref s) => {
530 s.source_by_path(path).map_err(ObjectError::transparent)
531 }
532 ObjectDebugSession::SourceBundle(ref s) => {
533 s.source_by_path(path).map_err(ObjectError::transparent)
534 }
535 ObjectDebugSession::PortablePdb(ref s) => {
536 s.source_by_path(path).map_err(ObjectError::transparent)
537 }
538 }
539 }
540}
541
542impl<'session> DebugSession<'session> for ObjectDebugSession<'_> {
543 type Error = ObjectError;
544 type FunctionIterator = ObjectFunctionIterator<'session>;
545 type FileIterator = ObjectFileIterator<'session>;
546
547 fn functions(&'session self) -> Self::FunctionIterator {
548 self.functions()
549 }
550
551 fn files(&'session self) -> Self::FileIterator {
552 self.files()
553 }
554
555 fn source_by_path(&self, path: &str) -> Result<Option<SourceFileDescriptor<'_>>, Self::Error> {
556 self.source_by_path(path)
557 }
558}
559
560#[allow(missing_docs)]
562pub enum ObjectFunctionIterator<'s> {
563 Breakpad(BreakpadFunctionIterator<'s>),
564 Dwarf(DwarfFunctionIterator<'s>),
565 Pdb(PdbFunctionIterator<'s>),
566 SourceBundle(SourceBundleFunctionIterator<'s>),
567 PortablePdb(PortablePdbFunctionIterator<'s>),
568}
569
570impl<'s> Iterator for ObjectFunctionIterator<'s> {
571 type Item = Result<Function<'s>, ObjectError>;
572
573 fn next(&mut self) -> Option<Self::Item> {
574 match *self {
575 ObjectFunctionIterator::Breakpad(ref mut i) => {
576 Some(i.next()?.map_err(ObjectError::transparent))
577 }
578 ObjectFunctionIterator::Dwarf(ref mut i) => {
579 Some(i.next()?.map_err(ObjectError::transparent))
580 }
581 ObjectFunctionIterator::Pdb(ref mut i) => {
582 Some(i.next()?.map_err(ObjectError::transparent))
583 }
584 ObjectFunctionIterator::SourceBundle(ref mut i) => {
585 Some(i.next()?.map_err(ObjectError::transparent))
586 }
587 ObjectFunctionIterator::PortablePdb(ref mut i) => {
588 Some(i.next()?.map_err(ObjectError::transparent))
589 }
590 }
591 }
592}
593
594#[allow(missing_docs)]
596#[allow(clippy::large_enum_variant)]
597pub enum ObjectFileIterator<'s> {
598 Breakpad(BreakpadFileIterator<'s>),
599 Dwarf(DwarfFileIterator<'s>),
600 Pdb(PdbFileIterator<'s>),
601 SourceBundle(SourceBundleFileIterator<'s>),
602 PortablePdb(PortablePdbFileIterator<'s>),
603}
604
605impl<'s> Iterator for ObjectFileIterator<'s> {
606 type Item = Result<FileEntry<'s>, ObjectError>;
607
608 fn next(&mut self) -> Option<Self::Item> {
609 match *self {
610 ObjectFileIterator::Breakpad(ref mut i) => {
611 Some(i.next()?.map_err(ObjectError::transparent))
612 }
613 ObjectFileIterator::Dwarf(ref mut i) => {
614 Some(i.next()?.map_err(ObjectError::transparent))
615 }
616 ObjectFileIterator::Pdb(ref mut i) => Some(i.next()?.map_err(ObjectError::transparent)),
617 ObjectFileIterator::SourceBundle(ref mut i) => {
618 Some(i.next()?.map_err(ObjectError::transparent))
619 }
620 ObjectFileIterator::PortablePdb(ref mut i) => {
621 Some(i.next()?.map_err(ObjectError::transparent))
622 }
623 }
624 }
625}
626
627#[allow(missing_docs)]
629pub enum SymbolIterator<'data, 'object> {
630 Breakpad(BreakpadSymbolIterator<'data>),
631 Elf(ElfSymbolIterator<'data, 'object>),
632 MachO(MachOSymbolIterator<'data>),
633 Pdb(PdbSymbolIterator<'data, 'object>),
634 Pe(PeSymbolIterator<'data, 'object>),
635 SourceBundle(SourceBundleSymbolIterator<'data>),
636 Wasm(WasmSymbolIterator<'data, 'object>),
637 PortablePdb(PortablePdbSymbolIterator<'data>),
638}
639
640impl<'data> Iterator for SymbolIterator<'data, '_> {
641 type Item = Symbol<'data>;
642
643 fn next(&mut self) -> Option<Self::Item> {
644 match_inner!(self, SymbolIterator(ref mut iter) => iter.next())
645 }
646}
647
648impl<'data> crate::base::Parse<'data> for PortablePdb<'data> {
649 type Error = symbolic_ppdb::FormatError;
650
651 fn parse_with_opts(data: &'data [u8], _opts: ParseObjectOptions) -> Result<Self, Self::Error> {
652 Self::parse(data)
653 }
654
655 fn test(data: &'data [u8]) -> bool {
656 Self::peek(data)
657 }
658}
659
660#[derive(Debug)]
661enum ArchiveInner<'d> {
662 Breakpad(MonoArchive<'d, BreakpadObject<'d>>),
663 Elf(MonoArchive<'d, ElfObject<'d>>),
664 MachO(MachArchive<'d>),
665 Pdb(MonoArchive<'d, PdbObject<'d>>),
666 Pe(MonoArchive<'d, PeObject<'d>>),
667 SourceBundle(MonoArchive<'d, SourceBundle<'d>>),
668 Wasm(MonoArchive<'d, WasmObject<'d>>),
669 PortablePdb(MonoArchive<'d, PortablePdbObject<'d>>),
670}
671
672#[derive(Debug)]
678pub struct Archive<'d>(ArchiveInner<'d>);
679
680impl<'d> Archive<'d> {
681 pub fn test(data: &[u8]) -> bool {
683 Self::peek(data) != FileFormat::Unknown
684 }
685
686 pub fn peek(data: &[u8]) -> FileFormat {
688 peek(data, true)
689 }
690
691 pub fn parse(data: &'d [u8]) -> Result<Self, ObjectError> {
693 Self::parse_with_opts(data, Default::default())
694 }
695
696 pub fn parse_with_opts(data: &'d [u8], opts: ParseObjectOptions) -> Result<Self, ObjectError> {
698 let archive = match Self::peek(data) {
699 FileFormat::Breakpad => Archive(ArchiveInner::Breakpad(MonoArchive::new(data, opts))),
700 FileFormat::Elf => Archive(ArchiveInner::Elf(MonoArchive::new(data, opts))),
701 FileFormat::MachO => {
702 let inner = MachArchive::parse_with_opts(data, opts)
703 .map(ArchiveInner::MachO)
704 .map_err(ObjectError::transparent)?;
705 Archive(inner)
706 }
707 FileFormat::Pdb => Archive(ArchiveInner::Pdb(MonoArchive::new(data, opts))),
708 FileFormat::Pe => Archive(ArchiveInner::Pe(MonoArchive::new(data, opts))),
709 FileFormat::SourceBundle => {
710 Archive(ArchiveInner::SourceBundle(MonoArchive::new(data, opts)))
711 }
712 FileFormat::Wasm => Archive(ArchiveInner::Wasm(MonoArchive::new(data, opts))),
713 FileFormat::PortablePdb => {
714 Archive(ArchiveInner::PortablePdb(MonoArchive::new(data, opts)))
715 }
716 FileFormat::Unknown => {
717 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
718 }
719 };
720
721 Ok(archive)
722 }
723
724 pub fn file_format(&self) -> FileFormat {
726 match self.0 {
727 ArchiveInner::Breakpad(_) => FileFormat::Breakpad,
728 ArchiveInner::Elf(_) => FileFormat::Elf,
729 ArchiveInner::MachO(_) => FileFormat::MachO,
730 ArchiveInner::Pdb(_) => FileFormat::Pdb,
731 ArchiveInner::Pe(_) => FileFormat::Pe,
732 ArchiveInner::Wasm(_) => FileFormat::Wasm,
733 ArchiveInner::SourceBundle(_) => FileFormat::SourceBundle,
734 ArchiveInner::PortablePdb(_) => FileFormat::PortablePdb,
735 }
736 }
737
738 pub fn objects(&self) -> ObjectIterator<'d, '_> {
740 ObjectIterator(map_inner!(self.0, ArchiveInner(ref a) =>
741 ObjectIteratorInner(a.objects())))
742 }
743
744 pub fn object_count(&self) -> usize {
746 match_inner!(self.0, ArchiveInner(ref a) => a.object_count())
747 }
748
749 pub fn object_by_index(&self, index: usize) -> Result<Option<Object<'d>>, ObjectError> {
754 match self.0 {
755 ArchiveInner::Breakpad(ref a) => a
756 .object_by_index(index)
757 .map(|opt| opt.map(Object::Breakpad))
758 .map_err(ObjectError::transparent),
759 ArchiveInner::Elf(ref a) => a
760 .object_by_index(index)
761 .map(|opt| opt.map(Object::Elf))
762 .map_err(ObjectError::transparent),
763 ArchiveInner::MachO(ref a) => a
764 .object_by_index(index)
765 .map(|opt| opt.map(Object::MachO))
766 .map_err(ObjectError::transparent),
767 ArchiveInner::Pdb(ref a) => a
768 .object_by_index(index)
769 .map(|opt| opt.map(Object::Pdb))
770 .map_err(ObjectError::transparent),
771 ArchiveInner::Pe(ref a) => a
772 .object_by_index(index)
773 .map(|opt| opt.map(Object::Pe))
774 .map_err(ObjectError::transparent),
775 ArchiveInner::SourceBundle(ref a) => a
776 .object_by_index(index)
777 .map(|opt| opt.map(Object::SourceBundle))
778 .map_err(ObjectError::transparent),
779 ArchiveInner::Wasm(ref a) => a
780 .object_by_index(index)
781 .map(|opt| opt.map(Object::Wasm))
782 .map_err(ObjectError::transparent),
783 ArchiveInner::PortablePdb(ref a) => a
784 .object_by_index(index)
785 .map(|opt| opt.map(Object::PortablePdb))
786 .map_err(ObjectError::transparent),
787 }
788 }
789
790 pub fn is_multi(&self) -> bool {
794 match_inner!(self.0, ArchiveInner(ref a) => a.is_multi())
795 }
796}
797
798impl<'slf, 'd: 'slf> AsSelf<'slf> for Archive<'d> {
799 type Ref = Archive<'slf>;
800
801 fn as_self(&'slf self) -> &'slf Self::Ref {
802 unsafe { std::mem::transmute(self) }
803 }
804}
805
806#[allow(clippy::large_enum_variant)]
807enum ObjectIteratorInner<'d, 'a> {
808 Breakpad(MonoArchiveObjects<'d, BreakpadObject<'d>>),
809 Elf(MonoArchiveObjects<'d, ElfObject<'d>>),
810 MachO(MachObjectIterator<'d, 'a>),
811 Pdb(MonoArchiveObjects<'d, PdbObject<'d>>),
812 Pe(MonoArchiveObjects<'d, PeObject<'d>>),
813 SourceBundle(MonoArchiveObjects<'d, SourceBundle<'d>>),
814 Wasm(MonoArchiveObjects<'d, WasmObject<'d>>),
815 PortablePdb(MonoArchiveObjects<'d, PortablePdbObject<'d>>),
816}
817
818pub struct ObjectIterator<'d, 'a>(ObjectIteratorInner<'d, 'a>);
820
821impl<'d> Iterator for ObjectIterator<'d, '_> {
822 type Item = Result<Object<'d>, ObjectError>;
823
824 fn next(&mut self) -> Option<Self::Item> {
825 Some(map_result!(
826 self.0,
827 ObjectIteratorInner(ref mut iter) => Object(iter.next()?)
828 ))
829 }
830
831 fn size_hint(&self) -> (usize, Option<usize>) {
832 match_inner!(self.0, ObjectIteratorInner(ref iter) => iter.size_hint())
833 }
834}
835
836impl std::iter::FusedIterator for ObjectIterator<'_, '_> {}
837impl ExactSizeIterator for ObjectIterator<'_, '_> {}
838
839