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