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, Permissions, 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.0)
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 #[inline]
150 fn permissions(&self) -> Permissions {
151 let p_flags = self.segment.p_flags(self.file.endian);
152 Permissions::new(
153 p_flags & elf::PF_R != 0,
154 p_flags & elf::PF_W != 0,
155 p_flags & elf::PF_X != 0,
156 )
157 }
158}
159
160#[allow(missing_docs)]
162pub trait ProgramHeader: Debug + Pod {
163 type Elf: FileHeader<ProgramHeader = Self, Endian = Self::Endian, Word = Self::Word>;
164 type Word: Into<u64>;
165 type Endian: endian::Endian;
166
167 fn p_type(&self, endian: Self::Endian) -> u32;
168 fn p_flags(&self, endian: Self::Endian) -> u32;
169 fn p_offset(&self, endian: Self::Endian) -> Self::Word;
170 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word;
171 fn p_paddr(&self, endian: Self::Endian) -> Self::Word;
172 fn p_filesz(&self, endian: Self::Endian) -> Self::Word;
173 fn p_memsz(&self, endian: Self::Endian) -> Self::Word;
174 fn p_align(&self, endian: Self::Endian) -> Self::Word;
175
176 fn file_range(&self, endian: Self::Endian) -> (u64, u64) {
178 (self.p_offset(endian).into(), self.p_filesz(endian).into())
179 }
180
181 fn data<'data, R: ReadRef<'data>>(
185 &self,
186 endian: Self::Endian,
187 data: R,
188 ) -> Result<&'data [u8], ()> {
189 let (offset, size) = self.file_range(endian);
190 data.read_bytes_at(offset, size)
191 }
192
193 fn data_as_array<'data, T: Pod, R: ReadRef<'data>>(
199 &self,
200 endian: Self::Endian,
201 data: R,
202 ) -> Result<&'data [T], ()> {
203 pod::slice_from_all_bytes(self.data(endian, data)?)
204 }
205
206 fn data_range<'data, R: ReadRef<'data>>(
211 &self,
212 endian: Self::Endian,
213 data: R,
214 address: u64,
215 size: u64,
216 ) -> Result<Option<&'data [u8]>, ()> {
217 Ok(read::util::data_range(
218 self.data(endian, data)?,
219 self.p_vaddr(endian).into(),
220 address,
221 size,
222 ))
223 }
224
225 fn dynamic<'data, R: ReadRef<'data>>(
230 &self,
231 endian: Self::Endian,
232 data: R,
233 ) -> read::Result<Option<&'data [<Self::Elf as FileHeader>::Dyn]>> {
234 if self.p_type(endian) != elf::PT_DYNAMIC {
235 return Ok(None);
236 }
237 let dynamic = self
238 .data_as_array(endian, data)
239 .read_error("Invalid ELF dynamic segment offset or size")?;
240 Ok(Some(dynamic))
241 }
242
243 fn interpreter<'data, R: ReadRef<'data>>(
248 &self,
249 endian: Self::Endian,
250 data: R,
251 ) -> read::Result<Option<&'data [u8]>> {
252 if self.p_type(endian) != elf::PT_INTERP {
253 return Ok(None);
254 }
255 let data = self
256 .data(endian, data)
257 .read_error("Invalid ELF interpreter segment offset or size")?;
258 let len = data
259 .iter()
260 .position(|&b| b == 0)
261 .read_error("Invalid ELF interpreter segment data")?;
262 Ok(Some(&data[..len]))
263 }
264
265 fn notes<'data, R: ReadRef<'data>>(
270 &self,
271 endian: Self::Endian,
272 data: R,
273 ) -> read::Result<Option<NoteIterator<'data, Self::Elf>>> {
274 if self.p_type(endian) != elf::PT_NOTE {
275 return Ok(None);
276 }
277 let data = self
278 .data(endian, data)
279 .read_error("Invalid ELF note segment offset or size")?;
280 let notes = NoteIterator::new(endian, self.p_align(endian), data)?;
281 Ok(Some(notes))
282 }
283}
284
285impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader32<Endian> {
286 type Word = u32;
287 type Endian = Endian;
288 type Elf = elf::FileHeader32<Endian>;
289
290 #[inline]
291 fn p_type(&self, endian: Self::Endian) -> u32 {
292 self.p_type.get(endian)
293 }
294
295 #[inline]
296 fn p_flags(&self, endian: Self::Endian) -> u32 {
297 self.p_flags.get(endian)
298 }
299
300 #[inline]
301 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
302 self.p_offset.get(endian)
303 }
304
305 #[inline]
306 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
307 self.p_vaddr.get(endian)
308 }
309
310 #[inline]
311 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
312 self.p_paddr.get(endian)
313 }
314
315 #[inline]
316 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
317 self.p_filesz.get(endian)
318 }
319
320 #[inline]
321 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
322 self.p_memsz.get(endian)
323 }
324
325 #[inline]
326 fn p_align(&self, endian: Self::Endian) -> Self::Word {
327 self.p_align.get(endian)
328 }
329}
330
331impl<Endian: endian::Endian> ProgramHeader for elf::ProgramHeader64<Endian> {
332 type Word = u64;
333 type Endian = Endian;
334 type Elf = elf::FileHeader64<Endian>;
335
336 #[inline]
337 fn p_type(&self, endian: Self::Endian) -> u32 {
338 self.p_type.get(endian)
339 }
340
341 #[inline]
342 fn p_flags(&self, endian: Self::Endian) -> u32 {
343 self.p_flags.get(endian)
344 }
345
346 #[inline]
347 fn p_offset(&self, endian: Self::Endian) -> Self::Word {
348 self.p_offset.get(endian)
349 }
350
351 #[inline]
352 fn p_vaddr(&self, endian: Self::Endian) -> Self::Word {
353 self.p_vaddr.get(endian)
354 }
355
356 #[inline]
357 fn p_paddr(&self, endian: Self::Endian) -> Self::Word {
358 self.p_paddr.get(endian)
359 }
360
361 #[inline]
362 fn p_filesz(&self, endian: Self::Endian) -> Self::Word {
363 self.p_filesz.get(endian)
364 }
365
366 #[inline]
367 fn p_memsz(&self, endian: Self::Endian) -> Self::Word {
368 self.p_memsz.get(endian)
369 }
370
371 #[inline]
372 fn p_align(&self, endian: Self::Endian) -> Self::Word {
373 self.p_align.get(endian)
374 }
375}