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 pub(super) file: &'file ElfFile<'data, Elf, R>,
25 pub(super) iter: iter::Enumerate<slice::Iter<'data, Elf::SectionHeader>>,
26}
27
28impl<'data, 'file, Elf, R> Iterator for ElfComdatIterator<'data, 'file, Elf, R>
29where
30 Elf: FileHeader,
31 R: ReadRef<'data>,
32{
33 type Item = ElfComdat<'data, 'file, Elf, R>;
34
35 fn next(&mut self) -> Option<Self::Item> {
36 for (_index: usize, section: &::SectionHeader) in self.iter.by_ref() {
37 if let Some(comdat: ElfComdat<'_, '_, Elf, R>) = ElfComdat::parse(self.file, section) {
38 return Some(comdat);
39 }
40 }
41 None
42 }
43}
44
45/// A COMDAT section group in an [`ElfFile32`](super::ElfFile32).
46pub type ElfComdat32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
47 ElfComdat<'data, 'file, elf::FileHeader32<Endian>, R>;
48/// A COMDAT section group in an [`ElfFile64`](super::ElfFile64).
49pub type ElfComdat64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
50 ElfComdat<'data, 'file, elf::FileHeader64<Endian>, R>;
51
52/// A COMDAT section group in an [`ElfFile`].
53///
54/// Most functionality is provided by the [`ObjectComdat`] trait implementation.
55#[derive(Debug)]
56pub struct ElfComdat<'data, 'file, Elf, R = &'data [u8]>
57where
58 Elf: FileHeader,
59 R: ReadRef<'data>,
60{
61 file: &'file ElfFile<'data, Elf, R>,
62 section: &'data Elf::SectionHeader,
63 sections: &'data [U32Bytes<Elf::Endian>],
64}
65
66impl<'data, 'file, Elf, R> ElfComdat<'data, 'file, Elf, R>
67where
68 Elf: FileHeader,
69 R: ReadRef<'data>,
70{
71 fn parse(
72 file: &'file ElfFile<'data, Elf, R>,
73 section: &'data Elf::SectionHeader,
74 ) -> Option<ElfComdat<'data, 'file, Elf, R>> {
75 let (flag: u32, sections: &[U32Bytes<<::ProgramHeader as ProgramHeader>::Endian>]) = section.group(file.endian, file.data).ok()??;
76 if flag != elf::GRP_COMDAT {
77 return None;
78 }
79 Some(ElfComdat {
80 file,
81 section,
82 sections,
83 })
84 }
85}
86
87impl<'data, 'file, Elf, R> read::private::Sealed for ElfComdat<'data, 'file, Elf, R>
88where
89 Elf: FileHeader,
90 R: ReadRef<'data>,
91{
92}
93
94impl<'data, 'file, Elf, R> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf, R>
95where
96 Elf: FileHeader,
97 R: ReadRef<'data>,
98{
99 type SectionIterator = ElfComdatSectionIterator<'data, 'file, Elf, R>;
100
101 #[inline]
102 fn kind(&self) -> ComdatKind {
103 ComdatKind::Any
104 }
105
106 #[inline]
107 fn symbol(&self) -> SymbolIndex {
108 SymbolIndex(self.section.sh_info(self.file.endian) as usize)
109 }
110
111 fn name_bytes(&self) -> read::Result<&[u8]> {
112 // FIXME: check sh_link
113 let index = self.section.sh_info(self.file.endian) as usize;
114 let symbol = self.file.symbols.symbol(index)?;
115 symbol.name(self.file.endian, self.file.symbols.strings())
116 }
117
118 fn name(&self) -> read::Result<&str> {
119 let name = self.name_bytes()?;
120 str::from_utf8(name)
121 .ok()
122 .read_error("Non UTF-8 ELF COMDAT name")
123 }
124
125 fn sections(&self) -> Self::SectionIterator {
126 ElfComdatSectionIterator {
127 file: self.file,
128 sections: self.sections.iter(),
129 }
130 }
131}
132
133/// An iterator for the sections in a COMDAT section group in an [`ElfFile32`](super::ElfFile32).
134pub type ElfComdatSectionIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
135 ElfComdatSectionIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
136/// An iterator for the sections in a COMDAT section group in an [`ElfFile64`](super::ElfFile64).
137pub type ElfComdatSectionIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
138 ElfComdatSectionIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
139
140/// An iterator for the sections in a COMDAT section group in an [`ElfFile`].
141#[derive(Debug)]
142pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]>
143where
144 Elf: FileHeader,
145 R: ReadRef<'data>,
146{
147 file: &'file ElfFile<'data, Elf, R>,
148 sections: slice::Iter<'data, U32Bytes<Elf::Endian>>,
149}
150
151impl<'data, 'file, Elf, R> Iterator for ElfComdatSectionIterator<'data, 'file, Elf, R>
152where
153 Elf: FileHeader,
154 R: ReadRef<'data>,
155{
156 type Item = SectionIndex;
157
158 fn next(&mut self) -> Option<Self::Item> {
159 let index: &U32Bytes<{unknown}> = self.sections.next()?;
160 Some(SectionIndex(index.get(self.file.endian) as usize))
161 }
162}
163