sbpf_disassembler/
section_header.rs

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,          // Section header table entry unused
15    SHT_PROGBITS = 0x01,      // Program data
16    SHT_SYMTAB = 0x02,        // Symbol table
17    SHT_STRTAB = 0x03,        // String table
18    SHT_RELA = 0x04,          // Relocation entries with addends
19    SHT_HASH = 0x05,          // Symbol hash table
20    SHT_DYNAMIC = 0x06,       // Dynamic linking information
21    SHT_NOTE = 0x07,          // Notes
22    SHT_NOBITS = 0x08,        // Program space with no data (bss)
23    SHT_REL = 0x09,           // Relocation entries, no addends
24    SHT_SHLIB = 0x0A,         // Reserved
25    SHT_DYNSYM = 0x0B,        // Dynamic linker symbol table
26    SHT_INIT_ARRAY = 0x0E,    // Array of constructors
27    SHT_FINI_ARRAY = 0x0F,    // Array of destructors
28    SHT_PREINIT_ARRAY = 0x10, // Array of pre-constructors
29    SHT_GROUP = 0x11,         // Section group
30    SHT_SYMTAB_SHNDX = 0x12,  //	Extended section indices
31    SHT_NUM = 0x13,           // Number of defined types.
32}
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, // An offset to a string in the .shstrtab section that represents the name of this section.
96    pub sh_type: SectionHeaderType, // Identifies the type of this header.
97    pub sh_flags: u64, // Identifies the attributes of the section.
98    pub sh_addr: u64, // Virtual address of the section in memory, for sections that are loaded.
99    pub sh_offset: u64, // Offset of the section in the file image.
100    pub sh_size: u64, // Size in bytes of the section in the file image. May be 0.
101    pub sh_link: u32, // Contains the section index of an associated section. This field is used for several purposes, depending on the type of section.
102    pub sh_info: u32, // Contains extra information about the section. This field is used for several purposes, depending on the type of section.
103    pub sh_addralign: u64, // Contains the required alignment of the section. This field must be a power of two.
104    pub sh_entsize: u64, // Contains the size, in bytes, of each entry, for sections that contain fixed-size entries. Otherwise, this field contains zero.
105}
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 = &section_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        // Verify we have the expected number of section headers.
202        assert_eq!(program.section_headers.len(), 6);
203        assert_eq!(program.section_header_entries.len(), 6);
204
205        // Verify section header entries have proper data.
206        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}