1#[cfg(feature = "compression")]
2use std::borrow::Cow;
3#[cfg(feature = "compression")]
4use std::vec::Vec;
5
6use core::fmt;
7use core::mem;
8use core::slice;
9
10#[cfg(feature = "compression")]
11use flate2::{Decompress, FlushDecompress};
12
13use {P32, P64, ElfFile};
14use header::{Header, Class};
15use zero::{read, read_array, read_str, read_strs_to_null, StrReaderIterator, Pod};
16use symbol_table;
17use dynamic::Dynamic;
18use hash::HashTable;
19
20pub fn parse_section_header<'a>(input: &'a [u8],
21 header: Header<'a>,
22 index: u16)
23 -> Result<SectionHeader<'a>, &'static str> {
24 assert!(index < SHN_LORESERVE,
26 "Attempt to get section for a reserved index");
27
28 let start = (index as u64 * header.pt2.sh_entry_size() as u64 +
29 header.pt2.sh_offset() as u64) as usize;
30 let end = start + header.pt2.sh_entry_size() as usize;
31
32 Ok(match header.pt1.class() {
33 Class::ThirtyTwo => {
34 let header: &'a SectionHeader_<P32> = read(&input[start..end]);
35 SectionHeader::Sh32(header)
36 }
37 Class::SixtyFour => {
38 let header: &'a SectionHeader_<P64> = read(&input[start..end]);
39 SectionHeader::Sh64(header)
40 }
41 Class::None | Class::Other(_) => unreachable!(),
42 })
43}
44
45#[derive(Debug, Clone)]
46pub struct SectionIter<'b, 'a: 'b> {
47 pub file: &'b ElfFile<'a>,
48 pub next_index: u16,
49}
50
51impl<'b, 'a> Iterator for SectionIter<'b, 'a> {
52 type Item = SectionHeader<'a>;
53
54 fn next(&mut self) -> Option<Self::Item> {
55 let count = self.file.header.pt2.sh_count();
56 if self.next_index >= count {
57 return None;
58 }
59
60 let result = self.file.section_header(self.next_index);
61 self.next_index += 1;
62 result.ok()
63 }
64}
65
66pub const SHN_UNDEF: u16 = 0;
68pub const SHN_LORESERVE: u16 = 0xff00;
69pub const SHN_LOPROC: u16 = 0xff00;
70pub const SHN_HIPROC: u16 = 0xff1f;
71pub const SHN_LOOS: u16 = 0xff20;
72pub const SHN_HIOS: u16 = 0xff3f;
73pub const SHN_ABS: u16 = 0xfff1;
74pub const SHN_COMMON: u16 = 0xfff2;
75pub const SHN_XINDEX: u16 = 0xffff;
76pub const SHN_HIRESERVE: u16 = 0xffff;
77
78#[derive(Clone, Copy, Debug)]
79pub enum SectionHeader<'a> {
80 Sh32(&'a SectionHeader_<P32>),
81 Sh64(&'a SectionHeader_<P64>),
82}
83
84macro_rules! getter {
85 ($name: ident, $typ: ident) => {
86 pub fn $name(&self) -> $typ {
87 match *self {
88 SectionHeader::Sh32(h) => h.$name as $typ,
89 SectionHeader::Sh64(h) => h.$name as $typ,
90 }
91 }
92 }
93}
94
95impl<'a> SectionHeader<'a> {
96 pub fn get_name(&self, elf_file: &ElfFile<'a>) -> Result<&'a str, &'static str> {
98 self.get_type().and_then(|typ| match typ {
99 ShType::Null => Err("Attempt to get name of null section"),
100 _ => elf_file.get_shstr(self.name()),
101 })
102 }
103
104 pub fn get_type(&self) -> Result<ShType, &'static str> {
105 self.type_().as_sh_type()
106 }
107
108 pub fn get_data(&self, elf_file: &ElfFile<'a>) -> Result<SectionData<'a>, &'static str> {
109 macro_rules! array_data {
110 ($data32: ident, $data64: ident) => {{
111 let data = self.raw_data(elf_file);
112 match elf_file.header.pt1.class() {
113 Class::ThirtyTwo => SectionData::$data32(read_array(data)),
114 Class::SixtyFour => SectionData::$data64(read_array(data)),
115 Class::None | Class::Other(_) => unreachable!(),
116 }
117 }}
118 }
119
120 self.get_type().and_then(|typ| Ok(match typ {
121 ShType::Null | ShType::NoBits => SectionData::Empty,
122 ShType::ProgBits |
123 ShType::ShLib |
124 ShType::OsSpecific(_) |
125 ShType::ProcessorSpecific(_) |
126 ShType::User(_) => SectionData::Undefined(self.raw_data(elf_file)),
127 ShType::SymTab => array_data!(SymbolTable32, SymbolTable64),
128 ShType::DynSym => array_data!(DynSymbolTable32, DynSymbolTable64),
129 ShType::StrTab => SectionData::StrArray(self.raw_data(elf_file)),
130 ShType::InitArray | ShType::FiniArray | ShType::PreInitArray => {
131 array_data!(FnArray32, FnArray64)
132 }
133 ShType::Rela => array_data!(Rela32, Rela64),
134 ShType::Rel => array_data!(Rel32, Rel64),
135 ShType::Dynamic => array_data!(Dynamic32, Dynamic64),
136 ShType::Group => {
137 let data = self.raw_data(elf_file);
138 unsafe {
139 let flags: &'a u32 = mem::transmute(&data[0]);
140 let indicies: &'a [u32] = read_array(&data[4..]);
141 SectionData::Group {
142 flags,
143 indicies,
144 }
145 }
146 }
147 ShType::SymTabShIndex => {
148 SectionData::SymTabShIndex(read_array(self.raw_data(elf_file)))
149 }
150 ShType::Note => {
151 let data = self.raw_data(elf_file);
152 match elf_file.header.pt1.class() {
153 Class::ThirtyTwo => return Err("32-bit binaries not implemented"),
154 Class::SixtyFour => {
155 let header: &'a NoteHeader = read(&data[0..12]);
156 let index = &data[12..];
157 SectionData::Note64(header, index)
158 }
159 Class::None | Class::Other(_) => return Err("Unknown ELF class"),
160 }
161 }
162 ShType::Hash => {
163 let data = self.raw_data(elf_file);
164 SectionData::HashTable(read(&data[0..12]))
165 }
166 }))
167 }
168
169 pub fn raw_data(&self, elf_file: &ElfFile<'a>) -> &'a [u8] {
170 assert_ne!(self.get_type().unwrap(), ShType::Null);
171 &elf_file.input[self.offset() as usize..(self.offset() + self.size()) as usize]
172 }
173
174 #[cfg(feature = "compression")]
175 pub fn decompressed_data(&self, elf_file: &ElfFile<'a>) -> Result<Cow<'a, [u8]>, &'static str> {
176 let raw = self.raw_data(elf_file);
177 Ok(if (self.flags() & SHF_COMPRESSED) == 0 {
178 Cow::Borrowed(raw)
179 } else {
180 fn read_compression_header<'a, T: Pod + Clone>(raw: &'a [u8]) -> Result<(T, &'a [u8]), &'static str> {
181 if raw.len() < mem::size_of::<T>() {
182 return Err("Unexpected EOF in compressed section");
183 }
184
185 let (header, rest) = raw.split_at(mem::size_of::<T>());
186 let mut header_bytes = Vec::with_capacity(mem::size_of::<T>());
187 header_bytes.resize(mem::size_of::<T>(), 0);
188 assert!(header_bytes.as_ptr() as usize % mem::align_of::<T>() == 0);
189 header_bytes.copy_from_slice(header);
190 let header: &T = read(&header_bytes);
191 Ok((header.clone(), rest))
192 }
193 let (compression_type, size, compressed_data) = match elf_file.header.pt1.class() {
194 Class::ThirtyTwo => {
195 let (header, rest) = read_compression_header::<CompressionHeader32>(raw)?;
196 (header.type_.as_compression_type(), header.size as usize, rest)
197 },
198 Class::SixtyFour => {
199 let (header, rest) = read_compression_header::<CompressionHeader64>(raw)?;
200 (header.type_.as_compression_type(), header.size as usize, rest)
201 },
202 Class::None | Class::Other(_) => unreachable!(),
203 };
204
205 if compression_type != Ok(CompressionType::Zlib) {
206 return Err("Unknown compression type");
207 }
208
209 let mut decompressed = Vec::with_capacity(size);
210 let mut decompress = Decompress::new(true);
211 if let Err(_) = decompress.decompress_vec(
212 compressed_data, &mut decompressed, FlushDecompress::Finish) {
213 return Err("Decompression error");
214 }
215 Cow::Owned(decompressed)
216 })
217 }
218
219 getter!(flags, u64);
220 getter!(name, u32);
221 getter!(address, u64);
222 getter!(offset, u64);
223 getter!(size, u64);
224 getter!(type_, ShType_);
225 getter!(link, u32);
226 getter!(info, u32);
227 getter!(entry_size, u32);
228 getter!(align, u64);
229}
230
231impl<'a> fmt::Display for SectionHeader<'a> {
232 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
233 macro_rules! sh_display {
234 ($sh: ident) => {{
235 writeln!(f, "Section header:")?;
236 writeln!(f, " name: {:?}", $sh.name)?;
237 writeln!(f, " type: {:?}", self.get_type())?;
238 writeln!(f, " flags: {:?}", $sh.flags)?;
239 writeln!(f, " address: {:?}", $sh.address)?;
240 writeln!(f, " offset: {:?}", $sh.offset)?;
241 writeln!(f, " size: {:?}", $sh.size)?;
242 writeln!(f, " link: {:?}", $sh.link)?;
243 writeln!(f, " align: {:?}", $sh.align)?;
244 writeln!(f, " entry size: {:?}", $sh.entry_size)?;
245 Ok(())
246 }}
247 }
248
249 match *self {
250 SectionHeader::Sh32(sh) => sh_display!(sh),
251 SectionHeader::Sh64(sh) => sh_display!(sh),
252 }
253 }
254}
255
256#[derive(Debug)]
257#[repr(C)]
258pub struct SectionHeader_<P> {
259 name: u32,
260 type_: ShType_,
261 flags: P,
262 address: P,
263 offset: P,
264 size: P,
265 link: u32,
266 info: u32,
267 align: P,
268 entry_size: P,
269}
270
271unsafe impl<P> Pod for SectionHeader_<P> {}
272
273#[derive(Copy, Clone)]
274pub struct ShType_(u32);
275
276#[derive(Copy, Clone, Debug, PartialEq, Eq)]
277pub enum ShType {
278 Null,
279 ProgBits,
280 SymTab,
281 StrTab,
282 Rela,
283 Hash,
284 Dynamic,
285 Note,
286 NoBits,
287 Rel,
288 ShLib,
289 DynSym,
290 InitArray,
291 FiniArray,
292 PreInitArray,
293 Group,
294 SymTabShIndex,
295 OsSpecific(u32),
296 ProcessorSpecific(u32),
297 User(u32),
298}
299
300impl ShType_ {
301 fn as_sh_type(self) -> Result<ShType, &'static str> {
302 match self.0 {
303 0 => Ok(ShType::Null),
304 1 => Ok(ShType::ProgBits),
305 2 => Ok(ShType::SymTab),
306 3 => Ok(ShType::StrTab),
307 4 => Ok(ShType::Rela),
308 5 => Ok(ShType::Hash),
309 6 => Ok(ShType::Dynamic),
310 7 => Ok(ShType::Note),
311 8 => Ok(ShType::NoBits),
312 9 => Ok(ShType::Rel),
313 10 => Ok(ShType::ShLib),
314 11 => Ok(ShType::DynSym),
315 14 => Ok(ShType::InitArray),
317 15 => Ok(ShType::FiniArray),
318 16 => Ok(ShType::PreInitArray),
319 17 => Ok(ShType::Group),
320 18 => Ok(ShType::SymTabShIndex),
321 st if (SHT_LOOS..=SHT_HIOS).contains(&st) => Ok(ShType::OsSpecific(st)),
322 st if (SHT_LOPROC..=SHT_HIPROC).contains(&st) => Ok(ShType::ProcessorSpecific(st)),
323 st if (SHT_LOUSER..=SHT_HIUSER).contains(&st) => Ok(ShType::User(st)),
324 _ => Err("Invalid sh type"),
325 }
326 }
327}
328
329impl fmt::Debug for ShType_ {
330 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331 self.as_sh_type().fmt(f)
332 }
333}
334
335#[derive(Debug)]
336pub enum SectionData<'a> {
337 Empty,
338 Undefined(&'a [u8]),
339 Group { flags: &'a u32, indicies: &'a [u32] },
340 StrArray(&'a [u8]),
341 FnArray32(&'a [u32]),
342 FnArray64(&'a [u64]),
343 SymbolTable32(&'a [symbol_table::Entry32]),
344 SymbolTable64(&'a [symbol_table::Entry64]),
345 DynSymbolTable32(&'a [symbol_table::DynEntry32]),
346 DynSymbolTable64(&'a [symbol_table::DynEntry64]),
347 SymTabShIndex(&'a [u32]),
348 Note64(&'a NoteHeader, &'a [u8]),
351 Rela32(&'a [Rela<P32>]),
352 Rela64(&'a [Rela<P64>]),
353 Rel32(&'a [Rel<P32>]),
354 Rel64(&'a [Rel<P64>]),
355 Dynamic32(&'a [Dynamic<P32>]),
356 Dynamic64(&'a [Dynamic<P64>]),
357 HashTable(&'a HashTable),
358}
359
360#[derive(Debug)]
361pub struct SectionStrings<'a> {
362 inner: StrReaderIterator<'a>,
363}
364
365impl<'a> Iterator for SectionStrings<'a> {
366 type Item = &'a str;
367
368 #[inline]
369 fn next(&mut self) -> Option<&'a str> {
370 self.inner.next()
371 }
372}
373
374impl<'a> SectionData<'a> {
375 pub fn strings(&self) -> Result<SectionStrings<'a>, ()> {
376 if let SectionData::StrArray(data) = *self {
377 Ok(SectionStrings { inner: read_strs_to_null(data) })
378 } else {
379 Err(())
380 }
381 }
382}
383
384pub const SHT_LOOS: u32 = 0x60000000;
386pub const SHT_HIOS: u32 = 0x6fffffff;
387pub const SHT_LOPROC: u32 = 0x70000000;
388pub const SHT_HIPROC: u32 = 0x7fffffff;
389pub const SHT_LOUSER: u32 = 0x80000000;
390pub const SHT_HIUSER: u32 = 0xffffffff;
391
392pub const SHF_WRITE: u64 = 0x1;
394pub const SHF_ALLOC: u64 = 0x2;
395pub const SHF_EXECINSTR: u64 = 0x4;
396pub const SHF_MERGE: u64 = 0x10;
397pub const SHF_STRINGS: u64 = 0x20;
398pub const SHF_INFO_LINK: u64 = 0x40;
399pub const SHF_LINK_ORDER: u64 = 0x80;
400pub const SHF_OS_NONCONFORMING: u64 = 0x100;
401pub const SHF_GROUP: u64 = 0x200;
402pub const SHF_TLS: u64 = 0x400;
403pub const SHF_COMPRESSED: u64 = 0x800;
404pub const SHF_MASKOS: u64 = 0x0ff00000;
405pub const SHF_MASKPROC: u64 = 0xf0000000;
406
407#[derive(Copy, Clone, Debug)]
408#[repr(C)]
409pub struct CompressionHeader64 {
410 type_: CompressionType_,
411 _reserved: u32,
412 size: u64,
413 align: u64,
414}
415
416#[derive(Copy, Clone, Debug)]
417#[repr(C)]
418pub struct CompressionHeader32 {
419 type_: CompressionType_,
420 size: u32,
421 align: u32,
422}
423
424unsafe impl Pod for CompressionHeader64 {}
425unsafe impl Pod for CompressionHeader32 {}
426
427#[derive(Copy, Clone)]
428pub struct CompressionType_(u32);
429
430#[derive(Copy, Clone, Debug, PartialEq, Eq)]
431pub enum CompressionType {
432 Zlib,
433 OsSpecific(u32),
434 ProcessorSpecific(u32),
435}
436
437impl CompressionType_ {
438 fn as_compression_type(&self) -> Result<CompressionType, &'static str> {
439 match self.0 {
440 1 => Ok(CompressionType::Zlib),
441 ct if (COMPRESS_LOOS..=COMPRESS_HIOS).contains(&ct) => Ok(CompressionType::OsSpecific(ct)),
442 ct if (COMPRESS_LOPROC..=COMPRESS_HIPROC).contains(&ct) => {
443 Ok(CompressionType::ProcessorSpecific(ct))
444 }
445 _ => Err("Invalid compression type"),
446 }
447 }
448}
449
450impl fmt::Debug for CompressionType_ {
451 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452 self.as_compression_type().fmt(f)
453 }
454}
455
456pub const COMPRESS_LOOS: u32 = 0x60000000;
458pub const COMPRESS_HIOS: u32 = 0x6fffffff;
459pub const COMPRESS_LOPROC: u32 = 0x70000000;
460pub const COMPRESS_HIPROC: u32 = 0x7fffffff;
461
462pub const GRP_COMDAT: u64 = 0x1;
464pub const GRP_MASKOS: u64 = 0x0ff00000;
465pub const GRP_MASKPROC: u64 = 0xf0000000;
466
467#[derive(Debug)]
468#[repr(C)]
469pub struct Rela<P> {
470 offset: P,
471 info: P,
472 addend: P,
473}
474
475#[derive(Debug)]
476#[repr(C)]
477pub struct Rel<P> {
478 offset: P,
479 info: P,
480}
481
482unsafe impl<P> Pod for Rela<P> {}
483unsafe impl<P> Pod for Rel<P> {}
484
485impl Rela<P32> {
486 pub fn get_offset(&self) -> u32 {
487 self.offset
488 }
489 pub fn get_addend(&self) -> u32 {
490 self.addend
491 }
492 pub fn get_symbol_table_index(&self) -> u32 {
493 self.info >> 8
494 }
495 pub fn get_type(&self) -> u8 {
496 self.info as u8
497 }
498}
499impl Rela<P64> {
500 pub fn get_offset(&self) -> u64 {
501 self.offset
502 }
503 pub fn get_addend(&self) -> u64 {
504 self.addend
505 }
506 pub fn get_symbol_table_index(&self) -> u32 {
507 (self.info >> 32) as u32
508 }
509 pub fn get_type(&self) -> u32 {
510 (self.info & 0xffffffff) as u32
511 }
512}
513impl Rel<P32> {
514 pub fn get_offset(&self) -> u32 {
515 self.offset
516 }
517 pub fn get_symbol_table_index(&self) -> u32 {
518 self.info >> 8
519 }
520 pub fn get_type(&self) -> u8 {
521 self.info as u8
522 }
523}
524impl Rel<P64> {
525 pub fn get_offset(&self) -> u64 {
526 self.offset
527 }
528 pub fn get_symbol_table_index(&self) -> u32 {
529 (self.info >> 32) as u32
530 }
531 pub fn get_type(&self) -> u32 {
532 (self.info & 0xffffffff) as u32
533 }
534}
535
536#[derive(Copy, Clone, Debug)]
537#[repr(C)]
538pub struct NoteHeader {
539 name_size: u32,
540 desc_size: u32,
541 type_: u32,
542}
543
544unsafe impl Pod for NoteHeader {}
545
546impl NoteHeader {
547 pub fn type_(&self) -> u32 {
548 self.type_
549 }
550
551 pub fn name<'a>(&'a self, input: &'a [u8]) -> &'a str {
552 let result = read_str(input);
553 assert_eq!(result.len(), (self.name_size - 1) as usize);
555 result
556 }
557
558 pub fn desc<'a>(&'a self, input: &'a [u8]) -> &'a [u8] {
559 unsafe {
561 let offset = (self.name_size + 3) & !0x3;
562 let ptr = (&input[0] as *const u8).offset(offset as isize);
563 slice::from_raw_parts(ptr, self.desc_size as usize)
564 }
565 }
566}
567
568pub fn sanity_check<'a>(header: SectionHeader<'a>, _file: &ElfFile<'a>) -> Result<(), &'static str> {
569 if header.get_type()? == ShType::Null {
570 return Ok(());
571 }
572 Ok(())
574}