1pub const PT_NULL: u32 = 0;
5pub const PT_LOAD: u32 = 1;
7pub const PT_DYNAMIC: u32 = 2;
9pub const PT_INTERP: u32 = 3;
11pub const PT_NOTE: u32 = 4;
13pub const PT_SHLIB: u32 = 5;
15pub const PT_PHDR: u32 = 6;
17pub const PT_TLS: u32 = 7;
19pub const PT_NUM: u32 = 8;
21pub const PT_LOOS: u32 = 0x6000_0000;
23pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550;
25pub const PT_GNU_PROPERTY: u32 = 0x6474_e553;
27pub const PT_GNU_STACK: u32 = 0x6474_e551;
29pub const PT_GNU_RELRO: u32 = 0x6474_e552;
31pub const PT_LOSUNW: u32 = 0x6fff_fffa;
33pub const PT_SUNWBSS: u32 = 0x6fff_fffa;
35pub const PT_SUNWSTACK: u32 = 0x6fff_fffb;
37pub const PT_HISUNW: u32 = 0x6fff_ffff;
39pub const PT_HIOS: u32 = 0x6fff_ffff;
41pub const PT_LOPROC: u32 = 0x7000_0000;
43pub const PT_ARM_EXIDX: u32 = 0x7000_0001;
45pub const PT_HIPROC: u32 = 0x7fff_ffff;
47
48pub const PF_X: u32 = 1;
52pub const PF_W: u32 = 1 << 1;
54pub const PF_R: u32 = 1 << 2;
56pub const PF_MASKOS: u32 = 0x0ff0_0000;
58pub 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 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 #[inline]
111 pub fn size(ctx: Ctx) -> usize {
112 use scroll::ctx::SizeWith;
113 Self::size_with(&ctx)
114 }
115 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 p_align : 2 << 20,
127 }
128 }
129 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 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 pub fn executable(&mut self) {
139 self.p_flags |= PF_X;
140 }
141 pub fn write(&mut self) {
143 self.p_flags |= PF_W;
144 }
145 pub fn read(&mut self) {
147 self.p_flags |= PF_R;
148 }
149 pub fn is_executable(&self) -> bool {
151 self.p_flags & PF_X != 0
152 }
153 pub fn is_read(&self) -> bool {
155 self.p_flags & PF_R != 0
156 }
157 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 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} macro_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 } 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 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 pub struct ProgramHeader {
372 pub p_type: u32,
374 pub p_offset: u32,
376 pub p_vaddr: u32,
378 pub p_paddr: u32,
380 pub p_filesz: u32,
382 pub p_memsz: u32,
384 pub p_flags: u32,
386 pub p_align: u32,
388 }
389
390 pub const SIZEOF_PHDR: usize = 32;
391
392 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 pub struct ProgramHeader {
406 pub p_type: u32,
408 pub p_flags: u32,
410 pub p_offset: u64,
412 pub p_vaddr: u64,
414 pub p_paddr: u64,
416 pub p_filesz: u64,
418 pub p_memsz: u64,
420 pub p_align: u64,
422 }
423
424 pub const SIZEOF_PHDR: usize = 56;
425
426 unsafe impl plain::Plain for ProgramHeader {}
428
429 elf_program_header_std_impl!(u64);
430}