1include!("constants_header.rs");
2
3macro_rules! elf_header {
4 ($size:ident) => {
5 use core::fmt;
6
7 #[repr(C)]
8 #[derive(Clone, Copy, Default, PartialEq)]
9 pub struct Header {
10 pub e_ident: [u8; SIZEOF_IDENT],
12 pub e_type: u16,
14 pub e_machine: u16,
16 pub e_version: u32,
18 pub e_entry: $size,
20 pub e_phoff: $size,
22 pub e_shoff: $size,
24 pub e_flags: u32,
26 pub e_ehsize: u16,
28 pub e_phentsize: u16,
30 pub e_phnum: u16,
32 pub e_shentsize: u16,
34 pub e_shnum: u16,
36 pub e_shstrndx: u16,
38 }
39
40 use plain;
41 unsafe impl plain::Plain for Header {}
43
44 impl Header {
45 pub fn from_bytes(bytes: &[u8; SIZEOF_EHDR]) -> &Header {
47 plain::from_bytes(bytes).unwrap()
50 }
51 }
52 impl fmt::Debug for Header {
53 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
54 f.debug_struct("Header")
55 .field("e_ident", &format_args!("{:?}", self.e_ident))
56 .field("e_type", &et_to_str(self.e_type))
57 .field("e_machine", &format_args!("0x{:x}", self.e_machine))
58 .field("e_version", &format_args!("0x{:x}", self.e_version))
59 .field("e_entry", &format_args!("0x{:x}", self.e_entry))
60 .field("e_phoff", &format_args!("0x{:x}", self.e_phoff))
61 .field("e_shoff", &format_args!("0x{:x}", self.e_shoff))
62 .field("e_flags", &format_args!("{:x}", self.e_flags))
63 .field("e_ehsize", &self.e_ehsize)
64 .field("e_phentsize", &self.e_phentsize)
65 .field("e_phnum", &self.e_phnum)
66 .field("e_shentsize", &self.e_shentsize)
67 .field("e_shnum", &self.e_shnum)
68 .field("e_shstrndx", &self.e_shstrndx)
69 .finish()
70 }
71 }
72 };
73}
74
75pub const ET_NONE: u16 = 0;
77pub const ET_REL: u16 = 1;
79pub const ET_EXEC: u16 = 2;
81pub const ET_DYN: u16 = 3;
83pub const ET_CORE: u16 = 4;
85pub const ET_NUM: u16 = 5;
87pub const ET_LOOS: u16 = 0xfe00;
89pub const ET_HIOS: u16 = 0xfeff;
91pub const ET_LOPROC: u16 = 0xff00;
93pub const ET_HIPROC: u16 = 0xffff;
95
96pub const ELFMAG: &[u8; 4] = b"\x7FELF";
98pub const SELFMAG: usize = 4;
100
101pub const EI_CLASS: usize = 4;
103pub const ELFCLASSNONE: u8 = 0;
105pub const ELFCLASS32: u8 = 1;
107pub const ELFCLASS64: u8 = 2;
109pub const ELFCLASSNUM: u8 = 3;
111
112pub const EI_DATA: usize = 5;
114pub const ELFDATANONE: u8 = 0;
116pub const ELFDATA2LSB: u8 = 1;
118pub const ELFDATA2MSB: u8 = 2;
120
121pub const EI_VERSION: usize = 6;
123pub const EV_CURRENT: u8 = 1;
125
126pub const EI_OSABI: usize = 7;
128pub const ELFOSABI_NONE: u8 = 0;
130pub const ELFOSABI_SYSV: u8 = ELFOSABI_NONE;
134pub const ELFOSABI_HPUX: u8 = 1;
136pub const ELFOSABI_NETBSD: u8 = 2;
138pub const ELFOSABI_GNU: u8 = 3;
140pub const ELFOSABI_LINUX: u8 = ELFOSABI_GNU;
144pub const ELFOSABI_SOLARIS: u8 = 6;
146pub const ELFOSABI_AIX: u8 = 7;
148pub const ELFOSABI_IRIX: u8 = 8;
150pub const ELFOSABI_FREEBSD: u8 = 9;
152pub const ELFOSABI_TRU64: u8 = 10;
154pub const ELFOSABI_MODESTO: u8 = 11;
156pub const ELFOSABI_OPENBSD: u8 = 12;
158pub const ELFOSABI_ARM_AEABI: u8 = 64;
160pub const ELFOSABI_ARM: u8 = 97;
162pub const ELFOSABI_STANDALONE: u8 = 255;
164
165pub const EI_ABIVERSION: usize = 8;
167
168pub const SIZEOF_IDENT: usize = 16;
170
171#[inline]
173pub fn class_to_str(et: u8) -> &'static str {
174 match et {
175 ELFCLASSNONE => "NONE",
176 ELFCLASS32 => "ELF32",
177 ELFCLASS64 => "ELF64",
178 _ => "UNKNOWN_CLASS",
179 }
180}
181
182#[inline]
184pub fn et_to_str(et: u16) -> &'static str {
185 match et {
186 ET_NONE => "NONE",
187 ET_REL => "REL",
188 ET_EXEC => "EXEC",
189 ET_DYN => "DYN",
190 ET_CORE => "CORE",
191 ET_NUM => "NUM",
192 _ => "UNKNOWN_ET",
193 }
194}
195
196if_alloc! {
197 use crate::error;
198 use scroll::{ctx, Endian};
199 use core::fmt;
200 use crate::container::{Ctx, Container};
201 use alloc::string::ToString;
202
203 #[derive(Copy, Clone, PartialEq)]
204 pub struct Header {
206 pub e_ident : [u8; SIZEOF_IDENT],
207 pub e_type : u16,
208 pub e_machine : u16,
209 pub e_version : u32,
210 pub e_entry : u64,
211 pub e_phoff : u64,
212 pub e_shoff : u64,
213 pub e_flags : u32,
214 pub e_ehsize : u16,
215 pub e_phentsize : u16,
216 pub e_phnum : u16,
217 pub e_shentsize : u16,
218 pub e_shnum : u16,
219 pub e_shstrndx : u16,
220 }
221
222 impl Header {
223 #[inline]
225 pub fn size(ctx: Ctx) -> usize {
226 use scroll::ctx::SizeWith;
227 Self::size_with(&ctx)
228 }
229 pub fn container(&self) -> error::Result<Container> {
231 use crate::error::Error;
232 match self.e_ident[EI_CLASS] {
233 ELFCLASS32 => { Ok(Container::Little) },
234 ELFCLASS64 => { Ok(Container::Big) },
235 class => Err(Error::Malformed(format!("Invalid class in Header: {}", class)))
236 }
237 }
238 pub fn endianness(&self) -> error::Result<scroll::Endian> {
240 use crate::error::Error;
241 match self.e_ident[EI_DATA] {
242 ELFDATA2LSB => { Ok(scroll::LE) },
243 ELFDATA2MSB => { Ok(scroll::BE) },
244 class => Err(Error::Malformed(format!("Invalid endianness in Header: {}", class)))
245 }
246 }
247 pub fn new(ctx: Ctx) -> Self {
248 use crate::elf32;
249 use crate::elf64;
250 let (typ, ehsize, phentsize, shentsize) = match ctx.container {
251 Container::Little => {
252 (ELFCLASS32, header32::SIZEOF_EHDR,
253 elf32::program_header::SIZEOF_PHDR,
254 elf32::section_header::SIZEOF_SHDR)
255 },
256 Container::Big => {
257 (ELFCLASS64, header64::SIZEOF_EHDR,
258 elf64::program_header::SIZEOF_PHDR,
259 elf64::section_header::SIZEOF_SHDR)
260 }
261 };
262 let byteorder = match ctx.le { Endian::Little => ELFDATA2LSB, Endian::Big => ELFDATA2MSB };
263 Header {
264 e_ident: [
265 127,
266 69,
267 76,
268 70,
269 typ,
270 byteorder,
271 EV_CURRENT,
272 ELFOSABI_NONE,
273 0,
274 0,
275 0,
276 0,
277 0,
278 0,
279 0,
280 0
281 ],
282 e_type: ET_DYN,
283 e_machine: EM_NONE,
284 e_version: 1,
285 e_entry: 0x0,
286 e_phoff: 0x0,
287 e_shoff: 0x0,
288 e_flags: 0,
289 e_ehsize: ehsize as u16,
290 e_phentsize: phentsize as u16,
291 e_phnum: 0,
292 e_shentsize: shentsize as u16,
293 e_shnum: 0,
294 e_shstrndx: 0,
295 }
296 }
297 }
298
299 impl fmt::Debug for Header {
300 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
301 f.debug_struct("Header")
302 .field("e_ident", &format_args!("{:?}", self.e_ident))
303 .field("e_type", &et_to_str(self.e_type))
304 .field("e_machine", &format_args!("0x{:x}", self.e_machine))
305 .field("e_version", &format_args!("0x{:x}", self.e_version))
306 .field("e_entry", &format_args!("0x{:x}", self.e_entry))
307 .field("e_phoff", &format_args!("0x{:x}", self.e_phoff))
308 .field("e_shoff", &format_args!("0x{:x}", self.e_shoff))
309 .field("e_flags", &format_args!("{:x}", self.e_flags))
310 .field("e_ehsize", &self.e_ehsize)
311 .field("e_phentsize", &self.e_phentsize)
312 .field("e_phnum", &self.e_phnum)
313 .field("e_shentsize", &self.e_shentsize)
314 .field("e_shnum", &self.e_shnum)
315 .field("e_shstrndx", &self.e_shstrndx)
316 .finish()
317 }
318 }
319
320 impl ctx::SizeWith<crate::container::Ctx> for Header {
321 fn size_with(ctx: &crate::container::Ctx) -> usize {
322 match ctx.container {
323 Container::Little => {
324 header32::SIZEOF_EHDR
325 },
326 Container::Big => {
327 header64::SIZEOF_EHDR
328 },
329 }
330 }
331 }
332
333 impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header {
334 type Error = crate::error::Error;
335 fn try_from_ctx(bytes: &'a [u8], _ctx: scroll::Endian) -> error::Result<(Self, usize)> {
336 use scroll::Pread;
337 if bytes.len() < SIZEOF_IDENT {
338 return Err(error::Error::Malformed("Too small".to_string()));
339 }
340 let ident: &[u8] = &bytes[..SIZEOF_IDENT];
341 if &ident[0..SELFMAG] != ELFMAG {
342 let magic: u64 = ident.pread_with(0, scroll::LE)?;
343 return Err(error::Error::BadMagic(magic));
344 }
345 let class = ident[EI_CLASS];
346 match class {
347 ELFCLASS32 => {
348 Ok((Header::from(bytes.pread::<header32::Header>(0)?), header32::SIZEOF_EHDR))
349 },
350 ELFCLASS64 => {
351 Ok((Header::from(bytes.pread::<header64::Header>(0)?), header64::SIZEOF_EHDR))
352 },
353 _ => {
354 Err(error::Error::Malformed(format!("invalid ELF class {:x}", class)))
355 }
356 }
357 }
358 }
359
360 impl ctx::TryIntoCtx<scroll::Endian> for Header {
361 type Error = crate::error::Error;
362 fn try_into_ctx(self, bytes: &mut [u8], _ctx: scroll::Endian) -> Result<usize, Self::Error> {
363 use scroll::Pwrite;
364 match self.container()? {
365 Container::Little => {
366 bytes.pwrite(header32::Header::from(self), 0)
367 },
368 Container::Big => {
369 bytes.pwrite(header64::Header::from(self), 0)
370 }
371 }
372 }
373 }
374 impl ctx::IntoCtx<crate::container::Ctx> for Header {
375 fn into_ctx(self, bytes: &mut [u8], ctx: crate::container::Ctx) {
376 use scroll::Pwrite;
377 match ctx.container {
378 Container::Little => {
379 bytes.pwrite_with(header32::Header::from(self), 0, ctx.le).unwrap()
380 },
381 Container::Big => {
382 bytes.pwrite_with(header64::Header::from(self), 0, ctx.le).unwrap()
383 }
384 };
385 }
386 }
387} macro_rules! elf_header_std_impl {
390 ($size:expr, $width:ty) => {
391
392 if_alloc! {
393 use crate::elf::header::Header as ElfHeader;
394 use crate::error::Error;
395 #[cfg(any(feature = "std", feature = "endian_fd"))]
396 use crate::error::Result;
397
398 use scroll::{ctx, Pread};
399
400 use core::result;
401
402 if_std! {
403 use std::fs::File;
404 use std::io::{Read};
405 }
406
407 impl From<ElfHeader> for Header {
408 fn from(eh: ElfHeader) -> Self {
409 Header {
410 e_ident: eh.e_ident,
411 e_type: eh.e_type,
412 e_machine: eh.e_machine,
413 e_version: eh.e_version,
414 e_entry: eh.e_entry as $width,
415 e_phoff: eh.e_phoff as $width,
416 e_shoff: eh.e_shoff as $width,
417 e_flags: eh.e_flags,
418 e_ehsize: eh.e_ehsize,
419 e_phentsize: eh.e_phentsize,
420 e_phnum: eh.e_phnum,
421 e_shentsize: eh.e_shentsize,
422 e_shnum: eh.e_shnum,
423 e_shstrndx: eh.e_shstrndx,
424 }
425 }
426 }
427
428 impl From<Header> for ElfHeader {
429 fn from(eh: Header) -> Self {
430 ElfHeader {
431 e_ident: eh.e_ident,
432 e_type: eh.e_type,
433 e_machine: eh.e_machine,
434 e_version: eh.e_version,
435 e_entry: u64::from(eh.e_entry),
436 e_phoff: u64::from(eh.e_phoff),
437 e_shoff: u64::from(eh.e_shoff),
438 e_flags: eh.e_flags,
439 e_ehsize: eh.e_ehsize,
440 e_phentsize: eh.e_phentsize,
441 e_phnum: eh.e_phnum,
442 e_shentsize: eh.e_shentsize,
443 e_shnum: eh.e_shnum,
444 e_shstrndx: eh.e_shstrndx,
445 }
446 }
447 }
448
449 impl<'a> ctx::TryFromCtx<'a, scroll::Endian> for Header {
450 type Error = crate::error::Error;
451 fn try_from_ctx(bytes: &'a [u8], _: scroll::Endian) -> result::Result<(Self, usize), Self::Error> {
452 let mut elf_header = Header::default();
453 let offset = &mut 0;
454 bytes.gread_inout(offset, &mut elf_header.e_ident)?;
455 let endianness =
456 match elf_header.e_ident[EI_DATA] {
457 ELFDATA2LSB => scroll::LE,
458 ELFDATA2MSB => scroll::BE,
459 d => return Err(Error::Malformed(format!("invalid ELF endianness DATA type {:x}", d)).into()),
460 };
461 elf_header.e_type = bytes.gread_with(offset, endianness)?;
462 elf_header.e_machine = bytes.gread_with(offset, endianness)?;
463 elf_header.e_version = bytes.gread_with(offset, endianness)?;
464 elf_header.e_entry = bytes.gread_with(offset, endianness)?;
465 elf_header.e_phoff = bytes.gread_with(offset, endianness)?;
466 elf_header.e_shoff = bytes.gread_with(offset, endianness)?;
467 elf_header.e_flags = bytes.gread_with(offset, endianness)?;
468 elf_header.e_ehsize = bytes.gread_with(offset, endianness)?;
469 elf_header.e_phentsize = bytes.gread_with(offset, endianness)?;
470 elf_header.e_phnum = bytes.gread_with(offset, endianness)?;
471 elf_header.e_shentsize = bytes.gread_with(offset, endianness)?;
472 elf_header.e_shnum = bytes.gread_with(offset, endianness)?;
473 elf_header.e_shstrndx = bytes.gread_with(offset, endianness)?;
474 Ok((elf_header, SIZEOF_EHDR))
475 }
476 }
477
478 impl ctx::TryIntoCtx<scroll::Endian> for Header {
479 type Error = crate::error::Error;
480 fn try_into_ctx(self, bytes: &mut [u8], _endianness: scroll::Endian) -> result::Result<usize, Self::Error> {
482 use scroll::{Pwrite};
483 let offset = &mut 0;
484 let endianness =
485 match self.e_ident[EI_DATA] {
486 ELFDATA2LSB => scroll::LE,
487 ELFDATA2MSB => scroll::BE,
488 d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()),
489 };
490 for i in 0..self.e_ident.len() {
491 bytes.gwrite(self.e_ident[i], offset)?;
492 }
493 bytes.gwrite_with(self.e_type , offset, endianness)?;
494 bytes.gwrite_with(self.e_machine , offset, endianness)?;
495 bytes.gwrite_with(self.e_version , offset, endianness)?;
496 bytes.gwrite_with(self.e_entry , offset, endianness)?;
497 bytes.gwrite_with(self.e_phoff , offset, endianness)?;
498 bytes.gwrite_with(self.e_shoff , offset, endianness)?;
499 bytes.gwrite_with(self.e_flags , offset, endianness)?;
500 bytes.gwrite_with(self.e_ehsize , offset, endianness)?;
501 bytes.gwrite_with(self.e_phentsize , offset, endianness)?;
502 bytes.gwrite_with(self.e_phnum , offset, endianness)?;
503 bytes.gwrite_with(self.e_shentsize , offset, endianness)?;
504 bytes.gwrite_with(self.e_shnum , offset, endianness)?;
505 bytes.gwrite_with(self.e_shstrndx , offset, endianness)?;
506 Ok(SIZEOF_EHDR)
507 }
508 }
509
510 impl Header {
511 #[cfg(feature = "std")]
513 pub fn from_fd(bytes: &mut File) -> Result<Header> {
514 let mut elf_header = [0; $size];
515 bytes.read_exact(&mut elf_header)?;
516 Ok(*Header::from_bytes(&elf_header))
517 }
518
519 #[cfg(feature = "endian_fd")]
520 pub fn parse(bytes: &[u8]) -> Result<Header> {
522 use super::{EI_DATA, ELFDATA2LSB, ELFDATA2MSB, SIZEOF_IDENT};
523
524 let mut elf_header = Header::default();
525 let mut offset = &mut 0;
526 for i in 0..SIZEOF_IDENT {
527 elf_header.e_ident[i] = bytes.gread(&mut offset)?;
528 }
529 let endianness =
530 match elf_header.e_ident[EI_DATA] {
531 ELFDATA2LSB => scroll::LE,
532 ELFDATA2MSB => scroll::BE,
533 d => return Err(Error::Malformed(format!("invalid ELF DATA type {:x}", d)).into()),
534 };
535 elf_header.e_type = bytes.gread_with(offset, endianness)?;
536 elf_header.e_machine = bytes.gread_with(offset, endianness)?;
537 elf_header.e_version = bytes.gread_with(offset, endianness)?;
538 elf_header.e_entry = bytes.gread_with(offset, endianness)?;
539 elf_header.e_phoff = bytes.gread_with(offset, endianness)?;
540 elf_header.e_shoff = bytes.gread_with(offset, endianness)?;
541 elf_header.e_flags = bytes.gread_with(offset, endianness)?;
542 elf_header.e_ehsize = bytes.gread_with(offset, endianness)?;
543 elf_header.e_phentsize = bytes.gread_with(offset, endianness)?;
544 elf_header.e_phnum = bytes.gread_with(offset, endianness)?;
545 elf_header.e_shentsize = bytes.gread_with(offset, endianness)?;
546 elf_header.e_shnum = bytes.gread_with(offset, endianness)?;
547 elf_header.e_shstrndx = bytes.gread_with(offset, endianness)?;
548 Ok(elf_header)
549 }
550 }
551 } };
553}
554
555macro_rules! elf_header_test {
558 ($class:expr) => {
559 #[cfg(test)]
560 mod tests {
561 use super::*;
562 use crate::container::{Container, Ctx};
563 use crate::elf::header::Header as ElfHeader;
564 use alloc::vec::Vec;
565 use scroll::{Pread, Pwrite};
566 #[test]
567 fn size_of() {
568 assert_eq!(::std::mem::size_of::<Header>(), SIZEOF_EHDR);
569 }
570 #[test]
571 fn header_read_write() {
572 let crt1: Vec<u8> = if $class == ELFCLASS64 {
573 include!("../../etc/crt1.rs")
574 } else {
575 include!("../../etc/crt132.rs")
576 };
577 let header: Header = crt1.pread(0).unwrap();
578 assert_eq!(header.e_type, ET_REL);
579 println!("header: {:?}", &header);
580 let mut bytes = [0u8; SIZEOF_EHDR];
581 bytes.pwrite(header, 0).unwrap();
582 let header2: Header = bytes.pread(0).unwrap();
583 assert_eq!(header, header2);
584 }
585 #[test]
586 fn elfheader_read_write() {
587 let (container, crt1): (Container, Vec<u8>) = if $class == ELFCLASS64 {
588 (Container::Big, include!("../../etc/crt1.rs"))
589 } else {
590 (Container::Little, include!("../../etc/crt132.rs"))
591 };
592 let header: Header = crt1.pread(0).unwrap();
593 assert_eq!(header.e_type, ET_REL);
594 println!("header: {:?}", &header);
595 let mut bytes = [0u8; SIZEOF_EHDR];
596 let header_ = Header::from(header.clone());
597 bytes.pwrite(header_, 0).unwrap();
598 let header2: Header = bytes.pread(0).unwrap();
599 assert_eq!(header, header2);
600 let header = ElfHeader::new(Ctx::from(container));
601 println!("header: {:?}", &header);
602
603 let mut bytes = vec![0; 100];
604 bytes.pwrite(header, 0).unwrap();
605 }
606 }
607 };
608}
609
610pub mod header32 {
611 pub use super::*;
612
613 pub const SIZEOF_EHDR: usize = 52;
614 pub const ELFCLASS: u8 = ELFCLASS32;
615
616 elf_header!(u32);
617 elf_header_std_impl!(SIZEOF_EHDR, u32);
618 elf_header_test!(ELFCLASS);
619}
620
621pub mod header64 {
622 pub use super::*;
623
624 pub const SIZEOF_EHDR: usize = 64;
625 pub const ELFCLASS: u8 = ELFCLASS64;
626
627 elf_header!(u64);
628 elf_header_std_impl!(SIZEOF_EHDR, u64);
629 elf_header_test!(ELFCLASS);
630}