Skip to content

Commit

Permalink
merge ihex srec and ti-txt BV implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
rbran committed Aug 8, 2024
1 parent 9703d76 commit 832c249
Show file tree
Hide file tree
Showing 11 changed files with 513 additions and 1,450 deletions.
9 changes: 8 additions & 1 deletion view/ihex/Cargo.lock → view/bintxt/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions view/srec/Cargo.toml → view/bintxt/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
[package]
name = "view-srec"
name = "view-bintxt"
version = "0.1.0"
authors = ["Rubens Brandao <[email protected]>"]
edition = "2021"

[dependencies]
binaryninja = { path = "../../rust" }
srec = "0.2.0"
ihex = "3.0.0"
log = "*"
srec = "0.2.0"

[lib]
crate-type = ["cdylib"]
Expand Down
237 changes: 237 additions & 0 deletions view/bintxt/src/ihex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
use binaryninja::binaryview::*;
use binaryninja::custombinaryview::*;
use binaryninja::rc::Ref;
use binaryninja::segment::SegmentBuilder;
use ihex::Record;

use crate::segment_after_address;
use crate::segment_from_address;
use crate::sort_and_merge_segments;
use crate::MergedSegment;
use crate::UnmergedSegment;

fn parse_ihex(string: &str) -> Result<(Vec<u8>, IHexViewData)> {
let mut reader = ihex::Reader::new(&string);
let mut unmerged_data: Vec<UnmergedSegment> = vec![];
let mut start = None;
let mut offset = None;
while let Some(record) = reader.next() {
let record = record.map_err(|e| {
log::error!("Unable to parse record: {e}");
()
})?;
match record {
ihex::Record::EndOfFile => break,
ihex::Record::Data {
offset: data_offset,
value,
} => {
let address = match offset {
Some(IHexOffset::Segment(offset)) => {
u64::from(offset) * 16 + u64::from(data_offset)
}
Some(IHexOffset::Linear(offset)) => {
u64::from(offset) << 16 | u64::from(data_offset)
}
None => data_offset.into(),
};
// check if the block is just extending the previous one
match unmerged_data.last_mut() {
// check if the block is just extending the previous one, merge both
Some(last) if last.end() == address => last.data.extend(value),
// otherwise just add a new block
_ => unmerged_data.push(UnmergedSegment {
address,
data: value,
}),
}
}
ihex::Record::StartSegmentAddress { cs, ip } => {
if start.is_some() {
log::error!("Multiple Start Address defined");
return Err(());
}
start = Some(IHexStart::Segment { _cs: cs, ip });
}
ihex::Record::StartLinearAddress(offset) => {
if start.is_some() {
log::error!("Multiple Start Address defined");
return Err(());
}
start = Some(IHexStart::Linear(offset));
}
ihex::Record::ExtendedSegmentAddress(segment_offset) => {
offset = Some(IHexOffset::Segment(segment_offset))
}
ihex::Record::ExtendedLinearAddress(linear_offset) => {
offset = Some(IHexOffset::Linear(linear_offset))
}
}
}
// can't have other record after the EoF record
if reader.next().is_some() {
log::error!("Found record after EoF record");
return Err(());
}

let merged = sort_and_merge_segments(unmerged_data)?;
Ok((
merged.data,
IHexViewData {
segments: merged.segments,
start,
},
))
}

pub struct IHexViewConstructor {
pub core: BinaryViewType,
}

impl AsRef<BinaryViewType> for IHexViewConstructor {
fn as_ref(&self) -> &BinaryViewType {
&self.core
}
}

impl CustomBinaryViewType for IHexViewConstructor {
fn create_custom_view<'builder>(
&self,
parent: &BinaryView,
builder: CustomViewBuilder<'builder, Self>,
) -> Result<CustomView<'builder>> {
let bytes = parent.len();
let mut buf = vec![0; bytes];
let bytes_read = parent.read(&mut buf, 0);
if bytes_read != bytes {
log::error!("IHex file is too small");
return Err(());
}
let string = String::from_utf8(buf).map_err(|_| {
log::error!("File contains invalid UTF8 characters");
})?;

let (data, segments) = parse_ihex(&string)?;

let parent_bin = BinaryView::from_data(&parent.file(), &data)?;
builder.create::<IHexView>(&parent_bin, segments)
}
}

impl BinaryViewTypeBase for IHexViewConstructor {
fn is_valid_for(&self, data: &BinaryView) -> bool {
// TODO check filename and identify the type if necessary
//let filename = data.file().filename();
//let filename = std::path::Path::new(filename.as_str());
//let filetype = filename
// .extension()
// .map(|ext| match ext.to_string_lossy().as_ref() {
// // General-purpose:
// "hex" | "mcs" | "int" | "ihex" | "ihe" | "ihx" => true,
// // Platform-specific:
// "h80" | "h86" | "a43" | "a90" => Some(true),
// // Binary or Intel hex:
// "obj" | "obl" | "obh" | "rom" | "eep" => true,
// // TODO: Split, banked, or paged:
// //.hxl–.hxh,[8] .h00–.h15, .p00–.pff[9]
// _ => false,
// });

// The biggest possible record is data record with 255 bytes: 268 bytes
let mut first_bytes = [0u8; 384];
let read_bytes = data.read(&mut first_bytes, 0);
let data = String::from_utf8_lossy(&first_bytes[0..read_bytes]);
let Some(line) = data.lines().next() else {
return false;
};
Record::from_record_string(line).is_ok()
}

fn is_deprecated(&self) -> bool {
false
}
}

pub struct IHexView {
core: Ref<BinaryView>,
segments: Vec<MergedSegment>,
start: Option<IHexStart>,
}

pub struct IHexViewData {
segments: Vec<MergedSegment>,
start: Option<IHexStart>,
}

#[derive(Clone, Copy, Debug)]
enum IHexStart {
Segment { _cs: u16, ip: u16 },
Linear(u32),
}

#[derive(Clone, Copy, Debug)]
enum IHexOffset {
Segment(u16),
Linear(u16),
}

impl AsRef<BinaryView> for IHexView {
fn as_ref(&self) -> &BinaryView {
&self.core
}
}

unsafe impl CustomBinaryView for IHexView {
type Args = IHexViewData;

fn new(handle: &BinaryView, _args: &Self::Args) -> Result<Self> {
Ok(Self {
core: handle.to_owned(),
// NOTE dummy values, final values are added on init
start: None,
segments: vec![],
})
}

fn init(&mut self, IHexViewData { start, segments }: Self::Args) -> Result<()> {
self.start = start;
self.segments = segments;

for segment in self.segments.iter() {
self.add_segment(
SegmentBuilder::from(*segment)
.executable(true)
.readable(true)
.contains_data(true)
.contains_code(true),
);
}
Ok(())
}
}

impl BinaryViewBase for IHexView {
fn entry_point(&self) -> u64 {
match self.start {
Some(IHexStart::Linear(addr)) => addr.into(),
Some(IHexStart::Segment { _cs, ip }) => ip.into(),
None => self.start(),
}
}

fn default_endianness(&self) -> binaryninja::Endianness {
binaryninja::Endianness::LittleEndian
}

fn address_size(&self) -> usize {
4
}

fn offset_valid(&self, offset: u64) -> bool {
segment_from_address(&self.segments, offset).is_some()
}

fn next_valid_offset_after(&self, offset: u64) -> u64 {
segment_after_address(&self.segments, offset)
}
}
Loading

0 comments on commit 832c249

Please sign in to comment.