summaryrefslogtreecommitdiff
path: root/view/bintxt/src/lib.rs
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2024-08-06 11:01:23 -0300
committerMason Reed <mason@vector35.com>2024-08-27 17:19:25 -0400
commit7e1027d904e66b0cadb277883cdfa7b13dcb209f (patch)
tree4451fe8134e7518d43b1e04c1446f56d3bb2091e /view/bintxt/src/lib.rs
parentfeca74615ab3e10e7e256630946d830d07414d08 (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.rs131
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()
+}