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> = 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 XcoffSymbolIterator {
221 file: self,
222 symbols: self.symbols.iter_none(),
223 }
224 }
225
226 fn dynamic_relocations(&self) -> Option<Self::DynamicRelocationIterator<'_>> {
227 None
229 }
230
231 fn imports(&self) -> Result<alloc::vec::Vec<Import<'data>>> {
232 Ok(Vec::new())
234 }
235
236 fn exports(&self) -> Result<alloc::vec::Vec<Export<'data>>> {
237 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#[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 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 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 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 *offset += u64::from(aux_header_size);
318 return Ok(None);
319 }
320 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 #[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 #[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#[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}