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