Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for split program images #164

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 77 additions & 15 deletions tool/microkit/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
//

use crate::util::bytes_to_struct;
use std::borrow::Cow;
use std::collections::HashMap;
use std::fs;
use std::path::Path;

#[repr(C, packed)]
#[derive(Copy, Clone)]
struct ElfHeader32 {
ident_magic: u32,
ident_class: u8,
Expand Down Expand Up @@ -45,6 +47,7 @@ struct ElfSymbol64 {
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
struct ElfSectionHeader64 {
name: u32,
type_: u32,
Expand All @@ -59,6 +62,7 @@ struct ElfSectionHeader64 {
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
struct ElfProgramHeader64 {
type_: u32,
flags: u32,
Expand All @@ -71,6 +75,7 @@ struct ElfProgramHeader64 {
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
struct ElfHeader64 {
ident_magic: u32,
ident_class: u8,
Expand Down Expand Up @@ -140,6 +145,39 @@ pub struct ElfFile {

impl ElfFile {
pub fn from_path(path: &Path) -> Result<ElfFile, String> {
Self::from_split_paths(path, None)
}

pub fn from_split_paths(
path: &Path,
path_for_symbols: Option<&Path>,
) -> Result<ElfFile, String> {
let reader = ElfFileReader::from_path(path)?;
let reader_for_symbols = match path_for_symbols {
Some(path_for_symbols) => Cow::Owned(ElfFileReader::from_path(path_for_symbols)?),
None => Cow::Borrowed(&reader),
};
let segments = reader.segments();
let symbols = reader_for_symbols.symbols()?;
Ok(ElfFile {
word_size: reader.word_size,
entry: reader.hdr.entry,
segments,
symbols,
})
}
}

#[derive(Clone)]
struct ElfFileReader<'a> {
path: &'a Path,
bytes: Vec<u8>,
word_size: usize,
hdr: ElfHeader64,
}

impl<'a> ElfFileReader<'a> {
fn from_path(path: &'a Path) -> Result<Self, String> {
let bytes = match fs::read(path) {
Ok(bytes) => bytes,
Err(err) => return Err(format!("Failed to read ELF '{}': {}", path.display(), err)),
Expand Down Expand Up @@ -172,9 +210,17 @@ impl ElfFile {
}
};

if word_size != 64 {
return Err(format!(
"ELF '{}': unsupported word size: '{}'",
path.display(),
word_size
));
}

// Now need to read the header into a struct
let hdr_bytes = &bytes[..hdr_size];
let hdr = unsafe { bytes_to_struct::<ElfHeader64>(hdr_bytes) };
let hdr = *unsafe { bytes_to_struct::<ElfHeader64>(hdr_bytes) };

// We have checked this above but we should check again once we actually cast it to
// a struct.
Expand All @@ -188,14 +234,23 @@ impl ElfFile {
));
}

let entry = hdr.entry;
Ok(Self {
path,
bytes,
word_size,
hdr,
})
}

fn segments(&self) -> Vec<ElfSegment> {
let hdr = &self.hdr;

// Read all the segments
let mut segments = Vec::with_capacity(hdr.phnum as usize);
for i in 0..hdr.phnum {
let phent_start = hdr.phoff + (i * hdr.phentsize) as u64;
let phent_end = phent_start + (hdr.phentsize as u64);
let phent_bytes = &bytes[phent_start as usize..phent_end as usize];
let phent_bytes = &self.bytes[phent_start as usize..phent_end as usize];

let phent = unsafe { bytes_to_struct::<ElfProgramHeader64>(phent_bytes) };

Expand All @@ -208,7 +263,7 @@ impl ElfFile {

let mut segment_data = vec![0; phent.memsz as usize];
segment_data[..phent.filesz as usize]
.copy_from_slice(&bytes[segment_start..segment_end]);
.copy_from_slice(&self.bytes[segment_start..segment_end]);

let segment = ElfSegment {
data: segment_data,
Expand All @@ -221,14 +276,20 @@ impl ElfFile {
segments.push(segment)
}

segments
}

fn symbols(&self) -> Result<HashMap<String, (ElfSymbol64, bool)>, String> {
let hdr = &self.hdr;

// Read all the section headers
let mut shents = Vec::with_capacity(hdr.shnum as usize);
let mut symtab_shent: Option<&ElfSectionHeader64> = None;
let mut shstrtab_shent: Option<&ElfSectionHeader64> = None;
for i in 0..hdr.shnum {
let shent_start = hdr.shoff + (i * hdr.shentsize) as u64;
let shent_end = shent_start + hdr.shentsize as u64;
let shent_bytes = &bytes[shent_start as usize..shent_end as usize];
let shent_bytes = &self.bytes[shent_start as usize..shent_end as usize];

let shent = unsafe { bytes_to_struct::<ElfSectionHeader64>(shent_bytes) };
match shent.type_ {
Expand All @@ -242,27 +303,27 @@ impl ElfFile {
if shstrtab_shent.is_none() {
return Err(format!(
"ELF '{}': unable to find string table section",
path.display()
self.path.display()
));
}

assert!(symtab_shent.is_some());
if symtab_shent.is_none() {
return Err(format!(
"ELF '{}': unable to find symbol table section",
path.display()
self.path.display()
));
}

// Reading the symbol table
let symtab_start = symtab_shent.unwrap().offset as usize;
let symtab_end = symtab_start + symtab_shent.unwrap().size as usize;
let symtab = &bytes[symtab_start..symtab_end];
let symtab = &self.bytes[symtab_start..symtab_end];

let symtab_str_shent = shents[symtab_shent.unwrap().link as usize];
let symtab_str_start = symtab_str_shent.offset as usize;
let symtab_str_end = symtab_str_start + symtab_str_shent.size as usize;
let symtab_str = &bytes[symtab_str_start..symtab_str_end];
let symtab_str = &self.bytes[symtab_str_start..symtab_str_end];

// Read all the symbols
let mut symbols: HashMap<String, (ElfSymbol64, bool)> = HashMap::new();
Expand Down Expand Up @@ -294,14 +355,11 @@ impl ElfFile {
offset += symbol_size;
}

Ok(ElfFile {
word_size,
entry,
segments,
symbols,
})
Ok(symbols)
}
}

impl ElfFile {
pub fn find_symbol(&self, variable_name: &str) -> Result<(u64, u64), String> {
if let Some((sym, duplicate)) = self.symbols.get(variable_name) {
if *duplicate {
Expand Down Expand Up @@ -340,7 +398,9 @@ impl ElfFile {

None
}
}

impl<'a> ElfFileReader<'a> {
fn get_string(strtab: &[u8], idx: usize) -> Result<&str, String> {
match strtab[idx..].iter().position(|&b| b == 0) {
Some(null_byte_pos) => {
Expand All @@ -359,7 +419,9 @@ impl ElfFile {
)),
}
}
}

impl ElfFile {
pub fn loadable_segments(&self) -> Vec<&ElfSegment> {
self.segments.iter().filter(|s| s.loadable).collect()
}
Expand Down
14 changes: 13 additions & 1 deletion tool/microkit/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3315,7 +3315,19 @@ fn main() -> Result<(), String> {
for pd in &system.protection_domains {
match get_full_path(&pd.program_image, &search_paths) {
Some(path) => {
let elf = ElfFile::from_path(&path).unwrap();
let path_for_symbols = pd
.program_image_for_symbols
.as_ref()
.map(|path_suffix| {
get_full_path(path_suffix, &search_paths).ok_or_else(|| {
format!(
"unable to find program image for symbols: '{}'",
path_suffix.display()
)
})
})
.transpose()?;
let elf = ElfFile::from_split_paths(&path, path_for_symbols.as_deref()).unwrap();
pd_elf_files.push(elf);
}
None => {
Expand Down
8 changes: 7 additions & 1 deletion tool/microkit/src/sdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ pub struct ProtectionDomain {
pub passive: bool,
pub stack_size: u64,
pub program_image: PathBuf,
pub program_image_for_symbols: Option<PathBuf>,
pub maps: Vec<SysMap>,
pub irqs: Vec<SysIrq>,
pub setvars: Vec<SysSetVar>,
Expand Down Expand Up @@ -397,6 +398,7 @@ impl ProtectionDomain {
let mut child_pds = Vec::new();

let mut program_image = None;
let mut program_image_for_symbols = None;
let mut virtual_machine = None;

// Default to minimum priority
Expand All @@ -421,7 +423,7 @@ impl ProtectionDomain {

match child.tag_name().name() {
"program_image" => {
check_attributes(xml_sdf, &child, &["path"])?;
check_attributes(xml_sdf, &child, &["path", "path_for_symbols"])?;
if program_image.is_some() {
return Err(value_error(
xml_sdf,
Expand All @@ -432,6 +434,9 @@ impl ProtectionDomain {

let program_image_path = checked_lookup(xml_sdf, &child, "path")?;
program_image = Some(Path::new(program_image_path).to_path_buf());

program_image_for_symbols =
child.attribute("path_for_symbols").map(PathBuf::from);
}
"map" => {
let map = SysMap::from_xml(xml_sdf, &child, true)?;
Expand Down Expand Up @@ -567,6 +572,7 @@ impl ProtectionDomain {
passive,
stack_size,
program_image: program_image.unwrap(),
program_image_for_symbols,
maps,
irqs,
setvars,
Expand Down
Loading