better error handling

master
Ales Katona 4 years ago
parent b9cc07fa1d
commit 9c4765ca95
Signed by: almindor
GPG Key ID: 2F773149BF38B48F

@ -38,6 +38,7 @@ pub struct Loadable {
rodata: SegmentSections, rodata: SegmentSections,
data: SegmentSections, data: SegmentSections,
bss: SegmentSections, bss: SegmentSections,
pub start_offset: Option<u64>,
} }
impl Loadable { impl Loadable {
@ -60,6 +61,10 @@ impl Loadable {
Self::section_names().len() Self::section_names().len()
} }
pub const fn segment_count() -> usize {
3
}
pub fn segment_sections(&self) -> impl Iterator<Item = &SegmentSections> { pub fn segment_sections(&self) -> impl Iterator<Item = &SegmentSections> {
let text = once(&self.text); let text = once(&self.text);
let rodata = once(&self.rodata); let rodata = once(&self.rodata);

@ -10,16 +10,33 @@ pub enum Error {
InvalidSectionName, InvalidSectionName,
InvalidSectionData, InvalidSectionData,
ParseError(Box<dyn std::error::Error>), ParseError(Box<dyn std::error::Error>),
TryFromIntError, // TryFromIntError,
LinkingError(Trace), LinkingError(Trace),
} }
// "backtrace" for error origin // "backtrace" for error origin
#[derive(Debug)] #[derive(Debug, Default)]
pub struct Trace { pub struct Trace {
origin: PathBuf, pub code: u32, // specific trace code, should be >= 700
offset: u64, // 0 indicates unknown/invalid pub message: &'static str,
source_info: Option<Box<dyn SourceInfo>>, pub origin: PathBuf,
pub offset: u64, // 0 indicates unknown/invalid
pub source_info: Option<Box<dyn SourceInfo>>,
}
impl Error {
// used for programmatic input/output handling, IDE's etc.
pub fn code(&self) -> u32 {
match self {
Error::IOError(_) => 100,
Error::InvalidObjectType(_) => 200,
Error::InvalidSectionName => 300,
Error::InvalidSectionData => 400,
Error::ParseError(_) => 500,
Error::TryFromIntError => 600,
Error::LinkingError(trace) => trace.code,
}
}
} }
pub trait SourceInfo: Debug + Display { pub trait SourceInfo: Debug + Display {
@ -42,12 +59,39 @@ impl From<std::num::TryFromIntError> for Error {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "TODO!") write!(f, "[{}] ", self.code())?;
match self {
Error::IOError(err) => write!(f, "IO error: {}", err),
Error::InvalidObjectType(ot) => write!(f, "Invalid object type: {}", ot),
Error::InvalidSectionName => write!(f, "Invalid section name"),
Error::InvalidSectionData => write!(f, "Invalid section data"),
Error::ParseError(err) => write!(f, "Parse error: {}", err),
Error::TryFromIntError => write!(f, "Integer conversion error"),
Error::LinkingError(trace) => write!(f, "Linking error: {}", trace),
}
} }
} }
impl Display for Trace { impl Display for Trace {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "TODO!") let mut new_line = ""; // new line in case of previous info only
if let Some(origin) = self.origin.to_str() {
new_line = "\n";
write!(f, "\n\t{}", origin)?;
}
if self.offset > 0 {
new_line = "\n";
write!(f, "\n@offset: {}", self.offset)?;
}
if let Some(si) = &self.source_info {
new_line = "\n";
write!(f, "\n{}", si)?;
}
write!(f, "{}{}", new_line, self.message)
} }
} }

@ -47,10 +47,10 @@ impl Output<ElfObject> for ElfOutput {
let strtab = make_strtab(); let strtab = make_strtab();
let mut ehdr = make_elf_header(); let mut ehdr = make_elf_header();
ehdr.e_shnum = Loadable::section_count() as u16 + 1; ehdr.e_shnum = Loadable::section_count() as u16 + 1; // +1 for .shstrtab
ehdr.e_phnum = 3; // TODO: probably move to loadable? ehdr.e_phnum = Loadable::segment_count() as u16;
ehdr.e_shstrndx = ehdr.e_shnum - 1; ehdr.e_shstrndx = ehdr.e_shnum - 1; // .shstrab is always last
ehdr.e_entry = 4096; // TODO: find .start symbol eventual location ehdr.e_entry = get_start_offset(loadable)?;
ehdr.e_phentsize = PHS; ehdr.e_phentsize = PHS;
ehdr.e_shentsize = SHS; ehdr.e_shentsize = SHS;
ehdr.e_phoff = EHS; ehdr.e_phoff = EHS;
@ -77,7 +77,6 @@ impl Output<ElfObject> for ElfOutput {
let mut name_idx = 0; let mut name_idx = 0;
// write section header table (text + rodata + data + bss) // write section header table (text + rodata + data + bss)
for sections in loadable.segment_sections() { for sections in loadable.segment_sections() {
// TODO: find out data_offset for these headers
let sh = make_section_header( let sh = make_section_header(
strtab.1[name_idx], strtab.1[name_idx],
ShType::ProgBits, ShType::ProgBits,
@ -216,6 +215,19 @@ fn make_strtab() -> (Vec<u8>, Vec<usize>) {
(strtab_bytes, indexes) (strtab_bytes, indexes)
} }
fn get_start_offset(loadable: &Loadable) -> Result<u64, Error> {
use crate::error::Trace;
loadable.start_offset.ok_or_else(|| {
let trace = Trace {
message: "Program entrypoint not found",
..Default::default()
};
Error::LinkingError(trace)
})
}
fn expand_path(path: &Path) -> Result<&str, Error> { fn expand_path(path: &Path) -> Result<&str, Error> {
use std::io::Error as IOError; use std::io::Error as IOError;
use std::io::ErrorKind; use std::io::ErrorKind;

@ -48,6 +48,7 @@ where
} }
} }
self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location
self.output.finalize(&self.relocatables, &self.loadable) self.output.finalize(&self.relocatables, &self.loadable)
} }

Loading…
Cancel
Save