1 | use core::fmt::Debug; |
2 | use core::{slice, str}; |
3 | |
4 | use crate::elf; |
5 | use crate::endian::{self, Endianness}; |
6 | use crate::pod::{self, Pod}; |
7 | use crate::read::{self, ObjectSegment, ReadError, ReadRef, SegmentFlags}; |
8 | |
9 | use super::{ElfFile, FileHeader, NoteIterator}; |
10 | |
11 | /// An iterator for the segments in an [`ElfFile32`](super::ElfFile32). |
12 | pub 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). |
15 | pub 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)] |
20 | pub struct ElfSegmentIterator<'data, 'file, Elf, R = &'data [u8]> |
21 | where |
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 | |
29 | impl<'data, 'file, Elf, R> Iterator for ElfSegmentIterator<'data, 'file, Elf, R> |
30 | where |
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: &'data ::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). |
50 | pub 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). |
53 | pub 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)] |
60 | pub struct ElfSegment<'data, 'file, Elf, R = &'data [u8]> |
61 | where |
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 | |
69 | impl<'data, 'file, Elf: FileHeader, R: ReadRef<'data>> ElfSegment<'data, 'file, Elf, R> { |
70 | /// Get the ELF file containing this segment. |
71 | pub fn elf_file(&self) -> &'file ElfFile<'data, Elf, R> { |
72 | self.file |
73 | } |
74 | |
75 | /// Get the raw ELF program header for the segment. |
76 | 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 | |
87 | impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R> |
88 | where |
89 | Elf: FileHeader, |
90 | R: ReadRef<'data>, |
91 | { |
92 | } |
93 | |
94 | impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R> |
95 | where |
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 | /// A trait for generic access to [`elf::ProgramHeader32`] and [`elf::ProgramHeader64`]. |
151 | #[allow (missing_docs)] |
152 | pub 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 | /// Return the offset and size of the segment in the file. |
167 | fn file_range(&self, endian: Self::Endian) -> (u64, u64) { |
168 | (self.p_offset(endian).into(), self.p_filesz(endian).into()) |
169 | } |
170 | |
171 | /// Return the segment data. |
172 | /// |
173 | /// Returns `Err` for invalid values. |
174 | 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 | /// Return the segment data as a slice of the given type. |
184 | /// |
185 | /// Allows padding at the end of the data. |
186 | /// Returns `Ok(&[])` if the segment has no data. |
187 | /// Returns `Err` for invalid values, including bad alignment. |
188 | 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 | /// Return the segment data in the given virtual address range |
197 | /// |
198 | /// Returns `Ok(None)` if the segment does not contain the address. |
199 | /// Returns `Err` for invalid values. |
200 | 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 | /// Return entries in a dynamic segment. |
216 | /// |
217 | /// Returns `Ok(None)` if the segment is not `PT_DYNAMIC`. |
218 | /// Returns `Err` for invalid values. |
219 | 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 | /// Return the data in an interpreter segment. |
234 | /// |
235 | /// Returns `Ok(None)` if the segment is not `PT_INTERP`. |
236 | /// Returns `Err` for invalid values. |
237 | 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 | /// Return a note iterator for the segment data. |
256 | /// |
257 | /// Returns `Ok(None)` if the segment does not contain notes. |
258 | /// Returns `Err` for invalid values. |
259 | 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 | |
275 | impl<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 | |
321 | impl<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 | } |
366 | |