Implement read support for intel hex files, some ObjectFileReader refactoring
This commit is contained in:
parent
51ad57bdaf
commit
a3a5d61838
116
src/file.rs
116
src/file.rs
@ -2,6 +2,7 @@ extern crate object;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::iter::repeat;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@ -29,7 +30,9 @@ struct IhexWriter;
|
||||
struct BinWriter;
|
||||
|
||||
struct ElfReader;
|
||||
struct IhexReader;
|
||||
struct IhexReader {
|
||||
file_contents: String,
|
||||
}
|
||||
struct BinReader {
|
||||
filesize: usize,
|
||||
file: File,
|
||||
@ -47,12 +50,12 @@ impl MemoryFileType {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn read_object_file(
|
||||
pub fn object_file_reader(
|
||||
filename: &PathBuf,
|
||||
) -> Result<Box<dyn ObjectFileReader>, std::io::Error> {
|
||||
match MemoryFileType::type_from_filename(filename.to_str().unwrap_or("")) {
|
||||
Some(MemoryFileType::Elf) => unimplemented!(),
|
||||
Some(MemoryFileType::Ihex) => unimplemented!(),
|
||||
Some(MemoryFileType::Ihex) => IhexReader::new(filename),
|
||||
Some(MemoryFileType::Bin) => BinReader::new(filename),
|
||||
None => {
|
||||
warn!("Can't determine an appropriate output type based on filename {}, reading as raw binary", filename.to_str().unwrap_or("<invalid utf-8>"));
|
||||
@ -85,21 +88,10 @@ pub trait ObjectFileReader {
|
||||
fn new(file: &PathBuf) -> Result<Box<dyn ObjectFileReader>, std::io::Error>
|
||||
where
|
||||
Self: Sized;
|
||||
fn len(&self) -> usize;
|
||||
/// Set buf's contents to the object file's first `text` section, up to `size` bytes
|
||||
fn read_first(
|
||||
&mut self,
|
||||
buf: &mut Vec<u8>,
|
||||
size: Option<u32>,
|
||||
) -> Result<(), Box<dyn std::error::Error>>;
|
||||
/// Set buf's contents to the object file's contents, starting from LMA `addr`` to a maximum of `size` bytes,
|
||||
/// or to the end of the section containing `addr`
|
||||
fn read_at(
|
||||
&mut self,
|
||||
buf: &mut Vec<u8>,
|
||||
addr: u32,
|
||||
size: Option<u32>,
|
||||
) -> Result<(), Box<dyn std::error::Error>>;
|
||||
/// Return the base address and entire data of `text` sections in the object file,
|
||||
/// copied into a Vec<u8>. This will allocate the necessary space for the entire memory
|
||||
/// map of the `text` sections, which in some cases is probably a horrible idea.
|
||||
fn read_all(&mut self, size: Option<u32>) -> Result<Vec<u8>, Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
/// An object that can write a block of memory to a file
|
||||
@ -252,36 +244,68 @@ impl ObjectFileReader for BinReader {
|
||||
let filesize = file.metadata()?.len().try_into().unwrap();
|
||||
Ok(Box::new(BinReader { file, filesize }))
|
||||
}
|
||||
fn len(&self) -> usize {
|
||||
self.filesize
|
||||
}
|
||||
fn read_at(
|
||||
&mut self,
|
||||
buf: &mut Vec<u8>,
|
||||
addr: u32,
|
||||
size: Option<u32>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if addr as usize > self.filesize {
|
||||
return Err("Can't read past the end of the file!".into());
|
||||
}
|
||||
|
||||
let size = std::cmp::min(
|
||||
size.unwrap_or(self.filesize as u32 - addr) as usize,
|
||||
self.filesize as usize - addr as usize,
|
||||
);
|
||||
|
||||
self.file.seek(std::io::SeekFrom::Start(addr.into()))?;
|
||||
buf.resize(size as usize, 0);
|
||||
Ok(self.file.read_exact(buf)?)
|
||||
}
|
||||
fn read_first(
|
||||
&mut self,
|
||||
buf: &mut Vec<u8>,
|
||||
size: Option<u32>,
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
fn read_all(&mut self, size: Option<u32>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
// The casting here is a bit janky...
|
||||
let size = std::cmp::min(size.unwrap_or(self.filesize as u32) as usize, self.filesize);
|
||||
buf.resize(size as usize, 0);
|
||||
Ok(self.file.read_exact(buf)?)
|
||||
let mut buf = Vec::from_iter(std::iter::repeat(0).take(size));
|
||||
self.file.read_exact(&mut buf)?;
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectFileReader for IhexReader {
|
||||
fn new(file: &PathBuf) -> Result<Box<dyn ObjectFileReader>, std::io::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
// Parse the entire file up front, since we need it for len() anyway. Only store the parsed sections.
|
||||
let file_contents = std::fs::read_to_string(file)?;
|
||||
|
||||
Ok(Box::new(IhexReader { file_contents }))
|
||||
}
|
||||
fn read_all(&mut self, size: Option<u32>) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
|
||||
let reader = ihex::Reader::new(&self.file_contents);
|
||||
let mut cur_base = 0;
|
||||
let mut data = Vec::new();
|
||||
for rec in reader {
|
||||
if let Ok(record) = rec {
|
||||
match record {
|
||||
ihex::Record::ExtendedLinearAddress(a) => {
|
||||
cur_base = (a as u32) << 16;
|
||||
debug!(
|
||||
"ihex: Got ExtendedLinearAddress, new base: {:08x}",
|
||||
(a as u32) << 16
|
||||
);
|
||||
}
|
||||
// Entry point address is not useful for a flash tool, but it is emitted by objcopy etc. so we need to support/ignore it
|
||||
ihex::Record::StartSegmentAddress { .. }
|
||||
| ihex::Record::StartLinearAddress(_) => (),
|
||||
|
||||
ihex::Record::Data { offset, mut value } => {
|
||||
let record_base = cur_base + (offset as u32);
|
||||
if (data.len() as u32) < record_base {
|
||||
debug!("Extending vec by {} to take up slack space", (record_base as usize) - data.len());
|
||||
data.extend(repeat(0xff).take((record_base as usize) - data.len()));
|
||||
}
|
||||
data.append(&mut value);
|
||||
}
|
||||
ihex::Record::EndOfFile => continue,
|
||||
_ => unimplemented!(
|
||||
"Only I32HEX format files are supported. We don't support record type {:?}",
|
||||
record
|
||||
),
|
||||
}
|
||||
} else {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::InvalidData,
|
||||
rec.unwrap_err().to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
@ -117,12 +117,9 @@ impl ObjectFileType {
|
||||
Self::Elf => MemoryFileType::Elf.mem_writer(),
|
||||
}
|
||||
}
|
||||
fn file_reader(
|
||||
&self,
|
||||
filename: &PathBuf,
|
||||
) -> Result<Box<dyn ObjectFileReader>, std::io::Error> {
|
||||
fn file_reader(&self, filename: &PathBuf) -> Result<Box<dyn ObjectFileReader>, std::io::Error> {
|
||||
match self {
|
||||
Self::Auto => MemoryFileType::read_object_file(filename),
|
||||
Self::Auto => MemoryFileType::object_file_reader(filename),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user