1use core::fmt::Debug;
2use core::{slice, str};
3
4use crate::elf;
5use crate::endian::{self, Endianness};
6use crate::pod::{self, Pod};
7use crate::read::{self, ObjectSegment, ReadError, ReadRef, SegmentFlags};
8
9use super::{ElfFile, FileHeader, NoteIterator};
10
11pub type ElfSegmentIterator32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
13 ElfSegmentIterator<'data, 'file, elf::FileHeader32<Endian>, R>;
14pub type ElfSegmentIterator64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
16 ElfSegmentIterator<'data, 'file, elf::FileHeader64<Endian>, R>;
17
18#[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 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
49pub type ElfSegment32<'data, 'file, Endian = Endianness, R = &'data [u8]> =
51 ElfSegment<'data, 'file, elf::FileHeader32<Endian>, R>;
52pub type ElfSegment64<'data, 'file, Endian = Endianness, R = &'data [u8]> =
54 ElfSegment<'data, 'file, elf::FileHeader64<Endian>, R>;
55
56#[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 pub fn elf_file(&self) -> &'file ElfFile<'data, Elf, R> {
72 self.file
73 }
74
75 pub fn elf_program_header(&self) -> &'data Elf::ProgramHeader {
77 self.segment
78 }
79
80 fn bytes(&self) -> read::Result<&'data [u8]> {
81 self.segment
82 .data(self.file.endian, self.file.data)
83 .read_error("Invalid ELF segment size or offset")
84 }
85}
86
87impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R>
88where
89 Elf: FileHeader,
90 R: ReadRef<'data>,
91{
92}
93
94impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R>
95where
96 Elf: FileHeader,
97 R: ReadRef<'data>,
98{
99 #[inline]
100 fn address(&self) -> u64 {
101 self.segment.p_vaddr(self.file.endian).into()
102 }
103
104 #[inline]
105 fn size(&self) -> u64 {
106 self.segment.p_memsz(self.file.endian).into()
107 }
108
109 #[inline]
110 fn align(&self) -> u64 {
111 self.segment.p_align(self.file.endian).into()
112 }
113
114 #[inline]
115 fn file_range(&self) -> (u64, u64) {
116 self.segment.file_range(self.file.endian)
117 }
118
119 #[inline]
120 fn data(&self) -> read::Result<&'data [u8]> {
121 self.bytes()
122 }
123
124 fn data_range(&self, address: u64, size: u64) -> read::Result<Option<&'data [u8]>> {
125 Ok(read::util::data_range(
126 self.bytes()?,
127 self.address(),
128 address,
129 size,
130 ))
131 }
132
133 #[inline]
134 fn name_bytes(&self) -> read::Result<Option<&[u8]>> {
135 Ok(None)
136 }
137
138 #[inline]
139 fn name(&self) -> read::Result<Option<&str>> {
140 Ok(None)
141 }
142
143 #[inline]
144 fn flags(&self) -> SegmentFlags {
145 let p_flags = self.segment.p_flags(self.file.endian);
146 SegmentFlags::Elf { p_flags }
147 }
148}
149
150#[allow(missing_docs)]
152pub trait ProgramHeader: Debug + Pod {
153 type Elf: FileHeader<ProgramHeader = Self, Endian = Self::Endian, Word = Self::Word>;
154 type Word: Into<u64>;
155 type Endian: endian::Endian;
156
157 fn p_type(&self, endian: Self::Endian) -> u32;
158 fn p_flags(&self, endian: Self::Endian) -> u32;
159 fn p_offset(&self, endian: Self::Endian) -> Self::Word;
160 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word;
161 fn p_paddr(&self, endian: Self::Endian) -> Self::Word;
162 fn p_filesz(&self, endian: Self::Endian) -> Self::Word;
163 fn p_memsz(&self, endian: Self::Endian) -> Self::Word;
164 fn p_align(&self, endian: Self::Endian) -> Self::Word;
165
166 fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
168 (self.p_offset(endian).into(), self.p_filesz(endian).into())
169 }
170
171 fn data<'data, R: ReadRef<'data>>(
175 &self,
176 endian: Self::Endian,
177 data: R,
178 ) -> Result<&'data [u8], ()> {
179 let (offset, size) = self.file_range(endian);
180 data.read_bytes_at(offset, size)
181 }
182
183 fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
189 &self,
190 endian: Self::Endian,
191 data: R,
192 ) -> Result<&'data [T], ()> {
193 pod::slice_from_all_bytes(self.data(endian, data)?)
194 }
195
196 fn data_range<'data, R: ReadRef<'data>>(
201 &self,
202 endian: Self::Endian,
203 data: R,
204 address: u64,
205 size: u64,
206 ) -> Result<Option<&'data [u8]>, ()> {
207 Ok(read::util::data_range(
208 self.data(endian, data)?,
209 self.p_vaddr(endian).into(),
210 address,
211 size,
212 ))
213 }
214
215 fn dynamic<'data, R: ReadRef<'data>>(
220 &self,
221 endian: Self::Endian,
222 data: R,
223 ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Dyn]>> {
224 if self.p_type(endian) != elf::PT_DYNAMIC {
225 return Ok(None);
226 }
227 let dynamic = self
228 .data_as_array(endian, data)
229 .read_error("Invalid ELF dynamic segment offset or size")?;
230 Ok(Some(dynamic))
231 }
232
233 fn interpreter<'data, R: ReadRef<'data>>(
238 &self,
239 endian: Self::Endian,
240 data: R,
241 ) -> read::Result<Option<&'data [u8]>> {
242 if self.p_type(endian) != elf::PT_INTERP {
243 return Ok(None);
244 }
245 let data = self
246 .data(endian, data)
247 .read_error("Invalid ELF interpreter segment offset or size")?;
248 let len = data
249 .iter()
250 .position(|&b| b == 0)
251 .read_error("Invalid ELF interpreter segment data")?;
252 Ok(Some(&data[..len]))
253 }
254
255 fn notes<'data, R: ReadRef<'data>>(
260 &self,
261 endian: Self::Endian,
262 data: R,
263 ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
264 if self.p_type(endian) != elf::PT_NOTE {
265 return Ok(None);
266 }
267 let data = self
268 .data(endian, data)
269 .read_error("Invalid ELF note segment offset or size")?;
270 let notes = NoteIterator::new(endian, self.p_align(endian), data)?;
271 Ok(Some(notes))
272 }
273}
274
275impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader32<Endian> {
276 type Word = u32;
277 type Endian = Endian;
278 type Elf = elf::FileHeader32<Endian>;
279
280 #[inline]
281 fn p_type(&self, endian: Self::Endian) -> u32 {
282 self.p_type.get(endian)
283 }
284
285 #[inline]
286 fn p_flags(&self, endian: Self::Endian) -> u32 {
287 self.p_flags.get(endian)
288 }
289
290 #[inline]
291 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
292 self.p_offset.get(endian)
293 }
294
295 #[inline]
296 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
297 self.p_vaddr.get(endian)
298 }
299
300 #[inline]
301 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
302 self.p_paddr.get(endian)
303 }
304
305 #[inline]
306 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
307 self.p_filesz.get(endian)
308 }
309
310 #[inline]
311 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
312 self.p_memsz.get(endian)
313 }
314
315 #[inline]
316 fn p_align(&self, endian: Self::Endian) -> Self::Word {
317 self.p_align.get(endian)
318 }
319}
320
321impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader64<Endian> {
322 type Word = u64;
323 type Endian = Endian;
324 type Elf = elf::FileHeader64<Endian>;
325
326 #[inline]
327 fn p_type(&self, endian: Self::Endian) -> u32 {
328 self.p_type.get(endian)
329 }
330
331 #[inline]
332 fn p_flags(&self, endian: Self::Endian) -> u32 {
333 self.p_flags.get(endian)
334 }
335
336 #[inline]
337 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
338 self.p_offset.get(endian)
339 }
340
341 #[inline]
342 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
343 self.p_vaddr.get(endian)
344 }
345
346 #[inline]
347 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
348 self.p_paddr.get(endian)
349 }
350
351 #[inline]
352 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
353 self.p_filesz.get(endian)
354 }
355
356 #[inline]
357 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
358 self.p_memsz.get(endian)
359 }
360
361 #[inline]
362 fn p_align(&self, endian: Self::Endian) -> Self::Word {
363 self.p_align.get(endian)
364 }
365}