elfkit/
section.rs

1use error::Error;
2use header::Header;
3use relocation::Relocation;
4use dynamic::Dynamic;
5use symbol::Symbol;
6use strtab::Strtab;
7use types;
8
9use std::io::{Read, Seek, SeekFrom, Write};
10use std::io::BufWriter;
11
12#[derive(Default, Debug, Clone)]
13pub struct SectionHeader {
14    pub name:       u32,
15    pub shtype:     types::SectionType,
16    pub flags:      types::SectionFlags,
17    pub addr:       u64,
18    pub offset:     u64,
19    pub size:       u64,
20    pub link:       u32,
21    pub info:       u32,
22    pub addralign:  u64,
23    pub entsize:    u64,
24}
25
26impl SectionHeader {
27    pub fn entsize(eh: &Header) -> usize {
28        4 + 4 + match eh.ident_class {
29            types::Class::Class64 => 6 * 8,
30            types::Class::Class32 => 6 * 4,
31        } + 4 + 4
32    }
33
34    pub fn from_reader<R>(io: &mut R, eh: &Header) -> Result<SectionHeader, Error>
35    where
36        R: Read,
37    {
38        elf_dispatch_endianness!(eh => {
39            let mut r = SectionHeader::default();
40            r.name   = read_u32(io)?;
41            let reb  = read_u32(io)?;
42            r.shtype = types::SectionType(reb);
43
44            elf_dispatch_uclass!(eh => {
45                let reb = read_uclass(io)?;
46                r.flags = match types::SectionFlags::from_bits(reb) {
47                    Some(v) => v,
48                    None => return Err(Error::InvalidSectionFlags(reb)),
49                };
50                r.addr   = read_uclass(io)?;
51                r.offset = read_uclass(io)?;
52                r.size   = read_uclass(io)?;
53                r.link   = read_u32(io)?;
54                r.info   = read_u32(io)?;
55                r.addralign = read_uclass(io)?;
56                r.entsize = read_uclass(io)?;
57                Ok(r)
58            })
59        })
60    }
61
62    pub fn to_writer<R>(&self, eh: &Header, io: &mut R) -> Result<(), Error>
63    where
64        R: Write,
65    {
66        let mut w = BufWriter::new(io);
67        elf_write_u32!(eh, w, self.name)?;
68        elf_write_u32!(eh, w, self.shtype.to_u32())?;
69        elf_write_uclass!(eh, w, self.flags.bits())?;
70
71        elf_write_uclass!(eh, w, self.addr)?;
72        elf_write_uclass!(eh, w, self.offset)?;
73        elf_write_uclass!(eh, w, self.size)?;
74        elf_write_u32!(eh, w, self.link)?;
75        elf_write_u32!(eh, w, self.info)?;
76        elf_write_uclass!(eh, w, self.addralign)?;
77        elf_write_uclass!(eh, w, self.entsize)?;
78        Ok(())
79    }
80}
81
82#[derive(Debug, Clone)]
83pub enum SectionContent {
84    None,
85    Unloaded,
86    Raw(Vec<u8>),
87    Relocations(Vec<Relocation>),
88    Symbols(Vec<Symbol>),
89    Dynamic(Vec<Dynamic>),
90    Strtab(Strtab),
91}
92
93impl Default for SectionContent {
94    fn default() -> Self {
95        SectionContent::None
96    }
97}
98impl SectionContent {
99    pub fn as_dynamic_mut(&mut self) -> Option<&mut Vec<Dynamic>> {
100        match self {
101            &mut SectionContent::Dynamic(ref mut v) => Some(v),
102            _ => None,
103        }
104    }
105    pub fn as_dynamic(&self) -> Option<&Vec<Dynamic>> {
106        match self {
107            &SectionContent::Dynamic(ref v) => Some(v),
108            _ => None,
109        }
110    }
111    pub fn into_dynamic(self) -> Option<Vec<Dynamic>> {
112        match self {
113            SectionContent::Dynamic(v) => Some(v),
114            _ => None,
115        }
116    }
117    pub fn as_strtab_mut(&mut self) -> Option<&mut Strtab> {
118        match self {
119            &mut SectionContent::Strtab(ref mut v) => Some(v),
120            _ => None,
121        }
122    }
123    pub fn as_symbols(&self) -> Option<&Vec<Symbol>> {
124        match self {
125            &SectionContent::Symbols(ref v) => Some(v),
126            _ => None,
127        }
128    }
129    pub fn as_symbols_mut(&mut self) -> Option<&mut Vec<Symbol>> {
130        match self {
131            &mut SectionContent::Symbols(ref mut v) => Some(v),
132            _ => None,
133        }
134    }
135    pub fn into_symbols(self) -> Option<Vec<Symbol>> {
136        match self {
137            SectionContent::Symbols(v) => Some(v),
138            _ => None,
139        }
140    }
141    pub fn as_relocations(&self) -> Option<&Vec<Relocation>> {
142        match self {
143            &SectionContent::Relocations(ref v) => Some(v),
144            _ => None,
145        }
146    }
147    pub fn as_relocations_mut(&mut self) -> Option<&mut Vec<Relocation>> {
148        match self {
149            &mut SectionContent::Relocations(ref mut v) => Some(v),
150            _ => None,
151        }
152    }
153    pub fn into_relocations(self) -> Option<Vec<Relocation>> {
154        match self {
155            SectionContent::Relocations(v) => Some(v),
156            _ => None,
157        }
158    }
159    pub fn as_raw(&self) -> Option<&Vec<u8>> {
160        match self {
161            &SectionContent::Raw(ref v) => Some(v),
162            _ => None,
163        }
164    }
165    pub fn as_raw_mut(&mut self) -> Option<&mut Vec<u8>> {
166        match self {
167            &mut SectionContent::Raw(ref mut v) => Some(v),
168            _ => None,
169        }
170    }
171    pub fn into_raw(self) -> Option<Vec<u8>> {
172        match self {
173            SectionContent::Raw(v) => Some(v),
174            _ => None,
175        }
176    }
177    pub fn size(&self, eh: &Header) -> usize {
178        match self {
179            &SectionContent::Unloaded => panic!("cannot size unloaded section"),
180            &SectionContent::None => 0,
181            &SectionContent::Raw(ref v) => v.len(),
182            &SectionContent::Dynamic(ref v) => v.len() * Dynamic::entsize(eh),
183            &SectionContent::Strtab(ref v) => v.len(eh),
184            &SectionContent::Symbols(ref v) => v.len() * Symbol::entsize(eh),
185            &SectionContent::Relocations(ref v) => v.len() * Relocation::entsize(eh),
186        }
187    }
188}
189
190#[derive(Debug, Default, Clone)]
191pub struct Section {
192    pub header:     SectionHeader,
193    pub name:       Vec<u8>,
194    pub content:    SectionContent,
195    pub addrlock:   bool,
196}
197
198
199impl Section {
200    pub fn size(&self, eh: &Header) -> usize {
201        self.content.size(eh)
202    }
203    pub fn new(
204        name:       Vec<u8>,
205        shtype:     types::SectionType,
206        flags:      types::SectionFlags,
207        content:    SectionContent,
208        link:       u32,
209        info:       u32,
210    ) -> Section {
211        Section {
212            name: name,
213            header: SectionHeader {
214                name: 0,
215                shtype: shtype,
216                flags: flags,
217                addr: 0,
218                offset: 0,
219                size: 0,
220                link: link,
221                info: info,
222                addralign: 0,
223                entsize: 0,
224            },
225            content: content,
226            addrlock: false,
227        }
228    }
229
230    pub fn sync(
231        &mut self,
232        eh: &Header,
233        mut linked: Option<&mut SectionContent>,
234    ) -> Result<(), Error> {
235        match self.content {
236            SectionContent::Unloaded => {
237                return Err(Error::SyncingUnloadedSection);
238            },
239            SectionContent::Relocations(_) => {
240                self.header.entsize = Relocation::entsize(eh) as u64;
241            }
242            SectionContent::Symbols(ref mut vv) => {
243                for (i, sym) in vv.iter().enumerate() {
244                    if sym.bind == types::SymbolBind::GLOBAL {
245                        self.header.info = i as u32;
246                        break;
247                    }
248                }
249                for v in vv {
250                    v.sync(linked.as_mut().map(|r| &mut **r), eh)?;
251                }
252                self.header.entsize = Symbol::entsize(eh) as u64;
253            }
254            SectionContent::Dynamic(ref mut vv) => {
255                for v in vv {
256                    v.sync(linked.as_mut().map(|r| &mut **r), eh)?;
257                }
258                self.header.entsize = Dynamic::entsize(eh) as u64;
259            }
260            SectionContent::Strtab(_) => {
261                self.header.entsize = Strtab::entsize(eh) as u64;
262            }
263            SectionContent::None | SectionContent::Raw(_) => {}
264        }
265        if self.header.shtype != types::SectionType::NOBITS {
266            self.header.size = self.size(eh) as u64;
267        }
268        Ok(())
269    }
270
271    pub fn from_reader<T>(
272        &mut self,
273        mut io: T,
274        linked: Option<&Section>,
275        eh: &Header,
276    ) -> Result<(), Error> where T: Read + Seek {
277        match self.content {
278            SectionContent::Unloaded => {},
279            _ => return Ok(()),
280        };
281        if self.header.shtype == types::SectionType::NOBITS {
282            self.content = SectionContent::None;
283            return Ok(());
284        };
285        io.seek(SeekFrom::Start(self.header.offset))?;
286        let mut bb = vec![0; self.header.size as usize];
287        io.read_exact(&mut bb)?;
288        let linked = linked.map(|s|&s.content);
289        self.content = match self.header.shtype {
290            types::SectionType::NOBITS => {
291                unreachable!();
292            },
293            types::SectionType::STRTAB => {
294                let io = bb.as_slice();
295                Strtab::from_reader(io, linked, eh)?
296            }
297            types::SectionType::RELA => {
298                let io = bb.as_slice();
299                Relocation::from_reader(io, linked, eh)?
300            }
301            types::SectionType::SYMTAB | types::SectionType::DYNSYM => {
302                let io = bb.as_slice();
303                Symbol::from_reader(io, linked, eh)?
304            }
305            types::SectionType::DYNAMIC => {
306                let io = bb.as_slice();
307                Dynamic::from_reader(io, linked, eh)?
308            }
309            _ => {
310                SectionContent::Raw(bb)
311            }
312        };
313        Ok(())
314    }
315
316
317    pub fn to_writer<R>(
318        &self,
319        mut io: R,
320        eh: &Header,
321    ) -> Result<(), Error> where R: Write + Seek {
322        match self.content {
323            SectionContent::Unloaded => return Ok(()),
324            _ => {},
325        };
326        io.seek(SeekFrom::Start(self.header.offset))?;
327
328        let rs = match &self.content {
329            &SectionContent::Unloaded => {
330                return Err(Error::WritingUnloadedSection);
331            },
332            &SectionContent::Relocations(ref vv) => {
333                let mut rs = 0;
334                for v in vv {
335                    rs += v.to_writer(&mut io, eh)?;
336                }
337                rs
338            }
339            &SectionContent::Symbols(ref vv) => {
340                let mut rs = 0;
341                for v in vv {
342                    rs += v.to_writer(&mut io, eh)?;
343                }
344                rs
345            }
346            &SectionContent::Dynamic(ref vv) => {
347                let mut rs = 0;
348                for v in vv {
349                    rs += v.to_writer(&mut io, eh)?;
350                }
351                rs
352            }
353            &SectionContent::Strtab(ref v) => {
354                v.to_writer(&mut io, eh)?
355            }
356            &SectionContent::None => {
357                0
358            },
359            &SectionContent::Raw(ref raw) => {
360                io.write(&raw)?
361            }
362        };
363
364        assert_eq!(
365            io.seek(SeekFrom::Current(0))?,
366            self.header.offset + self.content.size(eh) as u64,
367            "writing {} with header.size {} and content.size {} returned a written size {}",
368            String::from_utf8_lossy(&self.name),
369            self.content.size(eh),
370            self.header.size,
371            rs
372            );
373
374        Ok(())
375    }
376
377}