1 | use core::fmt::Debug; |
2 | use core::{mem, slice, str}; |
3 | |
4 | use crate::elf; |
5 | use crate::endian::{self, Endianness}; |
6 | use crate::pod::Pod; |
7 | use crate::read::{self, Bytes, 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: &::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 | 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 | |
77 | impl<'data, 'file, Elf, R> read::private::Sealed for ElfSegment<'data, 'file, Elf, R> |
78 | where |
79 | Elf: FileHeader, |
80 | R: ReadRef<'data>, |
81 | { |
82 | } |
83 | |
84 | impl<'data, 'file, Elf, R> ObjectSegment<'data> for ElfSegment<'data, 'file, Elf, R> |
85 | where |
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)] |
142 | pub 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 | |
244 | impl<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 | |
290 | impl<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 | |