mer/
section.rs

1use crate::{Elf, ElfError};
2use bit_field::BitField;
3use core::str;
4use scroll::Pread;
5
6#[derive(PartialEq, Eq)]
7pub enum SectionType {
8    /// The first section in a valid ELF's section table will be a null section. It does not detail
9    /// a real section.
10    Null,
11
12    /// Contains information defined by the program.
13    ProgBits,
14
15    /// Contains a symbol table.
16    SymTab,
17
18    /// Contains a string table.
19    StrTab,
20
21    /// Contains "Rela"-type relocations.
22    Rela,
23
24    /// Contains a symbol hash table.
25    Hash,
26
27    /// Contains tables used during dynamic linking.
28    Dynamic,
29
30    /// Contains note information.
31    Note,
32
33    /// Defines a section as containing uninitialized space. This section does not take up any
34    /// space in the file and is usually loaded with `0`s during program loading.
35    NoBits,
36
37    /// Contains "Rel"-type relocations.
38    Rel,
39
40    /// Reserved by the spec.
41    ShLib,
42
43    /// Contains a dynamic loader symbol table.
44    DynSym,
45
46    /// A section with type `0x60000000` through `0x6fffffff` inclusive is defined to be
47    /// environment-specific.
48    Os(u32),
49
50    /// A section with type `0x70000000` through `0x7fffffff` inclusive is defined to be
51    /// processor-specific.
52    Proc(u32),
53}
54
55#[derive(Debug, Pread)]
56#[repr(C)]
57pub struct SectionHeader {
58    pub name: u32,
59    pub section_type: u32,
60    pub flags: u64,
61    pub address: u64,
62    pub offset: u64,
63    pub size: u64,
64
65    /// Some sections are 'linked' to another section. This field contains the index of the linked
66    /// section.
67    pub link: u32,
68
69    /// Can contain extra information about a section.
70    pub info: u32,
71    pub alignment: u64,
72
73    /// If this section contains a table, this is the size of one entry
74    pub entry_size: u64,
75}
76
77impl SectionHeader {
78    pub(crate) fn validate(&self) -> Result<(), ElfError> {
79        match self.section_type {
80            0..=11 | 0x60000000..=0x7fffffff => Ok(()),
81            _ => Err(ElfError::SectionInvalidType),
82        }?;
83
84        Ok(())
85    }
86
87    pub fn section_type(&self) -> SectionType {
88        match self.section_type {
89            0 => SectionType::Null,
90            1 => SectionType::ProgBits,
91            2 => SectionType::SymTab,
92            3 => SectionType::StrTab,
93            4 => SectionType::Rela,
94            5 => SectionType::Hash,
95            6 => SectionType::Dynamic,
96            7 => SectionType::Note,
97            8 => SectionType::NoBits,
98            9 => SectionType::Rel,
99            10 => SectionType::ShLib,
100            11 => SectionType::DynSym,
101            0x60000000..=0x6fffffff => SectionType::Os(self.section_type),
102            0x70000000..=0x7fffffff => SectionType::Proc(self.section_type),
103
104            _ => panic!("section_type called on section with invalid type. Was validate called?"),
105        }
106    }
107
108    pub fn name<'a>(&self, elf: &'a Elf) -> Option<&'a str> {
109        if self.name == 0 {
110            return None;
111        }
112
113        let string_table = elf.sections().nth(elf.header.string_table_index as usize)?;
114        crate::from_utf8_null_terminated(&string_table.data(elf)?[(self.name as usize)..]).ok()
115    }
116
117    /// Get this section's data, as a byte slice. Returns `None` if the image isn't represented in
118    /// the file (for example, `NoBits` sections don't have any data).
119    pub fn data<'a>(&self, elf: &'a Elf) -> Option<&'a [u8]> {
120        match self.section_type() {
121            SectionType::Null | SectionType::NoBits => return None,
122            _ => (),
123        }
124
125        Some(&elf.bytes[(self.offset as usize)..((self.offset + self.size) as usize)])
126    }
127
128    /// Whether this section contains writable data
129    pub fn is_writable(&self) -> bool {
130        self.flags.get_bit(0)
131    }
132
133    /// Whether this section should be allocated into the memory image of the program
134    pub fn is_allocated(&self) -> bool {
135        self.flags.get_bit(1)
136    }
137
138    /// Whether this section contains executable instructions
139    pub fn is_executable(&self) -> bool {
140        self.flags.get_bit(2)
141    }
142}