1use std::{fmt::Debug, fmt::Display};
2
3use object::Endianness;
4use object::read::elf::ElfFile64;
5use serde::{Deserialize, Serialize};
6
7use crate::errors::DisassemblerError;
8use crate::section_header_entry::SectionHeaderEntry;
9
10#[allow(non_camel_case_types)]
11#[derive(Debug, Clone, Serialize, Deserialize)]
12#[repr(u32)]
13pub enum SectionHeaderType {
14 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, }
33
34impl TryFrom<u32> for SectionHeaderType {
35 type Error = DisassemblerError;
36
37 fn try_from(value: u32) -> Result<Self, Self::Error> {
38 Ok(match value {
39 0x00 => Self::SHT_NULL,
40 0x01 => Self::SHT_PROGBITS,
41 0x02 => Self::SHT_SYMTAB,
42 0x03 => Self::SHT_STRTAB,
43 0x04 => Self::SHT_RELA,
44 0x05 => Self::SHT_HASH,
45 0x06 => Self::SHT_DYNAMIC,
46 0x07 => Self::SHT_NOTE,
47 0x08 => Self::SHT_NOBITS,
48 0x09 => Self::SHT_REL,
49 0x0A => Self::SHT_SHLIB,
50 0x0B => Self::SHT_DYNSYM,
51 0x0E => Self::SHT_INIT_ARRAY,
52 0x0F => Self::SHT_FINI_ARRAY,
53 0x10 => Self::SHT_PREINIT_ARRAY,
54 0x11 => Self::SHT_GROUP,
55 0x12 => Self::SHT_SYMTAB_SHNDX,
56 0x13 => Self::SHT_NUM,
57 _ => return Err(DisassemblerError::InvalidSectionHeaderType),
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 }
90 }
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct SectionHeader {
95 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, }
106
107impl SectionHeader {
108 pub fn from_elf_file(
109 elf_file: &ElfFile64<Endianness>,
110 ) -> Result<(Vec<Self>, Vec<SectionHeaderEntry>), DisassemblerError> {
111 let endian = elf_file.endian();
112 let section_headers_data: Vec<_> = elf_file.elf_section_table().iter().collect();
113
114 let mut section_headers = Vec::new();
115 for sh in section_headers_data.iter() {
116 let sh_name = sh.sh_name.get(endian);
117 let sh_type = SectionHeaderType::try_from(sh.sh_type.get(endian))?;
118 let sh_flags = sh.sh_flags.get(endian);
119 let sh_addr = sh.sh_addr.get(endian);
120 let sh_offset = sh.sh_offset.get(endian);
121 let sh_size = sh.sh_size.get(endian);
122 let sh_link = sh.sh_link.get(endian);
123 let sh_info = sh.sh_info.get(endian);
124 let sh_addralign = sh.sh_addralign.get(endian);
125 let sh_entsize = sh.sh_entsize.get(endian);
126
127 section_headers.push(SectionHeader {
128 sh_name,
129 sh_type,
130 sh_flags,
131 sh_addr,
132 sh_offset,
133 sh_size,
134 sh_link,
135 sh_info,
136 sh_addralign,
137 sh_entsize,
138 });
139 }
140
141 let elf_header = elf_file.elf_header();
142 let e_shstrndx = elf_header.e_shstrndx.get(endian);
143 let shstrndx = §ion_headers[e_shstrndx as usize];
144 let shstrndx_value = elf_file.data()
145 [shstrndx.sh_offset as usize..shstrndx.sh_offset as usize + shstrndx.sh_size as usize]
146 .to_vec();
147
148 let mut indices: Vec<u32> = section_headers.iter().map(|h| h.sh_name).collect();
149 indices.push(shstrndx.sh_size as u32);
150 indices.sort_unstable();
151
152 let section_header_entries = section_headers
153 .iter()
154 .map(|s| {
155 let current_offset = s.sh_name as usize;
156 let next_index = indices.binary_search(&s.sh_name).unwrap() + 1;
157 let next_offset = *indices
158 .get(next_index)
159 .ok_or(DisassemblerError::InvalidString)?
160 as usize;
161
162 let label = String::from_utf8(shstrndx_value[current_offset..next_offset].to_vec())
163 .unwrap_or("default".to_string());
164
165 let data = elf_file.data()
166 [s.sh_offset as usize..s.sh_offset as usize + s.sh_size as usize]
167 .to_vec();
168
169 SectionHeaderEntry::new(label, s.sh_offset as usize, data)
170 })
171 .collect::<Result<Vec<_>, _>>()?;
172
173 Ok((section_headers, section_header_entries))
174 }
175
176 pub fn to_bytes(&self) -> Vec<u8> {
177 let mut b = self.sh_name.to_le_bytes().to_vec();
178 b.extend_from_slice(&(self.sh_type.clone() as u32).to_le_bytes());
179 b.extend_from_slice(&self.sh_flags.to_le_bytes());
180 b.extend_from_slice(&self.sh_addr.to_le_bytes());
181 b.extend_from_slice(&self.sh_offset.to_le_bytes());
182 b.extend_from_slice(&self.sh_size.to_le_bytes());
183 b.extend_from_slice(&self.sh_link.to_le_bytes());
184 b.extend_from_slice(&self.sh_info.to_le_bytes());
185 b.extend_from_slice(&self.sh_addralign.to_le_bytes());
186 b.extend_from_slice(&self.sh_entsize.to_le_bytes());
187 b
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 use hex_literal::hex;
194
195 use crate::program::Program;
196
197 #[test]
198 fn test_section_headers() {
199 let program = Program::from_bytes(&hex!("7F454C460201010000000000000000000300F700010000002001000000000000400000000000000028020000000000000000000040003800030040000600050001000000050000002001000000000000200100000000000020010000000000003000000000000000300000000000000000100000000000000100000004000000C001000000000000C001000000000000C0010000000000003C000000000000003C000000000000000010000000000000020000000600000050010000000000005001000000000000500100000000000070000000000000007000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007912A000000000007911182900000000B7000000010000002D21010000000000B70000000000000095000000000000001E0000000000000004000000000000000600000000000000C0010000000000000B0000000000000018000000000000000500000000000000F0010000000000000A000000000000000C00000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000120001002001000000000000300000000000000000656E747279706F696E7400002E74657874002E64796E737472002E64796E73796D002E64796E616D6963002E73687374727461620000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000600000000000000200100000000000020010000000000003000000000000000000000000000000008000000000000000000000000000000170000000600000003000000000000005001000000000000500100000000000070000000000000000400000000000000080000000000000010000000000000000F0000000B0000000200000000000000C001000000000000C001000000000000300000000000000004000000010000000800000000000000180000000000000007000000030000000200000000000000F001000000000000F0010000000000000C00000000000000000000000000000001000000000000000000000000000000200000000300000000000000000000000000000000000000FC010000000000002A00000000000000000000000000000001000000000000000000000000000000")).unwrap();
200
201 assert_eq!(program.section_headers.len(), 6);
203 assert_eq!(program.section_header_entries.len(), 6);
204
205 for entry in &program.section_header_entries {
207 assert!(!entry.label.is_empty());
208 if entry.label == ".text\0" {
209 assert!(!entry.data.is_empty());
210 assert!(!entry.ixs.is_empty());
211 }
212 }
213 }
214}