sbpf_disassembler/
program_header.rs

1use std::{fmt::Debug, io::Cursor};
2
3use serde::{Deserialize, Serialize};
4
5use crate::{cursor::ELFCursor, errors::EZBpfError};
6
7// Program Segment Flags
8pub const PF_X: u8 = 0x01;
9pub const PF_W: u8 = 0x02;
10pub const PF_R: u8 = 0x04;
11
12#[allow(non_camel_case_types)]
13#[derive(Debug, Clone, Serialize, Deserialize)]
14#[repr(u32)]
15pub enum ProgramType {
16    PT_NULL = 0x00,    // Program header table entry unused.
17    PT_LOAD = 0x01,    // Loadable segment.
18    PT_DYNAMIC = 0x02, // Dynamic linking information.
19    PT_INTERP = 0x03,  // Interpreter information.
20    PT_NOTE = 0x04,    // Auxiliary information.
21    PT_SHLIB = 0x05,   // Reserved.
22    PT_PHDR = 0x06,    // Segment containing program header table itself.
23    PT_TLS = 0x07,     // Thread-Local Storage template.
24}
25
26impl TryFrom<u32> for ProgramType {
27    type Error = EZBpfError;
28
29    fn try_from(value: u32) -> Result<Self, Self::Error> {
30        Ok(match value {
31            0 => Self::PT_NULL,
32            1 => Self::PT_LOAD,
33            2 => Self::PT_DYNAMIC,
34            3 => Self::PT_INTERP,
35            4 => Self::PT_NOTE,
36            5 => Self::PT_SHLIB,
37            6 => Self::PT_PHDR,
38            7 => Self::PT_TLS,
39            _ => return Err(EZBpfError::InvalidProgramType),
40        })
41    }
42}
43
44impl From<ProgramType> for u32 {
45    fn from(val: ProgramType) -> Self {
46        match val {
47            ProgramType::PT_NULL => 0,
48            ProgramType::PT_LOAD => 1,
49            ProgramType::PT_DYNAMIC => 2,
50            ProgramType::PT_INTERP => 3,
51            ProgramType::PT_NOTE => 4,
52            ProgramType::PT_SHLIB => 5,
53            ProgramType::PT_PHDR => 6,
54            ProgramType::PT_TLS => 7,
55        }
56    }
57}
58
59impl From<ProgramType> for &str {
60    fn from(val: ProgramType) -> Self {
61        match val {
62            ProgramType::PT_NULL => "PT_NULL",
63            ProgramType::PT_LOAD => "PT_LOAD",
64            ProgramType::PT_DYNAMIC => "PT_DYNAMIC",
65            ProgramType::PT_INTERP => "PT_INTERP",
66            ProgramType::PT_NOTE => "PT_NOTE",
67            ProgramType::PT_SHLIB => "PT_SHLIB",
68            ProgramType::PT_PHDR => "PT_PHDR",
69            ProgramType::PT_TLS => "PT_TLS",
70        }
71    }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct ProgramFlags(pub u32);
76
77impl From<u32> for ProgramFlags {
78    fn from(value: u32) -> Self {
79        Self(value & 7)
80    }
81}
82
83impl std::fmt::Display for ProgramFlags {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        let x = match self.0 & PF_X as u32 == PF_X as u32 {
86            true => "X",
87            false => "*",
88        };
89
90        let r = match self.0 & PF_R as u32 == PF_R as u32 {
91            true => "R",
92            false => "*",
93        };
94
95        let w = match self.0 & PF_W as u32 == PF_W as u32 {
96            true => "W",
97            false => "*",
98        };
99        f.write_str(&format!("{}/{}/{}", r, w, x))
100    }
101}
102
103#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct ProgramHeader {
105    pub p_type: ProgramType, // An offset to a string in the .shstrtab section that represents the name of this section.
106    pub p_flags: ProgramFlags, // Identifies the type of this header.
107    pub p_offset: u64,       // Offset of the segment in the file image.
108    pub p_vaddr: u64,        // Virtual address of the segment in memory.
109    pub p_paddr: u64, // On systems where physical address is relevant, reserved for segment's physical address.
110    pub p_filesz: u64, // Size in bytes of the section in the file image. May be 0.
111    pub p_memsz: u64, // Size in bytes of the segment in memory. May be 0.
112    pub p_align: u64, // 0 and 1 specify no alignment. Otherwise should be a positive, integral power of 2, with p_vaddr equating p_offset modulus p_align.
113}
114
115impl ProgramHeader {
116    pub fn from_bytes(b: &[u8]) -> Result<Self, EZBpfError> {
117        let mut c = Cursor::new(b);
118        c.read_program_header()
119    }
120
121    pub fn to_bytes(&self) -> Vec<u8> {
122        let mut b = (self.p_type.clone() as u32).to_le_bytes().to_vec();
123        b.extend_from_slice(&self.p_flags.0.to_le_bytes());
124        b.extend_from_slice(&self.p_offset.to_le_bytes());
125        b.extend_from_slice(&self.p_vaddr.to_le_bytes());
126        b.extend_from_slice(&self.p_paddr.to_le_bytes());
127        b.extend_from_slice(&self.p_filesz.to_le_bytes());
128        b.extend_from_slice(&self.p_memsz.to_le_bytes());
129        b.extend_from_slice(&self.p_align.to_le_bytes());
130        b
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use hex_literal::hex;
137
138    use crate::program_header::ProgramHeader;
139
140    #[test]
141    fn serialize_e2e() {
142        let b = hex!(
143            "0100000005000000780000000000000078000000000000007800000000000000080000000000000008000000000000000010000000000000"
144        );
145        let h = ProgramHeader::from_bytes(&b).unwrap();
146        assert_eq!(h.to_bytes(), &b)
147    }
148}