elf_utilities/section/
elf32.rs

1//! Type definitions for 32-bit ELF binaries.
2
3use std::collections::HashSet;
4
5use crate::*;
6
7use serde::{Deserialize, Serialize};
8
9use super::StrTabEntry;
10
11#[derive(Debug, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
12/// section's contents
13pub enum Contents32 {
14    /// almost section's data
15    Raw(Vec<u8>),
16    /// String Table
17    StrTab(Vec<StrTabEntry>),
18    /// symbol table's representation
19    Symbols(Vec<symbol::Symbol32>),
20    /// relocation symbol table's representation
21    RelaSymbols(Vec<relocation::Rela32>),
22    /// dynamic information's representation
23    Dynamics(Vec<dynamic::Dyn32>),
24}
25
26#[derive(Default, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
27pub struct Section32 {
28    pub name: String,
29    pub header: Shdr32,
30    pub contents: Contents32,
31}
32
33#[derive(Debug, Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize)]
34#[repr(C)]
35pub struct Shdr32 {
36    /// Section name, index in string tbl
37    pub sh_name: Elf32Word,
38    /// Type of section
39    pub sh_type: Elf32Word,
40    /// Miscellaneous section attributes
41    pub sh_flags: Elf32Word,
42    ///  Section virtual addr at execution
43    pub sh_addr: Elf32Addr,
44    /// Section file offset
45    pub sh_offset: Elf32Off,
46    /// Size of section in bytes
47    pub sh_size: Elf32Word,
48    /// Index of another section
49    pub sh_link: Elf32Word,
50    /// Additional section information
51    pub sh_info: Elf32Word,
52    /// Section alignment
53    pub sh_addralign: Elf32Word,
54    /// Entry size if section holds table
55    pub sh_entsize: Elf32Word,
56}
57
58/// A `Shdr32` builder
59///
60/// # Examples
61///
62/// ```
63/// use elf_utilities::section;
64/// let shdr: section::Shdr32 = section::ShdrPreparation32::default()
65///            .ty(section::Type::ProgBits)
66///            .flags(vec![section::Flag::Alloc, section::Flag::Write].iter())
67///            .into();
68///
69/// assert_eq!(section::Type::ProgBits, shdr.get_type());
70/// assert!(shdr.get_flags().contains(&section::Flag::Alloc));
71/// assert!(shdr.get_flags().contains(&section::Flag::Write));
72/// ```
73#[derive(Clone, Copy, Hash, PartialOrd, Ord, PartialEq, Eq)]
74#[repr(C)]
75pub struct ShdrPreparation32 {
76    /// Type of section
77    pub sh_type: section::Type,
78    /// Miscellaneous section attributes
79    pub sh_flags: Elf32Word,
80    /// Index of another section
81    pub sh_link: Elf32Word,
82    /// Additional section information
83    pub sh_info: Elf32Word,
84    /// Section alignment
85    pub sh_addralign: Elf32Word,
86}
87
88impl Default for Contents32 {
89    fn default() -> Self {
90        Contents32::Raw(Default::default())
91    }
92}
93
94impl Contents32 {
95    pub fn size(&self) -> usize {
96        match self {
97            Contents32::Raw(bytes) => bytes.len(),
98            Contents32::StrTab(strs) => {
99                // ELFの文字列テーブルは null-byte + (name + null-byte) * n という形状に
100                let total_len: usize = strs.iter().map(|s| s.v.len()).sum();
101                total_len + strs.len() + 1
102            }
103            Contents32::Symbols(syms) => symbol::Symbol32::SIZE * syms.len(),
104            Contents32::RelaSymbols(rela_syms) => {
105                relocation::Rela32::SIZE as usize * rela_syms.len()
106            }
107            Contents32::Dynamics(dyn_info) => dynamic::Dyn32::SIZE * dyn_info.len(),
108        }
109    }
110
111    pub fn new_string_table(strs: Vec<String>) -> Self {
112        let mut name_idx = 1;
113        let strs = strs
114            .iter()
115            .map(|s| {
116                let ent = StrTabEntry {
117                    v: s.clone(),
118                    idx: name_idx,
119                };
120                name_idx += s.len() + 1;
121                ent
122            })
123            .collect();
124
125        Contents32::StrTab(strs)
126    }
127}
128
129impl Default for Shdr32 {
130    fn default() -> Self {
131        Self {
132            sh_name: 0,
133            sh_type: 0,
134            sh_flags: 0,
135            sh_addr: 0,
136            sh_offset: 0,
137            sh_size: 0,
138            sh_link: 0,
139            sh_info: 0,
140            sh_addralign: 0,
141            sh_entsize: 0,
142        }
143    }
144}
145
146impl Section32 {
147    pub fn new(name: String, hdr: ShdrPreparation32, contents: Contents32) -> Self {
148        Self {
149            contents,
150            name,
151            header: hdr.into(),
152        }
153    }
154
155    /// create binary without header
156    pub fn to_le_bytes(&self) -> Vec<u8> {
157        match &self.contents {
158            Contents32::Raw(bytes) => bytes.clone(),
159            Contents32::StrTab(strs) => {
160                // ELFの文字列テーブルは null-byte + (name + null-byte) * n という形状に
161                // それに合うようにバイト列を構築.
162                let mut string_table: Vec<u8> = vec![0x00];
163
164                for st in strs {
165                    for byte in st.v.as_bytes() {
166                        string_table.push(*byte);
167                    }
168                    string_table.push(0x00);
169                }
170
171                string_table
172            }
173            Contents32::Symbols(syms) => {
174                let mut bytes = Vec::new();
175                for sym in syms.iter() {
176                    bytes.append(&mut sym.to_le_bytes());
177                }
178                bytes
179            }
180            Contents32::RelaSymbols(rela_syms) => {
181                let mut bytes = Vec::new();
182                for sym in rela_syms.iter() {
183                    bytes.append(&mut sym.to_le_bytes());
184                }
185                bytes
186            }
187            Contents32::Dynamics(dynamics) => {
188                let mut bytes = Vec::new();
189                for sym in dynamics.iter() {
190                    bytes.append(&mut sym.to_le_bytes());
191                }
192                bytes
193            }
194        }
195    }
196
197    pub fn new_null_section() -> Self {
198        Default::default()
199    }
200}
201
202#[allow(dead_code)]
203impl Shdr32 {
204    pub const SIZE: usize = 40;
205    // getter
206    pub fn get_type(&self) -> section::Type {
207        section::Type::from(self.sh_type)
208    }
209    pub fn get_flags(&self) -> HashSet<section::Flag> {
210        let mut mask: Elf32Word = 0b1;
211        let mut flags = HashSet::new();
212        loop {
213            if mask == 0 {
214                break;
215            }
216            if self.sh_flags & mask != 0 {
217                flags.insert(section::Flag::from(mask));
218            }
219            mask <<= 1;
220        }
221
222        flags
223    }
224    // setter
225    pub fn set_type(&mut self, ty: section::Type) {
226        self.sh_type = ty.into();
227    }
228    pub fn set_flags<'a, I>(&mut self, flags: I)
229    where
230        I: Iterator<Item = &'a section::Flag>,
231    {
232        for flag in flags {
233            self.sh_flags = self.sh_flags | Into::<Elf32Word>::into(*flag);
234        }
235    }
236
237    /// Create Vec<u8> from this.
238    ///
239    /// # Examples
240    ///
241    /// ```
242    /// use elf_utilities::section::Shdr32;
243    /// let null_sct : Shdr32 = Default::default();
244    ///
245    /// assert_eq!([0].repeat(Shdr32::SIZE), null_sct.to_le_bytes());
246    /// ```
247    pub fn to_le_bytes(&self) -> Vec<u8> {
248        bincode::serialize(self).unwrap()
249    }
250}
251
252impl ShdrPreparation32 {
253    pub fn ty(mut self, t: section::Type) -> Self {
254        self.sh_type = t;
255        self
256    }
257
258    pub fn flags<'a, I>(mut self, flags: I) -> Self
259    where
260        I: Iterator<Item = &'a section::Flag>,
261    {
262        for flag in flags {
263            self.sh_flags |= Into::<Elf32Word>::into(*flag);
264        }
265
266        self
267    }
268
269    pub fn link(mut self, link: Elf32Word) -> Self {
270        self.sh_link = link;
271        self
272    }
273    pub fn info(mut self, info: Elf32Word) -> Self {
274        self.sh_info = info;
275        self
276    }
277}
278
279impl Default for ShdrPreparation32 {
280    fn default() -> Self {
281        Self {
282            sh_type: section::Type::Null,
283            sh_flags: 0,
284            sh_link: 0,
285            sh_info: 0,
286            sh_addralign: 0,
287        }
288    }
289}
290impl Into<Shdr32> for ShdrPreparation32 {
291    fn into(self) -> Shdr32 {
292        Shdr32 {
293            sh_name: 0,
294            sh_type: self.sh_type.into(),
295            sh_flags: self.sh_flags,
296            sh_addr: 0,
297            sh_offset: 0,
298            sh_size: 0,
299            sh_link: self.sh_link,
300            sh_info: self.sh_info,
301            sh_addralign: self.sh_addralign,
302            sh_entsize: 0,
303        }
304    }
305}
306
307#[cfg(test)]
308mod elf32_tests {
309    use super::*;
310
311    #[test]
312    fn section32_test() {
313        let sct = Section32::new_null_section();
314
315        assert_eq!(vec![0x00; Shdr32::SIZE], sct.header.to_le_bytes(),);
316
317        assert_eq!(Vec::new() as Vec<u8>, sct.to_le_bytes(),);
318    }
319}