1#![no_std]
8#![feature(linkage)]
9
10use core::error::Error;
11use core::fmt;
12use core::ops::Range;
13use core::slice;
14
15pub use sel4_phdrs_constants::*;
16
17unsafe extern "Rust" {
18 safe fn __sel4_phdrs__locate_phdrs() -> Result<ProgramHeaders<'static>, &'static dyn Error>;
19}
20
21#[macro_export]
22macro_rules! register_locate_phdrs {
23 ($(#[$attrs:meta])* $path:path) => {
24 #[allow(non_snake_case)]
25 const _: () = {
26 $(#[$attrs])*
27 #[unsafe(no_mangle)]
28 fn __sel4_phdrs__locate_phdrs() -> $crate::_private::LocatePhdrsResult {
29 const F: fn() -> $crate::_private::LocatePhdrsResult = $path;
30 F()
31 }
32 };
33 };
34}
35
36register_locate_phdrs!(
37 #[linkage = "weak"]
38 default_locate_phdrs
39);
40
41pub fn locate_phdrs() -> Result<ProgramHeaders<'static>, &'static dyn Error> {
42 __sel4_phdrs__locate_phdrs()
43}
44
45pub struct ProgramHeaders<'a> {
46 slice: &'a [ProgramHeader],
47}
48
49impl<'a> ProgramHeaders<'a> {
50 #[allow(clippy::missing_safety_doc)]
51 pub unsafe fn new(start: *const ProgramHeader, n: usize) -> Self {
52 Self {
53 slice: unsafe { slice::from_raw_parts(start, n) },
54 }
55 }
56
57 pub fn as_slice(&self) -> &'a [ProgramHeader] {
58 self.slice
59 }
60
61 pub fn iter(&self) -> impl Iterator<Item = &'a ProgramHeader> {
62 self.as_slice().iter()
63 }
64
65 pub fn find_by_type(&self, ty: u32) -> Option<&'a ProgramHeader> {
66 self.iter().find(|phdr| phdr.p_type == ty)
67 }
68
69 pub fn footprint(&self) -> Option<Range<usize>> {
70 let start = self
71 .iter()
72 .filter(|phdr| phdr.p_type == PT_LOAD)
73 .map(|phdr| phdr.p_vaddr)
74 .min()?;
75 let end = self
76 .iter()
77 .filter(|phdr| phdr.p_type == PT_LOAD)
78 .map(|phdr| phdr.p_vaddr + phdr.p_memsz)
79 .max()?;
80 Some(start..end)
81 }
82}
83
84#[repr(C)]
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
86struct ElfHeader {
87 pub e_ident: ElfHeaderIdent,
88 pub e_type: u16,
89 pub e_machine: u16,
90 pub e_version: u32,
91 pub e_entry: usize,
92 pub e_phoff: usize,
93 pub e_shoff: usize,
94 pub e_flags: u32,
95 pub e_ehsize: u16,
96 pub e_phentsize: u16,
97 pub e_phnum: u16,
98 pub e_shentsize: u16,
99 pub e_shnum: u16,
100 pub e_shstrndx: u16,
101}
102
103#[repr(C)]
104#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
105struct ElfHeaderIdent {
106 pub magic: [u8; 4],
107 pub class: u8,
108 pub data: u8,
109 pub version: u8,
110 pub os_abi: u8,
111 pub abi_version: u8,
112 pub padding: [u8; 7],
113}
114
115const ELFMAG: [u8; 4] = [0x7f, b'E', b'L', b'F'];
116
117#[repr(C)]
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
119pub struct ProgramHeader {
120 pub p_type: u32,
121 #[cfg(target_pointer_width = "64")]
122 pub p_flags: u32,
123 pub p_offset: usize,
124 pub p_vaddr: usize,
125 pub p_paddr: usize,
126 pub p_filesz: usize,
127 pub p_memsz: usize,
128 #[cfg(target_pointer_width = "32")]
129 pub p_flags: u32,
130 pub p_align: usize,
131}
132
133pub const PT_NULL: u32 = 0;
134pub const PT_LOAD: u32 = 1;
135pub const PT_TLS: u32 = 7;
136pub const PT_GNU_EH_FRAME: u32 = 0x6474_e550;
137
138impl ProgramHeader {
139 #[allow(clippy::missing_safety_doc)]
140 pub unsafe fn bytes(&self) -> &'static [u8] {
141 unsafe { slice::from_raw_parts(self.p_vaddr as *const u8, self.p_memsz) }
142 }
143}
144
145pub fn default_locate_phdrs() -> Result<ProgramHeaders<'static>, &'static dyn Error> {
146 unsafe extern "C" {
147 safe static __ehdr_start: ElfHeader;
148 }
149 if __ehdr_start.e_ident.magic != ELFMAG {
150 return Err(&DefaultLocatePhdrsError::InvalidMagic);
151 }
152 if __ehdr_start.e_phoff != size_of::<ElfHeader>() {
153 return Err(&DefaultLocatePhdrsError::UnexpectedPhoff);
154 }
155 let start = (&raw const __ehdr_start)
156 .wrapping_byte_add(__ehdr_start.e_phoff)
157 .cast();
158 Ok(unsafe { ProgramHeaders::new(start, __ehdr_start.e_phnum.into()) })
159}
160
161#[derive(Debug, Copy, Clone)]
162pub enum DefaultLocatePhdrsError {
163 InvalidMagic,
164 UnexpectedPhoff,
165}
166
167impl fmt::Display for DefaultLocatePhdrsError {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 Self::InvalidMagic => write!(f, "invalid magic in ELF header"),
171 Self::UnexpectedPhoff => write!(f, "unexpected e_phoff in ELF header"),
172 }
173 }
174}
175
176impl Error for DefaultLocatePhdrsError {}
177
178#[doc(hidden)]
180pub mod _private {
181 use core::error::Error;
182
183 use super::ProgramHeaders;
184
185 pub type LocatePhdrsResult = Result<ProgramHeaders<'static>, &'static dyn Error>;
186}