sbpf_disassembler/
section_header.rs

1use std::{fmt::Debug, fmt::Display, io::Cursor};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{cursor::ELFCursor, errors::EZBpfError, instructions::Ix};
6
7#[allow(non_camel_case_types)]
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[repr(u32)]
10pub enum SectionHeaderType {
11    SHT_NULL = 0x00,          // Section header table entry unused
12    SHT_PROGBITS = 0x01,      // Program data
13    SHT_SYMTAB = 0x02,        // Symbol table
14    SHT_STRTAB = 0x03,        // String table
15    SHT_RELA = 0x04,          // Relocation entries with addends
16    SHT_HASH = 0x05,          // Symbol hash table
17    SHT_DYNAMIC = 0x06,       // Dynamic linking information
18    SHT_NOTE = 0x07,          // Notes
19    SHT_NOBITS = 0x08,        // Program space with no data (bss)
20    SHT_REL = 0x09,           // Relocation entries, no addends
21    SHT_SHLIB = 0x0A,         // Reserved
22    SHT_DYNSYM = 0x0B,        // Dynamic linker symbol table
23    SHT_INIT_ARRAY = 0x0E,    // Array of constructors
24    SHT_FINI_ARRAY = 0x0F,    // Array of destructors
25    SHT_PREINIT_ARRAY = 0x10, // Array of pre-constructors
26    SHT_GROUP = 0x11,         // Section group
27    SHT_SYMTAB_SHNDX = 0x12,  //	Extended section indices
28    SHT_NUM = 0x13,           // Number of defined types.
29}
30
31impl TryFrom<u32> for SectionHeaderType {
32    type Error = EZBpfError;
33
34    fn try_from(value: u32) -> Result<Self, Self::Error> {
35        Ok(match value {
36            0x00 => Self::SHT_NULL,
37            0x01 => Self::SHT_PROGBITS,
38            0x02 => Self::SHT_SYMTAB,
39            0x03 => Self::SHT_STRTAB,
40            0x04 => Self::SHT_RELA,
41            0x05 => Self::SHT_HASH,
42            0x06 => Self::SHT_DYNAMIC,
43            0x07 => Self::SHT_NOTE,
44            0x08 => Self::SHT_NOBITS,
45            0x09 => Self::SHT_REL,
46            0x0A => Self::SHT_SHLIB,
47            0x0B => Self::SHT_DYNSYM,
48            0x0E => Self::SHT_INIT_ARRAY,
49            0x0F => Self::SHT_FINI_ARRAY,
50            0x10 => Self::SHT_PREINIT_ARRAY,
51            0x11 => Self::SHT_GROUP,
52            0x12 => Self::SHT_SYMTAB_SHNDX,
53            0x13 => Self::SHT_NUM,
54            _ => return Err(EZBpfError::InvalidSectionHeaderType),
55        })
56    }
57}
58
59impl Display for SectionHeaderType {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        f.write_str(Into::<&str>::into(self.clone()))
62    }
63}
64
65impl From<SectionHeaderType> for &str {
66    fn from(val: SectionHeaderType) -> Self {
67        match val {
68            SectionHeaderType::SHT_NULL => "SHT_NULL",
69            SectionHeaderType::SHT_PROGBITS => "SHT_PROGBITS",
70            SectionHeaderType::SHT_SYMTAB => "SHT_SYMTAB",
71            SectionHeaderType::SHT_STRTAB => "SHT_STRTAB",
72            SectionHeaderType::SHT_RELA => "SHT_RELA",
73            SectionHeaderType::SHT_HASH => "SHT_HASH",
74            SectionHeaderType::SHT_DYNAMIC => "SHT_DYNAMIC",
75            SectionHeaderType::SHT_NOTE => "SHT_NOTE",
76            SectionHeaderType::SHT_NOBITS => "SHT_NOBITS",
77            SectionHeaderType::SHT_REL => "SHT_REL",
78            SectionHeaderType::SHT_SHLIB => "SHT_SHLIB",
79            SectionHeaderType::SHT_DYNSYM => "SHT_DYNSYM",
80            SectionHeaderType::SHT_INIT_ARRAY => "SHT_INIT_ARRAY",
81            SectionHeaderType::SHT_FINI_ARRAY => "SHT_FINI_ARRAY",
82            SectionHeaderType::SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY",
83            SectionHeaderType::SHT_GROUP => "SHT_GROUP",
84            SectionHeaderType::SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
85            SectionHeaderType::SHT_NUM => "SHT_NUM",
86        }
87    }
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct SectionHeader {
92    pub sh_name: u32, // An offset to a string in the .shstrtab section that represents the name of this section.
93    pub sh_type: SectionHeaderType, // Identifies the type of this header.
94    pub sh_flags: u64, // Identifies the attributes of the section.
95    pub sh_addr: u64, // Virtual address of the section in memory, for sections that are loaded.
96    pub sh_offset: u64, // Offset of the section in the file image.
97    pub sh_size: u64, // Size in bytes of the section in the file image. May be 0.
98    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.
99    pub sh_info: u32, // Contains extra information about the section. This field is used for several purposes, depending on the type of section.
100    pub sh_addralign: u64, // Contains the required alignment of the section. This field must be a power of two.
101    pub sh_entsize: u64, // Contains the size, in bytes, of each entry, for sections that contain fixed-size entries. Otherwise, this field contains zero.
102}
103
104impl SectionHeader {
105    pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
106        let mut c = Cursor::new(b);
107        c.read_section_header()
108    }
109
110    pub fn to_bytes(&self) -> Vec<u8> {
111        let mut b = self.sh_name.to_le_bytes().to_vec();
112        b.extend_from_slice(&(self.sh_type.clone() as u32).to_le_bytes());
113        b.extend_from_slice(&self.sh_flags.to_le_bytes());
114        b.extend_from_slice(&self.sh_addr.to_le_bytes());
115        b.extend_from_slice(&self.sh_offset.to_le_bytes());
116        b.extend_from_slice(&self.sh_size.to_le_bytes());
117        b.extend_from_slice(&self.sh_link.to_le_bytes());
118        b.extend_from_slice(&self.sh_info.to_le_bytes());
119        b.extend_from_slice(&self.sh_addralign.to_le_bytes());
120        b.extend_from_slice(&self.sh_entsize.to_le_bytes());
121        b
122    }
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct SectionHeaderEntry {
127    pub label: String,
128    pub offset: usize,
129    pub data: Vec<u8>,
130}
131
132impl SectionHeaderEntry {
133    pub fn to_ixs(&self) -> Result<Vec<Ix>, EZBpfError> {
134        if self.data.len() % 8 != 0 {
135            return Err(EZBpfError::InvalidDataLength);
136        }
137        let mut ixs: Vec<Ix> = vec![];
138        if self.data.len() >= 8 {
139            let mut c = Cursor::new(self.data.as_slice());
140            while let Ok(ix) = c.read_ix() {
141                ixs.push(ix)
142            }
143        }
144        Ok(ixs)
145    }
146}
147
148#[cfg(test)]
149mod test {
150    use hex_literal::hex;
151
152    use crate::section_header::SectionHeader;
153
154    #[test]
155    fn serialize_e2e() {
156        let b = hex!(
157            "07000000030000000000000000000000000000000000000080000000000000000A00000000000000000000000000000001000000000000000000000000000000"
158        );
159        let h = SectionHeader::from_bytes(&b).unwrap();
160        assert_eq!(h.to_bytes(), &b)
161    }
162}