diff --git a/Cargo.lock b/Cargo.lock index c7ac08f24..e8134d2f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2520,16 +2520,6 @@ dependencies = [ name = "sel4-platform-info-types" version = "0.1.0" -[[package]] -name = "sel4-render-elf-with-data" -version = "0.1.0" -dependencies = [ - "anyhow", - "fallible-iterator 0.2.0", - "num", - "object", -] - [[package]] name = "sel4-reset" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 97ddabb50..729ca3173 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -122,7 +122,6 @@ members = [ "crates/sel4-panicking/env", "crates/sel4-platform-info", "crates/sel4-platform-info/types", - "crates/sel4-render-elf-with-data", "crates/sel4-reset", "crates/sel4-reset/cli", "crates/sel4-root-task", diff --git a/crates/sel4-render-elf-with-data/Cargo.nix b/crates/sel4-render-elf-with-data/Cargo.nix deleted file mode 100644 index 2a64bec4b..000000000 --- a/crates/sel4-render-elf-with-data/Cargo.nix +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright 2023, Colias Group, LLC -# -# SPDX-License-Identifier: BSD-2-Clause -# - -{ mk, versions }: - -mk { - package.name = "sel4-render-elf-with-data"; - dependencies = { - object = { version = versions.object; features = [ "all" ]; }; - inherit (versions) anyhow fallible-iterator num; - }; -} diff --git a/crates/sel4-render-elf-with-data/Cargo.toml b/crates/sel4-render-elf-with-data/Cargo.toml deleted file mode 100644 index 45bc85914..000000000 --- a/crates/sel4-render-elf-with-data/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright 2023, Colias Group, LLC -# -# SPDX-License-Identifier: BSD-2-Clause -# -# -# This file is generated from './Cargo.nix'. You can edit this file directly -# if you are not using this project's Cargo manifest management tools. -# See 'hacking/cargo-manifest-management/README.md' for more information. -# - -[package] -name = "sel4-render-elf-with-data" -version = "0.1.0" -authors = ["Nick Spinale "] -edition = "2021" -license = "BSD-2-Clause" - -[dependencies] -anyhow = "1.0.66" -fallible-iterator = "0.2.0" -num = "0.4.1" -object = { version = "0.36.1", features = ["all"] } diff --git a/crates/sel4-render-elf-with-data/src/lib.rs b/crates/sel4-render-elf-with-data/src/lib.rs deleted file mode 100644 index 138e6baa2..000000000 --- a/crates/sel4-render-elf-with-data/src/lib.rs +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright 2023, Colias Group, LLC -// -// SPDX-License-Identifier: BSD-2-Clause -// - -use anyhow::{bail, Result}; -use num::{NumCast, PrimInt}; -use object::{ - elf::{FileHeader32, FileHeader64}, - read::elf::FileHeader, - Endian, Endianness, File, -}; - -pub use object::elf::{PF_R, PF_W, PF_X}; - -mod render; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum ElfBitWidth { - Elf32, - Elf64, -} - -impl ElfBitWidth { - pub fn detect(file_content: &[u8]) -> Result { - Ok(match File::parse(file_content)? { - File::Elf32(_) => Self::Elf32, - File::Elf64(_) => Self::Elf64, - _ => bail!("not ELF"), - }) - } -} - -pub type ConcreteFileHeader32 = FileHeader32; -pub type ConcreteFileHeader64 = FileHeader64; - -pub trait FileHeaderExt: FileHeader { - fn checked_add_signed(x: Self::Word, y: Self::Sword) -> Option; - fn write_word_bytes(endian: impl Endian, n: Self::Word) -> Vec; -} - -impl FileHeaderExt for ConcreteFileHeader32 { - fn checked_add_signed(x: Self::Word, y: Self::Sword) -> Option { - x.checked_add_signed(y) - } - - fn write_word_bytes(endian: impl Endian, n: Self::Word) -> Vec { - endian.write_u32_bytes(n).to_vec() - } -} - -impl FileHeaderExt for ConcreteFileHeader64 { - fn checked_add_signed(x: Self::Word, y: Self::Sword) -> Option { - x.checked_add_signed(y) - } - - fn write_word_bytes(endian: impl Endian, n: Self::Word) -> Vec { - endian.write_u64_bytes(n).to_vec() - } -} - -// NOTE -// The phdrs in output of render_with_data have p_align=1 regardless of the input. -// That is because the current consumers of the output do not use p_align. - -pub struct Input<'a, T: FileHeaderExt> { - pub symbolic_injections: Vec>, - pub image_start_patches: Vec, - pub image_end_patches: Vec, - pub concrete_patches: Vec<(Symbol, ConcreteValue)>, -} - -impl<'a, T: FileHeaderExt> Default for Input<'a, T> { - fn default() -> Self { - Self { - symbolic_injections: Default::default(), - image_start_patches: Default::default(), - image_end_patches: Default::default(), - concrete_patches: Default::default(), - } - } -} - -type Symbol = String; - -type ConcreteValue = ::Word; - -pub struct SymbolicInjection<'a, T: FileHeaderExt> { - pub align_modulus: T::Word, - pub align_residue: T::Word, - pub content: &'a [u8], - pub memsz: T::Word, - pub p_flags: u32, - pub patches: Vec<(Symbol, SymbolicValue)>, -} - -#[derive(Debug)] -pub struct SymbolicValue { - pub addend: T::Sword, -} - -impl<'a, T: FileHeaderExt> SymbolicInjection<'a, T> { - fn filesz(&self) -> T::Word { - NumCast::from(self.content.len()).unwrap() - } - - fn align_from(&self, addr: T::Word) -> T::Word { - align_from::(addr, self.align_modulus, self.align_residue) - } - - fn locate(&self, vaddr: T::Word) -> Result> { - Ok(Injection { - vaddr, - content: self.content, - memsz: self.memsz, - p_flags: self.p_flags, - patches: self - .patches - .iter() - .map(|(name, symbolic_value)| { - ( - name.clone(), - T::checked_add_signed(vaddr, symbolic_value.addend).unwrap(), - ) - }) - .collect::)>>(), - }) - } -} - -pub struct Injection<'a, T: FileHeaderExt> { - pub vaddr: T::Word, - pub content: &'a [u8], - pub memsz: T::Word, - pub p_flags: u32, - pub patches: Vec<(Symbol, ConcreteValue)>, -} - -impl<'a, T: FileHeaderExt> Injection<'a, T> { - fn vaddr(&self) -> T::Word { - self.vaddr - } - - fn filesz(&self) -> T::Word { - NumCast::from(self.content.len()).unwrap() - } - - fn memsz(&self) -> T::Word { - self.memsz - } - - fn content(&self) -> &'a [u8] { - self.content - } - - fn p_flags(&self) -> u32 { - self.p_flags - } - - fn patches(&self) -> impl Iterator)> { - self.patches.iter() - } -} - -fn align_from(addr: T::Word, modulus: T::Word, residue: T::Word) -> T::Word { - addr + (modulus + residue - addr % modulus) % modulus -} diff --git a/crates/sel4-render-elf-with-data/src/render.rs b/crates/sel4-render-elf-with-data/src/render.rs deleted file mode 100644 index e6856073c..000000000 --- a/crates/sel4-render-elf-with-data/src/render.rs +++ /dev/null @@ -1,214 +0,0 @@ -// -// Copyright 2023, Colias Group, LLC -// -// SPDX-License-Identifier: BSD-2-Clause -// - -use std::mem; - -use anyhow::{anyhow, ensure, Result}; -use num::{CheckedAdd, NumCast, ToPrimitive}; -use object::{ - elf::PT_LOAD, - read::elf::{ElfFile, FileHeader, ProgramHeader as _}, - read::ReadRef, - write::elf::{ProgramHeader, Writer}, - Object, ObjectSegment, ObjectSymbol, -}; - -use crate::{FileHeaderExt, Injection, Input}; - -impl<'a, T: FileHeaderExt> Input<'a, T> { - pub fn render_with_data(&self, orig: &[u8]) -> Result> { - self.render_with_data_already_parsed(&ElfFile::parse(orig)?) - } - - pub fn render_with_data_already_parsed<'b, R: ReadRef<'b>>( - &self, - orig_obj: &ElfFile<'b, T, R>, - ) -> Result> { - let orig_endian = orig_obj.endian(); - let orig_image_end = next_vaddr(orig_obj)?; - - let mut out_buf = vec![]; - let mut writer = Writer::new(orig_endian, orig_obj.is_64(), &mut out_buf); - - writer.reserve_file_header(); - writer.reserve_program_headers( - (loadable_segments(orig_obj).count() + self.symbolic_injections.len()).try_into()?, - ); - - let revised_offsets = loadable_segments(orig_obj) - .map(|phdr| { - let filesz = phdr.p_filesz(orig_endian).to_usize().unwrap(); - let offset = writer.reserve(filesz, 1); - Ok(offset) - }) - .collect::>>()?; - - let new_segments = { - let mut next_vaddr = orig_image_end; - self.symbolic_injections - .iter() - .map(|symbolic_injection| { - let filesz = symbolic_injection.filesz(); - let memsz = symbolic_injection.memsz; - let offset = writer.reserve(filesz.to_usize().unwrap(), 1); - let vaddr = symbolic_injection.align_from(next_vaddr); - next_vaddr = vaddr.checked_add(&memsz).unwrap(); - Ok((symbolic_injection.locate(vaddr)?, offset)) - }) - .collect::, usize)>>>()? - }; - - writer.write_file_header({ - let hdr = orig_obj.elf_header(); - &object::write::elf::FileHeader { - os_abi: hdr.e_ident().os_abi, - abi_version: hdr.e_ident().abi_version, - e_type: hdr.e_type(orig_endian), - e_machine: hdr.e_machine(orig_endian), - e_entry: hdr.e_entry(orig_endian).into(), - e_flags: hdr.e_flags(orig_endian), - } - })?; - - writer.write_align_program_headers(); - - for (phdr, revised_offset) in loadable_segments(orig_obj).zip(&revised_offsets) { - writer.write_program_header(&ProgramHeader { - p_type: phdr.p_type(orig_endian), - p_flags: phdr.p_flags(orig_endian), - p_offset: (*revised_offset).try_into()?, - p_vaddr: phdr.p_vaddr(orig_endian).into(), - p_paddr: phdr.p_paddr(orig_endian).into(), - p_filesz: phdr.p_filesz(orig_endian).into(), - p_memsz: phdr.p_memsz(orig_endian).into(), - p_align: 1, - }); - } - - for (injection, offset) in &new_segments { - let vaddr = injection.vaddr(); - writer.write_program_header(&ProgramHeader { - p_type: PT_LOAD, - p_flags: injection.p_flags(), - p_offset: (*offset).try_into()?, - p_vaddr: vaddr.into(), - p_paddr: vaddr.into(), - p_filesz: injection.filesz().into(), - p_memsz: injection.memsz().into(), - p_align: 1, - }); - } - - for (phdr, revised_offset) in loadable_segments(orig_obj).zip(&revised_offsets) { - writer.pad_until(*revised_offset); - writer.write(phdr.data(orig_endian, orig_obj.data()).ok().unwrap()); - } - - for (injection, offset) in &new_segments { - writer.pad_until(*offset); - writer.write(injection.content()); - } - - let mut recorded: Vec<(String, T::Word)> = vec![]; - { - let image_start = first_vaddr(orig_obj)?; - let image_end = new_segments - .iter() - .map(|(injection, _offset)| injection.vaddr() + injection.memsz()) - .max() - .unwrap_or(orig_image_end); - for name in &self.image_start_patches { - recorded.push((name.clone(), image_start)) - } - for name in &self.image_end_patches { - recorded.push((name.clone(), image_end)) - } - } - for (injection, _offset) in &new_segments { - for (name, value) in injection.patches() { - recorded.push((name.clone(), *value)) - } - } - for (name, value) in &self.concrete_patches { - recorded.push((name.clone(), *value)) - } - - let out_obj: &ElfFile = &ElfFile::parse(out_buf.as_slice())?; - let mut patches = vec![]; - for (name, value) in &recorded { - let patch_offset = - vaddr_to_offset(out_obj, get_symbol_vaddr(orig_obj, name)?)?.try_into()?; - let value_bytes = T::write_word_bytes(out_obj.endian(), *value); - patches.push((patch_offset, value_bytes)) - } - for (patch_offset, value_bytes) in patches { - out_buf[patch_offset..patch_offset + value_bytes.len()].copy_from_slice(&value_bytes); - } - - Ok(out_buf) - } -} - -fn loadable_segments<'a, 'b, T: FileHeaderExt, R: ReadRef<'b>>( - obj: &'a ElfFile<'b, T, R>, -) -> impl Iterator::ProgramHeader> + 'a { - obj.elf_program_headers() - .iter() - .filter(|phdr| phdr.p_type(obj.endian()) == PT_LOAD) -} - -fn get_symbol_vaddr<'a, T: FileHeaderExt, R: ReadRef<'a>>( - obj: &ElfFile<'a, T, R>, - name: &str, -) -> Result { - for symbol in obj.symbols() { - if symbol.name()? == name { - ensure!(usize::try_from(symbol.size()).unwrap() == mem::size_of::()); - return Ok(NumCast::from(symbol.address()).unwrap()); - } - } - Err(anyhow!("symbol '{}' not present", name)) -} - -fn vaddr_to_offset<'a, T: FileHeaderExt, R: ReadRef<'a>>( - obj: &ElfFile<'a, T, R>, - vaddr: T::Word, -) -> Result -where -{ - for segment in obj.segments() { - let start = segment.address(); - let end = start + segment.size(); - if (start..end).contains(&vaddr.into()) { - let offset_in_segment = vaddr.into() - start; - let (file_start, file_size) = segment.file_range(); - ensure!(offset_in_segment < file_size); - return Ok(file_start + offset_in_segment); - } - } - Err(anyhow!( - "vaddr '0x{:x}' not mapped", - >::into(vaddr) - )) -} - -fn first_vaddr<'a, T: FileHeaderExt, R: ReadRef<'a>>(obj: &ElfFile<'a, T, R>) -> Result -where -{ - loadable_segments(obj) - .map(|phdr| phdr.p_vaddr(obj.endian())) - .min() - .ok_or(anyhow!("no segments")) -} - -fn next_vaddr<'a, T: FileHeaderExt, R: ReadRef<'a>>(obj: &ElfFile<'a, T, R>) -> Result -where -{ - loadable_segments(obj) - .map(|phdr| phdr.p_vaddr(obj.endian()) + phdr.p_memsz(obj.endian())) - .max() - .ok_or(anyhow!("no segments")) -}