1use crate::endian::EndianParse;
3use crate::file::Class;
4use crate::parse::{ParseAt, ParseError, ParsingTable};
5
6pub type SegmentTable<'data, E> = ParsingTable<'data, E, ProgramHeader>;
7
8#[derive(Debug)]
12#[repr(C)]
13pub struct Elf32_Phdr {
14 pub p_type: u32,
15 pub p_offset: u32,
16 pub p_vaddr: u32,
17 pub p_paddr: u32,
18 pub p_filesz: u32,
19 pub p_memsz: u32,
20 pub p_flags: u32,
21 pub p_align: u32,
22}
23
24#[derive(Debug)]
28#[repr(C)]
29pub struct Elf64_Phdr {
30 pub p_type: u32,
31 pub p_flags: u32,
32 pub p_offset: u64,
33 pub p_vaddr: u64,
34 pub p_paddr: u64,
35 pub p_filesz: u64,
36 pub p_memsz: u64,
37 pub p_align: u64,
38}
39
40#[derive(Copy, Clone, Debug, PartialEq, Eq)]
45pub struct ProgramHeader {
46 pub p_type: u32,
48 pub p_offset: u64,
50 pub p_vaddr: u64,
52 pub p_paddr: u64,
54 pub p_filesz: u64,
56 pub p_memsz: u64,
58 pub p_flags: u32,
60 pub p_align: u64,
62}
63
64impl ParseAt for ProgramHeader {
65 fn parse_at<E: EndianParse>(
66 endian: E,
67 class: Class,
68 offset: &mut usize,
69 data: &[u8],
70 ) -> Result<Self, ParseError> {
71 if class == Class::ELF32 {
72 return Ok(ProgramHeader {
73 p_type: endian.parse_u32_at(offset, data)?,
74 p_offset: endian.parse_u32_at(offset, data)? as u64,
75 p_vaddr: endian.parse_u32_at(offset, data)? as u64,
76 p_paddr: endian.parse_u32_at(offset, data)? as u64,
77 p_filesz: endian.parse_u32_at(offset, data)? as u64,
78 p_memsz: endian.parse_u32_at(offset, data)? as u64,
79 p_flags: endian.parse_u32_at(offset, data)?,
80 p_align: endian.parse_u32_at(offset, data)? as u64,
81 });
82 }
83
84 let p_type = endian.parse_u32_at(offset, data)?;
86 let p_flags = endian.parse_u32_at(offset, data)?;
87 let p_offset = endian.parse_u64_at(offset, data)?;
88 let p_vaddr = endian.parse_u64_at(offset, data)?;
89 let p_paddr = endian.parse_u64_at(offset, data)?;
90 let p_filesz = endian.parse_u64_at(offset, data)?;
91 let p_memsz = endian.parse_u64_at(offset, data)?;
92 let p_align = endian.parse_u64_at(offset, data)?;
93 Ok(ProgramHeader {
94 p_type,
95 p_offset,
96 p_vaddr,
97 p_paddr,
98 p_filesz,
99 p_memsz,
100 p_flags,
101 p_align,
102 })
103 }
104
105 #[inline]
106 fn size_for(class: Class) -> usize {
107 match class {
108 Class::ELF32 => 32,
109 Class::ELF64 => 56,
110 }
111 }
112}
113
114impl ProgramHeader {
115 pub(crate) fn get_file_data_range(&self) -> Result<(usize, usize), ParseError> {
119 let start: usize = self.p_offset.try_into()?;
120 let size: usize = self.p_filesz.try_into()?;
121 let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
122 Ok((start, end))
123 }
124}
125
126#[cfg(test)]
127mod parse_tests {
128 use super::*;
129 use crate::endian::{BigEndian, LittleEndian};
130 use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
131
132 #[test]
133 fn parse_phdr32_lsb() {
134 test_parse_for(
135 LittleEndian,
136 Class::ELF32,
137 ProgramHeader {
138 p_type: 0x03020100,
139 p_offset: 0x07060504,
140 p_vaddr: 0xB0A0908,
141 p_paddr: 0x0F0E0D0C,
142 p_filesz: 0x13121110,
143 p_memsz: 0x17161514,
144 p_flags: 0x1B1A1918,
145 p_align: 0x1F1E1D1C,
146 },
147 );
148 }
149
150 #[test]
151 fn parse_phdr32_msb() {
152 test_parse_for(
153 BigEndian,
154 Class::ELF32,
155 ProgramHeader {
156 p_type: 0x00010203,
157 p_offset: 0x04050607,
158 p_vaddr: 0x08090A0B,
159 p_paddr: 0x0C0D0E0F,
160 p_filesz: 0x10111213,
161 p_memsz: 0x14151617,
162 p_flags: 0x18191A1B,
163 p_align: 0x1C1D1E1F,
164 },
165 );
166 }
167
168 #[test]
169 fn parse_phdr64_lsb() {
170 test_parse_for(
171 LittleEndian,
172 Class::ELF64,
173 ProgramHeader {
174 p_type: 0x03020100,
175 p_offset: 0x0F0E0D0C0B0A0908,
176 p_vaddr: 0x1716151413121110,
177 p_paddr: 0x1F1E1D1C1B1A1918,
178 p_filesz: 0x2726252423222120,
179 p_memsz: 0x2F2E2D2C2B2A2928,
180 p_flags: 0x07060504,
181 p_align: 0x3736353433323130,
182 },
183 );
184 }
185
186 #[test]
187 fn parse_phdr64_msb() {
188 test_parse_for(
189 BigEndian,
190 Class::ELF64,
191 ProgramHeader {
192 p_type: 0x00010203,
193 p_offset: 0x08090A0B0C0D0E0F,
194 p_vaddr: 0x1011121314151617,
195 p_paddr: 0x18191A1B1C1D1E1F,
196 p_filesz: 0x2021222324252627,
197 p_memsz: 0x28292A2B2C2D2E2F,
198 p_flags: 0x04050607,
199 p_align: 0x3031323334353637,
200 },
201 );
202 }
203
204 #[test]
205 fn parse_phdr32_lsb_fuzz_too_short() {
206 test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF32);
207 }
208
209 #[test]
210 fn parse_phdr32_msb_fuzz_too_short() {
211 test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF32);
212 }
213
214 #[test]
215 fn parse_phdr64_lsb_fuzz_too_short() {
216 test_parse_fuzz_too_short::<_, ProgramHeader>(LittleEndian, Class::ELF64);
217 }
218
219 #[test]
220 fn parse_phdr64_msb_fuzz_too_short() {
221 test_parse_fuzz_too_short::<_, ProgramHeader>(BigEndian, Class::ELF64);
222 }
223}