diff options
| author | Rubens Brandao <git@rubens.io> | 2024-08-06 11:01:23 -0300 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-08-27 17:19:25 -0400 |
| commit | 7e1027d904e66b0cadb277883cdfa7b13dcb209f (patch) | |
| tree | 4451fe8134e7518d43b1e04c1446f56d3bb2091e /view/bintxt/src/lib.rs | |
| parent | feca74615ab3e10e7e256630946d830d07414d08 (diff) | |
Implement IHEX, SREC and TI-TXT views
All bundled under the arch_bintxt/arch_bintext view plugin
Diffstat (limited to 'view/bintxt/src/lib.rs')
| -rw-r--r-- | view/bintxt/src/lib.rs | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/view/bintxt/src/lib.rs b/view/bintxt/src/lib.rs new file mode 100644 index 00000000..96cd1835 --- /dev/null +++ b/view/bintxt/src/lib.rs @@ -0,0 +1,131 @@ +mod ihex; +mod srec; +mod titxt; + +use binaryninja::segment::SegmentBuilder; +use ihex::*; +use srec::*; +use titxt::*; + +use std::ops::Range; + +#[no_mangle] +#[allow(non_snake_case)] +pub extern "C" fn CorePluginInit() -> bool { + binaryninja::logger::init(log::LevelFilter::Error).expect("Unable to initialize logger"); + + binaryninja::custombinaryview::register_view_type(c"ti-txt", c"TI-TXT", |core| { + TiTxtViewConstructor { core } + }); + + binaryninja::custombinaryview::register_view_type(c"srec", c"Motorola S-record", |core| { + SRecViewConstructor { core } + }); + + binaryninja::custombinaryview::register_view_type(c"ihex", c"Intel HEX", |core| { + IHexViewConstructor { core } + }); + + true +} + +struct UnmergedSegment { + address: u64, + data: Vec<u8>, +} + +impl UnmergedSegment { + fn end(&self) -> u64 { + self.address + u64::try_from(self.data.len()).unwrap() + } +} + +#[derive(Clone, Copy, Debug)] +pub struct MergedSegment { + address: u64, + len: u64, + data_offset: u64, +} + +impl MergedSegment { + fn address_range(&self) -> Range<u64> { + self.address..self.end() + } + + fn data_range(&self) -> Range<u64> { + self.data_offset..self.data_offset + self.len + } + + fn end(&self) -> u64 { + self.address + self.len + } +} + +impl From<MergedSegment> for SegmentBuilder { + fn from(segment: MergedSegment) -> Self { + SegmentBuilder::new(segment.address_range()).parent_backing(segment.data_range()) + } +} + +struct MergedSegments { + data: Vec<u8>, + segments: Vec<MergedSegment>, +} + +fn sort_and_merge_segments(mut unmerged_data: Vec<UnmergedSegment>) -> Result<MergedSegments, ()> { + // sort segments by address and len, so we can detect overlaps + unmerged_data.sort_unstable_by_key(|segment| (segment.address, segment.data.len())); + + let mut data: Vec<u8> = + Vec::with_capacity(unmerged_data.iter().map(|sector| sector.data.len()).sum()); + let mut segments: Vec<MergedSegment> = Vec::with_capacity(unmerged_data.len()); + for segment in unmerged_data.into_iter() { + // add the data to the data poll + let data_offset = u64::try_from(data.len()).unwrap(); + let segment_len = u64::try_from(segment.data.len()).unwrap(); + data.extend(segment.data); + match segments.last_mut() { + // if have a last segment and the current chunk just extend it, merge both + Some(last) if segment.address == last.end() => last.len += segment_len, + // the same sector overlap, then the data was defined multiple times. + Some(last) if segment.address < last.end() => { + log::error!("Chunks of data overlap"); + return Err(()); + } + // otherwise just create a new segment + _ => segments.push(MergedSegment { + address: segment.address, + len: segment_len, + data_offset, + }), + } + } + + Ok(MergedSegments { data, segments }) +} + +fn segment_from_address(segments: &[MergedSegment], offset: u64) -> Option<&MergedSegment> { + segments + .binary_search_by(|segment| { + let range = segment.address_range(); + if range.contains(&offset) { + return core::cmp::Ordering::Equal; + } + offset.cmp(&range.start) + }) + .ok() + .map(|idx| &segments[idx]) +} + +fn segment_after_address(segments: &[MergedSegment], offset: u64) -> u64 { + let sector = segments.iter().find_map(|sector| { + if sector.address >= offset { + Some(sector.address) + } else if sector.end() < offset { + Some(offset) + } else { + None + } + }); + sector.unwrap_or(offset).into() +} |
