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
10pub type ElfComdatIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
12    ElfComdatIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
13pub type ElfComdatIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
15    ElfComdatIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
16
17#[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(); 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
59pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
61    ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>;
62pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
64    ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>;
65
66#[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    pub fn elf_file(&self) -> &'file ElfFile<'data, Elf, R> {
102        self.file
103    }
104
105    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        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
157pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
159    ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
160pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
162    ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
163
164#[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}