object/read/elf/
comdat.rs

1use core::fmt::Debug;
2use core::{iter, slice, str};
3
4use crate::elf;
5use crate::endian::{Endianness, U32Bytes};
6use crate::read::{self, ComdatKind, ObjectComdat, ReadError, ReadRef, SectionIndex, SymbolIndex};
7
8use super::{ElfFile, FileHeader, SectionHeader, Sym};
9
10/// An iterator for the COMDAT section groups in an [`ElfFile32`](super::ElfFile32).
11pub type ElfComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
12    ElfComdatIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
13/// An iterator for the COMDAT section groups in an [`ElfFile64`](super::ElfFile64).
14pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
15    ElfComdatIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
16
17/// An iterator for the COMDAT section groups in an [`ElfFile`].
18#[derive(Debug)]
19pub struct ElfComdatIterator<'data, 'file, Elf, R = &'data [u8]>
20where
21    Elf: FileHeader,
22    R: ReadRef<'data>,
23{
24    file: &'file ElfFile<'data, Elf, R>,
25    iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
26}
27
28impl<'data, 'file, Elf, R> ElfComdatIterator<'data, 'file, Elf, R>
29where
30    Elf: FileHeader,
31    R: ReadRef<'data>,
32{
33    pub(super) fn new(
34        file: &'file ElfFile<'data, Elf, R>,
35    ) -> ElfComdatIterator<'data, 'file, Elf, R> {
36        let mut iter = file.sections.iter().enumerate();
37        iter.next(); // Skip null section.
38        ElfComdatIterator { file, iter }
39    }
40}
41
42impl<'data, 'file, Elf, R> Iterator for ElfComdatIterator<'data, 'file, Elf, R>
43where
44    Elf: FileHeader,
45    R: ReadRef<'data>,
46{
47    type Item = ElfComdat<'data, 'file, Elf, R>;
48
49    fn next(&mut self) -> Option<Self::Item> {
50        for (_index, section) in self.iter.by_ref() {
51            if let Some(comdat) = ElfComdat::parse(self.file, section) {
52                return Some(comdat);
53            }
54        }
55        None
56    }
57}
58
59/// A COMDAT section group in an [`ElfFile32`](super::ElfFile32).
60pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
61    ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>;
62/// A COMDAT section group in an [`ElfFile64`](super::ElfFile64).
63pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
64    ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>;
65
66/// A COMDAT section group in an [`ElfFile`].
67///
68/// Most functionality is provided by the [`ObjectComdat`] trait implementation.
69#[derive(Debug)]
70pub struct ElfComdat<'data, 'file, Elf, R = &'data [u8]>
71where
72    Elf: FileHeader,
73    R: ReadRef<'data>,
74{
75    file: &'file ElfFile<'data, Elf, R>,
76    section: &'data Elf::SectionHeader,
77    sections: &'data [U32Bytes<Elf::Endian>],
78}
79
80impl<'data, 'file, Elf, R> ElfComdat<'data, 'file, Elf, R>
81where
82    Elf: FileHeader,
83    R: ReadRef<'data>,
84{
85    fn parse(
86        file: &'file ElfFile<'data, Elf, R>,
87        section: &'data Elf::SectionHeader,
88    ) -> Option<ElfComdat<'data, 'file, Elf, R>> {
89        let (flag, sections) = section.group(file.endian, file.data).ok()??;
90        if flag != elf::GRP_COMDAT {
91            return None;
92        }
93        Some(ElfComdat {
94            file,
95            section,
96            sections,
97        })
98    }
99
100    /// Get the ELF file containing this COMDAT section group.
101    pub fn elf_file(&self) -> &'file ElfFile<'data, Elf, R> {
102        self.file
103    }
104
105    /// Get the raw ELF section header for the COMDAT section group.
106    pub fn elf_section_header(&self) -> &'data Elf::SectionHeader {
107        self.section
108    }
109}
110
111impl<'data, 'file, Elf, R> read::private::Sealed for ElfComdat<'data, 'file, Elf, R>
112where
113    Elf: FileHeader,
114    R: ReadRef<'data>,
115{
116}
117
118impl<'data, 'file, Elf, R> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf, R>
119where
120    Elf: FileHeader,
121    R: ReadRef<'data>,
122{
123    type SectionIterator = ElfComdatSectionIterator<'data, 'file, Elf, R>;
124
125    #[inline]
126    fn kind(&self) -> ComdatKind {
127        ComdatKind::Any
128    }
129
130    #[inline]
131    fn symbol(&self) -> SymbolIndex {
132        SymbolIndex(self.section.sh_info(self.file.endian) as usize)
133    }
134
135    fn name_bytes(&self) -> read::Result<&'data [u8]> {
136        // FIXME: check sh_link
137        let index = self.symbol();
138        let symbol = self.file.symbols.symbol(index)?;
139        symbol.name(self.file.endian, self.file.symbols.strings())
140    }
141
142    fn name(&self) -> read::Result<&'data str> {
143        let name = self.name_bytes()?;
144        str::from_utf8(name)
145            .ok()
146            .read_error("Non UTF-8 ELF COMDAT name")
147    }
148
149    fn sections(&self) -> Self::SectionIterator {
150        ElfComdatSectionIterator {
151            file: self.file,
152            sections: self.sections.iter(),
153        }
154    }
155}
156
157/// An iterator for the sections in a COMDAT section group in an [`ElfFile32`](super::ElfFile32).
158pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
159    ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
160/// An iterator for the sections in a COMDAT section group in an [`ElfFile64`](super::ElfFile64).
161pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
162    ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
163
164/// An iterator for the sections in a COMDAT section group in an [`ElfFile`].
165#[derive(Debug)]
166pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]>
167where
168    Elf: FileHeader,
169    R: ReadRef<'data>,
170{
171    file: &'file ElfFile<'data, Elf, R>,
172    sections: slice::Iter<'data, U32Bytes<Elf::Endian>>,
173}
174
175impl<'data, 'file, Elf, R> Iterator for ElfComdatSectionIterator<'data, 'file, Elf, R>
176where
177    Elf: FileHeader,
178    R: ReadRef<'data>,
179{
180    type Item = SectionIndex;
181
182    fn next(&mut self) -> Option<Self::Item> {
183        let index = self.sections.next()?;
184        Some(SectionIndex(index.get(self.file.endian) as usize))
185    }
186}