From 6e88feb9a78b0d1f4ece0880bef84d602f664db0 Mon Sep 17 00:00:00 2001 From: sawyer bristol Date: Fri, 21 Nov 2025 11:24:31 -0700 Subject: [PATCH] loader errors --- kernel/src/elf.rs | 163 +++++++++++++++++++++++------------------ kernel/src/main.rs | 3 + kernel/src/storage.rs | 44 +++++++---- kernel/src/syscalls.rs | 8 +- kernel/src/ui.rs | 7 +- 5 files changed, 131 insertions(+), 94 deletions(-) diff --git a/kernel/src/elf.rs b/kernel/src/elf.rs index 680396a..5413e31 100644 --- a/kernel/src/elf.rs +++ b/kernel/src/elf.rs @@ -20,69 +20,76 @@ use userlib_sys::{EntryFn, SyscallTable}; const ELF32_HDR_SIZE: usize = 52; -pub async unsafe fn load_binary(name: &ShortFileName) -> Option<(EntryFn, Bump)> { +#[derive(Debug)] +pub enum LoadError { + FailedToReadFile, + ElfIsNotPie, + UnknownRelocationType, + SyscallTableNotFound, +} + +pub async unsafe fn load_binary(name: &ShortFileName) -> Result<(EntryFn, Bump), LoadError> { let mut sd_lock = SDCARD.get().lock().await; - let sd = sd_lock.as_mut().unwrap(); + let sd = sd_lock.as_mut().expect("Sdcard locked"); let mut header_buf = [0; ELF32_HDR_SIZE]; - let (entry, bump) = sd - .read_file(name, |mut file| { - file.read(&mut header_buf).unwrap(); - let elf_header = Header::from_bytes(&header_buf); + sd.read_file(name, |mut file| { + file.read(&mut header_buf) + .map_err(|_| LoadError::FailedToReadFile)?; + let elf_header = Header::from_bytes(&header_buf); - // reject non-PIE - if elf_header.e_type != header::ET_DYN { - return None; + // reject non-PIE + if elf_header.e_type != header::ET_DYN { + return Err(LoadError::ElfIsNotPie); + } + + let mut ph_buf = vec![0_u8; elf_header.e_phentsize as usize]; + + let (total_size, min_vaddr, _max_vaddr) = + total_loadable_size(&mut file, elf_header, &mut ph_buf)?; + + let bump = Bump::with_capacity(total_size); + let base = bump.alloc_slice_fill_default::(total_size); + + // load each segment into bump, relative to base_ptr + for i in 0..elf_header.e_phnum { + file.seek_from_start(elf_header.e_phoff + (elf_header.e_phentsize * i) as u32) + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(&mut ph_buf) + .map_err(|_| LoadError::FailedToReadFile)?; + let ph = cast_phdr(&ph_buf); + + let seg_offset = (ph.p_vaddr - min_vaddr) as usize; + let segment = &mut base[seg_offset..seg_offset + ph.p_memsz as usize]; + + if ph.p_type == PT_LOAD { + load_segment(&mut file, &ph, segment)?; } + } - let mut ph_buf = vec![0_u8; elf_header.e_phentsize as usize]; + for i in 0..elf_header.e_shnum { + let sh = read_section(&mut file, elf_header, i.into())?; - let (total_size, min_vaddr, _max_vaddr) = - total_loadable_size(&mut file, elf_header, &mut ph_buf); - - let bump = Bump::with_capacity(total_size); - let base = bump.alloc_slice_fill_default::(total_size); - - // load each segment into bump, relative to base_ptr - for i in 0..elf_header.e_phnum { - file.seek_from_start(elf_header.e_phoff + (elf_header.e_phentsize * i) as u32) - .unwrap(); - file.read(&mut ph_buf).unwrap(); - let ph = cast_phdr(&ph_buf); - - let seg_offset = (ph.p_vaddr - min_vaddr) as usize; - let segment = &mut base[seg_offset..seg_offset + ph.p_memsz as usize]; - - if ph.p_type == PT_LOAD { - load_segment(&mut file, &ph, segment).unwrap(); - } + if sh.sh_type == SHT_REL { + apply_relocations(&sh, min_vaddr, base.as_mut_ptr(), &mut file)?; } + } - for i in 0..elf_header.e_shnum { - let sh = read_section(&mut file, elf_header, i.into()); + patch_syscalls(elf_header, base.as_mut_ptr(), min_vaddr, &mut file)?; - if sh.sh_type == SHT_REL { - apply_relocations(&sh, min_vaddr, base.as_mut_ptr(), &mut file).unwrap(); - } - } + // entry pointer is base_ptr + (entry - min_vaddr) + let entry_ptr: EntryFn = unsafe { + core::mem::transmute(base.as_ptr().add((elf_header.e_entry - min_vaddr) as usize)) + }; - patch_syscalls(elf_header, base.as_mut_ptr(), min_vaddr, &mut file).unwrap(); - - // entry pointer is base_ptr + (entry - min_vaddr) - let entry_ptr: EntryFn = unsafe { - core::mem::transmute(base.as_ptr().add((elf_header.e_entry - min_vaddr) as usize)) - }; - - Some((entry_ptr, bump)) - }) - .await - .expect("Failed to read file")?; - - Some((entry, bump)) + Ok((entry_ptr, bump)) + }) + .await + .map_err(|_| LoadError::FailedToReadFile)? } -fn load_segment(file: &mut File, ph: &ProgramHeader, segment: &mut [u8]) -> Result<(), ()> { +fn load_segment(file: &mut File, ph: &ProgramHeader, segment: &mut [u8]) -> Result<(), LoadError> { let filesz = ph.p_filesz as usize; let memsz = ph.p_memsz as usize; @@ -94,8 +101,10 @@ fn load_segment(file: &mut File, ph: &ProgramHeader, segment: &mut [u8]) -> Resu while remaining > 0 { let to_read = core::cmp::min(remaining, buf.len()); - file.seek_from_start(file_offset).unwrap(); - file.read(&mut buf[..to_read]).unwrap(); + file.seek_from_start(file_offset) + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(&mut buf[..to_read]) + .map_err(|_| LoadError::FailedToReadFile)?; segment[dst_offset..dst_offset + to_read].copy_from_slice(&buf[..to_read]); @@ -117,14 +126,16 @@ fn apply_relocations( min_vaddr: u32, base: *mut u8, file: &mut File, -) -> Result<(), ()> { +) -> Result<(), LoadError> { let mut reloc = [0_u8; 8]; let num_relocs = sh.sh_size as usize / sh.sh_entsize as usize; for i in 0..num_relocs { - file.seek_from_start(sh.sh_offset + (i as u32 * 8)).unwrap(); - file.read(&mut reloc).unwrap(); + file.seek_from_start(sh.sh_offset + (i as u32 * 8)) + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(&mut reloc) + .map_err(|_| LoadError::FailedToReadFile)?; let rel = cast_rel(&reloc); @@ -140,7 +151,7 @@ fn apply_relocations( } } _ => { - return Err(()); + return Err(LoadError::UnknownRelocationType); } } } @@ -152,15 +163,17 @@ fn patch_syscalls( base: *mut u8, min_vaddr: u32, file: &mut File, -) -> Result<(), ()> { +) -> Result<(), LoadError> { for i in 1..=elf_header.e_shnum { - let sh = read_section(file, elf_header, i.into()); + let sh = read_section(file, elf_header, i.into())?; // find the symbol table if sh.sh_type == SHT_SYMTAB { let mut symtab_buf = vec![0u8; sh.sh_size as usize]; - file.seek_from_start(sh.sh_offset).unwrap(); - file.read(&mut symtab_buf).unwrap(); + file.seek_from_start(sh.sh_offset) + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(&mut symtab_buf) + .map_err(|_| LoadError::FailedToReadFile)?; // Cast buffer into symbols let sym_count = sh.sh_size as usize / sh.sh_entsize as usize; @@ -169,22 +182,23 @@ fn patch_syscalls( &symtab_buf[i * sh.sh_entsize as usize..(i + 1) * sh.sh_entsize as usize]; let sym = cast_sym(sym_bytes); - let str_sh = read_section(file, elf_header, sh.sh_link); + let str_sh = read_section(file, elf_header, sh.sh_link)?; let mut name = Vec::new(); file.seek_from_start(str_sh.sh_offset + sym.st_name) - .unwrap(); + .map_err(|_| LoadError::FailedToReadFile)?; loop { let mut byte = [0u8; 1]; - file.read(&mut byte).unwrap(); + file.read(&mut byte) + .map_err(|_| LoadError::FailedToReadFile)?; if byte[0] == 0 { break; } name.push(byte[0]); } - let symbol_name = core::str::from_utf8(&name).unwrap(); + let symbol_name = core::str::from_utf8(&name).expect("symbol was not utf8"); if symbol_name == stringify!(SYS_CALL_TABLE) { let table_base = unsafe { base.add((sym.st_value as usize) - min_vaddr as usize) } @@ -219,20 +233,20 @@ fn patch_syscalls( } } } - Err(()) + Err(LoadError::SyscallTableNotFound) } fn total_loadable_size( file: &mut File, elf_header: &Header, ph_buf: &mut [u8], -) -> (usize, u32, u32) { +) -> Result<(usize, u32, u32), LoadError> { let mut min_vaddr = u32::MAX; let mut max_vaddr = 0u32; for i in 0..elf_header.e_phnum { file.seek_from_start(elf_header.e_phoff + (elf_header.e_phentsize * i) as u32) - .unwrap(); - file.read(ph_buf).unwrap(); + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(ph_buf).map_err(|_| LoadError::FailedToReadFile)?; let ph = cast_phdr(ph_buf); if ph.p_type == PT_LOAD { @@ -246,17 +260,22 @@ fn total_loadable_size( } let total_size = (max_vaddr - min_vaddr) as usize; - (total_size, min_vaddr, max_vaddr) + Ok((total_size, min_vaddr, max_vaddr)) } -fn read_section(file: &mut File, elf_header: &Header, section: u32) -> SectionHeader { +fn read_section( + file: &mut File, + elf_header: &Header, + section: u32, +) -> Result { let mut sh_buf = vec![0_u8; elf_header.e_shentsize as usize]; file.seek_from_start(elf_header.e_shoff + (elf_header.e_shentsize as u32 * section)) - .unwrap(); - file.read(&mut sh_buf).unwrap(); + .map_err(|_| LoadError::FailedToReadFile)?; + file.read(&mut sh_buf) + .map_err(|_| LoadError::FailedToReadFile)?; - cast_shdr(&sh_buf) + Ok(cast_shdr(&sh_buf)) } fn cast_phdr(buf: &[u8]) -> ProgramHeader { diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 39c270e..bc67eeb 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -5,6 +5,9 @@ #![allow(static_mut_refs)] #![feature(allocator_api)] #![feature(slice_ptr_get)] +#![deny(warnings)] +#![deny(clippy::redundant_clone)] +#![deny(clippy::unwrap_used)] extern crate alloc; diff --git a/kernel/src/storage.rs b/kernel/src/storage.rs index c77974b..874dbd5 100644 --- a/kernel/src/storage.rs +++ b/kernel/src/storage.rs @@ -52,6 +52,13 @@ impl Ord for FileName { } } +#[derive(Debug)] +pub enum SdCardError { + Volume0Missing, + RootDirMissing, + FileOpenFailed, +} + pub struct SdCard { det: Input<'static>, volume_mgr: VolMgr, @@ -104,30 +111,37 @@ impl SdCard { res.map_err(|_| ()) } - pub fn access_root_dir(&mut self, mut access: impl FnMut(Dir)) { - let volume0 = self.volume_mgr.open_volume(VolumeIdx(0)).unwrap(); - let root_dir = volume0.open_root_dir().unwrap(); + pub fn access_root_dir( + &mut self, + mut access: impl FnMut(Dir) -> R, + ) -> Result { + let volume0 = self + .volume_mgr + .open_volume(VolumeIdx(0)) + .map_err(|_| SdCardError::Volume0Missing)?; + let root_dir = volume0 + .open_root_dir() + .map_err(|_| SdCardError::RootDirMissing)?; - access(root_dir); + Ok(access(root_dir)) } - pub async fn read_file( + pub async fn read_file( &mut self, name: &ShortFileName, - mut access: impl FnMut(File) -> T, - ) -> Result { - let mut res = Err(()); + mut access: impl FnMut(File) -> R, + ) -> Result { self.access_root_dir(|root_dir| { - if let Ok(file) = root_dir.open_file_in_dir(name, Mode::ReadOnly) { - res = Ok(access(file)); - } - }); + let file = root_dir + .open_file_in_dir(name, Mode::ReadOnly) + .map_err(|_| SdCardError::FileOpenFailed)?; - res + Ok(access(file)) + })? } /// Returns a Vec of file names (long format) that match the given extension (e.g., "BIN") - pub fn list_files_by_extension(&mut self, ext: &str) -> Result, ()> { + pub fn list_files_by_extension(&mut self, ext: &str) -> Result, SdCardError> { let mut result = Vec::new(); // Only proceed if card is inserted @@ -151,7 +165,7 @@ impl SdCard { } }) .unwrap() - }); + })?; Ok(result) } diff --git a/kernel/src/syscalls.rs b/kernel/src/syscalls.rs index 357d7e6..46d7ec6 100644 --- a/kernel/src/syscalls.rs +++ b/kernel/src/syscalls.rs @@ -190,7 +190,7 @@ pub extern "C" fn list_dir( let sd = guard.as_mut().unwrap(); let mut wrote = 0; - sd.access_root_dir(|root| { + let _ = sd.access_root_dir(|root| { if dirs[0].is_empty() && dirs.len() >= 2 { unsafe { if dir == "/" { @@ -264,7 +264,7 @@ pub extern "C" fn read_file( let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard"); let sd = guard.as_mut().unwrap(); if !file.is_empty() { - sd.access_root_dir(|root| { + let _ = sd.access_root_dir(|root| { if let Ok(result) = recurse_file(&root, &components[1..count], |file| { file.seek_from_start(start_from as u32).unwrap_or(()); file.read(buf).unwrap() @@ -303,7 +303,7 @@ pub extern "C" fn write_file( let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard"); let sd = guard.as_mut().unwrap(); if !file.is_empty() { - sd.access_root_dir(|root| { + let _ = sd.access_root_dir(|root| { recurse_file(&root, &components[1..count], |file| { file.seek_from_start(start_from as u32).unwrap(); file.write(buf).unwrap() @@ -324,7 +324,7 @@ pub extern "C" fn file_len(str: *const u8, len: usize) -> usize { let mut guard = SDCARD.get().try_lock().expect("Failed to get sdcard"); let sd = guard.as_mut().unwrap(); if !file.is_empty() { - sd.access_root_dir(|root| { + let _ = sd.access_root_dir(|root| { if let Ok(result) = recurse_file(&root, &file[1..], |file| file.length()) { len = result } diff --git a/kernel/src/ui.rs b/kernel/src/ui.rs index 675ad86..fcc31bc 100644 --- a/kernel/src/ui.rs +++ b/kernel/src/ui.rs @@ -44,9 +44,10 @@ pub async fn ui_handler() { selections.selections[selections.current_selection as usize].clone(); let entry = unsafe { - load_binary(&selection.short_name) - .await - .expect("unable to load binary") + match load_binary(&selection.short_name).await { + Ok(entry) => entry, + Err(e) => panic!("unable to load binary: {:?}", e), + } }; BINARY_CH.send(entry).await; }