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