127 lines
3.9 KiB
Rust
127 lines
3.9 KiB
Rust
//! Basic ELF parsing functionality using the `elf` crate.
|
|
//!
|
|
//! This may be extended in the future to support loading programs, however we
|
|
//! currently use this for getting the sizes of sections in our kernel ELF at
|
|
//! runtime.
|
|
//!
|
|
//! This is used for implementing stacktraces in std::unwind.
|
|
//!
|
|
//! # TODO
|
|
//!
|
|
//! * Add support for loading binary programs (this should probably be written
|
|
//! in a different module)
|
|
|
|
use alloc::format;
|
|
use elf::{
|
|
ElfBytes, ParseError,
|
|
endian::LittleEndian,
|
|
parse::{ParseAt, ParsingTable},
|
|
section::{SectionHeader, SectionHeaderTable},
|
|
string_table::StringTable,
|
|
symbol::SymbolTable,
|
|
};
|
|
use limine::request::KernelFileRequest;
|
|
|
|
use crate::prelude::*;
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
/// The length of the ELF header in bytes.
|
|
pub const ELF_HEADER_LEN: usize = 64;
|
|
|
|
/// Information about our own ELF file to make ELF parsing easier, such as the
|
|
/// length of the file and a pointer to the contents.
|
|
#[used]
|
|
pub static KERNEL_FILE_REQUEST: KernelFileRequest = KernelFileRequest::new();
|
|
|
|
/// A list of errors that may occur when parsing ELF files.
|
|
#[derive(Debug)]
|
|
pub enum ElfError {
|
|
/// Returned if a section did not exist in [ElfReader::get_section_size].
|
|
SectionNotExists,
|
|
/// Parse errors returned by the `elf` crate.
|
|
OtherParseError(elf::ParseError),
|
|
}
|
|
|
|
impl From<elf::ParseError> for ElfError {
|
|
fn from(err: elf::ParseError) -> Self {
|
|
Self::OtherParseError(err)
|
|
}
|
|
}
|
|
|
|
pub struct ElfReader {
|
|
/// Structure returned by the `elf` crate having parsed the ELF header.
|
|
elf: ElfBytes<'static, LittleEndian>,
|
|
}
|
|
|
|
impl ElfReader {
|
|
/// Parses the ELF file for the kernel, this uses data from Limine's Kernel
|
|
/// File Request to get a slice over the whole executable file.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// Assumes a properly formed ELF file, and that Limine returns a correct
|
|
/// pointer to the start of the file as well as a valid length in bytes.
|
|
///
|
|
/// Both of these should be satisfied, but this function is marked unsafe
|
|
/// just in case, because we are derefererencing arbitrary pointers.
|
|
pub unsafe fn new() -> Result<Self, ElfError> {
|
|
let response = KERNEL_FILE_REQUEST
|
|
.get_response()
|
|
.expect("Didn't get the kernel file from Limine. That's odd.");
|
|
|
|
// We fetch these from Limine and use them to parse our own ELF file.
|
|
let file = response.file();
|
|
let file_start_ptr = file.addr();
|
|
let file_size = file.size() as usize;
|
|
|
|
// Safety: This slice should contain the whole bytes of the ELF file.
|
|
let elf_hdr_slice =
|
|
unsafe { core::slice::from_raw_parts(file_start_ptr, file_size) };
|
|
|
|
let elf: ElfBytes<'static, LittleEndian> =
|
|
elf::ElfBytes::minimal_parse(elf_hdr_slice)?;
|
|
|
|
Ok(Self { elf })
|
|
}
|
|
|
|
#[warn(clippy::unwrap_used)]
|
|
pub fn get_symbol_table(
|
|
&self,
|
|
) -> Result<
|
|
Option<(SymbolTable<'static, LittleEndian>, StringTable<'static>)>,
|
|
ElfError,
|
|
> {
|
|
// TODO: Remove .unwrap().
|
|
Ok(self.elf.symbol_table().unwrap())
|
|
}
|
|
|
|
/// Gets the section size of `section_name` in bytes.
|
|
pub fn get_section_size(
|
|
&self,
|
|
section_name: &'static str,
|
|
) -> Result<u64, ElfError> {
|
|
Ok(self.get_section_header(section_name)?.sh_size)
|
|
}
|
|
|
|
/// Gets the start address of the section `section_name` in memory.
|
|
pub fn get_section_addr(
|
|
&self,
|
|
section_name: &'static str,
|
|
) -> Result<*const u8, ElfError> {
|
|
Ok(self.get_section_header(section_name)?.sh_addr as *const u8)
|
|
}
|
|
|
|
/// Gets the section header of `section_name`.
|
|
pub fn get_section_header(
|
|
&self,
|
|
section_name: &'static str,
|
|
) -> Result<SectionHeader, ElfError> {
|
|
let section_hdr = self
|
|
.elf
|
|
.section_header_by_name(section_name)
|
|
.map_err(|_e| ElfError::SectionNotExists)?;
|
|
|
|
section_hdr.ok_or(ElfError::SectionNotExists)
|
|
}
|
|
}
|