elf/
section.rs

1//! Parsing the Section Header table
2use crate::endian::EndianParse;
3use crate::file::Class;
4use crate::parse::{ParseAt, ParseError, ParsingTable};
5
6pub type SectionHeaderTable<'data, E> = ParsingTable<'data, E, SectionHeader>;
7
8/// C-style 32-bit ELF Section Header definition
9///
10/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
11#[derive(Debug)]
12#[repr(C)]
13pub struct Elf32_Shdr {
14    pub sh_name: u32,
15    pub sh_type: u32,
16    pub sh_flags: u32,
17    pub sh_addr: u32,
18    pub sh_offset: u32,
19    pub sh_size: u32,
20    pub sh_link: u32,
21    pub sh_info: u32,
22    pub sh_addralign: u32,
23    pub sh_entsize: u32,
24}
25
26/// C-style 64-bit ELF Section Header definition
27///
28/// These C-style definitions are for users who want to implement their own ELF manipulation logic.
29#[derive(Debug)]
30#[repr(C)]
31pub struct Elf64_Shdr {
32    pub sh_name: u32,
33    pub sh_type: u32,
34    pub sh_flags: u64,
35    pub sh_addr: u64,
36    pub sh_offset: u64,
37    pub sh_size: u64,
38    pub sh_link: u32,
39    pub sh_info: u32,
40    pub sh_addralign: u64,
41    pub sh_entsize: u64,
42}
43
44/// Encapsulates the contents of an ELF Section Header
45///
46/// This is a Rust-native type that represents a Section Header that is bit-width-agnostic.
47#[derive(Copy, Clone, Debug, PartialEq, Eq)]
48pub struct SectionHeader {
49    /// Section Name
50    pub sh_name: u32,
51    /// Section Type
52    pub sh_type: u32,
53    /// Section Flags
54    pub sh_flags: u64,
55    /// in-memory address where this section is loaded
56    pub sh_addr: u64,
57    /// Byte-offset into the file where this section starts
58    pub sh_offset: u64,
59    /// Section size in bytes
60    pub sh_size: u64,
61    /// Defined by section type
62    pub sh_link: u32,
63    /// Defined by section type
64    pub sh_info: u32,
65    /// address alignment
66    pub sh_addralign: u64,
67    /// size of an entry if section data is an array of entries
68    pub sh_entsize: u64,
69}
70
71impl ParseAt for SectionHeader {
72    fn parse_at<E: EndianParse>(
73        endian: E,
74        class: Class,
75        offset: &mut usize,
76        data: &[u8],
77    ) -> Result<Self, ParseError> {
78        match class {
79            Class::ELF32 => Ok(SectionHeader {
80                sh_name: endian.parse_u32_at(offset, data)?,
81                sh_type: endian.parse_u32_at(offset, data)?,
82                sh_flags: endian.parse_u32_at(offset, data)? as u64,
83                sh_addr: endian.parse_u32_at(offset, data)? as u64,
84                sh_offset: endian.parse_u32_at(offset, data)? as u64,
85                sh_size: endian.parse_u32_at(offset, data)? as u64,
86                sh_link: endian.parse_u32_at(offset, data)?,
87                sh_info: endian.parse_u32_at(offset, data)?,
88                sh_addralign: endian.parse_u32_at(offset, data)? as u64,
89                sh_entsize: endian.parse_u32_at(offset, data)? as u64,
90            }),
91            Class::ELF64 => Ok(SectionHeader {
92                sh_name: endian.parse_u32_at(offset, data)?,
93                sh_type: endian.parse_u32_at(offset, data)?,
94                sh_flags: endian.parse_u64_at(offset, data)?,
95                sh_addr: endian.parse_u64_at(offset, data)?,
96                sh_offset: endian.parse_u64_at(offset, data)?,
97                sh_size: endian.parse_u64_at(offset, data)?,
98                sh_link: endian.parse_u32_at(offset, data)?,
99                sh_info: endian.parse_u32_at(offset, data)?,
100                sh_addralign: endian.parse_u64_at(offset, data)?,
101                sh_entsize: endian.parse_u64_at(offset, data)?,
102            }),
103        }
104    }
105
106    #[inline]
107    fn size_for(class: Class) -> usize {
108        match class {
109            Class::ELF32 => 40,
110            Class::ELF64 => 64,
111        }
112    }
113}
114
115impl SectionHeader {
116    /// Helper method which uses checked integer math to get a tuple of (start,end) for
117    /// this SectionHeader's (sh_offset, sh_offset + sh_size)
118    pub(crate) fn get_data_range(&self) -> Result<(usize, usize), ParseError> {
119        let start: usize = self.sh_offset.try_into()?;
120        let size: usize = self.sh_size.try_into()?;
121        let end = start.checked_add(size).ok_or(ParseError::IntegerOverflow)?;
122        Ok((start, end))
123    }
124}
125
126#[cfg(test)]
127mod parse_tests {
128    use super::*;
129    use crate::endian::{BigEndian, LittleEndian};
130    use crate::parse::{test_parse_for, test_parse_fuzz_too_short};
131
132    #[test]
133    fn parse_shdr32_lsb() {
134        test_parse_for(
135            LittleEndian,
136            Class::ELF32,
137            SectionHeader {
138                sh_name: 0x03020100,
139                sh_type: 0x07060504,
140                sh_flags: 0xB0A0908,
141                sh_addr: 0x0F0E0D0C,
142                sh_offset: 0x13121110,
143                sh_size: 0x17161514,
144                sh_link: 0x1B1A1918,
145                sh_info: 0x1F1E1D1C,
146                sh_addralign: 0x23222120,
147                sh_entsize: 0x27262524,
148            },
149        );
150    }
151
152    #[test]
153    fn parse_shdr32_msb() {
154        test_parse_for(
155            BigEndian,
156            Class::ELF32,
157            SectionHeader {
158                sh_name: 0x00010203,
159                sh_type: 0x04050607,
160                sh_flags: 0x08090A0B,
161                sh_addr: 0x0C0D0E0F,
162                sh_offset: 0x10111213,
163                sh_size: 0x14151617,
164                sh_link: 0x18191A1B,
165                sh_info: 0x1C1D1E1F,
166                sh_addralign: 0x20212223,
167                sh_entsize: 0x24252627,
168            },
169        );
170    }
171
172    #[test]
173    fn parse_shdr64_lsb() {
174        test_parse_for(
175            LittleEndian,
176            Class::ELF64,
177            SectionHeader {
178                sh_name: 0x03020100,
179                sh_type: 0x07060504,
180                sh_flags: 0x0F0E0D0C0B0A0908,
181                sh_addr: 0x1716151413121110,
182                sh_offset: 0x1F1E1D1C1B1A1918,
183                sh_size: 0x2726252423222120,
184                sh_link: 0x2B2A2928,
185                sh_info: 0x2F2E2D2C,
186                sh_addralign: 0x3736353433323130,
187                sh_entsize: 0x3F3E3D3C3B3A3938,
188            },
189        );
190    }
191
192    #[test]
193    fn parse_shdr64_msb() {
194        test_parse_for(
195            BigEndian,
196            Class::ELF64,
197            SectionHeader {
198                sh_name: 0x00010203,
199                sh_type: 0x04050607,
200                sh_flags: 0x08090A0B0C0D0E0F,
201                sh_addr: 0x1011121314151617,
202                sh_offset: 0x18191A1B1C1D1E1F,
203                sh_size: 0x2021222324252627,
204                sh_link: 0x28292A2B,
205                sh_info: 0x2C2D2E2F,
206                sh_addralign: 0x3031323334353637,
207                sh_entsize: 0x38393A3B3C3D3E3F,
208            },
209        );
210    }
211
212    #[test]
213    fn parse_shdr32_lsb_fuzz_too_short() {
214        test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF32);
215    }
216
217    #[test]
218    fn parse_shdr32_msb_fuzz_too_short() {
219        test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF32);
220    }
221
222    #[test]
223    fn parse_shdr64_lsb_fuzz_too_short() {
224        test_parse_fuzz_too_short::<_, SectionHeader>(LittleEndian, Class::ELF64);
225    }
226
227    #[test]
228    fn parse_shdr64_msb_fuzz_too_short() {
229        test_parse_fuzz_too_short::<_, SectionHeader>(BigEndian, Class::ELF64);
230    }
231}