1use core::fmt::Debug;
2use core::mem;
3
4use alloc::vec::Vec;
5
6use crate::endian::BigEndian as BE;
7use crate::pod::Pod;
8use crate::read::{
9 self, Architecture, Error, Export, FileFlags, Import, NoDynamicRelocationIterator, Object,
10 ObjectKind, ObjectSection, ReadError, ReadRef, Result, SectionIndex, SymbolIndex,
11};
12use crate::{xcoff, SkipDebugList};
13
14use super::{
15 CsectAux, FileAux, Rel, SectionHeader, SectionTable, Symbol, SymbolTable, XcoffComdat,
16 XcoffComdatIterator, XcoffSection, XcoffSectionIterator, XcoffSegment, XcoffSegmentIterator,
17 XcoffSymbol, XcoffSymbolIterator, XcoffSymbolTable,
18};
19
20pub type XcoffFile32<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader32, R>;
25
26pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>;
31
32#[cfg(target_pointer_width = "32")]
34pub type NativeXcoffFile<'data, R = &'data [u8]> = XcoffFile32<'data, R>;
35
36#[cfg(target_pointer_width = "64")]
38pub type NativeXcoffFile<'data, R = &'data [u8]> = XcoffFile64<'data, R>;
39
40#[derive(Debug)]
44pub struct XcoffFile<'data, Xcoff, R = &'data [u8]>
45where
46 Xcoff: FileHeader,
47 R: ReadRef<'data>,
48{
49 pub(super) data: SkipDebugList<R>,
50 pub(super) header: &'data Xcoff,
51 pub(super) aux_header: Option<&'data Xcoff::AuxHeader>,
52 pub(super) sections: SectionTable<'data, Xcoff>,
53 pub(super) symbols: SymbolTable<'data, Xcoff, R>,
54}
55
56impl<'data, Xcoff, R> XcoffFile<'data, Xcoff, R>
57where
58 Xcoff: FileHeader,
59 R: ReadRef<'data>,
60{
61 pub fn parse(data: R) -> Result<Self> {
63 let mut offset = 0;
64 let header = Xcoff::parse(data, &mut offset)?;
65 let aux_header = header.aux_header(data, &mut offset)?;
66 let sections = header.sections(data, &mut offset)?;
67 let symbols = header.symbols(data)?;
68
69 Ok(XcoffFile {
70 data: SkipDebugList(data),
71 header,
72 aux_header,
73 sections,
74 symbols,
75 })
76 }
77
78 pub fn data(&self) -> R {
80 self.data.0
81 }
82
83 #[deprecated(note = "Use `xcoff_header` instead")]
85 pub fn raw_header(&self) -> &'data Xcoff {
86 self.header
87 }
88
89 pub fn xcoff_header(&self) -> &'data Xcoff {
91 self.header
92 }
93
94 pub fn xcoff_aux_header(&self) -> Option<&'data Xcoff::AuxHeader> {
96 self.aux_header
97 }
98
99 pub fn xcoff_section_table(&self) -> &SectionTable<'data, Xcoff> {
101 &self.sections
102 }
103
104 pub fn xcoff_symbol_table(&self) -> &SymbolTable<'data, Xcoff, R> {
106 &self.symbols
107 }
108}
109
110impl<'data, Xcoff, R> read::private::Sealed for XcoffFile<'data, Xcoff, R>
111where
112 Xcoff: FileHeader,
113 R: ReadRef<'data>,
114{
115}
116
117impl<'data, Xcoff, R> Object<'data> for XcoffFile<'data, Xcoff, R>
118where
119 Xcoff: FileHeader,
120 R: ReadRef<'data>,
121{
122 type Segment<'file>
123 = XcoffSegment<'data, 'file, Xcoff, R>
124 where
125 Self: 'file,
126 'data: 'file;
127 type SegmentIterator<'file>
128 = XcoffSegmentIterator<'data, 'file, Xcoff, R>
129 where
130 Self: 'file,
131 'data: 'file;
132 type Section<'file>
133 = XcoffSection<'data, 'file, Xcoff, R>
134 where
135 Self: 'file,
136 'data: 'file;
137 type SectionIterator<'file>
138 = XcoffSectionIterator<'data, 'file, Xcoff, R>
139 where
140 Self: 'file,
141 'data: 'file;
142 type Comdat<'file>
143 = XcoffComdat<'data, 'file, Xcoff, R>
144 where
145 Self: 'file,
146 'data: 'file;
147 type ComdatIterator<'file>
148 = XcoffComdatIterator<'data, 'file, Xcoff, R>
149 where
150 Self: 'file,
151 'data: 'file;
152 type Symbol<'file>
153 = XcoffSymbol<'data, 'file, Xcoff, R>
154 where
155 Self: 'file,
156 'data: 'file;
157 type SymbolIterator<'file>
158 = XcoffSymbolIterator<'data, 'file, Xcoff, R>
159 where
160 Self: 'file,
161 'data: 'file;
162 type SymbolTable<'file>
163 = XcoffSymbolTable<'data, 'file, Xcoff, R>
164 where
165 Self: 'file,
166 'data: 'file;
167 type DynamicRelocationIterator<'file>
168 = NoDynamicRelocationIterator
169 where
170 Self: 'file,
171 'data: 'file;
172
173 fn architecture(&self) -> Architecture {
174 if self.is_64() {
175 Architecture::PowerPc64
176 } else {
177 Architecture::PowerPc
178 }
179 }
180
181 fn is_little_endian(&self) -> bool {
182 false
183 }
184
185 fn is_64(&self) -> bool {
186 self.header.is_type_64()
187 }
188
189 fn kind(&self) -> ObjectKind {
190 let flags = self.header.f_flags();
191 if flags & xcoff::F_EXEC != 0 {
192 ObjectKind::Executable
193 } else if flags & xcoff::F_SHROBJ != 0 {
194 ObjectKind::Dynamic
195 } else if flags & xcoff::F_RELFLG == 0 {
196 ObjectKind::Relocatable
197 } else {
198 ObjectKind::Unknown
199 }
200 }
201
202 fn segments(&self) -> XcoffSegmentIterator<'data, '_, Xcoff, R> {
203 XcoffSegmentIterator { file: self }
204 }
205
206 fn section_by_name_bytes<'file>(
207 &'file self,
208 section_name: &[u8],
209 ) -> Option<XcoffSection<'data, 'file, Xcoff, R>> {
210 self.sections()
211 .find(|section| section.name_bytes() == Ok(section_name))
212 }
213
214 fn section_by_index(&self, index: SectionIndex) -> Result<XcoffSection<'data, '_, Xcoff, R>> {
215 let section = self.sections.section(index)?;
216 Ok(XcoffSection {
217 file: self,
218 section,
219 index,
220 })
221 }
222
223 fn sections(&self) -> XcoffSectionIterator<'data, '_, Xcoff, R> {
224 XcoffSectionIterator {
225 file: self,
226 iter: self.sections.iter().enumerate(),
227 }
228 }
229
230 fn comdats(&self) -> XcoffComdatIterator<'data, '_, Xcoff, R> {
231 XcoffComdatIterator { file: self }
232 }
233
234 fn symbol_table(&self) -> Option<XcoffSymbolTable<'data, '_, Xcoff, R>> {
235 if self.symbols.is_empty() {
236 return None;
237 }
238 Some(XcoffSymbolTable {
239 symbols: &self.symbols,
240 file: self,
241 })
242 }
243
244 fn symbol_by_index(&self, index: SymbolIndex) -> Result<XcoffSymbol<'data, '_, Xcoff, R>> {
245 let symbol = self.symbols.symbol(index)?;
246 Ok(XcoffSymbol {
247 symbols: &self.symbols,
248 index,
249 symbol,
250 file: self,
251 })
252 }
253
254 fn symbols(&self) -> XcoffSymbolIterator<'data, '_, Xcoff, R> {
255 XcoffSymbolIterator {
256 file: self,
257 symbols: self.symbols.iter(),
258 }
259 }
260
261 fn dynamic_symbol_table<'file>(
262 &'file self,
263 ) -> Option<XcoffSymbolTable<'data, 'file, Xcoff, R>> {
264 None
265 }
266
267 fn dynamic_symbols(&self) -> XcoffSymbolIterator<'data, '_, Xcoff, R> {
268 XcoffSymbolIterator {
270 file: self,
271 symbols: self.symbols.iter_none(),
272 }
273 }
274
275 fn dynamic_relocations(&self) -> Option<Self::DynamicRelocationIterator<'_>> {
276 None
278 }
279
280 fn imports(&self) -> Result<alloc::vec::Vec<Import<'data>>> {
281 Ok(Vec::new())
283 }
284
285 fn exports(&self) -> Result<alloc::vec::Vec<Export<'data>>> {
286 Ok(Vec::new())
288 }
289
290 fn has_debug_symbols(&self) -> bool {
291 self.section_by_name(".debug").is_some() || self.section_by_name(".dwinfo").is_some()
292 }
293
294 fn relative_address_base(&self) -> u64 {
295 0
296 }
297
298 fn entry(&self) -> u64 {
299 if let Some(aux_header) = self.aux_header {
300 aux_header.o_entry().into()
301 } else {
302 0
303 }
304 }
305
306 fn flags(&self) -> FileFlags {
307 FileFlags::Xcoff {
308 f_flags: self.header.f_flags(),
309 }
310 }
311}
312
313#[allow(missing_docs)]
315pub trait FileHeader: Debug + Pod {
316 type Word: Into<u64>;
317 type AuxHeader: AuxHeader<Word = Self::Word>;
318 type SectionHeader: SectionHeader<Word = Self::Word, Rel = Self::Rel>;
319 type Symbol: Symbol<Word = Self::Word>;
320 type FileAux: FileAux;
321 type CsectAux: CsectAux;
322 type Rel: Rel<Word = Self::Word>;
323
324 fn is_type_64(&self) -> bool;
326
327 fn f_magic(&self) -> u16;
328 fn f_nscns(&self) -> u16;
329 fn f_timdat(&self) -> u32;
330 fn f_symptr(&self) -> Self::Word;
331 fn f_nsyms(&self) -> u32;
332 fn f_opthdr(&self) -> u16;
333 fn f_flags(&self) -> u16;
334
335 fn parse<'data, R: ReadRef<'data>>(data: R, offset: &mut u64) -> Result<&'data Self> {
341 let header = data
342 .read::<Self>(offset)
343 .read_error("Invalid XCOFF header size or alignment")?;
344 if !header.is_supported() {
345 return Err(Error("Unsupported XCOFF header"));
346 }
347 Ok(header)
348 }
349
350 fn is_supported(&self) -> bool {
351 (self.is_type_64() && self.f_magic() == xcoff::MAGIC_64)
352 || (!self.is_type_64() && self.f_magic() == xcoff::MAGIC_32)
353 }
354
355 fn aux_header<'data, R: ReadRef<'data>>(
357 &self,
358 data: R,
359 offset: &mut u64,
360 ) -> Result<Option<&'data Self::AuxHeader>> {
361 let aux_header_size = self.f_opthdr();
362 if self.f_flags() & xcoff::F_EXEC == 0 {
363 *offset += u64::from(aux_header_size);
367 return Ok(None);
368 }
369 if aux_header_size != mem::size_of::<Self::AuxHeader>() as u16 {
372 *offset += u64::from(aux_header_size);
373 return Ok(None);
374 }
375 let aux_header = data
376 .read::<Self::AuxHeader>(offset)
377 .read_error("Invalid XCOFF auxiliary header size")?;
378 Ok(Some(aux_header))
379 }
380
381 #[inline]
383 fn sections<'data, R: ReadRef<'data>>(
384 &self,
385 data: R,
386 offset: &mut u64,
387 ) -> Result<SectionTable<'data, Self>> {
388 SectionTable::parse(self, data, offset)
389 }
390
391 #[inline]
393 fn symbols<'data, R: ReadRef<'data>>(&self, data: R) -> Result<SymbolTable<'data, Self, R>> {
394 SymbolTable::parse(*self, data)
395 }
396}
397
398impl FileHeader for xcoff::FileHeader32 {
399 type Word = u32;
400 type AuxHeader = xcoff::AuxHeader32;
401 type SectionHeader = xcoff::SectionHeader32;
402 type Symbol = xcoff::Symbol32;
403 type FileAux = xcoff::FileAux32;
404 type CsectAux = xcoff::CsectAux32;
405 type Rel = xcoff::Rel32;
406
407 fn is_type_64(&self) -> bool {
408 false
409 }
410
411 fn f_magic(&self) -> u16 {
412 self.f_magic.get(BE)
413 }
414
415 fn f_nscns(&self) -> u16 {
416 self.f_nscns.get(BE)
417 }
418
419 fn f_timdat(&self) -> u32 {
420 self.f_timdat.get(BE)
421 }
422
423 fn f_symptr(&self) -> Self::Word {
424 self.f_symptr.get(BE)
425 }
426
427 fn f_nsyms(&self) -> u32 {
428 self.f_nsyms.get(BE)
429 }
430
431 fn f_opthdr(&self) -> u16 {
432 self.f_opthdr.get(BE)
433 }
434
435 fn f_flags(&self) -> u16 {
436 self.f_flags.get(BE)
437 }
438}
439
440impl FileHeader for xcoff::FileHeader64 {
441 type Word = u64;
442 type AuxHeader = xcoff::AuxHeader64;
443 type SectionHeader = xcoff::SectionHeader64;
444 type Symbol = xcoff::Symbol64;
445 type FileAux = xcoff::FileAux64;
446 type CsectAux = xcoff::CsectAux64;
447 type Rel = xcoff::Rel64;
448
449 fn is_type_64(&self) -> bool {
450 true
451 }
452
453 fn f_magic(&self) -> u16 {
454 self.f_magic.get(BE)
455 }
456
457 fn f_nscns(&self) -> u16 {
458 self.f_nscns.get(BE)
459 }
460
461 fn f_timdat(&self) -> u32 {
462 self.f_timdat.get(BE)
463 }
464
465 fn f_symptr(&self) -> Self::Word {
466 self.f_symptr.get(BE)
467 }
468
469 fn f_nsyms(&self) -> u32 {
470 self.f_nsyms.get(BE)
471 }
472
473 fn f_opthdr(&self) -> u16 {
474 self.f_opthdr.get(BE)
475 }
476
477 fn f_flags(&self) -> u16 {
478 self.f_flags.get(BE)
479 }
480}
481
482#[allow(missing_docs)]
484pub trait AuxHeader: Debug + Pod {
485 type Word: Into<u64>;
486
487 fn o_mflag(&self) -> u16;
488 fn o_vstamp(&self) -> u16;
489 fn o_tsize(&self) -> Self::Word;
490 fn o_dsize(&self) -> Self::Word;
491 fn o_bsize(&self) -> Self::Word;
492 fn o_entry(&self) -> Self::Word;
493 fn o_text_start(&self) -> Self::Word;
494 fn o_data_start(&self) -> Self::Word;
495 fn o_toc(&self) -> Self::Word;
496 fn o_snentry(&self) -> u16;
497 fn o_sntext(&self) -> u16;
498 fn o_sndata(&self) -> u16;
499 fn o_sntoc(&self) -> u16;
500 fn o_snloader(&self) -> u16;
501 fn o_snbss(&self) -> u16;
502 fn o_algntext(&self) -> u16;
503 fn o_algndata(&self) -> u16;
504 fn o_modtype(&self) -> u16;
505 fn o_cpuflag(&self) -> u8;
506 fn o_cputype(&self) -> u8;
507 fn o_maxstack(&self) -> Self::Word;
508 fn o_maxdata(&self) -> Self::Word;
509 fn o_debugger(&self) -> u32;
510 fn o_textpsize(&self) -> u8;
511 fn o_datapsize(&self) -> u8;
512 fn o_stackpsize(&self) -> u8;
513 fn o_flags(&self) -> u8;
514 fn o_sntdata(&self) -> u16;
515 fn o_sntbss(&self) -> u16;
516 fn o_x64flags(&self) -> Option<u16>;
517}
518
519impl AuxHeader for xcoff::AuxHeader32 {
520 type Word = u32;
521
522 fn o_mflag(&self) -> u16 {
523 self.o_mflag.get(BE)
524 }
525
526 fn o_vstamp(&self) -> u16 {
527 self.o_vstamp.get(BE)
528 }
529
530 fn o_tsize(&self) -> Self::Word {
531 self.o_tsize.get(BE)
532 }
533
534 fn o_dsize(&self) -> Self::Word {
535 self.o_dsize.get(BE)
536 }
537
538 fn o_bsize(&self) -> Self::Word {
539 self.o_bsize.get(BE)
540 }
541
542 fn o_entry(&self) -> Self::Word {
543 self.o_entry.get(BE)
544 }
545
546 fn o_text_start(&self) -> Self::Word {
547 self.o_text_start.get(BE)
548 }
549
550 fn o_data_start(&self) -> Self::Word {
551 self.o_data_start.get(BE)
552 }
553
554 fn o_toc(&self) -> Self::Word {
555 self.o_toc.get(BE)
556 }
557
558 fn o_snentry(&self) -> u16 {
559 self.o_snentry.get(BE)
560 }
561
562 fn o_sntext(&self) -> u16 {
563 self.o_sntext.get(BE)
564 }
565
566 fn o_sndata(&self) -> u16 {
567 self.o_sndata.get(BE)
568 }
569
570 fn o_sntoc(&self) -> u16 {
571 self.o_sntoc.get(BE)
572 }
573
574 fn o_snloader(&self) -> u16 {
575 self.o_snloader.get(BE)
576 }
577
578 fn o_snbss(&self) -> u16 {
579 self.o_snbss.get(BE)
580 }
581
582 fn o_algntext(&self) -> u16 {
583 self.o_algntext.get(BE)
584 }
585
586 fn o_algndata(&self) -> u16 {
587 self.o_algndata.get(BE)
588 }
589
590 fn o_modtype(&self) -> u16 {
591 self.o_modtype.get(BE)
592 }
593
594 fn o_cpuflag(&self) -> u8 {
595 self.o_cpuflag
596 }
597
598 fn o_cputype(&self) -> u8 {
599 self.o_cputype
600 }
601
602 fn o_maxstack(&self) -> Self::Word {
603 self.o_maxstack.get(BE)
604 }
605
606 fn o_maxdata(&self) -> Self::Word {
607 self.o_maxdata.get(BE)
608 }
609
610 fn o_debugger(&self) -> u32 {
611 self.o_debugger.get(BE)
612 }
613
614 fn o_textpsize(&self) -> u8 {
615 self.o_textpsize
616 }
617
618 fn o_datapsize(&self) -> u8 {
619 self.o_datapsize
620 }
621
622 fn o_stackpsize(&self) -> u8 {
623 self.o_stackpsize
624 }
625
626 fn o_flags(&self) -> u8 {
627 self.o_flags
628 }
629
630 fn o_sntdata(&self) -> u16 {
631 self.o_sntdata.get(BE)
632 }
633
634 fn o_sntbss(&self) -> u16 {
635 self.o_sntbss.get(BE)
636 }
637
638 fn o_x64flags(&self) -> Option<u16> {
639 None
640 }
641}
642
643impl AuxHeader for xcoff::AuxHeader64 {
644 type Word = u64;
645
646 fn o_mflag(&self) -> u16 {
647 self.o_mflag.get(BE)
648 }
649
650 fn o_vstamp(&self) -> u16 {
651 self.o_vstamp.get(BE)
652 }
653
654 fn o_tsize(&self) -> Self::Word {
655 self.o_tsize.get(BE)
656 }
657
658 fn o_dsize(&self) -> Self::Word {
659 self.o_dsize.get(BE)
660 }
661
662 fn o_bsize(&self) -> Self::Word {
663 self.o_bsize.get(BE)
664 }
665
666 fn o_entry(&self) -> Self::Word {
667 self.o_entry.get(BE)
668 }
669
670 fn o_text_start(&self) -> Self::Word {
671 self.o_text_start.get(BE)
672 }
673
674 fn o_data_start(&self) -> Self::Word {
675 self.o_data_start.get(BE)
676 }
677
678 fn o_toc(&self) -> Self::Word {
679 self.o_toc.get(BE)
680 }
681
682 fn o_snentry(&self) -> u16 {
683 self.o_snentry.get(BE)
684 }
685
686 fn o_sntext(&self) -> u16 {
687 self.o_sntext.get(BE)
688 }
689
690 fn o_sndata(&self) -> u16 {
691 self.o_sndata.get(BE)
692 }
693
694 fn o_sntoc(&self) -> u16 {
695 self.o_sntoc.get(BE)
696 }
697
698 fn o_snloader(&self) -> u16 {
699 self.o_snloader.get(BE)
700 }
701
702 fn o_snbss(&self) -> u16 {
703 self.o_snbss.get(BE)
704 }
705
706 fn o_algntext(&self) -> u16 {
707 self.o_algntext.get(BE)
708 }
709
710 fn o_algndata(&self) -> u16 {
711 self.o_algndata.get(BE)
712 }
713
714 fn o_modtype(&self) -> u16 {
715 self.o_modtype.get(BE)
716 }
717
718 fn o_cpuflag(&self) -> u8 {
719 self.o_cpuflag
720 }
721
722 fn o_cputype(&self) -> u8 {
723 self.o_cputype
724 }
725
726 fn o_maxstack(&self) -> Self::Word {
727 self.o_maxstack.get(BE)
728 }
729
730 fn o_maxdata(&self) -> Self::Word {
731 self.o_maxdata.get(BE)
732 }
733
734 fn o_debugger(&self) -> u32 {
735 self.o_debugger.get(BE)
736 }
737
738 fn o_textpsize(&self) -> u8 {
739 self.o_textpsize
740 }
741
742 fn o_datapsize(&self) -> u8 {
743 self.o_datapsize
744 }
745
746 fn o_stackpsize(&self) -> u8 {
747 self.o_stackpsize
748 }
749
750 fn o_flags(&self) -> u8 {
751 self.o_flags
752 }
753
754 fn o_sntdata(&self) -> u16 {
755 self.o_sntdata.get(BE)
756 }
757
758 fn o_sntbss(&self) -> u16 {
759 self.o_sntbss.get(BE)
760 }
761
762 fn o_x64flags(&self) -> Option<u16> {
763 Some(self.o_x64flags.get(BE))
764 }
765}