goblin/elf/
program_header.rs

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