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
127pub fn peek(data: &[u8], archive: bool) -> FileFormat {
132 if data.len() < 16 {
133 return FileFormat::Unknown;
134 }
135
136 if ElfObject::test(data) {
137 FileFormat::Elf
138 } else if PeObject::test(data) {
139 FileFormat::Pe
140 } else if PdbObject::test(data) {
141 FileFormat::Pdb
142 } else if SourceBundle::test(data) {
143 FileFormat::SourceBundle
144 } else if BreakpadObject::test(data) {
145 FileFormat::Breakpad
146 } else if WasmObject::test(data) {
147 FileFormat::Wasm
148 } else if PortablePdbObject::test(data) {
149 FileFormat::PortablePdb
150 } else {
151 let magic = goblin::mach::parse_magic_and_ctx(data, 0).map(|(magic, _)| magic);
152
153 match magic {
154 Ok(goblin::mach::fat::FAT_MAGIC) => {
155 use scroll::Pread;
156 if data.pread_with::<u32>(4, scroll::BE).is_ok()
157 && archive
158 && MachArchive::test(data)
159 {
160 FileFormat::MachO
161 } else {
162 FileFormat::Unknown
163 }
164 }
165 Ok(
166 goblin::mach::header::MH_CIGAM_64
167 | goblin::mach::header::MH_CIGAM
168 | goblin::mach::header::MH_MAGIC_64
169 | goblin::mach::header::MH_MAGIC,
170 ) => FileFormat::MachO,
171 _ => FileFormat::Unknown,
172 }
173 }
174}
175
176#[allow(clippy::large_enum_variant)]
178#[derive(Debug)]
179pub enum Object<'data> {
180 Breakpad(BreakpadObject<'data>),
182 Elf(ElfObject<'data>),
184 MachO(MachObject<'data>),
186 Pdb(PdbObject<'data>),
188 Pe(PeObject<'data>),
190 SourceBundle(SourceBundle<'data>),
192 Wasm(WasmObject<'data>),
194 PortablePdb(PortablePdbObject<'data>),
196}
197
198impl<'data> Object<'data> {
199 pub fn test(data: &[u8]) -> bool {
201 Self::peek(data) != FileFormat::Unknown
202 }
203
204 pub fn peek(data: &[u8]) -> FileFormat {
206 peek(data, false)
207 }
208
209 pub fn parse(data: &'data [u8]) -> Result<Self, ObjectError> {
211 macro_rules! parse_object {
212 ($kind:ident, $file:ident, $data:expr) => {
213 Object::$kind($file::parse(data).map_err(ObjectError::transparent)?)
214 };
215 }
216
217 let object = match Self::peek(data) {
218 FileFormat::Breakpad => parse_object!(Breakpad, BreakpadObject, data),
219 FileFormat::Elf => parse_object!(Elf, ElfObject, data),
220 FileFormat::MachO => parse_object!(MachO, MachObject, data),
221 FileFormat::Pdb => parse_object!(Pdb, PdbObject, data),
222 FileFormat::Pe => parse_object!(Pe, PeObject, data),
223 FileFormat::SourceBundle => parse_object!(SourceBundle, SourceBundle, data),
224 FileFormat::Wasm => parse_object!(Wasm, WasmObject, data),
225 FileFormat::PortablePdb => parse_object!(PortablePdb, PortablePdbObject, data),
226 FileFormat::Unknown => {
227 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
228 }
229 };
230
231 Ok(object)
232 }
233
234 pub fn file_format(&self) -> FileFormat {
236 match *self {
237 Object::Breakpad(_) => FileFormat::Breakpad,
238 Object::Elf(_) => FileFormat::Elf,
239 Object::MachO(_) => FileFormat::MachO,
240 Object::Pdb(_) => FileFormat::Pdb,
241 Object::Pe(_) => FileFormat::Pe,
242 Object::SourceBundle(_) => FileFormat::SourceBundle,
243 Object::Wasm(_) => FileFormat::Wasm,
244 Object::PortablePdb(_) => FileFormat::PortablePdb,
245 }
246 }
247
248 pub fn code_id(&self) -> Option<CodeId> {
254 match_inner!(self, Object(ref o) => o.code_id())
255 }
256
257 pub fn debug_id(&self) -> DebugId {
262 match_inner!(self, Object(ref o) => o.debug_id())
263 }
264
265 pub fn arch(&self) -> Arch {
267 match_inner!(self, Object(ref o) => o.arch())
268 }
269
270 pub fn kind(&self) -> ObjectKind {
272 match_inner!(self, Object(ref o) => o.kind())
273 }
274
275 pub fn load_address(&self) -> u64 {
277 match_inner!(self, Object(ref o) => o.load_address())
278 }
279
280 pub fn has_symbols(&self) -> bool {
282 match_inner!(self, Object(ref o) => o.has_symbols())
283 }
284
285 pub fn symbols(&self) -> SymbolIterator<'data, '_> {
287 map_inner!(self, Object(ref o) => SymbolIterator(o.symbols()))
288 }
289
290 pub fn symbol_map(&self) -> SymbolMap<'data> {
292 match_inner!(self, Object(ref o) => o.symbol_map())
293 }
294
295 pub fn has_debug_info(&self) -> bool {
297 match_inner!(self, Object(ref o) => o.has_debug_info())
298 }
299
300 pub fn debug_session(&self) -> Result<ObjectDebugSession<'data>, ObjectError> {
314 match *self {
315 Object::Breakpad(ref o) => o
316 .debug_session()
317 .map(ObjectDebugSession::Breakpad)
318 .map_err(ObjectError::transparent),
319 Object::Elf(ref o) => o
320 .debug_session()
321 .map(ObjectDebugSession::Dwarf)
322 .map_err(ObjectError::transparent),
323 Object::MachO(ref o) => o
324 .debug_session()
325 .map(ObjectDebugSession::Dwarf)
326 .map_err(ObjectError::transparent),
327 Object::Pdb(ref o) => o
328 .debug_session()
329 .map(ObjectDebugSession::Pdb)
330 .map_err(ObjectError::transparent),
331 Object::Pe(ref o) => o
332 .debug_session()
333 .map(ObjectDebugSession::Dwarf)
334 .map_err(ObjectError::transparent),
335 Object::SourceBundle(ref o) => o
336 .debug_session()
337 .map(ObjectDebugSession::SourceBundle)
338 .map_err(ObjectError::transparent),
339 Object::Wasm(ref o) => o
340 .debug_session()
341 .map(ObjectDebugSession::Dwarf)
342 .map_err(ObjectError::transparent),
343 Object::PortablePdb(ref o) => o
344 .debug_session()
345 .map(ObjectDebugSession::PortablePdb)
346 .map_err(ObjectError::transparent),
347 }
348 }
349
350 pub fn has_unwind_info(&self) -> bool {
352 match_inner!(self, Object(ref o) => o.has_unwind_info())
353 }
354
355 pub fn has_sources(&self) -> bool {
357 match_inner!(self, Object(ref o) => o.has_sources())
358 }
359
360 pub fn is_malformed(&self) -> bool {
362 match_inner!(self, Object(ref o) => o.is_malformed())
363 }
364
365 pub fn data(&self) -> &'data [u8] {
367 match_inner!(self, Object(ref o) => o.data())
368 }
369}
370
371impl<'slf, 'data: 'slf> AsSelf<'slf> for Object<'data> {
372 type Ref = Object<'slf>;
373
374 fn as_self(&'slf self) -> &'slf Self::Ref {
375 unsafe { std::mem::transmute(self) }
376 }
377}
378
379impl<'data: 'object, 'object> ObjectLike<'data, 'object> for Object<'data> {
380 type Error = ObjectError;
381 type Session = ObjectDebugSession<'data>;
382 type SymbolIterator = SymbolIterator<'data, 'object>;
383
384 fn file_format(&self) -> FileFormat {
385 self.file_format()
386 }
387
388 fn code_id(&self) -> Option<CodeId> {
389 self.code_id()
390 }
391
392 fn debug_id(&self) -> DebugId {
393 self.debug_id()
394 }
395
396 fn arch(&self) -> Arch {
397 self.arch()
398 }
399
400 fn kind(&self) -> ObjectKind {
401 self.kind()
402 }
403
404 fn load_address(&self) -> u64 {
405 self.load_address()
406 }
407
408 fn has_symbols(&self) -> bool {
409 self.has_symbols()
410 }
411
412 fn symbol_map(&self) -> SymbolMap<'data> {
413 self.symbol_map()
414 }
415
416 fn symbols(&'object self) -> Self::SymbolIterator {
417 self.symbols()
418 }
419
420 fn has_debug_info(&self) -> bool {
421 self.has_debug_info()
422 }
423
424 fn debug_session(&self) -> Result<Self::Session, Self::Error> {
425 self.debug_session()
426 }
427
428 fn has_unwind_info(&self) -> bool {
429 self.has_unwind_info()
430 }
431
432 fn has_sources(&self) -> bool {
433 self.has_sources()
434 }
435
436 fn is_malformed(&self) -> bool {
437 self.is_malformed()
438 }
439}
440
441#[allow(clippy::large_enum_variant)]
443#[allow(missing_docs)]
444pub enum ObjectDebugSession<'d> {
445 Breakpad(BreakpadDebugSession<'d>),
446 Dwarf(DwarfDebugSession<'d>),
447 Pdb(PdbDebugSession<'d>),
448 SourceBundle(SourceBundleDebugSession<'d>),
449 PortablePdb(PortablePdbDebugSession<'d>),
450}
451
452impl ObjectDebugSession<'_> {
453 pub fn functions(&self) -> ObjectFunctionIterator<'_> {
461 match *self {
462 ObjectDebugSession::Breakpad(ref s) => ObjectFunctionIterator::Breakpad(s.functions()),
463 ObjectDebugSession::Dwarf(ref s) => ObjectFunctionIterator::Dwarf(s.functions()),
464 ObjectDebugSession::Pdb(ref s) => ObjectFunctionIterator::Pdb(s.functions()),
465 ObjectDebugSession::SourceBundle(ref s) => {
466 ObjectFunctionIterator::SourceBundle(s.functions())
467 }
468 ObjectDebugSession::PortablePdb(ref s) => {
469 ObjectFunctionIterator::PortablePdb(s.functions())
470 }
471 }
472 }
473
474 pub fn files(&self) -> ObjectFileIterator<'_> {
476 match *self {
477 ObjectDebugSession::Breakpad(ref s) => ObjectFileIterator::Breakpad(s.files()),
478 ObjectDebugSession::Dwarf(ref s) => ObjectFileIterator::Dwarf(s.files()),
479 ObjectDebugSession::Pdb(ref s) => ObjectFileIterator::Pdb(s.files()),
480 ObjectDebugSession::SourceBundle(ref s) => ObjectFileIterator::SourceBundle(s.files()),
481 ObjectDebugSession::PortablePdb(ref s) => ObjectFileIterator::PortablePdb(s.files()),
482 }
483 }
484
485 pub fn source_by_path(
488 &self,
489 path: &str,
490 ) -> Result<Option<SourceFileDescriptor<'_>>, ObjectError> {
491 match *self {
492 ObjectDebugSession::Breakpad(ref s) => {
493 s.source_by_path(path).map_err(ObjectError::transparent)
494 }
495 ObjectDebugSession::Dwarf(ref s) => {
496 s.source_by_path(path).map_err(ObjectError::transparent)
497 }
498 ObjectDebugSession::Pdb(ref s) => {
499 s.source_by_path(path).map_err(ObjectError::transparent)
500 }
501 ObjectDebugSession::SourceBundle(ref s) => {
502 s.source_by_path(path).map_err(ObjectError::transparent)
503 }
504 ObjectDebugSession::PortablePdb(ref s) => {
505 s.source_by_path(path).map_err(ObjectError::transparent)
506 }
507 }
508 }
509}
510
511impl<'session> DebugSession<'session> for ObjectDebugSession<'_> {
512 type Error = ObjectError;
513 type FunctionIterator = ObjectFunctionIterator<'session>;
514 type FileIterator = ObjectFileIterator<'session>;
515
516 fn functions(&'session self) -> Self::FunctionIterator {
517 self.functions()
518 }
519
520 fn files(&'session self) -> Self::FileIterator {
521 self.files()
522 }
523
524 fn source_by_path(&self, path: &str) -> Result<Option<SourceFileDescriptor<'_>>, Self::Error> {
525 self.source_by_path(path)
526 }
527}
528
529#[allow(missing_docs)]
531pub enum ObjectFunctionIterator<'s> {
532 Breakpad(BreakpadFunctionIterator<'s>),
533 Dwarf(DwarfFunctionIterator<'s>),
534 Pdb(PdbFunctionIterator<'s>),
535 SourceBundle(SourceBundleFunctionIterator<'s>),
536 PortablePdb(PortablePdbFunctionIterator<'s>),
537}
538
539impl<'s> Iterator for ObjectFunctionIterator<'s> {
540 type Item = Result<Function<'s>, ObjectError>;
541
542 fn next(&mut self) -> Option<Self::Item> {
543 match *self {
544 ObjectFunctionIterator::Breakpad(ref mut i) => {
545 Some(i.next()?.map_err(ObjectError::transparent))
546 }
547 ObjectFunctionIterator::Dwarf(ref mut i) => {
548 Some(i.next()?.map_err(ObjectError::transparent))
549 }
550 ObjectFunctionIterator::Pdb(ref mut i) => {
551 Some(i.next()?.map_err(ObjectError::transparent))
552 }
553 ObjectFunctionIterator::SourceBundle(ref mut i) => {
554 Some(i.next()?.map_err(ObjectError::transparent))
555 }
556 ObjectFunctionIterator::PortablePdb(ref mut i) => {
557 Some(i.next()?.map_err(ObjectError::transparent))
558 }
559 }
560 }
561}
562
563#[allow(missing_docs)]
565#[allow(clippy::large_enum_variant)]
566pub enum ObjectFileIterator<'s> {
567 Breakpad(BreakpadFileIterator<'s>),
568 Dwarf(DwarfFileIterator<'s>),
569 Pdb(PdbFileIterator<'s>),
570 SourceBundle(SourceBundleFileIterator<'s>),
571 PortablePdb(PortablePdbFileIterator<'s>),
572}
573
574impl<'s> Iterator for ObjectFileIterator<'s> {
575 type Item = Result<FileEntry<'s>, ObjectError>;
576
577 fn next(&mut self) -> Option<Self::Item> {
578 match *self {
579 ObjectFileIterator::Breakpad(ref mut i) => {
580 Some(i.next()?.map_err(ObjectError::transparent))
581 }
582 ObjectFileIterator::Dwarf(ref mut i) => {
583 Some(i.next()?.map_err(ObjectError::transparent))
584 }
585 ObjectFileIterator::Pdb(ref mut i) => Some(i.next()?.map_err(ObjectError::transparent)),
586 ObjectFileIterator::SourceBundle(ref mut i) => {
587 Some(i.next()?.map_err(ObjectError::transparent))
588 }
589 ObjectFileIterator::PortablePdb(ref mut i) => {
590 Some(i.next()?.map_err(ObjectError::transparent))
591 }
592 }
593 }
594}
595
596#[allow(missing_docs)]
598pub enum SymbolIterator<'data, 'object> {
599 Breakpad(BreakpadSymbolIterator<'data>),
600 Elf(ElfSymbolIterator<'data, 'object>),
601 MachO(MachOSymbolIterator<'data>),
602 Pdb(PdbSymbolIterator<'data, 'object>),
603 Pe(PeSymbolIterator<'data, 'object>),
604 SourceBundle(SourceBundleSymbolIterator<'data>),
605 Wasm(WasmSymbolIterator<'data, 'object>),
606 PortablePdb(PortablePdbSymbolIterator<'data>),
607}
608
609impl<'data> Iterator for SymbolIterator<'data, '_> {
610 type Item = Symbol<'data>;
611
612 fn next(&mut self) -> Option<Self::Item> {
613 match_inner!(self, SymbolIterator(ref mut iter) => iter.next())
614 }
615}
616
617impl<'data> crate::base::Parse<'data> for PortablePdb<'data> {
618 type Error = symbolic_ppdb::FormatError;
619
620 fn parse(data: &'data [u8]) -> Result<Self, Self::Error> {
621 Self::parse(data)
622 }
623
624 fn test(data: &'data [u8]) -> bool {
625 Self::peek(data)
626 }
627}
628
629#[derive(Debug)]
630enum ArchiveInner<'d> {
631 Breakpad(MonoArchive<'d, BreakpadObject<'d>>),
632 Elf(MonoArchive<'d, ElfObject<'d>>),
633 MachO(MachArchive<'d>),
634 Pdb(MonoArchive<'d, PdbObject<'d>>),
635 Pe(MonoArchive<'d, PeObject<'d>>),
636 SourceBundle(MonoArchive<'d, SourceBundle<'d>>),
637 Wasm(MonoArchive<'d, WasmObject<'d>>),
638 PortablePdb(MonoArchive<'d, PortablePdbObject<'d>>),
639}
640
641#[derive(Debug)]
647pub struct Archive<'d>(ArchiveInner<'d>);
648
649impl<'d> Archive<'d> {
650 pub fn test(data: &[u8]) -> bool {
652 Self::peek(data) != FileFormat::Unknown
653 }
654
655 pub fn peek(data: &[u8]) -> FileFormat {
657 peek(data, true)
658 }
659
660 pub fn parse(data: &'d [u8]) -> Result<Self, ObjectError> {
662 let archive = match Self::peek(data) {
663 FileFormat::Breakpad => Archive(ArchiveInner::Breakpad(MonoArchive::new(data))),
664 FileFormat::Elf => Archive(ArchiveInner::Elf(MonoArchive::new(data))),
665 FileFormat::MachO => {
666 let inner = MachArchive::parse(data)
667 .map(ArchiveInner::MachO)
668 .map_err(ObjectError::transparent)?;
669 Archive(inner)
670 }
671 FileFormat::Pdb => Archive(ArchiveInner::Pdb(MonoArchive::new(data))),
672 FileFormat::Pe => Archive(ArchiveInner::Pe(MonoArchive::new(data))),
673 FileFormat::SourceBundle => Archive(ArchiveInner::SourceBundle(MonoArchive::new(data))),
674 FileFormat::Wasm => Archive(ArchiveInner::Wasm(MonoArchive::new(data))),
675 FileFormat::PortablePdb => Archive(ArchiveInner::PortablePdb(MonoArchive::new(data))),
676 FileFormat::Unknown => {
677 return Err(ObjectError::new(ObjectErrorRepr::UnsupportedObject))
678 }
679 };
680
681 Ok(archive)
682 }
683
684 pub fn file_format(&self) -> FileFormat {
686 match self.0 {
687 ArchiveInner::Breakpad(_) => FileFormat::Breakpad,
688 ArchiveInner::Elf(_) => FileFormat::Elf,
689 ArchiveInner::MachO(_) => FileFormat::MachO,
690 ArchiveInner::Pdb(_) => FileFormat::Pdb,
691 ArchiveInner::Pe(_) => FileFormat::Pe,
692 ArchiveInner::Wasm(_) => FileFormat::Wasm,
693 ArchiveInner::SourceBundle(_) => FileFormat::SourceBundle,
694 ArchiveInner::PortablePdb(_) => FileFormat::PortablePdb,
695 }
696 }
697
698 pub fn objects(&self) -> ObjectIterator<'d, '_> {
700 ObjectIterator(map_inner!(self.0, ArchiveInner(ref a) =>
701 ObjectIteratorInner(a.objects())))
702 }
703
704 pub fn object_count(&self) -> usize {
706 match_inner!(self.0, ArchiveInner(ref a) => a.object_count())
707 }
708
709 pub fn object_by_index(&self, index: usize) -> Result<Option<Object<'d>>, ObjectError> {
714 match self.0 {
715 ArchiveInner::Breakpad(ref a) => a
716 .object_by_index(index)
717 .map(|opt| opt.map(Object::Breakpad))
718 .map_err(ObjectError::transparent),
719 ArchiveInner::Elf(ref a) => a
720 .object_by_index(index)
721 .map(|opt| opt.map(Object::Elf))
722 .map_err(ObjectError::transparent),
723 ArchiveInner::MachO(ref a) => a
724 .object_by_index(index)
725 .map(|opt| opt.map(Object::MachO))
726 .map_err(ObjectError::transparent),
727 ArchiveInner::Pdb(ref a) => a
728 .object_by_index(index)
729 .map(|opt| opt.map(Object::Pdb))
730 .map_err(ObjectError::transparent),
731 ArchiveInner::Pe(ref a) => a
732 .object_by_index(index)
733 .map(|opt| opt.map(Object::Pe))
734 .map_err(ObjectError::transparent),
735 ArchiveInner::SourceBundle(ref a) => a
736 .object_by_index(index)
737 .map(|opt| opt.map(Object::SourceBundle))
738 .map_err(ObjectError::transparent),
739 ArchiveInner::Wasm(ref a) => a
740 .object_by_index(index)
741 .map(|opt| opt.map(Object::Wasm))
742 .map_err(ObjectError::transparent),
743 ArchiveInner::PortablePdb(ref a) => a
744 .object_by_index(index)
745 .map(|opt| opt.map(Object::PortablePdb))
746 .map_err(ObjectError::transparent),
747 }
748 }
749
750 pub fn is_multi(&self) -> bool {
754 match_inner!(self.0, ArchiveInner(ref a) => a.is_multi())
755 }
756}
757
758impl<'slf, 'd: 'slf> AsSelf<'slf> for Archive<'d> {
759 type Ref = Archive<'slf>;
760
761 fn as_self(&'slf self) -> &'slf Self::Ref {
762 unsafe { std::mem::transmute(self) }
763 }
764}
765
766#[allow(clippy::large_enum_variant)]
767enum ObjectIteratorInner<'d, 'a> {
768 Breakpad(MonoArchiveObjects<'d, BreakpadObject<'d>>),
769 Elf(MonoArchiveObjects<'d, ElfObject<'d>>),
770 MachO(MachObjectIterator<'d, 'a>),
771 Pdb(MonoArchiveObjects<'d, PdbObject<'d>>),
772 Pe(MonoArchiveObjects<'d, PeObject<'d>>),
773 SourceBundle(MonoArchiveObjects<'d, SourceBundle<'d>>),
774 Wasm(MonoArchiveObjects<'d, WasmObject<'d>>),
775 PortablePdb(MonoArchiveObjects<'d, PortablePdbObject<'d>>),
776}
777
778pub struct ObjectIterator<'d, 'a>(ObjectIteratorInner<'d, 'a>);
780
781impl<'d> Iterator for ObjectIterator<'d, '_> {
782 type Item = Result<Object<'d>, ObjectError>;
783
784 fn next(&mut self) -> Option<Self::Item> {
785 Some(map_result!(
786 self.0,
787 ObjectIteratorInner(ref mut iter) => Object(iter.next()?)
788 ))
789 }
790
791 fn size_hint(&self) -> (usize, Option<usize>) {
792 match_inner!(self.0, ObjectIteratorInner(ref iter) => iter.size_hint())
793 }
794}
795
796impl std::iter::FusedIterator for ObjectIterator<'_, '_> {}
797impl ExactSizeIterator for ObjectIterator<'_, '_> {}
798
799