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 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