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