1use core::fmt::Debug;
2use core::{mem, slice, str};
3
4use crate::elf;
5use crate::endian::{self, Endianness};
6use crate::pod::Pod;
7use crate::read::{self, Bytes, ObjectSegment, ReadError, ReadRef, SegmentFlags};
8
9use super::{ElfFile, FileHeader, NoteIterator};
10
11/// An iterator for the segments in an [`ElfFile32`](super::ElfFile32).
12pub type ElfSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
13 ElfSegmentIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
14/// An iterator for the segments in an [`ElfFile64`](super::ElfFile64).
15pub type ElfSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
16 ElfSegmentIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
17
18/// An iterator for the segments in an [`ElfFile`].
19#[derive(Debug)]
20pub struct ElfSegmentIterator<'data, 'file, Elf, R = &'data [u8]>
21where
22 Elf: FileHeader,
23 R: ReadRef<'data>,
24{
25 pub(super) file: &'file ElfFile<'data, Elf, R>,
26 pub(super) iter: slice::Iter<'data, Elf::ProgramHeader>,
27}
28
29impl<'data, 'file, Elf, R> Iterator for ElfSegmentIterator<'data, 'file, Elf, R>
30where
31 Elf: FileHeader,
32 R: ReadRef<'data>,
33{
34 type Item = ElfSegment<'data, 'file, Elf, R>;
35
36 fn next(&mut self) -> Option<Self::Item> {
37 for segment: &::ProgramHeader in self.iter.by_ref() {
38 if segment.p_type(self.file.endian) == elf::PT_LOAD {
39 return Some(ElfSegment {
40 file: self.file,
41 segment,
42 });
43 }
44 }
45 None
46 }
47}
48
49/// A segment in an [`ElfFile32`](super::ElfFile32).
50pub type ElfSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
51 ElfSegment<'data, 'file, elf::FileHeader32<Endian>, R>;
52/// A segment in an [`ElfFile64`](super::ElfFile64).
53pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
54 ElfSegment<'data, 'file, elf::FileHeader64<Endian>, R>;
55
56/// A segment in an [`ElfFile`].
57///
58/// Most functionality is provided by the [`ObjectSegment`] trait implementation.
59#[derive(Debug)]
60pub struct ElfSegment<'data, 'file, Elf, R = &'data [u8]>
61where
62 Elf: FileHeader,
63 R: ReadRef<'data>,
64{
65 pub(super) file: &'file ElfFile<'data, Elf, R>,
66 pub(super) segment: &'data Elf::ProgramHeader,
67}
68
69impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSegment<'data, 'file, Elf, R> {
70 fn bytes(&self) -> read::Result<&'data [u8]> {
71 self.segment
72 .data(self.file.endian, self.file.data)
73 .read_error("Invalid ELF segment size or offset")
74 }
75}
76
77impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R>
78where
79 Elf: FileHeader,
80 R: ReadRef<'data>,
81{
82}
83
84impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R>
85where
86 Elf: FileHeader,
87 R: ReadRef<'data>,
88{
89 #[inline]
90 fn address(&self) -> u64 {
91 self.segment.p_vaddr(self.file.endian).into()
92 }
93
94 #[inline]
95 fn size(&self) -> u64 {
96 self.segment.p_memsz(self.file.endian).into()
97 }
98
99 #[inline]
100 fn align(&self) -> u64 {
101 self.segment.p_align(self.file.endian).into()
102 }
103
104 #[inline]
105 fn file_range(&self) -> (u64, u64) {
106 self.segment.file_range(self.file.endian)
107 }
108
109 #[inline]
110 fn data(&self) -> read::Result<&'data [u8]> {
111 self.bytes()
112 }
113
114 fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
115 Ok(read::util::data_range(
116 self.bytes()?,
117 self.address(),
118 address,
119 size,
120 ))
121 }
122
123 #[inline]
124 fn name_bytes(&self) -> read::Result<Option<&[u8]>> {
125 Ok(None)
126 }
127
128 #[inline]
129 fn name(&self) -> read::Result<Option<&str>> {
130 Ok(None)
131 }
132
133 #[inline]
134 fn flags(&self) -> SegmentFlags {
135 let p_flags = self.segment.p_flags(self.file.endian);
136 SegmentFlags::Elf { p_flags }
137 }
138}
139
140/// A trait for generic access to [`elf::ProgramHeader32`] and [`elf::ProgramHeader64`].
141#[allow(missing_docs)]
142pub trait ProgramHeader: Debug + Pod {
143 type Elf: FileHeader<ProgramHeader = Self, Endian = Self::Endian, Word = Self::Word>;
144 type Word: Into<u64>;
145 type Endian: endian::Endian;
146
147 fn p_type(&self, endian: Self::Endian) -> u32;
148 fn p_flags(&self, endian: Self::Endian) -> u32;
149 fn p_offset(&self, endian: Self::Endian) -> Self::Word;
150 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word;
151 fn p_paddr(&self, endian: Self::Endian) -> Self::Word;
152 fn p_filesz(&self, endian: Self::Endian) -> Self::Word;
153 fn p_memsz(&self, endian: Self::Endian) -> Self::Word;
154 fn p_align(&self, endian: Self::Endian) -> Self::Word;
155
156 /// Return the offset and size of the segment in the file.
157 fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
158 (self.p_offset(endian).into(), self.p_filesz(endian).into())
159 }
160
161 /// Return the segment data.
162 ///
163 /// Returns `Err` for invalid values.
164 fn data<'data, R: ReadRef<'data>>(
165 &self,
166 endian: Self::Endian,
167 data: R,
168 ) -> Result<&'data [u8], ()> {
169 let (offset, size) = self.file_range(endian);
170 data.read_bytes_at(offset, size)
171 }
172
173 /// Return the segment data as a slice of the given type.
174 ///
175 /// Allows padding at the end of the data.
176 /// Returns `Ok(&[])` if the segment has no data.
177 /// Returns `Err` for invalid values, including bad alignment.
178 fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
179 &self,
180 endian: Self::Endian,
181 data: R,
182 ) -> Result<&'data [T], ()> {
183 let mut data = self.data(endian, data).map(Bytes)?;
184 data.read_slice(data.len() / mem::size_of::<T>())
185 }
186
187 /// Return the segment data in the given virtual address range
188 ///
189 /// Returns `Ok(None)` if the segment does not contain the address.
190 /// Returns `Err` for invalid values.
191 fn data_range<'data, R: ReadRef<'data>>(
192 &self,
193 endian: Self::Endian,
194 data: R,
195 address: u64,
196 size: u64,
197 ) -> Result<Option<&'data [u8]>, ()> {
198 Ok(read::util::data_range(
199 self.data(endian, data)?,
200 self.p_vaddr(endian).into(),
201 address,
202 size,
203 ))
204 }
205
206 /// Return entries in a dynamic segment.
207 ///
208 /// Returns `Ok(None)` if the segment is not `PT_DYNAMIC`.
209 /// Returns `Err` for invalid values.
210 fn dynamic<'data, R: ReadRef<'data>>(
211 &self,
212 endian: Self::Endian,
213 data: R,
214 ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Dyn]>> {
215 if self.p_type(endian) != elf::PT_DYNAMIC {
216 return Ok(None);
217 }
218 let dynamic = self
219 .data_as_array(endian, data)
220 .read_error("Invalid ELF dynamic segment offset or size")?;
221 Ok(Some(dynamic))
222 }
223
224 /// Return a note iterator for the segment data.
225 ///
226 /// Returns `Ok(None)` if the segment does not contain notes.
227 /// Returns `Err` for invalid values.
228 fn notes<'data, R: ReadRef<'data>>(
229 &self,
230 endian: Self::Endian,
231 data: R,
232 ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
233 if self.p_type(endian) != elf::PT_NOTE {
234 return Ok(None);
235 }
236 let data = self
237 .data(endian, data)
238 .read_error("Invalid ELF note segment offset or size")?;
239 let notes = NoteIterator::new(endian, self.p_align(endian), data)?;
240 Ok(Some(notes))
241 }
242}
243
244impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader32<Endian> {
245 type Word = u32;
246 type Endian = Endian;
247 type Elf = elf::FileHeader32<Endian>;
248
249 #[inline]
250 fn p_type(&self, endian: Self::Endian) -> u32 {
251 self.p_type.get(endian)
252 }
253
254 #[inline]
255 fn p_flags(&self, endian: Self::Endian) -> u32 {
256 self.p_flags.get(endian)
257 }
258
259 #[inline]
260 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
261 self.p_offset.get(endian)
262 }
263
264 #[inline]
265 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
266 self.p_vaddr.get(endian)
267 }
268
269 #[inline]
270 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
271 self.p_paddr.get(endian)
272 }
273
274 #[inline]
275 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
276 self.p_filesz.get(endian)
277 }
278
279 #[inline]
280 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
281 self.p_memsz.get(endian)
282 }
283
284 #[inline]
285 fn p_align(&self, endian: Self::Endian) -> Self::Word {
286 self.p_align.get(endian)
287 }
288}
289
290impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader64<Endian> {
291 type Word = u64;
292 type Endian = Endian;
293 type Elf = elf::FileHeader64<Endian>;
294
295 #[inline]
296 fn p_type(&self, endian: Self::Endian) -> u32 {
297 self.p_type.get(endian)
298 }
299
300 #[inline]
301 fn p_flags(&self, endian: Self::Endian) -> u32 {
302 self.p_flags.get(endian)
303 }
304
305 #[inline]
306 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
307 self.p_offset.get(endian)
308 }
309
310 #[inline]
311 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
312 self.p_vaddr.get(endian)
313 }
314
315 #[inline]
316 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
317 self.p_paddr.get(endian)
318 }
319
320 #[inline]
321 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
322 self.p_filesz.get(endian)
323 }
324
325 #[inline]
326 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
327 self.p_memsz.get(endian)
328 }
329
330 #[inline]
331 fn p_align(&self, endian: Self::Endian) -> Self::Word {
332 self.p_align.get(endian)
333 }
334}
335