1 | use core::fmt::Debug; |
2 | use core::{iter, slice, str}; |
3 | |
4 | use crate::elf; |
5 | use crate::endian::{Endianness, U32Bytes}; |
6 | use crate::read::{self, ComdatKind, ObjectComdat, ReadError, ReadRef, SectionIndex, SymbolIndex}; |
7 | |
8 | use super::{ElfFile, FileHeader, SectionHeader, Sym}; |
9 | |
10 | /// An iterator for the COMDAT section groups in an [`ElfFile32`](super::ElfFile32). |
11 | pub 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). |
14 | pub 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)] |
19 | pub struct ElfComdatIterator<'data, 'file, Elf, R = &'data [u8]> |
20 | where |
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 | |
28 | impl<'data, 'file, Elf, R> ElfComdatIterator<'data, 'file, Elf, R> |
29 | where |
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: impl Iterator = file.sections.iter().enumerate(); |
37 | iter.next(); // Skip null section. |
38 | ElfComdatIterator { file, iter } |
39 | } |
40 | } |
41 | |
42 | impl<'data, 'file, Elf, R> Iterator for ElfComdatIterator<'data, 'file, Elf, R> |
43 | where |
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: usize, section: &'data ::SectionHeader) in self.iter.by_ref() { |
51 | if let Some(comdat: ElfComdat<'_, '_, Elf, R>) = 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). |
60 | pub 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). |
63 | pub 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)] |
70 | pub struct ElfComdat<'data, 'file, Elf, R = &'data [u8]> |
71 | where |
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 | |
80 | impl<'data, 'file, Elf, R> ElfComdat<'data, 'file, Elf, R> |
81 | where |
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 | |
111 | impl<'data, 'file, Elf, R> read::private::Sealed for ElfComdat<'data, 'file, Elf, R> |
112 | where |
113 | Elf: FileHeader, |
114 | R: ReadRef<'data>, |
115 | { |
116 | } |
117 | |
118 | impl<'data, 'file, Elf, R> ObjectComdat<'data> for ElfComdat<'data, 'file, Elf, R> |
119 | where |
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). |
158 | pub 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). |
161 | pub 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)] |
166 | pub struct ElfComdatSectionIterator<'data, 'file, Elf, R = &'data [u8]> |
167 | where |
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 | |
175 | impl<'data, 'file, Elf, R> Iterator for ElfComdatSectionIterator<'data, 'file, Elf, R> |
176 | where |
177 | Elf: FileHeader, |
178 | R: ReadRef<'data>, |
179 | { |
180 | type Item = SectionIndex; |
181 | |
182 | fn next(&mut self) -> Option<Self::Item> { |
183 | let index: &'data U32Bytes<{unknown}> = self.sections.next()?; |
184 | Some(SectionIndex(index.get(self.file.endian) as usize)) |
185 | } |
186 | } |
187 | |