Skip to main content

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, 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
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
26/// A 64-bit XCOFF object file.
27///
28/// This is a file that starts with [`xcoff::FileHeader64`], and corresponds
29/// to [`crate::FileKind::Xcoff64`].
30pub type XcoffFile64<'data, R = &'data [u8]> = XcoffFile<'data, xcoff::FileHeader64, R>;
31
32/// The XCOFF file format that matches the pointer width of the target platform.
33#[cfg(target_pointer_width = "32")]
34pub type NativeXcoffFile<'data, R = &'data [u8]> = XcoffFile32<'data, R>;
35
36/// The XCOFF file format that matches the pointer width of the target platform.
37#[cfg(target_pointer_width = "64")]
38pub type NativeXcoffFile<'data, R = &'data [u8]> = XcoffFile64<'data, R>;
39
40/// A partially parsed XCOFF file.
41///
42/// Most functionality is provided by the [`Object`] trait implementation.
43#[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    /// Parse the raw XCOFF file data.
62    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    /// Returns the raw data.
79    pub fn data(&self) -> R {
80        self.data.0
81    }
82
83    /// Returns the raw XCOFF file header.
84    #[deprecated(note = "Use `xcoff_header` instead")]
85    pub fn raw_header(&self) -> &'data Xcoff {
86        self.header
87    }
88
89    /// Get the raw XCOFF file header.
90    pub fn xcoff_header(&self) -> &'data Xcoff {
91        self.header
92    }
93
94    /// Get the raw XCOFF auxiliary header.
95    pub fn xcoff_aux_header(&self) -> Option<&'data Xcoff::AuxHeader> {
96        self.aux_header
97    }
98
99    /// Get the XCOFF section table.
100    pub fn xcoff_section_table(&self) -> &SectionTable<'data, Xcoff> {
101        &self.sections
102    }
103
104    /// Get the XCOFF symbol table.
105    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        // TODO: return the symbols in the STYP_LOADER section.
269        XcoffSymbolIterator {
270            file: self,
271            symbols: self.symbols.iter_none(),
272        }
273    }
274
275    fn dynamic_relocations(&self) -> Option<Self::DynamicRelocationIterator<'_>> {
276        // TODO: return the relocations in the STYP_LOADER section.
277        None
278    }
279
280    fn imports(&self) -> Result<alloc::vec::Vec<Import<'data>>> {
281        // TODO: return the imports in the STYP_LOADER section.
282        Ok(Vec::new())
283    }
284
285    fn exports(&self) -> Result<alloc::vec::Vec<Export<'data>>> {
286        // TODO: return the exports in the STYP_LOADER section.
287        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/// A trait for generic access to [`xcoff::FileHeader32`] and [`xcoff::FileHeader64`].
314#[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    /// Return true if this type is a 64-bit header.
325    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    // Provided methods.
336
337    /// Read the file header.
338    ///
339    /// Also checks that the magic field in the file header is a supported format.
340    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    /// Read the auxiliary file header.
356    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            // No auxiliary header is required for an object file that is not an executable.
364            // TODO: Some AIX programs generate auxiliary headers for 32-bit object files
365            // that end after the data_start field.
366            *offset += u64::from(aux_header_size);
367            return Ok(None);
368        }
369        // Executables, however, must have auxiliary headers that include the
370        // full structure definitions.
371        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    /// Read the section table.
382    #[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    /// Return the symbol table.
392    #[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/// A trait for generic access to [`xcoff::AuxHeader32`] and [`xcoff::AuxHeader64`].
483#[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}