Work on object file interface.
Add ability to write ELF files that works. Set up trait and basic reader for bin files.
This commit is contained in:
parent
ee007da5d4
commit
51ad57bdaf
127
src/file.rs
127
src/file.rs
@ -1,5 +1,10 @@
|
||||
extern crate object;
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::ValueEnum;
|
||||
use log::debug;
|
||||
use log::warn;
|
||||
@ -23,8 +28,38 @@ struct ElfWriter;
|
||||
struct IhexWriter;
|
||||
struct BinWriter;
|
||||
|
||||
struct ElfReader;
|
||||
struct IhexReader;
|
||||
struct BinReader {
|
||||
filesize: usize,
|
||||
file: File,
|
||||
}
|
||||
|
||||
/// Build a new object to manage writing type T
|
||||
impl MemoryFileType {
|
||||
fn type_from_filename(filename: &str) -> Option<MemoryFileType> {
|
||||
let filename = filename.to_lowercase();
|
||||
let (_, extension) = filename.rsplit_once('.').unwrap_or(("", ""));
|
||||
match extension {
|
||||
"elf" => Some(MemoryFileType::Elf),
|
||||
"hex" | "ihex" => Some(MemoryFileType::Ihex),
|
||||
"bin" | "raw" => Some(MemoryFileType::Bin),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn read_object_file(
|
||||
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::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>"));
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn mem_writer(&self) -> Box<dyn MemoryWriter> {
|
||||
match *self {
|
||||
MemoryFileType::Elf => Box::new(ElfWriter),
|
||||
@ -32,21 +67,41 @@ impl MemoryFileType {
|
||||
MemoryFileType::Bin => Box::new(BinWriter),
|
||||
}
|
||||
}
|
||||
pub fn mem_writer_from_filename(filename: &str) -> Box<dyn MemoryWriter> {
|
||||
let filename = filename.to_lowercase();
|
||||
let (_, extension) = filename.rsplit_once('.').unwrap_or(("", ""));
|
||||
match extension {
|
||||
"elf" => Box::new(ElfWriter),
|
||||
"hex" | "ihex" => Box::new(IhexWriter),
|
||||
"bin" | "raw" => Box::new(BinWriter),
|
||||
_ => {
|
||||
warn!("Can't determine an appropriate output type based on filename {}, writing as raw binary", filename);
|
||||
pub fn mem_writer_for_file(filename: &PathBuf) -> Box<dyn MemoryWriter> {
|
||||
match MemoryFileType::type_from_filename(filename.to_str().unwrap_or("")) {
|
||||
Some(MemoryFileType::Elf) => Box::new(ElfWriter),
|
||||
Some(MemoryFileType::Ihex) => Box::new(IhexWriter),
|
||||
Some(MemoryFileType::Bin) => Box::new(BinWriter),
|
||||
None => {
|
||||
warn!("Can't determine an appropriate output type based on filename {}, writing as raw binary", filename.to_str().unwrap_or("<invalid utf-8>"));
|
||||
Box::new(BinWriter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An object that can read a block of memory from an object file
|
||||
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>>;
|
||||
}
|
||||
|
||||
/// An object that can write a block of memory to a file
|
||||
pub trait MemoryWriter {
|
||||
fn write_mem(
|
||||
@ -57,8 +112,6 @@ pub trait MemoryWriter {
|
||||
) -> Result<(), Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
// object is not well documented, see how this API must be used here:
|
||||
// https://github.com/gimli-rs/object/blob/master/src/write/elf/object.rs#L217
|
||||
impl MemoryWriter for ElfWriter {
|
||||
fn write_mem(
|
||||
&mut self,
|
||||
@ -69,6 +122,9 @@ impl MemoryWriter for ElfWriter {
|
||||
debug!("Writing as ELF with base address 0x{:x}", addr);
|
||||
let mut buf = Vec::new();
|
||||
|
||||
// object is not well documented, see how this API must be used here:
|
||||
// https://github.com/gimli-rs/object/blob/master/src/write/elf/object.rs#L217
|
||||
|
||||
let mut writer = object::write::elf::Writer::new(Endianness::Little, false, &mut buf);
|
||||
|
||||
// Calculating offsets
|
||||
@ -99,12 +155,6 @@ impl MemoryWriter for ElfWriter {
|
||||
e_machine: elf::EM_ARM,
|
||||
e_entry: addr.into(),
|
||||
e_flags: M33_FLAGS,
|
||||
// e_ident: elf::Ident,
|
||||
// e_type: elf::ET_EXEC,
|
||||
// e_entry: addr,
|
||||
// e_flags: elf::EF_ARM_ABI_FLOAT_HARD | elf::EF_ARM_EABI_VER5,
|
||||
// e_machine: elf::EM_ARM,
|
||||
// e_version: elf::EV_CURRENT,
|
||||
})?;
|
||||
writer.write_align(4);
|
||||
writer.write(&data);
|
||||
@ -192,3 +242,46 @@ impl MemoryWriter for BinWriter {
|
||||
Ok(output.write_all(data)?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectFileReader for BinReader {
|
||||
fn new(file: &PathBuf) -> Result<Box<dyn ObjectFileReader>, std::io::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let file = File::open(file)?;
|
||||
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>> {
|
||||
// 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)?)
|
||||
}
|
||||
}
|
||||
|
25
src/main.rs
25
src/main.rs
@ -11,6 +11,7 @@ use std::{
|
||||
use anyhow::{anyhow, Context, Error};
|
||||
use clap_num::maybe_hex;
|
||||
use env_logger::Env;
|
||||
use file::ObjectFileReader;
|
||||
use log::{debug, error, info, log_enabled, warn, Level};
|
||||
|
||||
use hidapi::{DeviceInfo, HidApi};
|
||||
@ -108,14 +109,23 @@ enum ObjectFileType {
|
||||
}
|
||||
|
||||
impl ObjectFileType {
|
||||
fn mem_writer(&self, filename: &str) -> Box<dyn MemoryWriter> {
|
||||
fn mem_writer(&self, filename: &PathBuf) -> Box<dyn MemoryWriter> {
|
||||
match self {
|
||||
Self::Auto => MemoryFileType::mem_writer_from_filename(filename),
|
||||
Self::Auto => MemoryFileType::mem_writer_for_file(filename),
|
||||
Self::Bin => MemoryFileType::Bin.mem_writer(),
|
||||
Self::Ihex => MemoryFileType::Ihex.mem_writer(),
|
||||
Self::Elf => MemoryFileType::Elf.mem_writer(),
|
||||
}
|
||||
}
|
||||
fn file_reader(
|
||||
&self,
|
||||
filename: &PathBuf,
|
||||
) -> Result<Box<dyn ObjectFileReader>, std::io::Error> {
|
||||
match self {
|
||||
Self::Auto => MemoryFileType::read_object_file(filename),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Args, Debug)]
|
||||
@ -139,6 +149,8 @@ struct ReadArgs {
|
||||
#[derive(Args, Debug)]
|
||||
struct WriteArgs {
|
||||
file: PathBuf,
|
||||
#[arg(short = 't', long = "type", value_enum, default_value_t = ObjectFileType::Auto)]
|
||||
filetype: ObjectFileType,
|
||||
|
||||
/// USB device to act on
|
||||
#[command(flatten)]
|
||||
@ -212,12 +224,9 @@ fn write_file_to_flash(args: &WriteArgs) -> Result<(), Error> {
|
||||
let api = HidApi::new()?;
|
||||
let isp = connect_device(&api, &args.devspec)?;
|
||||
|
||||
let infile = fs::read(args.file.as_path())
|
||||
let infile = args.filetype.file_reader(&args.file)
|
||||
.with_context(|| format!("Opening {} for reading", args.file.display()))?;
|
||||
let in_obj = object::File::parse(&*infile)
|
||||
.with_context(|| format!("Parsing {} as a binary object", args.file.display()))?;
|
||||
|
||||
println!("{:?}", in_obj.sections());
|
||||
|
||||
let flash_start = args.addr.unwrap_or(isp.GetFlashStartAddress()?);
|
||||
let flash_size = args.size.unwrap_or(isp.GetFlashSizeInBytes()?);
|
||||
@ -267,7 +276,7 @@ fn read_flash_to_file(args: &ReadArgs) -> Result<(), Error> {
|
||||
}
|
||||
};
|
||||
|
||||
let mut writer = args.filetype.mem_writer(args.file.to_str().unwrap_or(""));
|
||||
let mut writer = args.filetype.mem_writer(&args.file);
|
||||
|
||||
let write_pb: ProgressBar = ProgressBar::new(buf.len() as u64)
|
||||
.with_style(read_write_style())
|
||||
@ -281,7 +290,7 @@ fn read_flash_to_file(args: &ReadArgs) -> Result<(), Error> {
|
||||
.write_mem(&mut write_pb.wrap_write(output), flash_start, &buf)
|
||||
.or_else(|e| Err(anyhow!("Error writing to object file: {}", e)))?;
|
||||
write_pb.finish_using_style();
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user