1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::Elf;
use crate::ElfError;
use core::str;
use scroll_derive::Pread;
use bit_field::BitField;

#[derive(PartialEq, Eq)]
pub enum SectionType {
    /// The first section in a valid ELF's section table will be a null section. It does not detail
    /// a real section.
    Null,

    /// Contains information defined by the program.
    ProgBits,

    /// Contains a symbol table.
    SymTab,

    /// Contains a string table.
    StrTab,

    /// Contains "Rela"-type relocations.
    Rela,

    /// Contains a symbol hash table.
    Hash,

    /// Contains tables used during dynamic linking.
    Dynamic,

    /// Contains note information.
    Note,

    /// Defines a section as containing uninitialized space. This section does not take up any
    /// space in the file and is usually loaded with `0`s during program loading.
    NoBits,

    /// Contains "Rel"-type relocations.
    Rel,

    /// Reserved by the spec.
    ShLib,

    /// Contains a dynamic loader symbol table.
    DynSym,

    /// A section with type `0x60000000` through `0x6fffffff` inclusive is defined to be
    /// environment-specific.
    Os(u32),

    /// A section with type `0x70000000` through `0x7fffffff` inclusive is defined to be
    /// processor-specific.
    Proc(u32),
}

#[derive(Debug, Pread)]
#[repr(C)]
pub struct SectionHeader {
    pub name: u32,
    pub section_type: u32,
    pub flags: u64,
    pub address: u64,
    pub offset: u64,
    pub size: u64,

    /// Some sections are 'linked' to another section. This field contains the index of the linked
    /// section.
    pub link: u32,

    /// Can contain extra information about a section.
    pub info: u32,
    pub alignment: u64,

    /// If this section contains a table, this is the size of one entry
    pub entry_size: u64,
}

impl SectionHeader {
    pub(crate) fn validate(&self) -> Result<(), ElfError> {
        match self.section_type {
            0..=11 | 0x60000000..=0x7fffffff => Ok(()),
            _ => Err(ElfError::SectionInvalidType),
        }?;

        Ok(())
    }

    pub fn section_type(&self) -> SectionType {
        match self.section_type {
            0 => SectionType::Null,
            1 => SectionType::ProgBits,
            2 => SectionType::SymTab,
            3 => SectionType::StrTab,
            4 => SectionType::Rela,
            5 => SectionType::Hash,
            6 => SectionType::Dynamic,
            7 => SectionType::Note,
            8 => SectionType::NoBits,
            9 => SectionType::Rel,
            10 => SectionType::ShLib,
            11 => SectionType::DynSym,
            0x60000000..=0x6fffffff => SectionType::Os(self.section_type),
            0x70000000..=0x7fffffff => SectionType::Proc(self.section_type),

            _ => panic!("section_type called on section with invalid type. Was validate called?"),
        }
    }

    pub fn name<'a>(&self, elf: &'a Elf) -> Option<&'a str> {
        if self.name == 0 {
            return None;
        }

        let string_table = elf.sections().nth(elf.header.string_table_index as usize)?;
        crate::from_utf8_null_terminated(&string_table.data(elf)?[(self.name as usize)..]).ok()
    }

    /// Get this section's data, as a byte slice. Returns `None` if the image isn't represented in
    /// the file (for example, `NoBits` sections don't have any data).
    pub fn data<'a>(&self, elf: &'a Elf) -> Option<&'a [u8]> {
        match self.section_type() {
            SectionType::Null | SectionType::NoBits => return None,
            _ => (),
        }

        Some(&elf.bytes[(self.offset as usize)..((self.offset + self.size) as usize)])
    }

    /// Whether this section contains writable data
    pub fn is_writable(&self) -> bool {
        self.flags.get_bit(0)
    }

    /// Whether this section should be allocated into the memory image of the program
    pub fn is_allocated(&self) -> bool {
        self.flags.get_bit(1)
    }

    /// Whether this section contains executable instructions
    pub fn is_executable(&self) -> bool {
        self.flags.get_bit(2)
    }
}