1 /* Legal values for p_type (segment type). */
2
3 /// Program header table entry unused
4 pub const PT_NULL: u32 = 0;
5 /// Loadable program segment
6 pub const PT_LOAD: u32 = 1;
7 /// Dynamic linking information
8 pub const PT_DYNAMIC: u32 = 2;
9 /// Program interpreter
10 pub const PT_INTERP: u32 = 3;
11 /// Auxiliary information
12 pub const PT_NOTE: u32 = 4;
13 /// Reserved
14 pub const PT_SHLIB: u32 = 5;
15 /// Entry for header table itself
16 pub const PT_PHDR: u32 = 6;
17 /// Thread-local storage segment
18 pub const PT_TLS: u32 = 7;
19 /// Number of defined types
20 pub const PT_NUM: u32 = 8;
21 /// Start of OS-specific
22 pub const PT_LOOS: u32 = 0x6000_0000;
23 /// GCC .eh_frame_hdr segment
24 pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550;
25 /// Indicates stack executability
26 pub const PT_GNU_STACK: u32 = 0x6474_e551;
27 /// Read-only after relocation
28 pub const PT_GNU_RELRO: u32 = 0x6474_e552;
29 /// Sun Specific segment
30 pub const PT_LOSUNW: u32 = 0x6fff_fffa;
31 /// Sun Specific segment
32 pub const PT_SUNWBSS: u32 = 0x6fff_fffa;
33 /// Stack segment
34 pub const PT_SUNWSTACK: u32 = 0x6fff_fffb;
35 /// End of OS-specific
36 pub const PT_HISUNW: u32 = 0x6fff_ffff;
37 /// End of OS-specific
38 pub const PT_HIOS: u32 = 0x6fff_ffff;
39 /// Start of processor-specific
40 pub const PT_LOPROC: u32 = 0x7000_0000;
41 /// ARM unwind segment
42 pub const PT_ARM_EXIDX: u32 = 0x7000_0001;
43 /// End of processor-specific
44 pub const PT_HIPROC: u32 = 0x7fff_ffff;
45
46 /* Legal values for p_flags (segment flags). */
47
48 /// Segment is executable
49 pub const PF_X: u32 = 1;
50 /// Segment is writable
51 pub const PF_W: u32 = 1 << 1;
52 /// Segment is readable
53 pub const PF_R: u32 = 1 << 2;
54
pt_to_str(pt: u32) -> &'static str55 pub fn pt_to_str(pt: u32) -> &'static str {
56 match pt {
57 PT_NULL => "PT_NULL",
58 PT_LOAD => "PT_LOAD",
59 PT_DYNAMIC => "PT_DYNAMIC",
60 PT_INTERP => "PT_INTERP",
61 PT_NOTE => "PT_NOTE",
62 PT_SHLIB => "PT_SHLIB",
63 PT_PHDR => "PT_PHDR",
64 PT_TLS => "PT_TLS",
65 PT_NUM => "PT_NUM",
66 PT_LOOS => "PT_LOOS",
67 PT_GNU_EH_FRAME => "PT_GNU_EH_FRAME",
68 PT_GNU_STACK => "PT_GNU_STACK",
69 PT_GNU_RELRO => "PT_GNU_RELRO",
70 PT_SUNWBSS => "PT_SUNWBSS",
71 PT_SUNWSTACK => "PT_SUNWSTACK",
72 PT_HIOS => "PT_HIOS",
73 PT_LOPROC => "PT_LOPROC",
74 PT_HIPROC => "PT_HIPROC",
75 PT_ARM_EXIDX => "PT_ARM_EXIDX",
76 _ => "UNKNOWN_PT",
77 }
78 }
79
80 if_alloc! {
81 use core::fmt;
82 use scroll::ctx;
83 use core::result;
84 use core::ops::Range;
85 use crate::container::{Ctx, Container};
86 use crate::alloc::vec::Vec;
87
88 #[derive(Default, PartialEq, Clone)]
89 /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants
90 pub struct ProgramHeader {
91 pub p_type : u32,
92 pub p_flags : u32,
93 pub p_offset: u64,
94 pub p_vaddr : u64,
95 pub p_paddr : u64,
96 pub p_filesz: u64,
97 pub p_memsz : u64,
98 pub p_align : u64,
99 }
100
101 impl ProgramHeader {
102 /// Return the size of the underlying program header, given a `Ctx`
103 #[inline]
104 pub fn size(ctx: Ctx) -> usize {
105 use scroll::ctx::SizeWith;
106 Self::size_with(&ctx)
107 }
108 /// Create a new `PT_LOAD` ELF program header
109 pub fn new() -> Self {
110 ProgramHeader {
111 p_type : PT_LOAD,
112 p_flags : 0,
113 p_offset: 0,
114 p_vaddr : 0,
115 p_paddr : 0,
116 p_filesz: 0,
117 p_memsz : 0,
118 //TODO: check if this is true for 32-bit pt_load
119 p_align : 2 << 20,
120 }
121 }
122 /// Returns this program header's file offset range
123 pub fn file_range(&self) -> Range<usize> {
124 (self.p_offset as usize..self.p_offset as usize + self.p_filesz as usize)
125 }
126 /// Returns this program header's virtual memory range
127 pub fn vm_range(&self) -> Range<usize> {
128 (self.p_vaddr as usize..self.p_vaddr as usize + self.p_memsz as usize)
129 }
130 /// Sets the executable flag
131 pub fn executable(&mut self) {
132 self.p_flags |= PF_X;
133 }
134 /// Sets the write flag
135 pub fn write(&mut self) {
136 self.p_flags |= PF_W;
137 }
138 /// Sets the read flag
139 pub fn read(&mut self) {
140 self.p_flags |= PF_R;
141 }
142 /// Whether this program header is executable
143 pub fn is_executable(&self) -> bool {
144 self.p_flags & PF_X != 0
145 }
146 /// Whether this program header is readable
147 pub fn is_read(&self) -> bool {
148 self.p_flags & PF_R != 0
149 }
150 /// Whether this program header is writable
151 pub fn is_write(&self) -> bool {
152 self.p_flags & PF_W != 0
153 }
154 #[cfg(feature = "endian_fd")]
155 pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> crate::error::Result<Vec<ProgramHeader>> {
156 use scroll::Pread;
157 let mut program_headers = Vec::with_capacity(count);
158 for _ in 0..count {
159 let phdr = bytes.gread_with(&mut offset, ctx)?;
160 program_headers.push(phdr);
161 }
162 Ok(program_headers)
163 }
164 }
165
166 impl fmt::Debug for ProgramHeader {
167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 f.debug_struct("ProgramHeader")
169 .field("p_type", &pt_to_str(self.p_type))
170 .field("p_flags", &format_args!("0x{:x}", self.p_flags))
171 .field("p_offset", &format_args!("0x{:x}", self.p_offset))
172 .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr))
173 .field("p_paddr", &format_args!("0x{:x}", self.p_paddr))
174 .field("p_filesz", &format_args!("0x{:x}", self.p_filesz))
175 .field("p_memsz", &format_args!("0x{:x}", self.p_memsz))
176 .field("p_align", &self.p_align)
177 .finish()
178 }
179 }
180
181 impl ctx::SizeWith<Ctx> for ProgramHeader {
182 fn size_with(ctx: &Ctx) -> usize {
183 match ctx.container {
184 Container::Little => {
185 program_header32::SIZEOF_PHDR
186 },
187 Container::Big => {
188 program_header64::SIZEOF_PHDR
189 },
190 }
191 }
192 }
193
194 impl<'a> ctx::TryFromCtx<'a, Ctx> for ProgramHeader {
195 type Error = crate::error::Error;
196 fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
197 use scroll::Pread;
198 let res = match container {
199 Container::Little => {
200 (bytes.pread_with::<program_header32::ProgramHeader>(0, le)?.into(), program_header32::SIZEOF_PHDR)
201 },
202 Container::Big => {
203 (bytes.pread_with::<program_header64::ProgramHeader>(0, le)?.into(), program_header64::SIZEOF_PHDR)
204 }
205 };
206 Ok(res)
207 }
208 }
209
210 impl ctx::TryIntoCtx<Ctx> for ProgramHeader {
211 type Error = crate::error::Error;
212 fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
213 use scroll::Pwrite;
214 match container {
215 Container::Little => {
216 let phdr: program_header32::ProgramHeader = self.into();
217 Ok(bytes.pwrite_with(phdr, 0, le)?)
218 },
219 Container::Big => {
220 let phdr: program_header64::ProgramHeader = self.into();
221 Ok(bytes.pwrite_with(phdr, 0, le)?)
222 }
223 }
224 }
225 }
226 } // end if_alloc
227
228 macro_rules! elf_program_header_std_impl { ($size:ty) => {
229
230 #[cfg(test)]
231 mod tests {
232 use super::*;
233 #[test]
234 fn size_of() {
235 assert_eq!(::std::mem::size_of::<ProgramHeader>(), SIZEOF_PHDR);
236 }
237 }
238
239 if_alloc! {
240
241 use crate::elf::program_header::ProgramHeader as ElfProgramHeader;
242 #[cfg(any(feature = "std", feature = "endian_fd"))]
243 use crate::error::Result;
244
245 use core::slice;
246 use core::fmt;
247
248 use plain::Plain;
249
250 if_std! {
251 use std::fs::File;
252 use std::io::{Seek, Read};
253 use std::io::SeekFrom::Start;
254 }
255
256 impl From<ProgramHeader> for ElfProgramHeader {
257 fn from(ph: ProgramHeader) -> Self {
258 ElfProgramHeader {
259 p_type : ph.p_type,
260 p_flags : ph.p_flags,
261 p_offset : u64::from(ph.p_offset),
262 p_vaddr : u64::from(ph.p_vaddr),
263 p_paddr : u64::from(ph.p_paddr),
264 p_filesz : u64::from(ph.p_filesz),
265 p_memsz : u64::from(ph.p_memsz),
266 p_align : u64::from(ph.p_align),
267 }
268 }
269 }
270
271 impl From<ElfProgramHeader> for ProgramHeader {
272 fn from(ph: ElfProgramHeader) -> Self {
273 ProgramHeader {
274 p_type : ph.p_type,
275 p_flags : ph.p_flags,
276 p_offset : ph.p_offset as $size,
277 p_vaddr : ph.p_vaddr as $size,
278 p_paddr : ph.p_paddr as $size,
279 p_filesz : ph.p_filesz as $size,
280 p_memsz : ph.p_memsz as $size,
281 p_align : ph.p_align as $size,
282 }
283 }
284 }
285
286 impl fmt::Debug for ProgramHeader {
287 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
288 f.debug_struct("ProgramHeader")
289 .field("p_type", &pt_to_str(self.p_type))
290 .field("p_flags", &format_args!("0x{:x}", self.p_flags))
291 .field("p_offset", &format_args!("0x{:x}", self.p_offset))
292 .field("p_vaddr", &format_args!("0x{:x}", self.p_vaddr))
293 .field("p_paddr", &format_args!("0x{:x}", self.p_paddr))
294 .field("p_filesz", &format_args!("0x{:x}", self.p_filesz))
295 .field("p_memsz", &format_args!("0x{:x}", self.p_memsz))
296 .field("p_align", &self.p_align)
297 .finish()
298 }
299 }
300
301 impl ProgramHeader {
302 #[cfg(feature = "endian_fd")]
303 pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: ::scroll::Endian) -> Result<Vec<ProgramHeader>> {
304 use scroll::Pread;
305 let mut program_headers = vec![ProgramHeader::default(); count];
306 let offset = &mut offset;
307 bytes.gread_inout_with(offset, &mut program_headers, ctx)?;
308 Ok(program_headers)
309 }
310
311 pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec<ProgramHeader> {
312 let mut phdrs = vec![ProgramHeader::default(); phnum];
313 phdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries");
314 phdrs
315 }
316
317 pub unsafe fn from_raw_parts<'a>(phdrp: *const ProgramHeader,
318 phnum: usize)
319 -> &'a [ProgramHeader] {
320 slice::from_raw_parts(phdrp, phnum)
321 }
322
323 #[cfg(feature = "std")]
324 pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result<Vec<ProgramHeader>> {
325 let mut phdrs = vec![ProgramHeader::default(); count];
326 fd.seek(Start(offset))?;
327 unsafe {
328 fd.read_exact(plain::as_mut_bytes(&mut *phdrs))?;
329 }
330 Ok(phdrs)
331 }
332 }
333 } // end if_alloc
334 };}
335
336 #[cfg(feature = "alloc")]
337 use scroll::{Pread, Pwrite, SizeWith};
338
339 pub mod program_header32 {
340 pub use crate::elf::program_header::*;
341
342 #[repr(C)]
343 #[derive(Copy, Clone, PartialEq, Default)]
344 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
345 /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory
346 pub struct ProgramHeader {
347 /// Segment type
348 pub p_type: u32,
349 /// Segment file offset
350 pub p_offset: u32,
351 /// Segment virtual address
352 pub p_vaddr: u32,
353 /// Segment physical address
354 pub p_paddr: u32,
355 /// Segment size in file
356 pub p_filesz: u32,
357 /// Segment size in memory
358 pub p_memsz: u32,
359 /// Segment flags
360 pub p_flags: u32,
361 /// Segment alignment
362 pub p_align: u32,
363 }
364
365 pub const SIZEOF_PHDR: usize = 32;
366
367 use plain;
368 // Declare that this is a plain type.
369 unsafe impl plain::Plain for ProgramHeader {}
370
371 elf_program_header_std_impl!(u32);
372 }
373
374
375 pub mod program_header64 {
376 pub use crate::elf::program_header::*;
377
378 #[repr(C)]
379 #[derive(Copy, Clone, PartialEq, Default)]
380 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, SizeWith))]
381 /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory
382 pub struct ProgramHeader {
383 /// Segment type
384 pub p_type: u32,
385 /// Segment flags
386 pub p_flags: u32,
387 /// Segment file offset
388 pub p_offset: u64,
389 /// Segment virtual address
390 pub p_vaddr: u64,
391 /// Segment physical address
392 pub p_paddr: u64,
393 /// Segment size in file
394 pub p_filesz: u64,
395 /// Segment size in memory
396 pub p_memsz: u64,
397 /// Segment alignment
398 pub p_align: u64,
399 }
400
401 pub const SIZEOF_PHDR: usize = 56;
402
403 use plain;
404 // Declare that this is a plain type.
405 unsafe impl plain::Plain for ProgramHeader {}
406
407 elf_program_header_std_impl!(u64);
408 }
409