1#![no_std]
2
3use core::{mem::{size_of, align_of}, fmt};
4
5macro_rules! c_enum {
6 (
7 $vis:vis $name:ident($ty:ty) {
8 $($item:ident = $value:expr),*
9 } $catch:pat => $return:expr
10 ) => {
11 #[derive(::core::clone::Clone, ::core::marker::Copy, ::core::cmp::PartialEq, ::core::cmp::Eq)]
12 #[repr(transparent)]
13 $vis struct $name($ty);
14 impl $name {
15 $(
16 #[allow(non_upper_case_globals)]
17 $vis const $item: Self = Self($value);
18 )*
19 $vis fn validate(self) -> Result<()> {
20 match self.0 {
21 $($value => Ok(()),)*
22 $catch => $return
23 }
24 }
25 }
26 impl ::core::fmt::Debug for $name {
27 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
28 #[derive(Debug)]
29 struct Unknown($ty);
30 match *self {
31 $(Self::$item => f.write_str(stringify!($item)),)*
32 Self(value) => Unknown(value).fmt(f)
33 }
34 }
35 }
36 impl ::core::convert::TryFrom<$ty> for $name {
37 type Error = $crate::Error;
38 fn try_from(value: $ty) -> $crate::Result<Self> {
39 match value {
40 $($value => Ok(Self::$item),)*
41 $catch => $return
42 }
43 }
44 }
45 impl ::core::convert::From<$name> for $ty {
46 fn from(value: $name) -> Self {
47 value.0
48 }
49 }
50 }
51}
52macro_rules! c_flags {
53 (
54 $vis:vis $name:ident($ty:ty) {
55 $($item:ident = $value:expr),*
56 } $catch:pat => $return:expr
57 ) => {
58 #[derive(::core::clone::Clone, ::core::marker::Copy, ::core::cmp::PartialEq, ::core::cmp::Eq)]
59 #[repr(transparent)]
60 $vis struct $name($ty);
61 impl $name {
62 #[allow(non_upper_case_globals)]
63 $vis const None: Self = Self(0);
64 $(
65 #[allow(non_upper_case_globals)]
66 $vis const $item: Self = Self($value);
67 )*
68 #[allow(non_upper_case_globals)]
69 $vis const Mask: Self = Self($($value|)* 0);
70 pub fn any(self, bits: Self) -> bool {
72 self & bits != Self::None
73 }
74 pub fn all(self, bits: Self) -> bool {
76 self & bits == bits
77 }
78 }
79 impl ::core::ops::BitAnd for $name {
80 type Output = Self;
81 fn bitand(self, rhs: Self) -> Self::Output {
82 Self(self.0 & rhs.0)
83 }
84 }
85 impl ::core::ops::BitAndAssign for $name {
86 fn bitand_assign(&mut self, rhs: Self) {
87 self.0 &= rhs.0
88 }
89 }
90 impl ::core::ops::BitOr for $name {
91 type Output = Self;
92 fn bitor(self, rhs: Self) -> Self::Output {
93 Self(self.0 | rhs.0)
94 }
95 }
96 impl ::core::ops::BitOrAssign for $name {
97 fn bitor_assign(&mut self, rhs: Self) {
98 self.0 |= rhs.0
99 }
100 }
101 impl ::core::ops::BitXor for $name {
102 type Output = Self;
103 fn bitxor(self, rhs: Self) -> Self::Output {
104 Self(self.0 ^ rhs.0)
105 }
106 }
107 impl ::core::ops::BitXorAssign for $name {
108 fn bitxor_assign(&mut self, rhs: Self) {
109 self.0 ^= rhs.0
110 }
111 }
112 impl ::core::ops::Not for $name {
113 type Output = Self;
114 fn not(self) -> Self::Output {
115 Self(!self.0)
116 }
117 }
118 impl ::core::fmt::Debug for $name {
119 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
120 #[derive(Debug)]
121 struct Unknown($ty);
122 $(
123 #[derive(Debug)]
124 struct $item;
125 )*
126 let mut list = f.debug_tuple(stringify!($name));
127 $(if self.all(Self($value)) { list.field(&$item); })*
128 let invalid = *self & !Self::Mask;
129 if invalid != Self::None {
130 list.field(&Unknown(self.0));
131 }
132 list.finish()
133 }
134 }
135 impl ::core::convert::TryFrom<$ty> for $name {
136 type Error = $crate::Error;
137 fn try_from(value: $ty) -> $crate::Result<Self> {
138 match Self(value) & !Self::Mask {
139 Self::None => Ok(Self(value)),
140 $catch => $return
141 }
142 }
143 }
144 impl ::core::convert::From<$name> for $ty {
145 fn from(value: $name) -> Self {
146 value.0
147 }
148 }
149 }
150}
151pub type Result<T> = core::result::Result<T, Error>;
152#[derive(Debug)]
153pub enum Error {
154 IntegerOverflow,
155 IndexOutOfRange,
156 Unaligned,
157 UnexpectedEoF,
158 InvalidMagic,
159 InvalidFormat,
160 InvalidVersion,
161 UnsupportedFileType(u16),
162 UnsupportedMachine(u16),
163 UnsupportedProgramType(u32),
164 UnsupportedProgramFlags(ProgramFlags),
165 UnsupportedSectionType(u32),
166 UnsupportedSectionFlags(SectionFlags),
167 WrongProgramType { expected: ProgramType, actual: ProgramType },
168 WrongProgramFlags { expected: ProgramFlags, actual: ProgramFlags },
169 WrongSectionType { expected: SectionType, actual: SectionType },
170 WrongSectionFlags { expected: SectionFlags, actual: SectionFlags },
171 UnterminatedString,
172 NotUtf8(core::str::Utf8Error)
173}
174
175#[derive(Debug, Clone, Copy)]
176#[repr(transparent)]
177pub struct Address(u32);
178impl Address {
179 pub fn as_usize(self) -> Result<usize> {
180 self.0.try_into().map_err(|_| Error::IntegerOverflow)
181 }
182}
183#[derive(Debug, Clone, Copy)]
184#[repr(transparent)]
185pub struct Offset(u32);
186impl Offset {
187 pub fn as_usize(self) -> Result<usize> {
188 self.0.try_into().map_err(|_| Error::IntegerOverflow)
189 }
190}
191
192pub struct Elf<'a> {
215 data: &'a [u8],
216 pub header: &'a Header,
217 pub section_names: StringTable<'a>
218}
219impl<'a> Elf<'a> {
220 pub fn new(elf: &'a [u32]) -> Result<Self> {
221 assert_eq!(align_of::<u32>(), align_of::<Header>());
222 let data = unsafe { core::slice::from_raw_parts(elf.as_ptr() as *const u8, elf.len() * size_of::<u32>()) };
223 let header = unsafe { Header::new_assume_aligned(data)? };
224 let section_name_table = header.section_header(data, header.section_name_table)?;
225 let section_names = StringTable(section_name_table.data(data)?);
226 Ok(Self {
227 data,
228 header,
229 section_names
230 })
231 }
232 pub fn program(&self, index: u16) -> Result<Program<'a>> {
233 let header = self.header.program_header(self.data, index)?;
234 header.data(self.data).map(|data| Program::new(header, data))
235 }
236 pub fn programs(&'a self) -> Result<TableIter<Program<'a>>> {
238 TableIter::new(self.data, self.header.ph_offset, self.header.ph_count, self.header.ph_entry_size)
239 }
240 pub fn section_name(&'a self, section: &Section<'a>) -> Result<&'a str> {
242 self.section_names.get_str(section.header.name)
243 }
244 pub fn section(&self, index: u16) -> Result<Section<'a>> {
245 let header = self.header.section_header(self.data, index)?;
246 header.data(self.data).map(|data| Section::new(header, data))
247 }
248 pub fn sections(&'a self) -> Result<TableIter<Section<'a>>> {
250 TableIter::new(self.data, self.header.sh_offset, self.header.sh_count, self.header.sh_entry_size)
251 }
252}
253impl<'a> fmt::Debug for Elf<'a> {
254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255 f.debug_struct("Elf")
256 .field("data", &[..])
257 .field("header", &self.header)
258 .field("section_names", &self.section_names)
259 .finish()
260 }
261}
262
263#[derive(Debug)]
264#[repr(C)]
265pub struct Header {
266 pub ident: [u8; 16],
267 pub ty: FileType,
268 pub machine: Machine,
269 pub version: u32,
270 pub entry: Address,
271 pub ph_offset: Offset,
272 pub sh_offset: Offset,
273 pub flags: u32,
274 pub header_size: u16,
275 pub ph_entry_size: u16,
276 pub ph_count: u16,
277 pub sh_entry_size: u16,
278 pub sh_count: u16,
279 pub section_name_table: u16
280}
281impl Header {
282 pub fn new(elf: &[u32]) -> Result<&Self> {
283 assert_eq!(align_of::<u32>(), align_of::<Self>());
284 unsafe {
285 let len = elf.len() * size_of::<u32>();
286 Self::new_assume_aligned(core::slice::from_raw_parts(elf.as_ptr() as *const u8, len))
287 }
288 }
289 pub fn new_aligned(elf: &[u8]) -> Result<&Self> {
291 assert_eq!(align_of::<u32>(), align_of::<Self>());
292 if elf.as_ptr() as usize & 0b11 != 0 {
293 Err(Error::Unaligned)
294 } else {
295 unsafe { Self::new_assume_aligned(elf) }
296 }
297 }
298 pub unsafe fn new_assume_aligned(elf: &[u8]) -> Result<&Self> {
303 if elf.len() < size_of::<Self>() {
304 return Err(Error::UnexpectedEoF)
305 }
306 let elf = &*(elf.as_ptr() as *const Header);
307 if &elf.ident[..4] != b"\x7fELF" {
308 return Err(Error::InvalidMagic)
309 }
310 if elf.ident[4] != 1 || elf.ident[5] != 1 {
311 return Err(Error::InvalidFormat)
313 }
314 if elf.ident[6] != 1 || elf.version != 1 {
315 return Err(Error::InvalidVersion)
316 }
317 elf.machine.validate()?;
318 Ok(elf)
319 }
320 pub fn program_header<'a>(&'a self, elf: &'a [u8], index: u16) -> Result<&'a ProgramHeader> {
321 if index >= self.ph_count {
322 Err(Error::IndexOutOfRange)
323 } else {
324 let offset: usize = self.ph_offset.as_usize()? + (self.ph_entry_size as usize * index as usize);
325 ProgramHeader::new(&elf[offset..])
326 }
327 }
328 pub fn section_header<'a>(&'a self, elf: &'a [u8], index: u16) -> Result<&'a SectionHeader> {
329 if index >= self.sh_count {
330 Err(Error::IndexOutOfRange)
331 } else {
332 let offset: usize = self.sh_offset.as_usize()? + (self.sh_entry_size as usize * index as usize);
333 SectionHeader::new(&elf[offset..])
334 }
335 }
336}
337
338pub struct TableIter<'a, T: 'a + TableEntry<'a>> {
339 elf: &'a [u8],
340 offset: Offset,
341 count: u16,
342 size: u16,
343 index: u16,
344 _marker: core::marker::PhantomData<T>
345}
346impl<'a, T: 'a + TableEntry<'a>> TableIter<'a, T> {
347 pub fn new(elf: &'a [u8], offset: Offset, count: u16, size: u16) -> Result<Self> {
348 assert_eq!(align_of::<u32>(), align_of::<T::Header>());
349 if elf.as_ptr() as usize & 0b11 != 0 || size & 0b11 != 0 {
350 Err(Error::Unaligned)
351 } else {
352 Ok(Self {
353 elf,
354 offset,
355 count,
356 size,
357 index: 0,
358 _marker: core::marker::PhantomData,
359 })
360 }
361 }
362}
363impl<'a, T: 'a + TableEntry<'a>> Iterator for TableIter<'a, T> {
364 type Item = Result<T>;
365 fn next(&mut self) -> Option<Self::Item> {
366 if self.index == self.count {
367 None
368 } else {
369 let offset = match self.offset.as_usize() {
370 Ok(offset) => offset,
371 Err(e) => return Some(Err(e))
372 };
373 let offset = offset + self.index as usize * self.size as usize;
374 self.index += 1;
375 self.elf.get(offset..).map(|header| T::new(self.elf, header))
376 }
377 }
378}
379
380pub trait TableEntry<'a> where Self: Sized {
381 type Header;
382 fn new(elf: &'a [u8], header: &'a [u8]) -> Result<Self>;
383}
384
385
386pub struct Program<'a> {
388 pub header: &'a ProgramHeader,
389 pub data: &'a [u8]
390}
391impl<'a> Program<'a> {
392 pub fn new(header: &'a ProgramHeader, data: &'a [u8]) -> Self {
393 Self {
394 header,
395 data
396 }
397 }
398 pub fn check_type(&self, ty: ProgramType) -> Result<()> {
400 if self.header.ty != ty {
401 Err(Error::WrongProgramType { expected: ty, actual: self.header.ty })
402 } else {
403 Ok(())
404 }
405 }
406 pub fn check_flag(&self, flags: ProgramFlags) -> Result<()> {
407 if self.header.flags.all(flags) {
408 Ok(())
409 } else {
410 Err(Error::WrongProgramFlags { expected: flags, actual: self.header.flags })
411 }
412 }
413}
414impl<'a> fmt::Debug for Program<'a> {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 self.header.fmt(f)
417 }
418}
419impl<'a> TableEntry<'a> for Program<'a> {
420 type Header = ProgramHeader;
421 fn new(elf: &'a [u8], header: &'a [u8]) -> Result<Self> {
422 let header = ProgramHeader::new(header)?;
423 Ok(Self::new(header, header.data(elf)?))
424 }
425}
426#[derive(Debug)]
427#[repr(C)]
428pub struct ProgramHeader {
429 pub ty: ProgramType,
430 pub offset: Offset,
431 pub virt_addr: Address,
432 pub phys_addr: Address,
433 pub file_size: u32,
434 pub mem_size: u32,
435 pub flags: ProgramFlags,
436 pub align: u32
437}
438impl ProgramHeader {
439 pub fn new(header: &[u8]) -> Result<&Self> {
440 if header.len() < size_of::<Self>() {
441 return Err(Error::UnexpectedEoF)
442 }
443 if header.as_ptr() as usize & 0b11 != 0 {
444 return Err(Error::Unaligned)
445 }
446 let header = unsafe { &*(header.as_ptr() as *const ProgramHeader) };
447 Ok(header)
448 }
449 pub fn data<'a>(&'a self, elf: &'a [u8]) -> Result<&'a [u8]> {
450 let size: usize = self.file_size.try_into().map_err(|_| Error::IntegerOverflow)?;
451 let offset = self.offset.as_usize()?;
452 elf.get(offset..offset + size).ok_or(Error::UnexpectedEoF)
453 }
454}
455
456pub struct Section<'a> {
458 pub header: &'a SectionHeader,
459 pub data: &'a [u8]
460}
461impl<'a> Section<'a> {
462 pub fn new(header: &'a SectionHeader, data: &'a [u8]) -> Self {
463 Self {
464 header,
465 data
466 }
467 }
468 pub fn check_type(&self, ty: SectionType) -> Result<()> {
470 if self.header.ty != ty {
471 Err(Error::WrongSectionType { expected: ty, actual: self.header.ty })
472 } else {
473 Ok(())
474 }
475 }
476 pub fn check_flag(&self, flags: SectionFlags) -> Result<()> {
477 if self.header.flags.all(flags) {
478 Ok(())
479 } else {
480 Err(Error::WrongSectionFlags { expected: flags, actual: self.header.flags })
481 }
482 }
483}
484impl<'a> fmt::Debug for Section<'a> {
485 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
486 self.header.fmt(f)
487 }
488}
489impl<'a> TableEntry<'a> for Section<'a> {
490 type Header = SectionHeader;
491 fn new(elf: &'a [u8], header: &'a [u8]) -> Result<Self> {
492 let header = SectionHeader::new(header)?;
493 Ok(Self::new(header, header.data(elf)?))
494 }
495}
496#[derive(Debug)]
497#[repr(C)]
498pub struct SectionHeader {
499 pub name: u32,
500 pub ty: SectionType,
501 pub flags: SectionFlags,
502 pub address: Address,
503 pub offset: Offset,
504 pub size: u32,
505 pub link: u32,
506 pub info: u32,
507 pub alignment: u32,
508 pub entry_size: u32
509}
510impl SectionHeader {
511 pub fn new(header: &[u8]) -> Result<&Self> {
512 if header.len() < size_of::<Self>() {
513 return Err(Error::UnexpectedEoF)
514 }
515 if header.as_ptr() as usize & 0b11 != 0 {
516 return Err(Error::Unaligned)
517 }
518 let header = unsafe { &*(header.as_ptr() as *const SectionHeader) };
519 Ok(header)
520 }
521 pub fn data<'a>(&'a self, elf: &'a [u8]) -> Result<&'a [u8]> {
522 let size: usize = self.size.try_into().map_err(|_| Error::IntegerOverflow)?;
523 let offset = self.offset.as_usize()?;
524 elf.get(offset..offset + size).ok_or(Error::UnexpectedEoF)
525 }
526}
527
528#[derive(Copy, Clone)]
529pub struct StringTable<'a>(&'a [u8]);
530impl<'a> StringTable<'a> {
531 pub fn new(section: Section<'a>) -> Result<Self> {
535 section.check_type(SectionType::StringTable)?;
536 section.check_flag(SectionFlags::Strings)?;
537 Ok(Self(section.data))
538 }
539 pub fn get_str(self, index: u32) -> Result<&'a str> {
540 self.get_bytes(index)
541 .and_then(|b|
542 core::str::from_utf8(b)
543 .map_err(Error::NotUtf8)
544 )
545 }
546 pub fn get_bytes(self, index: u32) -> Result<&'a [u8]> {
548 self.0.get(index as usize..).ok_or(Error::IndexOutOfRange)
549 .and_then(|s| {
550 let end = memchr::memchr(0, s).ok_or(Error::UnterminatedString)?;
551 Ok(&s[0..end])
552 })
553 }
554 pub fn get_ptr(self) -> *const u8 {
558 self.0.as_ptr()
559 }
560 pub fn len(self) -> usize {
562 self.0.len()
563 }
564 pub fn is_empty(self) -> bool {
566 self.0.is_empty()
567 }
568}
569impl<'a> fmt::Debug for StringTable<'a> {
570 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
571 f.debug_tuple("StringTable")
572 .field(&[..])
573 .finish()
574 }
575}
576
577c_enum!{
578 pub FileType(u16) {
579 None = 0,
580 Relocatable = 1,
581 Executable = 2,
582 SharedObject = 3,
583 Core = 4
584 } v => Err(Error::UnsupportedFileType(v))
585}
586c_enum!{
587 pub Machine(u16) {
588 RiscV = 243
589 } v => Err(Error::UnsupportedMachine(v))
590}
591c_enum!{
592 pub ProgramType(u32) {
593 Null = 0,
594 Load = 1,
595 Dynamic = 2,
596 Interpreter = 3,
597 Note = 4,
598 ProgramHeader = 6,
599 ThreadLocalStorage = 7,
600 GnuStack = 0x6474E551,
601 RiscVAttributes = 0x70000003
602 } v => Err(Error::UnsupportedProgramType(v))
603}
604c_flags!{
605 pub ProgramFlags(u32) {
606 Read = 0b001,
607 Exec = 0b010,
608 Write = 0b100
609 } v => Err(Error::UnsupportedProgramFlags(v))
610}
611c_enum!{
612 pub SectionType(u32) {
613 Null = 0,
614 Program = 1,
615 SymbolTable = 2,
616 StringTable = 3,
617 Rela = 4,
618 HashTable = 5,
619 Dynamic = 6,
620 Note = 7,
621 NoBits = 8,
622 Rel = 9,
623 DynamicSymbolTable = 11,
624 InitArray = 14,
625 FiniArray = 15,
626 PreinitArray = 16,
627 Group = 17,
628 SymbolIndex = 18
629 } v => Err(Error::UnsupportedSectionType(v))
630}
631c_flags!{
632 pub SectionFlags(u32) {
633 Write = 0x1,
634 Alloc = 0x2,
635 Exec = 0x4,
636 Merge = 0x10,
637 Strings = 0x20,
638 InfoLink = 0x40,
639 LinkOrder = 0x80,
640 OsNonconforming = 0x100,
641 Group = 0x200,
642 Tls = 0x400,
643 Compressed = 0x800
644 } v => Err(Error::UnsupportedSectionFlags(v))
645}