object/read/xcoff/
file.rs

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