1use {
2 crate::{errors::DisassemblerError, section_header_entry::SectionHeaderEntry},
3 object::{Endianness, read::elf::ElfFile64},
4 serde::{Deserialize, Serialize},
5 std::fmt::{Debug, Display},
6};
7
8#[allow(non_camel_case_types)]
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[repr(u32)]
11pub enum SectionHeaderType {
12 SHT_NULL = 0x00, SHT_PROGBITS = 0x01, SHT_SYMTAB = 0x02, SHT_STRTAB = 0x03, SHT_RELA = 0x04, SHT_HASH = 0x05, SHT_DYNAMIC = 0x06, SHT_NOTE = 0x07, SHT_NOBITS = 0x08, SHT_REL = 0x09, SHT_SHLIB = 0x0A, SHT_DYNSYM = 0x0B, SHT_INIT_ARRAY = 0x0E, SHT_FINI_ARRAY = 0x0F, SHT_PREINIT_ARRAY = 0x10, SHT_GROUP = 0x11, SHT_SYMTAB_SHNDX = 0x12, SHT_NUM = 0x13, SHT_GNU_HASH = 0x6ffffff6, }
32
33impl TryFrom<u32> for SectionHeaderType {
34 type Error = DisassemblerError;
35
36 fn try_from(value: u32) -> Result<Self, Self::Error> {
37 Ok(match value {
38 0x00 => Self::SHT_NULL,
39 0x01 => Self::SHT_PROGBITS,
40 0x02 => Self::SHT_SYMTAB,
41 0x03 => Self::SHT_STRTAB,
42 0x04 => Self::SHT_RELA,
43 0x05 => Self::SHT_HASH,
44 0x06 => Self::SHT_DYNAMIC,
45 0x07 => Self::SHT_NOTE,
46 0x08 => Self::SHT_NOBITS,
47 0x09 => Self::SHT_REL,
48 0x0A => Self::SHT_SHLIB,
49 0x0B => Self::SHT_DYNSYM,
50 0x0E => Self::SHT_INIT_ARRAY,
51 0x0F => Self::SHT_FINI_ARRAY,
52 0x10 => Self::SHT_PREINIT_ARRAY,
53 0x11 => Self::SHT_GROUP,
54 0x12 => Self::SHT_SYMTAB_SHNDX,
55 0x13 => Self::SHT_NUM,
56 0x6ffffff6 => Self::SHT_GNU_HASH,
57 _ => return Err(DisassemblerError::InvalidSectionHeaderType(value)),
58 })
59 }
60}
61
62impl Display for SectionHeaderType {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 f.write_str(Into::<&str>::into(self.clone()))
65 }
66}
67
68impl From<SectionHeaderType> for &str {
69 fn from(val: SectionHeaderType) -> Self {
70 match val {
71 SectionHeaderType::SHT_NULL => "SHT_NULL",
72 SectionHeaderType::SHT_PROGBITS => "SHT_PROGBITS",
73 SectionHeaderType::SHT_SYMTAB => "SHT_SYMTAB",
74 SectionHeaderType::SHT_STRTAB => "SHT_STRTAB",
75 SectionHeaderType::SHT_RELA => "SHT_RELA",
76 SectionHeaderType::SHT_HASH => "SHT_HASH",
77 SectionHeaderType::SHT_DYNAMIC => "SHT_DYNAMIC",
78 SectionHeaderType::SHT_NOTE => "SHT_NOTE",
79 SectionHeaderType::SHT_NOBITS => "SHT_NOBITS",
80 SectionHeaderType::SHT_REL => "SHT_REL",
81 SectionHeaderType::SHT_SHLIB => "SHT_SHLIB",
82 SectionHeaderType::SHT_DYNSYM => "SHT_DYNSYM",
83 SectionHeaderType::SHT_INIT_ARRAY => "SHT_INIT_ARRAY",
84 SectionHeaderType::SHT_FINI_ARRAY => "SHT_FINI_ARRAY",
85 SectionHeaderType::SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY",
86 SectionHeaderType::SHT_GROUP => "SHT_GROUP",
87 SectionHeaderType::SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
88 SectionHeaderType::SHT_NUM => "SHT_NUM",
89 SectionHeaderType::SHT_GNU_HASH => "SHT_GNU_HASH",
90 }
91 }
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct SectionHeader {
96 pub sh_name: u32, pub sh_type: SectionHeaderType, pub sh_flags: u64, pub sh_addr: u64, pub sh_offset: u64, pub sh_size: u64, pub sh_link: u32, pub sh_info: u32, pub sh_addralign: u64, pub sh_entsize: u64, }
107
108impl SectionHeader {
109 pub fn from_elf_file(
110 elf_file: &ElfFile64<Endianness>,
111 ) -> Result<(Vec<Self>, Vec<SectionHeaderEntry>), Vec<DisassemblerError>> {
112 let endian = elf_file.endian();
113 let section_headers_data: Vec<_> = elf_file.elf_section_table().iter().collect();
114
115 let mut errors = Vec::new();
116
117 let mut section_headers = Vec::new();
118 for sh in section_headers_data.iter() {
119 let sh_name = sh.sh_name.get(endian);
120 let sh_type = SectionHeaderType::try_from(sh.sh_type.get(endian)).unwrap_or_else(|e| {
121 errors.push(e);
122 SectionHeaderType::SHT_NULL
123 });
124 let sh_flags = sh.sh_flags.get(endian);
125 let sh_addr = sh.sh_addr.get(endian);
126 let sh_offset = sh.sh_offset.get(endian);
127 let sh_size = sh.sh_size.get(endian);
128 let sh_link = sh.sh_link.get(endian);
129 let sh_info = sh.sh_info.get(endian);
130 let sh_addralign = sh.sh_addralign.get(endian);
131 let sh_entsize = sh.sh_entsize.get(endian);
132
133 section_headers.push(SectionHeader {
134 sh_name,
135 sh_type,
136 sh_flags,
137 sh_addr,
138 sh_offset,
139 sh_size,
140 sh_link,
141 sh_info,
142 sh_addralign,
143 sh_entsize,
144 });
145 }
146
147 if section_headers.is_empty() {
151 return Ok((Vec::new(), Vec::new()));
152 }
153
154 let data = elf_file.data();
155 let elf_header = elf_file.elf_header();
156 let e_shstrndx = elf_header.e_shstrndx.get(endian);
157 let Some(shstrndx) = section_headers.get(e_shstrndx as usize) else {
158 errors.push(DisassemblerError::InvalidShstrndx {
159 shstrndx: e_shstrndx,
160 shnum: section_headers.len(),
161 });
162 return Err(errors);
163 };
164 let strtab_start = shstrndx.sh_offset as usize;
165 let strtab_end = strtab_start.saturating_add(shstrndx.sh_size as usize);
166 let Some(shstrndx_value) = data.get(strtab_start..strtab_end) else {
167 errors.push(DisassemblerError::SectionDataOutOfBounds {
168 section: ".shstrtab".to_string(),
169 offset: shstrndx.sh_offset,
170 size: shstrndx.sh_size,
171 file_len: data.len(),
172 });
173 return Err(errors);
174 };
175 let shstrndx_value = shstrndx_value.to_vec();
176
177 let mut section_header_entries = Vec::with_capacity(section_headers.len());
178 for s in §ion_headers {
179 let current_offset = s.sh_name as usize;
180
181 let label = match shstrndx_value.get(current_offset..) {
183 Some(label_bytes) if !label_bytes.is_empty() => {
184 let null_pos = label_bytes
185 .iter()
186 .position(|&b| b == 0)
187 .unwrap_or(label_bytes.len());
188 String::from_utf8(
189 label_bytes[..=null_pos.min(label_bytes.len().saturating_sub(1))].to_vec(),
190 )
191 .unwrap_or("default".to_string())
192 }
193 _ => {
194 errors.push(DisassemblerError::InvalidSectionName {
195 sh_name: s.sh_name,
196 strtab_len: shstrndx_value.len(),
197 });
198 "default".to_string()
199 }
200 };
201
202 let data_start = s.sh_offset as usize;
203 let data_end = data_start.saturating_add(s.sh_size as usize);
204 let section_data = match data.get(data_start..data_end) {
205 Some(d) => d.to_vec(),
206 None => {
207 errors.push(DisassemblerError::SectionDataOutOfBounds {
208 section: label.trim_end_matches('\0').to_string(),
209 offset: s.sh_offset,
210 size: s.sh_size,
211 file_len: data.len(),
212 });
213 data.get(data_start..)
215 .map(<[u8]>::to_vec)
216 .unwrap_or_default()
217 }
218 };
219
220 match SectionHeaderEntry::new(label, s.sh_offset as usize, section_data) {
221 Ok(entry) => section_header_entries.push(entry),
222 Err(e) => errors.push(e),
223 }
224 }
225
226 if errors.is_empty() {
227 Ok((section_headers, section_header_entries))
228 } else {
229 Err(errors)
230 }
231 }
232
233 pub fn to_bytes(&self) -> Vec<u8> {
234 let mut b = self.sh_name.to_le_bytes().to_vec();
235 b.extend_from_slice(&(self.sh_type.clone() as u32).to_le_bytes());
236 b.extend_from_slice(&self.sh_flags.to_le_bytes());
237 b.extend_from_slice(&self.sh_addr.to_le_bytes());
238 b.extend_from_slice(&self.sh_offset.to_le_bytes());
239 b.extend_from_slice(&self.sh_size.to_le_bytes());
240 b.extend_from_slice(&self.sh_link.to_le_bytes());
241 b.extend_from_slice(&self.sh_info.to_le_bytes());
242 b.extend_from_slice(&self.sh_addralign.to_le_bytes());
243 b.extend_from_slice(&self.sh_entsize.to_le_bytes());
244 b
245 }
246}
247
248#[cfg(test)]
249mod tests {
250 use {super::*, crate::program::Program, hex_literal::hex};
251
252 #[test]
253 fn test_section_headers() {
254 let program = Program::from_bytes(&hex!("7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000")).unwrap();
255
256 assert_eq!(program.section_headers.len(), 6);
258 assert_eq!(program.section_header_entries.len(), 6);
259 }
260
261 #[test]
262 fn test_section_header_type_conversions() {
263 assert!(matches!(
265 SectionHeaderType::try_from(0x00),
266 Ok(SectionHeaderType::SHT_NULL)
267 ));
268 assert!(matches!(
269 SectionHeaderType::try_from(0x01),
270 Ok(SectionHeaderType::SHT_PROGBITS)
271 ));
272 assert!(matches!(
273 SectionHeaderType::try_from(0x02),
274 Ok(SectionHeaderType::SHT_SYMTAB)
275 ));
276 assert!(matches!(
277 SectionHeaderType::try_from(0x03),
278 Ok(SectionHeaderType::SHT_STRTAB)
279 ));
280 assert!(matches!(
281 SectionHeaderType::try_from(0x04),
282 Ok(SectionHeaderType::SHT_RELA)
283 ));
284 assert!(matches!(
285 SectionHeaderType::try_from(0x05),
286 Ok(SectionHeaderType::SHT_HASH)
287 ));
288 assert!(matches!(
289 SectionHeaderType::try_from(0x06),
290 Ok(SectionHeaderType::SHT_DYNAMIC)
291 ));
292 assert!(matches!(
293 SectionHeaderType::try_from(0x07),
294 Ok(SectionHeaderType::SHT_NOTE)
295 ));
296 assert!(matches!(
297 SectionHeaderType::try_from(0x08),
298 Ok(SectionHeaderType::SHT_NOBITS)
299 ));
300 assert!(matches!(
301 SectionHeaderType::try_from(0x09),
302 Ok(SectionHeaderType::SHT_REL)
303 ));
304 assert!(matches!(
305 SectionHeaderType::try_from(0x0A),
306 Ok(SectionHeaderType::SHT_SHLIB)
307 ));
308 assert!(matches!(
309 SectionHeaderType::try_from(0x0B),
310 Ok(SectionHeaderType::SHT_DYNSYM)
311 ));
312 assert!(matches!(
313 SectionHeaderType::try_from(0x0E),
314 Ok(SectionHeaderType::SHT_INIT_ARRAY)
315 ));
316 assert!(matches!(
317 SectionHeaderType::try_from(0x0F),
318 Ok(SectionHeaderType::SHT_FINI_ARRAY)
319 ));
320 assert!(matches!(
321 SectionHeaderType::try_from(0x10),
322 Ok(SectionHeaderType::SHT_PREINIT_ARRAY)
323 ));
324 assert!(matches!(
325 SectionHeaderType::try_from(0x11),
326 Ok(SectionHeaderType::SHT_GROUP)
327 ));
328 assert!(matches!(
329 SectionHeaderType::try_from(0x12),
330 Ok(SectionHeaderType::SHT_SYMTAB_SHNDX)
331 ));
332 assert!(matches!(
333 SectionHeaderType::try_from(0x13),
334 Ok(SectionHeaderType::SHT_NUM)
335 ));
336 assert!(matches!(
337 SectionHeaderType::try_from(0x6ffffff6),
338 Ok(SectionHeaderType::SHT_GNU_HASH)
339 ));
340
341 assert!(SectionHeaderType::try_from(0xFF).is_err());
343 }
344
345 #[test]
346 fn test_section_header_type_to_str() {
347 assert_eq!(<&str>::from(SectionHeaderType::SHT_NULL), "SHT_NULL");
349 assert_eq!(
350 <&str>::from(SectionHeaderType::SHT_PROGBITS),
351 "SHT_PROGBITS"
352 );
353 assert_eq!(<&str>::from(SectionHeaderType::SHT_SYMTAB), "SHT_SYMTAB");
354 assert_eq!(<&str>::from(SectionHeaderType::SHT_STRTAB), "SHT_STRTAB");
355 assert_eq!(<&str>::from(SectionHeaderType::SHT_RELA), "SHT_RELA");
356 assert_eq!(<&str>::from(SectionHeaderType::SHT_HASH), "SHT_HASH");
357 assert_eq!(<&str>::from(SectionHeaderType::SHT_DYNAMIC), "SHT_DYNAMIC");
358 assert_eq!(<&str>::from(SectionHeaderType::SHT_NOTE), "SHT_NOTE");
359 assert_eq!(<&str>::from(SectionHeaderType::SHT_NOBITS), "SHT_NOBITS");
360 assert_eq!(<&str>::from(SectionHeaderType::SHT_REL), "SHT_REL");
361 assert_eq!(<&str>::from(SectionHeaderType::SHT_SHLIB), "SHT_SHLIB");
362 assert_eq!(<&str>::from(SectionHeaderType::SHT_DYNSYM), "SHT_DYNSYM");
363 assert_eq!(
364 <&str>::from(SectionHeaderType::SHT_INIT_ARRAY),
365 "SHT_INIT_ARRAY"
366 );
367 assert_eq!(
368 <&str>::from(SectionHeaderType::SHT_FINI_ARRAY),
369 "SHT_FINI_ARRAY"
370 );
371 assert_eq!(
372 <&str>::from(SectionHeaderType::SHT_PREINIT_ARRAY),
373 "SHT_PREINIT_ARRAY"
374 );
375 assert_eq!(<&str>::from(SectionHeaderType::SHT_GROUP), "SHT_GROUP");
376 assert_eq!(
377 <&str>::from(SectionHeaderType::SHT_SYMTAB_SHNDX),
378 "SHT_SYMTAB_SHNDX"
379 );
380 assert_eq!(<&str>::from(SectionHeaderType::SHT_NUM), "SHT_NUM");
381 assert_eq!(
382 <&str>::from(SectionHeaderType::SHT_GNU_HASH),
383 "SHT_GNU_HASH"
384 );
385 }
386
387 #[test]
388 fn test_section_header_type_display() {
389 assert_eq!(SectionHeaderType::SHT_PROGBITS.to_string(), "SHT_PROGBITS");
390 assert_eq!(SectionHeaderType::SHT_DYNAMIC.to_string(), "SHT_DYNAMIC");
391 }
392
393 #[test]
394 fn test_section_header_to_bytes() {
395 let header = SectionHeader {
396 sh_name: 1,
397 sh_type: SectionHeaderType::SHT_PROGBITS,
398 sh_flags: 6,
399 sh_addr: 0x120,
400 sh_offset: 0x120,
401 sh_size: 48,
402 sh_link: 0,
403 sh_info: 0,
404 sh_addralign: 8,
405 sh_entsize: 0,
406 };
407
408 let bytes = header.to_bytes();
409 assert_eq!(bytes.len(), 64);
410
411 assert_eq!(
413 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
414 1
415 );
416 assert_eq!(
417 u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
418 1
419 );
420 }
421}