object/read/xcoff/
symbol.rs

1use alloc::fmt;
2use core::convert::TryInto;
3use core::fmt::Debug;
4use core::marker::PhantomData;
5use core::str;
6
7use crate::endian::{BigEndian as BE, U32Bytes};
8use crate::pod::{bytes_of, Pod};
9use crate::read::{
10    self, Bytes, Error, ObjectSymbol, ObjectSymbolTable, ReadError, ReadRef, Result, SectionIndex,
11    StringTable, SymbolFlags, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
12};
13use crate::xcoff;
14
15use super::{FileHeader, XcoffFile};
16
17/// A table of symbol entries in an XCOFF file.
18///
19/// Also includes the string table used for the symbol names.
20///
21/// Returned by [`FileHeader::symbols`].
22#[derive(Debug)]
23pub struct SymbolTable<'data, Xcoff, R = &'data [u8]>
24where
25    Xcoff: FileHeader,
26    R: ReadRef<'data>,
27{
28    symbols: &'data [xcoff::SymbolBytes],
29    strings: StringTable<'data, R>,
30    header: PhantomData<Xcoff>,
31}
32
33impl<'data, Xcoff, R> Default for SymbolTable<'data, Xcoff, R>
34where
35    Xcoff: FileHeader,
36    R: ReadRef<'data>,
37{
38    fn default() -> Self {
39        Self {
40            symbols: &[],
41            strings: StringTable::default(),
42            header: PhantomData,
43        }
44    }
45}
46
47impl<'data, Xcoff, R> SymbolTable<'data, Xcoff, R>
48where
49    Xcoff: FileHeader,
50    R: ReadRef<'data>,
51{
52    /// Parse the symbol table.
53    pub fn parse(header: Xcoff, data: R) -> Result<Self> {
54        let mut offset = header.f_symptr().into();
55        let (symbols, strings) = if offset != 0 {
56            let symbols = data
57                .read_slice(&mut offset, header.f_nsyms() as usize)
58                .read_error("Invalid XCOFF symbol table offset or size")?;
59
60            // Parse the string table.
61            // Note: don't update data when reading length; the length includes itself.
62            let length = data
63                .read_at::<U32Bytes<_>>(offset)
64                .read_error("Missing XCOFF string table")?
65                .get(BE);
66            let str_end = offset
67                .checked_add(length as u64)
68                .read_error("Invalid XCOFF string table length")?;
69            let strings = StringTable::new(data, offset, str_end);
70
71            (symbols, strings)
72        } else {
73            (&[][..], StringTable::default())
74        };
75
76        Ok(SymbolTable {
77            symbols,
78            strings,
79            header: PhantomData,
80        })
81    }
82
83    /// Return the string table used for the symbol names.
84    #[inline]
85    pub fn strings(&self) -> StringTable<'data, R> {
86        self.strings
87    }
88
89    /// Iterate over the symbols.
90    ///
91    /// This does not return null symbols.
92    #[inline]
93    pub fn iter<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> {
94        SymbolIterator {
95            symbols: self,
96            index: 0,
97        }
98    }
99
100    /// Empty symbol iterator.
101    #[inline]
102    pub(super) fn iter_none<'table>(&'table self) -> SymbolIterator<'data, 'table, Xcoff, R> {
103        SymbolIterator {
104            symbols: self,
105            index: self.symbols.len(),
106        }
107    }
108
109    /// Return the symbol entry at the given index and offset.
110    pub fn get<T: Pod>(&self, index: SymbolIndex, offset: usize) -> Result<&'data T> {
111        let entry = index
112            .0
113            .checked_add(offset)
114            .and_then(|x| self.symbols.get(x))
115            .read_error("Invalid XCOFF symbol index")?;
116        let bytes = bytes_of(entry);
117        Bytes(bytes).read().read_error("Invalid XCOFF symbol data")
118    }
119
120    /// Get the symbol at the given index.
121    ///
122    /// This does not check if the symbol is null, but does check if the index is in bounds.
123    fn symbol_unchecked(&self, index: SymbolIndex) -> Result<&'data Xcoff::Symbol> {
124        self.get::<Xcoff::Symbol>(index, 0)
125    }
126
127    /// Get the symbol at the given index.
128    ///
129    /// Returns an error for null symbols and out of bounds indices.
130    /// Note that this is unable to check whether the index is an auxiliary symbol.
131    pub fn symbol(&self, index: SymbolIndex) -> Result<&'data Xcoff::Symbol> {
132        let symbol = self.symbol_unchecked(index)?;
133        if symbol.is_null() {
134            return Err(Error("Invalid XCOFF symbol index"));
135        }
136        Ok(symbol)
137    }
138
139    /// Return a file auxiliary symbol.
140    pub fn aux_file(&self, index: SymbolIndex, offset: usize) -> Result<&'data Xcoff::FileAux> {
141        debug_assert!(self.symbol(index)?.has_aux_file());
142        let aux_file = self.get::<Xcoff::FileAux>(index, offset)?;
143        if let Some(aux_type) = aux_file.x_auxtype() {
144            if aux_type != xcoff::AUX_FILE {
145                return Err(Error("Invalid index for file auxiliary symbol."));
146            }
147        }
148        Ok(aux_file)
149    }
150
151    /// Return the csect auxiliary symbol.
152    pub fn aux_csect(&self, index: SymbolIndex, offset: usize) -> Result<&'data Xcoff::CsectAux> {
153        debug_assert!(self.symbol(index)?.has_aux_csect());
154        let aux_csect = self.get::<Xcoff::CsectAux>(index, offset)?;
155        if let Some(aux_type) = aux_csect.x_auxtype() {
156            if aux_type != xcoff::AUX_CSECT {
157                return Err(Error("Invalid index/offset for csect auxiliary symbol."));
158            }
159        }
160        Ok(aux_csect)
161    }
162
163    /// Return true if the symbol table is empty.
164    #[inline]
165    pub fn is_empty(&self) -> bool {
166        self.symbols.is_empty()
167    }
168
169    /// The number of symbol table entries.
170    ///
171    /// This includes auxiliary symbol table entries.
172    #[inline]
173    pub fn len(&self) -> usize {
174        self.symbols.len()
175    }
176}
177
178/// An iterator for symbol entries in an XCOFF file.
179///
180/// Yields the index and symbol structure for each symbol.
181#[derive(Debug)]
182pub struct SymbolIterator<'data, 'table, Xcoff, R = &'data [u8]>
183where
184    Xcoff: FileHeader,
185    R: ReadRef<'data>,
186{
187    symbols: &'table SymbolTable<'data, Xcoff, R>,
188    index: usize,
189}
190
191impl<'data, 'table, Xcoff: FileHeader, R: ReadRef<'data>> Iterator
192    for SymbolIterator<'data, 'table, Xcoff, R>
193{
194    type Item = (SymbolIndex, &'data Xcoff::Symbol);
195
196    fn next(&mut self) -> Option<Self::Item> {
197        loop {
198            let index = SymbolIndex(self.index);
199            let symbol = self.symbols.symbol_unchecked(index).ok()?;
200            self.index += 1 + symbol.n_numaux() as usize;
201            if !symbol.is_null() {
202                return Some((index, symbol));
203            }
204        }
205    }
206}
207
208/// A symbol table in an [`XcoffFile32`](super::XcoffFile32).
209pub type XcoffSymbolTable32<'data, 'file, R = &'data [u8]> =
210    XcoffSymbolTable<'data, 'file, xcoff::FileHeader32, R>;
211/// A symbol table in an [`XcoffFile64`](super::XcoffFile64).
212pub type XcoffSymbolTable64<'data, 'file, R = &'data [u8]> =
213    XcoffSymbolTable<'data, 'file, xcoff::FileHeader64, R>;
214
215/// A symbol table in an [`XcoffFile`].
216#[derive(Debug, Clone, Copy)]
217pub struct XcoffSymbolTable<'data, 'file, Xcoff, R = &'data [u8]>
218where
219    Xcoff: FileHeader,
220    R: ReadRef<'data>,
221{
222    pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
223    pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
224}
225
226impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
227    for XcoffSymbolTable<'data, 'file, Xcoff, R>
228{
229}
230
231impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbolTable<'data>
232    for XcoffSymbolTable<'data, 'file, Xcoff, R>
233{
234    type Symbol = XcoffSymbol<'data, 'file, Xcoff, R>;
235    type SymbolIterator = XcoffSymbolIterator<'data, 'file, Xcoff, R>;
236
237    fn symbols(&self) -> Self::SymbolIterator {
238        XcoffSymbolIterator {
239            file: self.file,
240            symbols: self.symbols.iter(),
241        }
242    }
243
244    fn symbol_by_index(&self, index: SymbolIndex) -> read::Result<Self::Symbol> {
245        let symbol = self.symbols.symbol(index)?;
246        Ok(XcoffSymbol {
247            file: self.file,
248            symbols: self.symbols,
249            index,
250            symbol,
251        })
252    }
253}
254
255/// An iterator for the symbols in an [`XcoffFile32`](super::XcoffFile32).
256pub type XcoffSymbolIterator32<'data, 'file, R = &'data [u8]> =
257    XcoffSymbolIterator<'data, 'file, xcoff::FileHeader32, R>;
258/// An iterator for the symbols in an [`XcoffFile64`](super::XcoffFile64).
259pub type XcoffSymbolIterator64<'data, 'file, R = &'data [u8]> =
260    XcoffSymbolIterator<'data, 'file, xcoff::FileHeader64, R>;
261
262/// An iterator for the symbols in an [`XcoffFile`].
263pub struct XcoffSymbolIterator<'data, 'file, Xcoff, R = &'data [u8]>
264where
265    Xcoff: FileHeader,
266    R: ReadRef<'data>,
267{
268    pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
269    pub(super) symbols: SymbolIterator<'data, 'file, Xcoff, R>,
270}
271
272impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> fmt::Debug
273    for XcoffSymbolIterator<'data, 'file, Xcoff, R>
274{
275    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
276        f.debug_struct("XcoffSymbolIterator").finish()
277    }
278}
279
280impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> Iterator
281    for XcoffSymbolIterator<'data, 'file, Xcoff, R>
282{
283    type Item = XcoffSymbol<'data, 'file, Xcoff, R>;
284
285    fn next(&mut self) -> Option<Self::Item> {
286        let (index, symbol) = self.symbols.next()?;
287        Some(XcoffSymbol {
288            file: self.file,
289            symbols: self.symbols.symbols,
290            index,
291            symbol,
292        })
293    }
294}
295
296/// A symbol in an [`XcoffFile32`](super::XcoffFile32).
297pub type XcoffSymbol32<'data, 'file, R = &'data [u8]> =
298    XcoffSymbol<'data, 'file, xcoff::FileHeader32, R>;
299/// A symbol in an [`XcoffFile64`](super::XcoffFile64).
300pub type XcoffSymbol64<'data, 'file, R = &'data [u8]> =
301    XcoffSymbol<'data, 'file, xcoff::FileHeader64, R>;
302
303/// A symbol in an [`XcoffFile`].
304///
305/// Most functionality is provided by the [`ObjectSymbol`] trait implementation.
306#[derive(Debug, Clone, Copy)]
307pub struct XcoffSymbol<'data, 'file, Xcoff, R = &'data [u8]>
308where
309    Xcoff: FileHeader,
310    R: ReadRef<'data>,
311{
312    pub(super) file: &'file XcoffFile<'data, Xcoff, R>,
313    pub(super) symbols: &'file SymbolTable<'data, Xcoff, R>,
314    pub(super) index: SymbolIndex,
315    pub(super) symbol: &'data Xcoff::Symbol,
316}
317
318impl<'data, 'file, Xcoff, R> XcoffSymbol<'data, 'file, Xcoff, R>
319where
320    Xcoff: FileHeader,
321    R: ReadRef<'data>,
322{
323    /// Get the XCOFF file containing this symbol.
324    pub fn xcoff_file(&self) -> &'file XcoffFile<'data, Xcoff, R> {
325        self.file
326    }
327
328    /// Get the raw XCOFF symbol structure.
329    pub fn xcoff_symbol(&self) -> &'data Xcoff::Symbol {
330        self.symbol
331    }
332}
333
334impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> read::private::Sealed
335    for XcoffSymbol<'data, 'file, Xcoff, R>
336{
337}
338
339impl<'data, 'file, Xcoff: FileHeader, R: ReadRef<'data>> ObjectSymbol<'data>
340    for XcoffSymbol<'data, 'file, Xcoff, R>
341{
342    #[inline]
343    fn index(&self) -> SymbolIndex {
344        self.index
345    }
346
347    fn name_bytes(&self) -> Result<&'data [u8]> {
348        if self.symbol.has_aux_file() {
349            // By convention the file name is in the first auxiliary entry.
350            self.symbols
351                .aux_file(self.index, 1)?
352                .fname(self.symbols.strings)
353        } else {
354            self.symbol.name(self.symbols.strings)
355        }
356    }
357
358    fn name(&self) -> Result<&'data str> {
359        let name = self.name_bytes()?;
360        str::from_utf8(name)
361            .ok()
362            .read_error("Non UTF-8 XCOFF symbol name")
363    }
364
365    #[inline]
366    fn address(&self) -> u64 {
367        match self.symbol.n_sclass() {
368            // Relocatable address.
369            xcoff::C_EXT
370            | xcoff::C_WEAKEXT
371            | xcoff::C_HIDEXT
372            | xcoff::C_FCN
373            | xcoff::C_BLOCK
374            | xcoff::C_STAT
375            | xcoff::C_INFO => self.symbol.n_value().into(),
376            _ => 0,
377        }
378    }
379
380    #[inline]
381    fn size(&self) -> u64 {
382        if self.symbol.has_aux_csect() {
383            // XCOFF32 must have the csect auxiliary entry as the last auxiliary entry.
384            // XCOFF64 doesn't require this, but conventionally does.
385            if let Ok(aux_csect) = self
386                .file
387                .symbols
388                .aux_csect(self.index, self.symbol.n_numaux() as usize)
389            {
390                let sym_type = aux_csect.sym_type();
391                if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM {
392                    return aux_csect.x_scnlen();
393                }
394            }
395        }
396        0
397    }
398
399    fn kind(&self) -> SymbolKind {
400        if self.symbol.has_aux_csect() {
401            if let Ok(aux_csect) = self
402                .file
403                .symbols
404                .aux_csect(self.index, self.symbol.n_numaux() as usize)
405            {
406                let sym_type = aux_csect.sym_type();
407                if sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_CM {
408                    return match aux_csect.x_smclas() {
409                        xcoff::XMC_PR | xcoff::XMC_GL => SymbolKind::Text,
410                        xcoff::XMC_RO | xcoff::XMC_RW | xcoff::XMC_TD | xcoff::XMC_BS => {
411                            SymbolKind::Data
412                        }
413                        xcoff::XMC_TL | xcoff::XMC_UL => SymbolKind::Tls,
414                        xcoff::XMC_DS | xcoff::XMC_TC0 | xcoff::XMC_TC => {
415                            // `Metadata` might be a better kind for these if we had it.
416                            SymbolKind::Data
417                        }
418                        _ => SymbolKind::Unknown,
419                    };
420                } else if sym_type == xcoff::XTY_LD {
421                    // A function entry point. Neither `Text` nor `Label` are a good fit for this.
422                    return SymbolKind::Text;
423                } else if sym_type == xcoff::XTY_ER {
424                    return SymbolKind::Unknown;
425                }
426            }
427        }
428        match self.symbol.n_sclass() {
429            xcoff::C_FILE => SymbolKind::File,
430            _ => SymbolKind::Unknown,
431        }
432    }
433
434    fn section(&self) -> SymbolSection {
435        match self.symbol.n_scnum() {
436            xcoff::N_ABS => SymbolSection::Absolute,
437            xcoff::N_UNDEF => SymbolSection::Undefined,
438            xcoff::N_DEBUG => SymbolSection::None,
439            index if index > 0 => SymbolSection::Section(SectionIndex(index as usize)),
440            _ => SymbolSection::Unknown,
441        }
442    }
443
444    #[inline]
445    fn is_undefined(&self) -> bool {
446        self.symbol.is_undefined()
447    }
448
449    /// Return true if the symbol is a definition of a function or data object.
450    #[inline]
451    fn is_definition(&self) -> bool {
452        if self.symbol.n_scnum() <= 0 {
453            return false;
454        }
455        if self.symbol.has_aux_csect() {
456            if let Ok(aux_csect) = self
457                .symbols
458                .aux_csect(self.index, self.symbol.n_numaux() as usize)
459            {
460                let sym_type = aux_csect.sym_type();
461                sym_type == xcoff::XTY_SD || sym_type == xcoff::XTY_LD || sym_type == xcoff::XTY_CM
462            } else {
463                false
464            }
465        } else {
466            false
467        }
468    }
469
470    #[inline]
471    fn is_common(&self) -> bool {
472        self.symbol.n_sclass() == xcoff::C_EXT && self.symbol.n_scnum() == xcoff::N_UNDEF
473    }
474
475    #[inline]
476    fn is_weak(&self) -> bool {
477        self.symbol.n_sclass() == xcoff::C_WEAKEXT
478    }
479
480    fn scope(&self) -> SymbolScope {
481        if self.symbol.n_scnum() == xcoff::N_UNDEF {
482            SymbolScope::Unknown
483        } else {
484            match self.symbol.n_sclass() {
485                xcoff::C_EXT | xcoff::C_WEAKEXT => {
486                    let visibility = self.symbol.n_type() & xcoff::SYM_V_MASK;
487                    if visibility == xcoff::SYM_V_HIDDEN {
488                        SymbolScope::Linkage
489                    } else {
490                        SymbolScope::Dynamic
491                    }
492                }
493                _ => SymbolScope::Compilation,
494            }
495        }
496    }
497
498    #[inline]
499    fn is_global(&self) -> bool {
500        match self.symbol.n_sclass() {
501            xcoff::C_EXT | xcoff::C_WEAKEXT => true,
502            _ => false,
503        }
504    }
505
506    #[inline]
507    fn is_local(&self) -> bool {
508        !self.is_global()
509    }
510
511    #[inline]
512    fn flags(&self) -> SymbolFlags<SectionIndex, SymbolIndex> {
513        let mut x_smtyp = 0;
514        let mut x_smclas = 0;
515        let mut containing_csect = None;
516        if self.symbol.has_aux_csect() {
517            if let Ok(aux_csect) = self
518                .file
519                .symbols
520                .aux_csect(self.index, self.symbol.n_numaux() as usize)
521            {
522                x_smtyp = aux_csect.x_smtyp();
523                x_smclas = aux_csect.x_smclas();
524                if aux_csect.sym_type() == xcoff::XTY_LD {
525                    containing_csect = Some(SymbolIndex(aux_csect.x_scnlen() as usize))
526                }
527            }
528        }
529        SymbolFlags::Xcoff {
530            n_sclass: self.symbol.n_sclass(),
531            x_smtyp,
532            x_smclas,
533            containing_csect,
534        }
535    }
536}
537
538/// A trait for generic access to [`xcoff::Symbol32`] and [`xcoff::Symbol64`].
539#[allow(missing_docs)]
540pub trait Symbol: Debug + Pod {
541    type Word: Into<u64>;
542
543    fn n_value(&self) -> Self::Word;
544    fn n_scnum(&self) -> i16;
545    fn n_type(&self) -> u16;
546    fn n_sclass(&self) -> u8;
547    fn n_numaux(&self) -> u8;
548
549    fn name_offset(&self) -> Option<u32>;
550    fn name<'data, R: ReadRef<'data>>(
551        &'data self,
552        strings: StringTable<'data, R>,
553    ) -> Result<&'data [u8]>;
554
555    /// Return the section index for the symbol.
556    fn section(&self) -> Option<SectionIndex> {
557        let index = self.n_scnum();
558        if index > 0 {
559            Some(SectionIndex(index as usize))
560        } else {
561            None
562        }
563    }
564
565    /// Return true if the symbol is a null placeholder.
566    #[inline]
567    fn is_null(&self) -> bool {
568        self.n_sclass() == xcoff::C_NULL
569    }
570
571    /// Return true if the symbol is undefined.
572    #[inline]
573    fn is_undefined(&self) -> bool {
574        let n_sclass = self.n_sclass();
575        (n_sclass == xcoff::C_EXT || n_sclass == xcoff::C_WEAKEXT)
576            && self.n_scnum() == xcoff::N_UNDEF
577    }
578
579    /// Return true if the symbol has file auxiliary entry.
580    fn has_aux_file(&self) -> bool {
581        self.n_numaux() > 0 && self.n_sclass() == xcoff::C_FILE
582    }
583
584    /// Return true if the symbol has csect auxiliary entry.
585    ///
586    /// A csect auxiliary entry is required for each symbol table entry that has
587    /// a storage class value of C_EXT, C_WEAKEXT, or C_HIDEXT.
588    fn has_aux_csect(&self) -> bool {
589        let sclass = self.n_sclass();
590        self.n_numaux() > 0
591            && (sclass == xcoff::C_EXT || sclass == xcoff::C_WEAKEXT || sclass == xcoff::C_HIDEXT)
592    }
593}
594
595impl Symbol for xcoff::Symbol64 {
596    type Word = u64;
597
598    fn n_value(&self) -> Self::Word {
599        self.n_value.get(BE)
600    }
601
602    fn n_scnum(&self) -> i16 {
603        self.n_scnum.get(BE)
604    }
605
606    fn n_type(&self) -> u16 {
607        self.n_type.get(BE)
608    }
609
610    fn n_sclass(&self) -> u8 {
611        self.n_sclass
612    }
613
614    fn n_numaux(&self) -> u8 {
615        self.n_numaux
616    }
617
618    fn name_offset(&self) -> Option<u32> {
619        Some(self.n_offset.get(BE))
620    }
621
622    /// Parse the symbol name for XCOFF64.
623    fn name<'data, R: ReadRef<'data>>(
624        &'data self,
625        strings: StringTable<'data, R>,
626    ) -> Result<&'data [u8]> {
627        strings
628            .get(self.n_offset.get(BE))
629            .read_error("Invalid XCOFF symbol name offset")
630    }
631}
632
633impl Symbol for xcoff::Symbol32 {
634    type Word = u32;
635
636    fn n_value(&self) -> Self::Word {
637        self.n_value.get(BE)
638    }
639
640    fn n_scnum(&self) -> i16 {
641        self.n_scnum.get(BE)
642    }
643
644    fn n_type(&self) -> u16 {
645        self.n_type.get(BE)
646    }
647
648    fn n_sclass(&self) -> u8 {
649        self.n_sclass
650    }
651
652    fn n_numaux(&self) -> u8 {
653        self.n_numaux
654    }
655
656    fn name_offset(&self) -> Option<u32> {
657        if self.n_name[0] == 0 {
658            let offset = u32::from_be_bytes(self.n_name[4..8].try_into().unwrap());
659            Some(offset)
660        } else {
661            None
662        }
663    }
664
665    /// Parse the symbol name for XCOFF32.
666    fn name<'data, R: ReadRef<'data>>(
667        &'data self,
668        strings: StringTable<'data, R>,
669    ) -> Result<&'data [u8]> {
670        if let Some(offset) = self.name_offset() {
671            // If the name starts with 0 then the last 4 bytes are a string table offset.
672            strings
673                .get(offset)
674                .read_error("Invalid XCOFF symbol name offset")
675        } else {
676            // The name is inline and padded with nulls.
677            Ok(match memchr::memchr(b'\0', &self.n_name) {
678                Some(end) => &self.n_name[..end],
679                None => &self.n_name,
680            })
681        }
682    }
683}
684
685/// A trait for generic access to [`xcoff::FileAux32`] and [`xcoff::FileAux64`].
686#[allow(missing_docs)]
687pub trait FileAux: Debug + Pod {
688    fn x_fname(&self) -> &[u8; 8];
689    fn x_ftype(&self) -> u8;
690    fn x_auxtype(&self) -> Option<u8>;
691
692    fn name_offset(&self) -> Option<u32> {
693        let x_fname = self.x_fname();
694        if x_fname[0] == 0 {
695            Some(u32::from_be_bytes(x_fname[4..8].try_into().unwrap()))
696        } else {
697            None
698        }
699    }
700
701    /// Parse the x_fname field, which may be an inline string or a string table offset.
702    fn fname<'data, R: ReadRef<'data>>(
703        &'data self,
704        strings: StringTable<'data, R>,
705    ) -> Result<&'data [u8]> {
706        if let Some(offset) = self.name_offset() {
707            // If the name starts with 0 then the last 4 bytes are a string table offset.
708            strings
709                .get(offset)
710                .read_error("Invalid XCOFF symbol name offset")
711        } else {
712            // The name is inline and padded with nulls.
713            let x_fname = self.x_fname();
714            Ok(match memchr::memchr(b'\0', x_fname) {
715                Some(end) => &x_fname[..end],
716                None => x_fname,
717            })
718        }
719    }
720}
721
722impl FileAux for xcoff::FileAux64 {
723    fn x_fname(&self) -> &[u8; 8] {
724        &self.x_fname
725    }
726
727    fn x_ftype(&self) -> u8 {
728        self.x_ftype
729    }
730
731    fn x_auxtype(&self) -> Option<u8> {
732        Some(self.x_auxtype)
733    }
734}
735
736impl FileAux for xcoff::FileAux32 {
737    fn x_fname(&self) -> &[u8; 8] {
738        &self.x_fname
739    }
740
741    fn x_ftype(&self) -> u8 {
742        self.x_ftype
743    }
744
745    fn x_auxtype(&self) -> Option<u8> {
746        None
747    }
748}
749
750/// A trait for generic access to [`xcoff::CsectAux32`] and [`xcoff::CsectAux64`].
751#[allow(missing_docs)]
752pub trait CsectAux: Debug + Pod {
753    fn x_scnlen(&self) -> u64;
754    fn x_parmhash(&self) -> u32;
755    fn x_snhash(&self) -> u16;
756    fn x_smtyp(&self) -> u8;
757    fn x_smclas(&self) -> u8;
758    fn x_stab(&self) -> Option<u32>;
759    fn x_snstab(&self) -> Option<u16>;
760    fn x_auxtype(&self) -> Option<u8>;
761
762    fn alignment(&self) -> u8 {
763        self.x_smtyp() >> 3
764    }
765    fn sym_type(&self) -> u8 {
766        self.x_smtyp() & 0x07
767    }
768}
769
770impl CsectAux for xcoff::CsectAux64 {
771    fn x_scnlen(&self) -> u64 {
772        self.x_scnlen_lo.get(BE) as u64 | ((self.x_scnlen_hi.get(BE) as u64) << 32)
773    }
774
775    fn x_parmhash(&self) -> u32 {
776        self.x_parmhash.get(BE)
777    }
778
779    fn x_snhash(&self) -> u16 {
780        self.x_snhash.get(BE)
781    }
782
783    fn x_smtyp(&self) -> u8 {
784        self.x_smtyp
785    }
786
787    fn x_smclas(&self) -> u8 {
788        self.x_smclas
789    }
790
791    fn x_stab(&self) -> Option<u32> {
792        None
793    }
794
795    fn x_snstab(&self) -> Option<u16> {
796        None
797    }
798
799    fn x_auxtype(&self) -> Option<u8> {
800        Some(self.x_auxtype)
801    }
802}
803
804impl CsectAux for xcoff::CsectAux32 {
805    fn x_scnlen(&self) -> u64 {
806        self.x_scnlen.get(BE) as u64
807    }
808
809    fn x_parmhash(&self) -> u32 {
810        self.x_parmhash.get(BE)
811    }
812
813    fn x_snhash(&self) -> u16 {
814        self.x_snhash.get(BE)
815    }
816
817    fn x_smtyp(&self) -> u8 {
818        self.x_smtyp
819    }
820
821    fn x_smclas(&self) -> u8 {
822        self.x_smclas
823    }
824
825    fn x_stab(&self) -> Option<u32> {
826        Some(self.x_stab.get(BE))
827    }
828
829    fn x_snstab(&self) -> Option<u16> {
830        Some(self.x_snstab.get(BE))
831    }
832
833    fn x_auxtype(&self) -> Option<u8> {
834        None
835    }
836}