1macro_rules! elf_section_header {
2 ($size:ident) => {
3 #[repr(C)]
7 #[derive(Copy, Clone, Eq, PartialEq, Default)]
8 #[cfg_attr(
9 feature = "alloc",
10 derive(scroll::Pread, scroll::Pwrite, scroll::SizeWith)
11 )]
12 pub struct SectionHeader {
16 pub sh_name: u32,
18 pub sh_type: u32,
20 pub sh_flags: $size,
22 pub sh_addr: $size,
24 pub sh_offset: $size,
26 pub sh_size: $size,
28 pub sh_link: u32,
30 pub sh_info: u32,
32 pub sh_addralign: $size,
34 pub sh_entsize: $size,
36 }
37
38 use plain;
39 unsafe impl plain::Plain for SectionHeader {}
41
42 impl ::core::fmt::Debug for SectionHeader {
43 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
44 f.debug_struct("SectionHeader")
45 .field("sh_name", &self.sh_name)
46 .field("sh_type", &sht_to_str(self.sh_type))
47 .field("sh_flags", &format_args!("0x{:x}", self.sh_flags))
48 .field("sh_addr", &format_args!("0x{:x}", self.sh_addr))
49 .field("sh_offset", &format_args!("0x{:x}", self.sh_offset))
50 .field("sh_size", &format_args!("0x{:x}", self.sh_size))
51 .field("sh_link", &format_args!("0x{:x}", self.sh_link))
52 .field("sh_info", &format_args!("0x{:x}", self.sh_info))
53 .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign))
54 .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize))
55 .finish()
56 }
57 }
58 };
59}
60
61pub const SHN_UNDEF: u32 = 0;
63pub const SHN_LORESERVE: u32 = 0xff00;
65pub const SHN_LOPROC: u32 = 0xff00;
67pub const SHN_BEFORE: u32 = 0xff00;
69pub const SHN_AFTER: u32 = 0xff01;
71pub const SHN_HIPROC: u32 = 0xff1f;
73pub const SHN_LOOS: u32 = 0xff20;
75pub const SHN_HIOS: u32 = 0xff3f;
77pub const SHN_ABS: u32 = 0xfff1;
79pub const SHN_COMMON: u32 = 0xfff2;
81pub const SHN_XINDEX: u32 = 0xffff;
83pub const SHN_HIRESERVE: u32 = 0xffff;
85
86pub const SHT_NULL: u32 = 0;
89pub const SHT_PROGBITS: u32 = 1;
91pub const SHT_SYMTAB: u32 = 2;
93pub const SHT_STRTAB: u32 = 3;
95pub const SHT_RELA: u32 = 4;
97pub const SHT_HASH: u32 = 5;
99pub const SHT_DYNAMIC: u32 = 6;
101pub const SHT_NOTE: u32 = 7;
103pub const SHT_NOBITS: u32 = 8;
105pub const SHT_REL: u32 = 9;
107pub const SHT_SHLIB: u32 = 10;
109pub const SHT_DYNSYM: u32 = 11;
111pub const SHT_INIT_ARRAY: u32 = 14;
113pub const SHT_FINI_ARRAY: u32 = 15;
115pub const SHT_PREINIT_ARRAY: u32 = 16;
117pub const SHT_GROUP: u32 = 17;
119pub const SHT_SYMTAB_SHNDX: u32 = 18;
121pub const SHT_NUM: u32 = 19;
123pub const SHT_LOOS: u32 = 0x6000_0000;
125pub const SHT_GNU_ATTRIBUTES: u32 = 0x6fff_fff5;
127pub const SHT_GNU_HASH: u32 = 0x6fff_fff6;
129pub const SHT_GNU_LIBLIST: u32 = 0x6fff_fff7;
131pub const SHT_CHECKSUM: u32 = 0x6fff_fff8;
133pub const SHT_LOSUNW: u32 = 0x6fff_fffa;
135pub const SHT_SUNW_MOVE: u32 = 0x6fff_fffa;
136pub const SHT_SUNW_COMDAT: u32 = 0x6fff_fffb;
137pub const SHT_SUNW_SYMINFO: u32 = 0x6fff_fffc;
138pub const SHT_GNU_VERDEF: u32 = 0x6fff_fffd;
140pub const SHT_GNU_VERNEED: u32 = 0x6fff_fffe;
142pub const SHT_GNU_VERSYM: u32 = 0x6fff_ffff;
144pub const SHT_HISUNW: u32 = 0x6fff_ffff;
146pub const SHT_HIOS: u32 = 0x6fff_ffff;
148pub const SHT_LOPROC: u32 = 0x7000_0000;
150pub const SHT_X86_64_UNWIND: u32 = 0x7000_0001;
152pub const SHT_HIPROC: u32 = 0x7fff_ffff;
154pub const SHT_LOUSER: u32 = 0x8000_0000;
156pub const SHT_HIUSER: u32 = 0x8fff_ffff;
158
159pub const SHF_WRITE: u32 = 0x1;
162pub const SHF_ALLOC: u32 = 0x2;
164pub const SHF_EXECINSTR: u32 = 0x4;
166pub const SHF_MERGE: u32 = 0x10;
168pub const SHF_STRINGS: u32 = 0x20;
170pub const SHF_INFO_LINK: u32 = 0x40;
172pub const SHF_LINK_ORDER: u32 = 0x80;
174pub const SHF_OS_NONCONFORMING: u32 = 0x100;
176pub const SHF_GROUP: u32 = 0x200;
178pub const SHF_TLS: u32 = 0x400;
180pub const SHF_COMPRESSED: u32 = 0x800;
182pub const SHF_MASKOS: u32 = 0x0ff0_0000;
184pub const SHF_MASKPROC: u32 = 0xf000_0000;
186pub const SHF_ORDERED: u32 = 1 << 30;
188pub const SHF_NUM_REGULAR_FLAGS: usize = 12;
190pub const SHF_EXCLUDE: u32 = 0x80000000; pub const SHF_FLAGS: [u32; SHF_NUM_REGULAR_FLAGS] = [
194 SHF_WRITE,
195 SHF_ALLOC,
196 SHF_EXECINSTR,
197 SHF_MERGE,
198 SHF_STRINGS,
199 SHF_INFO_LINK,
200 SHF_LINK_ORDER,
201 SHF_OS_NONCONFORMING,
202 SHF_GROUP,
203 SHF_TLS,
204 SHF_COMPRESSED,
205 SHF_ORDERED,
206];
207
208pub fn sht_to_str(sht: u32) -> &'static str {
209 match sht {
210 SHT_NULL => "SHT_NULL",
211 SHT_PROGBITS => "SHT_PROGBITS",
212 SHT_SYMTAB => "SHT_SYMTAB",
213 SHT_STRTAB => "SHT_STRTAB",
214 SHT_RELA => "SHT_RELA",
215 SHT_HASH => "SHT_HASH",
216 SHT_DYNAMIC => "SHT_DYNAMIC",
217 SHT_NOTE => "SHT_NOTE",
218 SHT_NOBITS => "SHT_NOBITS",
219 SHT_REL => "SHT_REL",
220 SHT_SHLIB => "SHT_SHLIB",
221 SHT_DYNSYM => "SHT_DYNSYM",
222 SHT_INIT_ARRAY => "SHT_INIT_ARRAY",
223 SHT_FINI_ARRAY => "SHT_FINI_ARRAY",
224 SHT_PREINIT_ARRAY => "SHT_PREINIT_ARRAY",
225 SHT_GROUP => "SHT_GROUP",
226 SHT_SYMTAB_SHNDX => "SHT_SYMTAB_SHNDX",
227 SHT_NUM => "SHT_NUM",
228 SHT_LOOS => "SHT_LOOS",
229 SHT_GNU_ATTRIBUTES => "SHT_GNU_ATTRIBUTES",
230 SHT_GNU_HASH => "SHT_GNU_HASH",
231 SHT_GNU_LIBLIST => "SHT_GNU_LIBLIST",
232 SHT_CHECKSUM => "SHT_CHECKSUM",
233 SHT_SUNW_MOVE => "SHT_SUNW_MOVE",
234 SHT_SUNW_COMDAT => "SHT_SUNW_COMDAT",
235 SHT_SUNW_SYMINFO => "SHT_SUNW_SYMINFO",
236 SHT_GNU_VERDEF => "SHT_GNU_VERDEF",
237 SHT_GNU_VERNEED => "SHT_GNU_VERNEED",
238 SHT_GNU_VERSYM => "SHT_GNU_VERSYM",
239 SHT_LOPROC => "SHT_LOPROC",
240 SHT_X86_64_UNWIND => "SHT_X86_64_UNWIND",
241 SHT_HIPROC => "SHT_HIPROC",
242 SHT_LOUSER => "SHT_LOUSER",
243 SHT_HIUSER => "SHT_HIUSER",
244 _ => "UNKNOWN_SHT",
245 }
246}
247
248pub fn shf_to_str(shf: u32) -> &'static str {
249 match shf {
250 SHF_WRITE => "SHF_WRITE",
251 SHF_ALLOC => "SHF_ALLOC",
252 SHF_EXECINSTR => "SHF_EXECINSTR",
253 SHF_MERGE => "SHF_MERGE",
254 SHF_STRINGS => "SHF_STRINGS",
255 SHF_INFO_LINK => "SHF_INFO_LINK",
256 SHF_LINK_ORDER => "SHF_LINK_ORDER",
257 SHF_OS_NONCONFORMING => "SHF_OS_NONCONFORMING",
258 SHF_GROUP => "SHF_GROUP",
259 SHF_TLS => "SHF_TLS",
260 SHF_COMPRESSED => "SHF_COMPRESSED",
261 SHF_ORDERED => "SHF_ORDERED",
263 _ => "SHF_UNKNOWN",
264 }
265}
266
267macro_rules! elf_section_header_std_impl { ($size:ty) => {
268
269 #[cfg(test)]
270 mod tests {
271 use super::*;
272 #[test]
273 fn size_of() {
274 assert_eq!(::std::mem::size_of::<SectionHeader>(), SIZEOF_SHDR);
275 }
276 }
277
278 if_alloc! {
279 use crate::elf::section_header::SectionHeader as ElfSectionHeader;
280
281 use plain::Plain;
282 use alloc::vec::Vec;
283
284 if_std! {
285 use crate::error::Result;
286
287 use std::fs::File;
288 use std::io::{Read, Seek};
289 use std::io::SeekFrom::Start;
290 }
291
292 impl From<SectionHeader> for ElfSectionHeader {
293 fn from(sh: SectionHeader) -> Self {
294 ElfSectionHeader {
295 sh_name: sh.sh_name as usize,
296 sh_type: sh.sh_type,
297 sh_flags: u64::from(sh.sh_flags),
298 sh_addr: u64::from(sh.sh_addr),
299 sh_offset: u64::from(sh.sh_offset),
300 sh_size: u64::from(sh.sh_size),
301 sh_link: sh.sh_link,
302 sh_info: sh.sh_info,
303 sh_addralign: u64::from(sh.sh_addralign),
304 sh_entsize: u64::from(sh.sh_entsize),
305 }
306 }
307 }
308 impl From<ElfSectionHeader> for SectionHeader {
309 fn from(sh: ElfSectionHeader) -> Self {
310 SectionHeader {
311 sh_name : sh.sh_name as u32,
312 sh_type : sh.sh_type,
313 sh_flags : sh.sh_flags as $size,
314 sh_addr : sh.sh_addr as $size,
315 sh_offset : sh.sh_offset as $size,
316 sh_size : sh.sh_size as $size,
317 sh_link : sh.sh_link,
318 sh_info : sh.sh_info,
319 sh_addralign: sh.sh_addralign as $size,
320 sh_entsize : sh.sh_entsize as $size,
321 }
322 }
323 }
324
325 impl SectionHeader {
326 pub fn from_bytes(bytes: &[u8], shnum: usize) -> Vec<SectionHeader> {
328 let mut shdrs = vec![SectionHeader::default(); shnum];
329 shdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries");
330 shdrs
331 }
332
333 #[cfg(feature = "std")]
334 pub fn from_fd(fd: &mut File, offset: u64, shnum: usize) -> Result<Vec<SectionHeader>> {
336 let mut shdrs = vec![SectionHeader::default(); shnum];
337 fd.seek(Start(offset))?;
338 unsafe {
339 fd.read_exact(plain::as_mut_bytes(&mut *shdrs))?;
340 }
341 Ok(shdrs)
342 }
343 }
344 } };}
346
347pub mod section_header32 {
348 pub use crate::elf::section_header::*;
349
350 elf_section_header!(u32);
351
352 pub const SIZEOF_SHDR: usize = 40;
353
354 elf_section_header_std_impl!(u32);
355}
356
357pub mod section_header64 {
358
359 pub use crate::elf::section_header::*;
360
361 elf_section_header!(u64);
362
363 pub const SIZEOF_SHDR: usize = 64;
364
365 elf_section_header_std_impl!(u64);
366}
367
368if_alloc! {
373 use crate::error;
374 use core::fmt;
375 use core::result;
376 use core::ops::Range;
377 use scroll::ctx;
378 use crate::container::{Container, Ctx};
379
380 #[cfg(feature = "endian_fd")]
381 use alloc::vec::Vec;
382
383 #[derive(Default, PartialEq, Clone)]
384 pub struct SectionHeader {
386 pub sh_name: usize,
388 pub sh_type: u32,
390 pub sh_flags: u64,
392 pub sh_addr: u64,
394 pub sh_offset: u64,
396 pub sh_size: u64,
398 pub sh_link: u32,
400 pub sh_info: u32,
402 pub sh_addralign: u64,
404 pub sh_entsize: u64,
406 }
407
408 impl SectionHeader {
409 #[inline]
411 pub fn size(ctx: Ctx) -> usize {
412 use scroll::ctx::SizeWith;
413 Self::size_with(&ctx)
414 }
415 pub fn new() -> Self {
416 SectionHeader {
417 sh_name: 0,
418 sh_type: SHT_PROGBITS,
419 sh_flags: u64::from(SHF_ALLOC),
420 sh_addr: 0,
421 sh_offset: 0,
422 sh_size: 0,
423 sh_link: 0,
424 sh_info: 0,
425 sh_addralign: 2 << 8,
426 sh_entsize: 0,
427 }
428 }
429 pub fn file_range(&self) -> Option<Range<usize>> {
432 if self.sh_type == SHT_NOBITS {
435 None
436 } else {
437 Some(self.sh_offset as usize..(self.sh_offset as usize).saturating_add(self.sh_size as usize))
438 }
439 }
440 pub fn vm_range(&self) -> Range<usize> {
442 self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize)
443 }
444 #[cfg(feature = "endian_fd")]
447 pub fn parse(bytes: &[u8], offset: usize, count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
448 if offset == 0 {
450 return Ok(Vec::new());
451 }
452 Self::parse_from(bytes, offset, count, ctx)
453 }
454 #[cfg(feature = "endian_fd")]
457 pub fn parse_from(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
458 use scroll::Pread;
459 let empty_sh = bytes.gread_with::<SectionHeader>(&mut offset, ctx)?;
460 if count == 0 as usize {
461 count = empty_sh.sh_size as usize;
465 }
466
467 if count > bytes.len() / Self::size(ctx) {
469 return Err(error::Error::BufferTooShort(count, "section headers"));
470 }
471 let mut section_headers = Vec::with_capacity(count);
472 section_headers.push(empty_sh);
473 for _ in 1..count {
474 let shdr = bytes.gread_with(&mut offset, ctx)?;
475 section_headers.push(shdr);
476 }
477 Ok(section_headers)
478 }
479 pub fn check_size(&self, size: usize) -> error::Result<()> {
480 if self.sh_type == SHT_NOBITS || self.sh_size == 0 {
481 return Ok(());
482 }
483 let (end, overflow) = self.sh_offset.overflowing_add(self.sh_size);
484 if overflow || end > size as u64 {
485 let message = format!("Section {} size ({}) + offset ({}) is out of bounds. Overflowed: {}",
486 self.sh_name, self.sh_offset, self.sh_size, overflow);
487 return Err(error::Error::Malformed(message));
488 }
489 let (_, overflow) = self.sh_addr.overflowing_add(self.sh_size);
490 if overflow {
491 let message = format!("Section {} size ({}) + addr ({}) is out of bounds. Overflowed: {}",
492 self.sh_name, self.sh_addr, self.sh_size, overflow);
493 return Err(error::Error::Malformed(message));
494 }
495 Ok(())
496 }
497 pub fn is_relocation(&self) -> bool {
498 self.sh_type == SHT_RELA
499 }
500 pub fn is_executable(&self) -> bool {
501 self.is_alloc() && self.sh_flags as u32 & SHF_EXECINSTR == SHF_EXECINSTR
502 }
503 pub fn is_writable(&self) -> bool {
504 self.is_alloc() && self.sh_flags as u32 & SHF_WRITE == SHF_WRITE
505 }
506 pub fn is_alloc(&self) -> bool {
507 self.sh_flags as u32 & SHF_ALLOC == SHF_ALLOC
508 }
509 }
510
511 impl fmt::Debug for SectionHeader {
512 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
513 f.debug_struct("SectionHeader")
514 .field("sh_name", &self.sh_name)
515 .field("sh_type", &sht_to_str(self.sh_type))
516 .field("sh_flags", &format_args!("0x{:x}", self.sh_flags))
517 .field("sh_addr", &format_args!("0x{:x}", self.sh_addr))
518 .field("sh_offset", &format_args!("0x{:x}", self.sh_offset))
519 .field("sh_size", &format_args!("0x{:x}", self.sh_size))
520 .field("sh_link", &format_args!("0x{:x}", self.sh_link))
521 .field("sh_info", &format_args!("0x{:x}", self.sh_info))
522 .field("sh_addralign", &format_args!("0x{:x}", self.sh_addralign))
523 .field("sh_entsize", &format_args!("0x{:x}", self.sh_entsize))
524 .finish()
525 }
526 }
527
528 impl ctx::SizeWith<Ctx> for SectionHeader {
529 fn size_with( &Ctx { container, .. }: &Ctx) -> usize {
530 match container {
531 Container::Little => {
532 section_header32::SIZEOF_SHDR
533 },
534 Container::Big => {
535 section_header64::SIZEOF_SHDR
536 },
537 }
538 }
539 }
540
541 impl<'a> ctx::TryFromCtx<'a, Ctx> for SectionHeader {
542 type Error = crate::error::Error;
543 fn try_from_ctx(bytes: &'a [u8], Ctx {container, le}: Ctx) -> result::Result<(Self, usize), Self::Error> {
544 use scroll::Pread;
545 let res = match container {
546 Container::Little => {
547 (bytes.pread_with::<section_header32::SectionHeader>(0, le)?.into(), section_header32::SIZEOF_SHDR)
548 },
549 Container::Big => {
550 (bytes.pread_with::<section_header64::SectionHeader>(0, le)?.into(), section_header64::SIZEOF_SHDR)
551 }
552 };
553 Ok(res)
554 }
555 }
556
557 impl ctx::TryIntoCtx<Ctx> for SectionHeader {
558 type Error = crate::error::Error;
559 fn try_into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<usize, Self::Error> {
560 use scroll::Pwrite;
561 match container {
562 Container::Little => {
563 let shdr: section_header32::SectionHeader = self.into();
564 Ok(bytes.pwrite_with(shdr, 0, le)?)
565 },
566 Container::Big => {
567 let shdr: section_header64::SectionHeader = self.into();
568 Ok(bytes.pwrite_with(shdr, 0, le)?)
569 }
570 }
571 }
572 }
573 impl ctx::IntoCtx<Ctx> for SectionHeader {
574 fn into_ctx(self, bytes: &mut [u8], Ctx {container, le}: Ctx) {
575 use scroll::Pwrite;
576 match container {
577 Container::Little => {
578 let shdr: section_header32::SectionHeader = self.into();
579 bytes.pwrite_with(shdr, 0, le).unwrap();
580 },
581 Container::Big => {
582 let shdr: section_header64::SectionHeader = self.into();
583 bytes.pwrite_with(shdr, 0, le).unwrap();
584 }
585 }
586 }
587 }
588}