From 3c339241dd03f8c8e882786727eb03525264e9c4 Mon Sep 17 00:00:00 2001 From: Michael House Date: Wed, 6 Sep 2023 06:11:51 -0500 Subject: [PATCH 1/3] Refactored Table functionality into TableView --- README.md | 1 - src/binary.rs | 2 +- src/tables/info/relocation.rs | 2 +- src/tables/mod.rs | 3 +- src/tables/table.rs | 236 ++++++++++++++-------------------- 5 files changed, 99 insertions(+), 145 deletions(-) diff --git a/README.md b/README.md index 750aeef..df69a7a 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,6 @@ This release is going to be all about gathering context about executable code, i not outright disassembling it. - [ ] Add find-page-address page size calculation methods -- [ ] Create Function wrapper struct for symbol that includes binary data - [ ] Investigate integrating (or writing) a disassembly crate for deaf - [ ] Add methods for interrogating the target platform of the binary - [ ] Use `EI_OSABI` and `e_machine` values in file header diff --git a/src/binary.rs b/src/binary.rs index 45ecee6..bbd2fc4 100644 --- a/src/binary.rs +++ b/src/binary.rs @@ -2,7 +2,7 @@ use std::path::Path; use std::fs; use crate::Section; -use crate::tables::{Table,StringItem}; +use crate::tables::{Table,TableView,StringItem}; use crate::headers::FileHeader; use crate::errors::{Error,Result}; use crate::common::{ diff --git a/src/tables/info/relocation.rs b/src/tables/info/relocation.rs index 8edcbae..c5c9a4a 100644 --- a/src/tables/info/relocation.rs +++ b/src/tables/info/relocation.rs @@ -1,4 +1,4 @@ -use crate::errors::{Result, Error}; +use crate::errors::Result; use crate::common::Convert; /// Representation of the info field in a Relocation record diff --git a/src/tables/mod.rs b/src/tables/mod.rs index 7dfa521..fd4cd13 100644 --- a/src/tables/mod.rs +++ b/src/tables/mod.rs @@ -23,5 +23,6 @@ pub use items::{ pub use table::{ Table, - TableMut + TableMut, + TableView }; \ No newline at end of file diff --git a/src/tables/table.rs b/src/tables/table.rs index bda1e10..d34ce05 100644 --- a/src/tables/table.rs +++ b/src/tables/table.rs @@ -1,158 +1,157 @@ use std::marker::PhantomData; - use crate::errors::{Error,Result}; use crate::common::{ByteIter,SHType,Layout,Width}; use crate::tables::{TableItem,StringItem,RelaItem,RelItem,SymbolItem}; use crate::Section; -pub struct Table<'a,T> -where - T: TableItem + Default -{ - item: PhantomData, - section: &'a Section -} - -pub struct TableMut<'a,T> -where - T: TableItem + Default -{ - item: PhantomData, - section: &'a mut Section -} - -impl<'a,T> Table<'a,T> +/// Shared table interface between Table and TableMut +pub trait TableView where T: TableItem + Default { + /// Get an immutable reference to the internal section + fn section(&self) -> &Section; - /// Create a new table from the given section - fn new(section: &'a Section) -> Self { - Self { - item: PhantomData {}, - section: section, - } - } - - /// Get an iterator over the data + /// Get an iterator over each item's binary data fn iterator(&self) -> ByteIter { ByteIter::new( - self.section.data(), + self.section().data(), T::delimiter( - self.section.entity_size())) + self.section().entity_size())) } /// Get a slice of data that represents an item - fn item_data(&self, index: usize) -> Result<&[u8]> { + fn data(&self, index: usize) -> Result<&[u8]> { self.iterator() .nth(index) .ok_or(Error::OutOfBoundsError) } - /// True if items are all the same size - pub fn has_fixed_size(&self) -> bool { - self.section.entity_size() > 0 - } - - /// True if items can be different sizes - pub fn has_variable_size(&self) -> bool { - !self.has_fixed_size() + /// Get the offset of an item from the index + fn offset(&self, index: usize) -> usize { + if self.has_fixed_size() { + self.section().entity_size() * index + } else { + self.iterator() + .enumerate() + .take_while(|(i,_)| i < &index) + .fold(0,|a,(_,e)| a + e.len()) + } } /// Get an element from the table - pub fn at(&self, index: usize) -> Result { - T::parse(self.item_data(index)?,&self.section) + fn at(&self, index: usize) -> Result { + T::parse(self.data(index)?,self.section()) } /// Get an element from the table at a byte offset - pub fn at_offset(&self, offset: usize) -> Result { + fn at_offset(&self, offset: usize) -> Result { self.iterator() .offset(offset) .next() .ok_or(Error::OutOfBoundsError) - .and_then(|d| T::parse(d,&self.section)) + .and_then(|d| T::parse(d,self.section())) } /// Get all items from the table - pub fn items(&self) -> Result> { + fn items(&self) -> Result> { self.iterator() - .map(|b| T::parse(b,&self.section)) + .map(|b| T::parse(b,self.section())) .collect() } /// Get the number of items in the table - pub fn len(&self) -> usize { + fn len(&self) -> usize { if self.has_fixed_size() { - self.section.entity_count() + self.section().entity_count() } else { self.iterator().count() } } /// Get the number of bytes in the table - pub fn size(&self) -> usize { - self.section.body_size() + fn size(&self) -> usize { + self.section().body_size() } /// Get the layout being used by this table - pub fn layout(&self) -> Layout { - self.section.layout() + fn layout(&self) -> Layout { + self.section().layout() } /// Get the width being used by this table - pub fn width(&self) -> Width { - self.section.width() + fn width(&self) -> Width { + self.section().width() + } + + /// True if items are all the same size + fn has_fixed_size(&self) -> bool { + self.section().entity_size() > 0 + } + + /// True if items can be different sizes + fn has_variable_size(&self) -> bool { + !self.has_fixed_size() } + } -impl<'a,T> TableMut<'a,T> +/// A Section represented as an immutable Table +pub struct Table<'a,T> where T: TableItem + Default { + item: PhantomData, + section: &'a Section +} - /// Create a new mutable table for the given section - fn new(section: &'a mut Section) -> Self { +/// A Section represented as a mutable Table +pub struct TableMut<'a,T> +where + T: TableItem + Default +{ + item: PhantomData, + section: &'a mut Section +} + +impl<'a,T> Table<'a,T> +where + T: TableItem + Default +{ + /// Create a new table from the given section + fn new(section: &'a Section) -> Self { Self { item: PhantomData {}, - section: section, + section, } } +} - /// Get an iterator over the data - fn iterator(&self) -> ByteIter { - ByteIter::new( - self.section.data(), - T::delimiter( - self.section.entity_size())) +impl<'a,T> TableView for Table<'a,T> +where + T: TableItem + Default +{ + fn section(&self) -> &Section { + self.section } +} - /// Get a slice of data that represents an item - fn item_data(&self, index: usize) -> Result<&[u8]> { - self.iterator() - .nth(index) - .ok_or(Error::OutOfBoundsError) - } +impl<'a,T> TableMut<'a,T> +where + T: TableItem + Default +{ - /// Get the offset of an item from the index - fn item_offset(&self, index: usize) -> usize { - if self.has_fixed_size() { - self.section.entity_size() * index - } else { - self.iterator() - .enumerate() - .take_while(|(i,_)| i < &index) - .fold(0,|a,(_,e)| a + e.len()) + /// Create a new mutable table for the given section + fn new(section: &'a mut Section) -> Self { + Self { + item: PhantomData {}, + section: section, } } - /// Get the total size of the table - fn table_size(&self) -> usize { - self.section.body_size() - } - /// Reserve space at an offset in the section fn reserve(&mut self, offset: usize, size: usize) { - let length = self.table_size() + size; + let length = self.size() + size; self.section .data_mut() @@ -164,7 +163,7 @@ where /// Discard space at an offset in the section fn discard(&mut self, offset: usize, size: usize) { - let length = self.table_size() - size; + let length = self.size() - size; self.section .data_mut() @@ -190,7 +189,7 @@ where item.set_width(self.width()); let size = item.size(); - let offset = self.item_offset(index); + let offset = self.offset(index); // reserve additional space self.reserve(offset,size); @@ -206,8 +205,8 @@ where /// Remove an item from the table by index pub fn remove(&mut self, index: usize) -> Result { - let data = self.item_data(index)?; - let offset = self.item_offset(index); + let data = self.data(index)?; + let offset = self.offset(index); let size = data.len(); let item = T::parse(data,&self.section)?; @@ -218,59 +217,14 @@ where Ok(item) } - /// Get an element from the table - pub fn at(&self, index: usize) -> Result { - T::parse(self.item_data(index)?,&self.section) - } - - /// Get an element from the table at a byte offset - pub fn at_offset(&self, offset: usize) -> Result { - self.iterator() - .offset(offset) - .next() - .ok_or(Error::OutOfBoundsError) - .and_then(|d| T::parse(d,&self.section)) - } - - /// Get all items from the table - pub fn items(&self) -> Result> { - self.iterator() - .map(|b| T::parse(b,&self.section)) - .collect() - } - - /// True if items are all the same size - pub fn has_fixed_size(&self) -> bool { - self.section.entity_size() > 0 - } - - /// True if items can be different sizes - pub fn has_variable_size(&self) -> bool { - !self.has_fixed_size() - } - - /// Get the number of items in the table - pub fn len(&self) -> usize { - if self.has_fixed_size() { - self.section.entity_count() - } else { - self.iterator().count() - } - } - - /// Get the number of bytes in the table - pub fn size(&self) -> usize { - self.table_size() - } - - /// Get the layout being used by this table - pub fn layout(&self) -> Layout { - self.section.layout() - } +} - /// Get the width being used by this table - pub fn width(&self) -> Width { - self.section.width() +impl<'a,T> TableView for TableMut<'a,T> +where + T: TableItem + Default +{ + fn section(&self) -> &Section { + self.section } } @@ -402,8 +356,8 @@ where #[cfg(test)] mod tests { use super::*; - use crate::headers::{FileHeader}; - use crate::common::{SectionType}; + use crate::headers::FileHeader; + use crate::common::SectionType; use crate::utilities::read; use crate::utilities::tests::{ From 34119e5bbb2d9a4309432bbddf1e63836500a48c Mon Sep 17 00:00:00 2001 From: Michael House Date: Wed, 6 Sep 2023 11:45:36 -0500 Subject: [PATCH 2/3] Converted Array struct to Array/ArrayMut table specialization --- src/arrays/array.rs | 468 ------------------------- src/arrays/item.rs | 52 --- src/arrays/mod.rs | 8 - src/binary.rs | 27 +- src/common/item.rs | 2 +- src/lib.rs | 1 - src/section.rs | 36 +- src/tables/items/array.rs | 87 +++++ src/tables/items/mod.rs | 3 + src/tables/items/relocation.rs | 2 +- src/tables/items/traits.rs | 4 +- src/tables/mod.rs | 1 + src/tables/table.rs | 601 +++++++++++++++------------------ src/utilities.rs | 6 +- 14 files changed, 408 insertions(+), 890 deletions(-) delete mode 100644 src/arrays/array.rs delete mode 100644 src/arrays/item.rs delete mode 100644 src/arrays/mod.rs create mode 100644 src/tables/items/array.rs diff --git a/src/arrays/array.rs b/src/arrays/array.rs deleted file mode 100644 index 2277967..0000000 --- a/src/arrays/array.rs +++ /dev/null @@ -1,468 +0,0 @@ -use crate::errors::{Error, Result}; -use crate::common::{Width,Layout,SHType}; -use crate::headers::SectionHeader; -use crate::arrays::ArrayItem; -use crate::common::ByteIter; - -/// A section interpreted as an array -/// -/// Each Array instance is considered to be -/// a series of ArrayItem structs. Arrays can -/// be parsed from a SectionHeader and a byte -/// buffer containing the body of the section. -pub struct Array { - offset: usize, - layout: Layout, - width: Width, - kind: SHType, - entity_size: usize, - section_size: usize, - values: Vec -} - -impl Array { - - /// Create a new array given type and position information - pub fn new(offset: usize, size: usize, layout: Layout, width: Width, kind: SHType, entity_size: usize) -> Self { - Self { - offset: offset, - layout: layout, - width: width, - kind: kind, - entity_size: entity_size, - section_size: size, - values: vec![], - } - } - - /// Read array items from a byte buffer - /// - /// Reads from an offset to offset + section_size - pub fn read(&mut self, bytes: &[u8]) -> Result { - let start = self.offset; - let end = self.offset + self.section_size; - - let size = self.entity_size; - - // check that the entity size is > 0 - if size == 0 { - return Err(Error::MalformedDataError); - } - - // check that the section has data - if self.section_size == 0 { - return Err(Error::MalformedDataError); - } - - // check that entities fit cleanly into section - if self.section_size % size != 0 { - return Err(Error::MalformedDataError); - } - - // reserve a temporary buffer for entities - let mut values = vec![]; - values.reserve(self.section_size / size); - - for data in ByteIter::length(&bytes[start..end],size) { - // add the address to values - values.push(ArrayItem::read( - self.layout, - self.width, - data - )?); - } - - // don't update self until successful read - self.values = values; - Ok(self.values.len()) - } - - /// Write array items to a byte buffer - /// - /// Writes from the *beginning* of the given byte slice - pub fn write(&self, bytes: &mut [u8]) -> Result { - - // check buffer is big enough - if bytes.len() > self.size() { - return Err(Error::OutOfBoundsError); - } - - let size = self.entity_size; - - // iterate all contained addresses - for (i,value) in self.values.iter().enumerate() { - - // calculate item position in the output buffer - let start = i * size; - let end = start + size; - - // get a constrained, mutable slice of bytes to write to - let buffer = &mut bytes[start..end]; - - // write the item to the byte slice - value.write(buffer)?; - } - - Ok(self.values.len()) - } - - /// The number of items in this array - pub fn len(&self) -> usize { - self.values.len() - } - - /// The calculated size of the array in bytes - pub fn size(&self) -> usize { - self.len() * self.entity_size - } - - /// Get a reference to an array item at index - pub fn get(&self, index: usize) -> Option<&ArrayItem> { - self.values.get(index) - } - - /// Get a mutable reference to an array item at index - pub fn get_mut(&mut self, index: usize) -> Option<&mut ArrayItem> { - self.values.get_mut(index) - } - - /// Insert an array item at index, pushing other items right - pub fn insert(&mut self, index: usize, mut item: ArrayItem) { - item.set_layout(self.layout); - item.set_width(self.width); - self.values.insert(index,item); - } - - /// Append an array item to the array - pub fn push(&mut self, mut item: ArrayItem) { - item.set_layout(self.layout); - item.set_width(self.width); - self.values.push(item); - } - - /// Remove and return an array item from this array - pub fn remove(&mut self, index: usize) -> ArrayItem { - self.values.remove(index) - } - -} - -impl TryFrom<&SectionHeader> for Array { - type Error = Error; - - fn try_from(header: &SectionHeader) -> Result { - match header.kind() { - SHType::SHT_INIT_ARRAY | SHType::SHT_PREINIT_ARRAY | SHType::SHT_FINI_ARRAY - => Ok(Self::new( - header.offset(), - header.body_size(), - header.layout(), - header.width(), - header.kind(), - header.entsize() - )), - _ => Err(Error::WrongSectionError) - } - } -} - -impl TryFrom for Array { - type Error = Error; - - fn try_from(header: SectionHeader) -> Result { - Self::try_from(&header) - } -} - - -#[cfg(test)] -mod tests { - use super::*; - - use crate::headers::{FileHeader,SectionHeader}; - - use crate::utilities::read; - - use crate::utilities::tests::{ - LIBQSCINTILLA_FINI_ARRAY as FINI_TEST, - LIBQSCINTILLA_INIT_ARRAY as INIT_TEST, - }; - - #[test] - fn test_extract_real_init_array() { - let b = read("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0").unwrap(); - - let file_header = FileHeader::parse(&b).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let section_headers = SectionHeader::parse_all( - &b, - count, - offset, - size, - layout, - width); - - assert!(section_headers.is_ok()); - let headers = section_headers.unwrap(); - - let result = headers.iter().find(|&h| - h.kind() == SHType::SHT_INIT_ARRAY); - - assert!(result.is_some()); - - let header = result.unwrap(); - let result = Array::try_from(header); - - assert!(result.is_ok()); - - let mut array = result.unwrap(); - - assert!(array.read(&b).is_ok()); - assert_eq!(array.len(),INIT_TEST.length); - } - - #[test] - fn test_extract_real_fini_array() { - let b = read("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0").unwrap(); - - let file_header = FileHeader::parse(&b).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let section_headers = SectionHeader::parse_all( - &b, - count, - offset, - size, - layout, - width); - - assert!(section_headers.is_ok()); - let headers = section_headers.unwrap(); - - let result = headers.iter().find(|&h| - h.kind() == SHType::SHT_FINI_ARRAY); - - assert!(result.is_some()); - - let header = result.unwrap(); - let result = Array::try_from(header); - - assert!(result.is_ok()); - - let mut array = result.unwrap(); - - assert!(array.read(&b).is_ok()); - assert_eq!(array.len(),FINI_TEST.length); - } - - #[test] - fn test_read_init_array() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - INIT_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_INIT_ARRAY, - INIT_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(INIT_TEST.bytes); - assert!(result.is_ok()); - - // verify that the array has the expected number of elements - assert_eq!(array.len(),INIT_TEST.length); - } - - #[test] - fn test_read_fini_array() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - FINI_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_FINI_ARRAY, - FINI_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(FINI_TEST.bytes); - assert!(result.is_ok()); - - // verify that the array has the expected number of elements - assert_eq!(array.len(),FINI_TEST.length); - } - - #[test] - fn test_write_init_array_with_no_changes() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - INIT_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_INIT_ARRAY, - INIT_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(INIT_TEST.bytes); - assert!(result.is_ok()); - - // initialize a buffer big enough for array data - let mut buffer: Vec = vec![]; - buffer.resize(array.size(),0x00); - - // write to the new array - let result = array.write(buffer.as_mut_slice()); - assert!(result.is_ok()); - - // verify that the written array is the same as original - assert_eq!(buffer.as_slice(),INIT_TEST.bytes); - } - - #[test] - fn test_write_fini_array_with_no_changes() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - FINI_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_FINI_ARRAY, - FINI_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(FINI_TEST.bytes); - assert!(result.is_ok()); - - // initialize a buffer big enough for array data - let mut buffer: Vec = vec![]; - buffer.resize(array.size(),0x00); - - // write to the new array - let result = array.write(buffer.as_mut_slice()); - assert!(result.is_ok()); - - // verify that the written array is the same as original - assert_eq!(buffer.as_slice(),FINI_TEST.bytes); - } - - #[test] - fn test_write_init_array_with_changes() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - INIT_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_INIT_ARRAY, - INIT_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(INIT_TEST.bytes); - assert!(result.is_ok()); - - // get an element from the array - let result = array.get_mut(1); - assert!(result.is_some()); - - // change the value of the element - if let Some(item) = result { - item.set_value(123); - } - - // initialize a buffer big enough for modified table data - let mut buffer: Vec = vec![]; - buffer.resize(array.size(),0x00); - - // write to the new table - let result = array.write(buffer.as_mut_slice()); - assert!(result.is_ok()); - - // verify that the written table is not the same as original - assert_ne!(buffer.as_slice(),INIT_TEST.bytes); - - // read the buffer and verify success - let result = array.read(&buffer); - assert!(result.is_ok()); - - // get an element from the table - let result = array.get(1); - assert!(result.is_some()); - - // check the element is changed - let item = result.unwrap(); - assert_eq!(item.value(),123); - } - - #[test] - fn test_write_fini_array_with_changes() { - - // directly initialize an array - let mut array = Array::new( - 0, // because we're reading directly - FINI_TEST.size, - Layout::Little, - Width::X64, - SHType::SHT_FINI_ARRAY, - FINI_TEST.entsize - ); - - // read the test array and verify success - let result = array.read(FINI_TEST.bytes); - assert!(result.is_ok()); - - // get an element from the array - let result = array.get_mut(0); - assert!(result.is_some()); - - // change the value of the element - if let Some(item) = result { - item.set_value(123); - } - - // initialize a buffer big enough for modified table data - let mut buffer: Vec = vec![]; - buffer.resize(array.size(),0x00); - - // write to the new table - let result = array.write(buffer.as_mut_slice()); - assert!(result.is_ok()); - - // verify that the written table is not the same as original - assert_ne!(buffer.as_slice(),FINI_TEST.bytes); - - // read the buffer and verify success - let result = array.read(&buffer); - assert!(result.is_ok()); - - // get an element from the table - let result = array.get(0); - assert!(result.is_some()); - - // check the element is changed - let item = result.unwrap(); - assert_eq!(item.value(),123); - } -} \ No newline at end of file diff --git a/src/arrays/item.rs b/src/arrays/item.rs deleted file mode 100644 index aff8074..0000000 --- a/src/arrays/item.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::errors::{Result}; -use crate::common::{Width,Layout}; -use crate::common::ranges::ADDRESS; -use crate::common::{Item}; - -/// Wraps and hides the more general purpose Item -pub struct ArrayItem(Item); - -impl ArrayItem { - - /// Create an ArrayItem with a value - pub fn new(value: i64) -> Self { - Self(Item::new(ADDRESS) - .with_value(value)) - } - - /// Read an ArrayItem from a given byte buffer with layout and width - pub fn read(layout: Layout, width: Width, bytes: &[u8]) -> Result { - Item::new(ADDRESS) - .with_width(width) - .with_layout(layout) - .parse(bytes) - .map(|i| Self(i)) - } - - /// Write this ArrayItem to the provided byte buffer - pub fn write(&self, bytes: &mut [u8]) -> Result<()> { - self.0.write(bytes)?; - Ok(()) - } - - /// Set the layout for this ArrayItem - pub fn set_layout(&mut self, layout: Layout) { - self.0.set_layout(layout); - } - - /// Set the width of this ArrayItem - pub fn set_width(&mut self, width: Width) { - self.0.set_width(width); - } - - /// Get the internal ArrayItem value - pub fn value(&self) -> i64 { - self.0.get() - } - - /// Set the internal ArrayItem value - pub fn set_value(&mut self, value: i64) { - self.0.set(value); - } - -} \ No newline at end of file diff --git a/src/arrays/mod.rs b/src/arrays/mod.rs deleted file mode 100644 index 1b52911..0000000 --- a/src/arrays/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Module that defines arrays (init, fini etc.) and array items -//! - -mod item; -mod array; - -pub use item::ArrayItem; -pub use array::Array; \ No newline at end of file diff --git a/src/binary.rs b/src/binary.rs index bbd2fc4..5a02829 100644 --- a/src/binary.rs +++ b/src/binary.rs @@ -213,23 +213,16 @@ mod tests { #[test] fn test_display_sections() { - // let binary = Binary::load("assets/libvpf/libvpf.so.4.1").unwrap(); - - // for name in binary.section_names() { - // dbg!(name); - // } - - // let names = binary - // .sections(SectionType::Strings) - // .iter() - // .map(|s| s.name()) - // .map(|i| binary.section_name(i)) - // .collect::>>() - // .unwrap(); - - // assert_eq!(names[0].as_str(),".dynstr"); - // assert_eq!(names[1].as_str(),".shstrtab"); - // assert_eq!(names[2].as_str(),".strtab"); + let path = "assets/libvpf/libvpf.so.4.1"; + let binary = Binary::load(path).unwrap(); + + for (i,section) in binary.sections.iter().enumerate() { + let kind = section.kind(); + let index = section.name(); + let name = binary.section_name(index).unwrap(); + + println!("{}: {} (kind={:?})",i,name,kind); + } } } \ No newline at end of file diff --git a/src/common/item.rs b/src/common/item.rs index ad2b9e6..115c542 100644 --- a/src/common/item.rs +++ b/src/common/item.rs @@ -1,5 +1,5 @@ use crate::common::{Width, Layout, FromBytes, IntoBytes, Convert, Ranges, Field}; -use crate::errors::{Result}; +use crate::errors::Result; use std::fmt::Debug; diff --git a/src/lib.rs b/src/lib.rs index a73555c..56867c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ pub mod errors; pub mod common; pub mod headers; pub mod tables; -pub mod arrays; mod segment; mod section; diff --git a/src/section.rs b/src/section.rs index 87e9e78..1a5522c 100644 --- a/src/section.rs +++ b/src/section.rs @@ -1,9 +1,9 @@ use crate::headers::SectionHeader; -use crate::errors::{Result}; +use crate::errors::{Result,Error}; use crate::common::{Layout,Width,SectionType,Update,Updateable}; /// A Section extracted from an ELF file -#[derive(Debug)] +#[derive(Debug,Clone)] pub struct Section { header: SectionHeader, data: Vec, @@ -26,7 +26,12 @@ impl Section { let end = start + size; let mut section = Section::new(header); - section.data = data[start..end].into(); + + section.data = data + .get(start..end) + .unwrap_or_default() + .into(); + Ok(section) } @@ -38,7 +43,10 @@ impl Section { let start = offset + index * size; let end = start + size; - data[start..end].copy_from_slice(&self.data); + data.get_mut(start..end) + .ok_or(Error::OutOfBoundsError)? + .copy_from_slice(&self.data); + Ok(self.size()) } @@ -75,14 +83,30 @@ impl Section { &mut self.data } - pub fn slice(&self, offset: usize, size: usize) -> &[u8] { + pub fn slice_unchecked(&self, offset: usize, size: usize) -> &[u8] { &self.data[offset..offset + size] } - pub fn slice_mut(&mut self, offset: usize, size: usize) -> &mut [u8] { + pub fn slice_mut_unchecked(&mut self, offset: usize, size: usize) -> &mut [u8] { &mut self.data[offset..offset + size] } + pub fn slice(&self, offset: usize, size: usize) -> Result<&[u8]> { + if offset + size <= self.data.len() { + Ok(self.slice_unchecked(offset, size)) + } else { + Err(Error::OutOfBoundsError) + } + } + + pub fn slice_mut(&mut self, offset: usize, size: usize) -> Result<&mut [u8]> { + if offset + size <= self.data.len() { + Ok(self.slice_mut_unchecked(offset, size)) + } else { + Err(Error::OutOfBoundsError) + } + } + pub fn set_data(&mut self, data: Vec) { self.data = data; } diff --git a/src/tables/items/array.rs b/src/tables/items/array.rs new file mode 100644 index 0000000..94ad17e --- /dev/null +++ b/src/tables/items/array.rs @@ -0,0 +1,87 @@ +use crate::errors::Result; +use crate::common::{Width,Layout}; +use crate::common::ranges::ADDRESS; +use crate::tables::TableItem; +use crate::common::Item; + +/// A specialization of item for reading addresses from Arrays +#[derive(Clone,PartialEq)] +pub struct ArrayItem { + item: Item +} + +impl ArrayItem { + + pub(crate) fn make(value: i64) -> Self { + Self::new().with_value(value) + } + + pub(crate) fn new() -> Self { + Self { item: Item::new(ADDRESS) } + } + + /// Builder method to add a layout to an ArrayItem + pub(crate) fn with_layout(mut self, layout: Layout) -> Self { + self.set_layout(layout); + self + } + + /// Builder method to add a width to an ArrayItem + pub(crate) fn with_width(mut self, width: Width) -> Self { + self.set_width(width); + self + } + + /// Builder method to add a value to an ArrayItem + pub(crate) fn with_value(mut self, value: i64) -> Self { + self.set_value(value); + self + } + + /// Get the internal value + pub fn value(&self) -> i64 { + self.item.get() + } + + /// Set the internal value + pub fn set_value(&mut self, value: i64) { + self.item.set(value); + } + +} + +impl TableItem for ArrayItem { + + fn set_layout(&mut self, layout: Layout){ + self.item.set_layout(layout); + } + + fn set_width(&mut self, width: Width){ + self.item.set_width(width); + } + + fn read(&mut self, b: &[u8]) -> Result<()> { + self.item.read(b).map(|_| ()) + } + + fn write(&self, b: &mut [u8]) -> Result<()> { + self.item.write(b) + } + + fn size(&self) -> usize { + self.item.size() + } + +} + +impl Default for ArrayItem { + fn default() -> Self { + Self::new() + } +} + +impl From for ArrayItem { + fn from(value: i64) -> Self { + Self::make(value) + } +} \ No newline at end of file diff --git a/src/tables/items/mod.rs b/src/tables/items/mod.rs index 19594dd..d6d921d 100644 --- a/src/tables/items/mod.rs +++ b/src/tables/items/mod.rs @@ -3,10 +3,13 @@ mod traits; mod string; mod symbol; mod relocation; +mod array; pub use traits::TableItem; + pub use string::StringItem; pub use symbol::SymbolItem; +pub use array::ArrayItem; pub use relocation::{ RelItem, RelaItem diff --git a/src/tables/items/relocation.rs b/src/tables/items/relocation.rs index 7df4c30..0b8c163 100644 --- a/src/tables/items/relocation.rs +++ b/src/tables/items/relocation.rs @@ -1,5 +1,5 @@ use crate::common::{Width,Layout,Item,ranges::*}; -use crate::tables::info::{RelocationInfo}; +use crate::tables::info::RelocationInfo; use crate::tables::TableItem; use crate::errors::Result; diff --git a/src/tables/items/traits.rs b/src/tables/items/traits.rs index d6b043d..ebf809c 100644 --- a/src/tables/items/traits.rs +++ b/src/tables/items/traits.rs @@ -11,11 +11,11 @@ pub trait TableItem: Default { } /// Parse the item directly from the byte array - fn parse(b: &[u8], section: &Section) -> Result where Self: Sized { + fn parse(data: &[u8], section: &Section) -> Result where Self: Sized { let mut item = Self::default(); item.set_layout(section.layout()); item.set_width(section.width()); - item.read(b)?; + item.read(data)?; Ok(item) } diff --git a/src/tables/mod.rs b/src/tables/mod.rs index fd4cd13..62824e9 100644 --- a/src/tables/mod.rs +++ b/src/tables/mod.rs @@ -19,6 +19,7 @@ pub use items::{ RelaItem, StringItem, SymbolItem, + ArrayItem, }; pub use table::{ diff --git a/src/tables/table.rs b/src/tables/table.rs index d34ce05..288aa15 100644 --- a/src/tables/table.rs +++ b/src/tables/table.rs @@ -1,9 +1,24 @@ use std::marker::PhantomData; use crate::errors::{Error,Result}; use crate::common::{ByteIter,SHType,Layout,Width}; -use crate::tables::{TableItem,StringItem,RelaItem,RelItem,SymbolItem}; +use crate::tables::{TableItem,StringItem,RelaItem,RelItem,SymbolItem,ArrayItem}; use crate::Section; +pub type Array<'a> = Table<'a,ArrayItem>; +pub type ArrayMut<'a> = TableMut<'a,ArrayItem>; + +pub type SymbolTable<'a> = Table<'a,SymbolItem>; +pub type SymbolTableMut<'a> = TableMut<'a,SymbolItem>; + +pub type RelTable<'a> = Table<'a,RelItem>; +pub type RelTableMut<'a> = TableMut<'a,RelItem>; + +pub type RelaTable<'a> = Table<'a,RelaItem>; +pub type RelaTableMut<'a> = TableMut<'a,RelaItem>; + +pub type StringTable<'a> = Table<'a,StringItem>; +pub type StringTableMut<'a> = TableMut<'a,StringItem>; + /// Shared table interface between Table and TableMut pub trait TableView where @@ -195,7 +210,7 @@ where self.reserve(offset,size); // get a constrained, mutable slice of bytes - let data = self.section.slice_mut(offset,size); + let data = self.section.slice_mut(offset,size)?; // write the item to the byte slice item.write(data)?; @@ -326,6 +341,30 @@ impl<'a> TryFrom<&'a mut Section> for TableMut<'a, RelItem> } } +impl<'a> TryFrom<&'a Section> for Table<'a, ArrayItem> +{ + type Error = Error; + + fn try_from(section: &'a Section) -> Result { + match section.header().kind() { + SHType::SHT_INIT_ARRAY | SHType::SHT_PREINIT_ARRAY | SHType::SHT_FINI_ARRAY => Ok(Self::new(section)), + _ => Err(Error::WrongSectionError) + } + } +} + +impl<'a> TryFrom<&'a mut Section> for TableMut<'a, ArrayItem> +{ + type Error = Error; + + fn try_from(section: &'a mut Section) -> Result { + match section.header().kind() { + SHType::SHT_INIT_ARRAY | SHType::SHT_PREINIT_ARRAY | SHType::SHT_FINI_ARRAY => Ok(Self::new(section)), + _ => Err(Error::WrongSectionError) + } + } +} + impl<'a,T> From> for Table<'a,T> where T: TableItem + Default @@ -357,42 +396,44 @@ where mod tests { use super::*; use crate::headers::FileHeader; - use crate::common::SectionType; use crate::utilities::read; use crate::utilities::tests::{ LIBJPEG_DYNSYM as SYM_TEST, LIBVPF_SHSTRTAB as STR_TEST, LIBVPF_RELA_DYN as RELA_TEST, + LIBQSCINTILLA_FINI_ARRAY as FINI_TEST, + LIBQSCINTILLA_INIT_ARRAY as INIT_TEST, }; + macro_rules! section { + ( $path: expr, $index: expr ) => { + read($path) + .and_then(|d| FileHeader::parse(&d) + .and_then(|h| Ok((d,h)))) + .and_then(|(d,h)| + Section::read_all( + &d, + h.shnum(), + h.shoff(), + h.shentsize(), + h.data(), + h.class() + ) + ) + .and_then(|s| s + .get($index) + .ok_or(Error::NotFound) + .cloned()) + .expect("Section not found") + }; + } + #[test] fn test_read_symbols_as_table() { - let data = read("assets/libjpeg/libjpeg.so.9").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = sections - .iter() - .find(|&h| h.kind() == SectionType::DynamicSymbols) - .unwrap(); + let section = section!("assets/libjpeg/libjpeg.so.9", SYM_TEST.index); - let result = Table::::try_from(section); + let result = SymbolTable::try_from(§ion); assert!(result.is_ok()); let table = result.unwrap(); @@ -401,29 +442,9 @@ mod tests { #[test] fn test_read_strings_as_table() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let index = file_header.shstrndx(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = §ions[index]; + let section = section!("assets/libvpf/libvpf.so.4.1", STR_TEST.index); - let result = Table::::try_from(section); + let result = StringTable::try_from(§ion); assert!(result.is_ok()); let table = result.unwrap(); @@ -432,31 +453,9 @@ mod tests { #[test] fn test_read_relocations_addend_as_table() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = sections - .iter() - .find(|&h| h.kind() == SectionType::RelocationsAddend) - .unwrap(); - - let result = Table::::try_from(section); + let section = section!("assets/libvpf/libvpf.so.4.1", RELA_TEST.index); + + let result = RelaTable::try_from(§ion); assert!(result.is_ok()); let table = result.unwrap(); @@ -465,29 +464,9 @@ mod tests { #[test] fn test_write_strings_prepend() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let index = file_header.shstrndx(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[index]; + let mut section = section!("assets/libvpf/libvpf.so.4.1", STR_TEST.index); - let result = TableMut::::try_from(section); + let result = StringTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -515,29 +494,9 @@ mod tests { #[test] fn test_write_strings_append() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let index = file_header.shstrndx(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[index]; + let mut section = section!("assets/libvpf/libvpf.so.4.1", STR_TEST.index); - let result = TableMut::::try_from(section); + let result = StringTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -566,29 +525,9 @@ mod tests { #[test] fn test_write_strings_insert() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let index = file_header.shstrndx(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[index]; + let mut section = section!("assets/libvpf/libvpf.so.4.1", STR_TEST.index); - let result = TableMut::::try_from(section); + let result = StringTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -617,29 +556,9 @@ mod tests { #[test] fn test_write_strings_remove() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let index = file_header.shstrndx(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[index]; + let mut section = section!("assets/libvpf/libvpf.so.4.1", STR_TEST.index); - let result = TableMut::::try_from(section); + let result = StringTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -668,28 +587,9 @@ mod tests { #[test] fn test_write_symbols_prepend() { - let data = read("assets/libjpeg/libjpeg.so.9").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); + let mut section = section!("assets/libjpeg/libjpeg.so.9", SYM_TEST.index); - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[SYM_TEST.index]; - - let result = TableMut::::try_from(section); + let result = SymbolTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -718,28 +618,9 @@ mod tests { #[test] fn test_write_symbols_append() { - let data = read("assets/libjpeg/libjpeg.so.9").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); + let mut section = section!("assets/libjpeg/libjpeg.so.9", SYM_TEST.index); - let section = &mut sections[SYM_TEST.index]; - - let result = TableMut::::try_from(section); + let result = SymbolTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -768,28 +649,9 @@ mod tests { #[test] fn test_write_symbols_insert() { - let data = read("assets/libjpeg/libjpeg.so.9").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); + let mut section = section!("assets/libjpeg/libjpeg.so.9", SYM_TEST.index); - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[SYM_TEST.index]; - - let result = TableMut::::try_from(section); + let result = SymbolTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -818,28 +680,9 @@ mod tests { #[test] fn test_write_symbols_remove() { - let data = read("assets/libjpeg/libjpeg.so.9").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); + let mut section = section!("assets/libjpeg/libjpeg.so.9", SYM_TEST.index); - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[SYM_TEST.index]; - - let result = TableMut::::try_from(section); + let result = SymbolTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -856,28 +699,9 @@ mod tests { #[test] fn test_write_relocations_addend_prepend() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); + let mut section = section!("assets/libvpf/libvpf.so.4.1", RELA_TEST.index); - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[RELA_TEST.index]; - - let result = TableMut::::try_from(section); + let result = RelaTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -903,28 +727,9 @@ mod tests { #[test] fn test_write_relocations_addend_append() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); + let mut section = section!("assets/libvpf/libvpf.so.4.1", RELA_TEST.index); - let section = &mut sections[RELA_TEST.index]; - - let result = TableMut::::try_from(section); + let result = RelaTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -950,28 +755,9 @@ mod tests { #[test] fn test_write_relocations_addend_insert() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); - - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[RELA_TEST.index]; + let mut section = section!("assets/libvpf/libvpf.so.4.1", RELA_TEST.index); - let result = TableMut::::try_from(section); + let result = RelaTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -997,28 +783,9 @@ mod tests { #[test] fn test_write_relocations_addend_remove() { - let data = read("assets/libvpf/libvpf.so.4.1").unwrap(); + let mut section = section!("assets/libvpf/libvpf.so.4.1", RELA_TEST.index); - let file_header = FileHeader::parse(&data).unwrap(); - - let count = file_header.shnum(); - let offset = file_header.shoff(); - let size = file_header.shentsize(); - let layout = file_header.data(); - let width = file_header.class(); - - let mut sections = Section::read_all( - &data, - count, - offset, - size, - layout, - width - ).unwrap(); - - let section = &mut sections[RELA_TEST.index]; - - let result = TableMut::::try_from(section); + let result = RelaTableMut::try_from(&mut section); assert!(result.is_ok()); let mut table = result.unwrap(); @@ -1032,5 +799,177 @@ mod tests { assert_eq!(table.len(),RELA_TEST.length - 1); assert_eq!(table.size(),RELA_TEST.size - RELA_TEST.entsize); } - + + #[test] + fn test_read_init_array_as_array() { + let section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", INIT_TEST.index); + + let result = Array::try_from(§ion); + assert!(result.is_ok()); + + let array = result.unwrap(); + assert_eq!(array.len(),INIT_TEST.length); + } + + #[test] + fn test_read_fini_array_as_array() { + let section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", FINI_TEST.index); + + let result = Array::try_from(§ion); + assert!(result.is_ok()); + + let array = result.unwrap(); + assert_eq!(array.len(),FINI_TEST.length); + } + + #[test] + fn test_write_init_array_append() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", INIT_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),INIT_TEST.length); + assert_eq!(array.size(),INIT_TEST.size); + + let result = array.append(123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),INIT_TEST.length + 1); + assert_eq!(array.size(),INIT_TEST.size + INIT_TEST.entsize); + + let result = array.at(array.len() - 1); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + + #[test] + fn test_write_fini_array_append() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", FINI_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),FINI_TEST.length); + assert_eq!(array.size(),FINI_TEST.size); + + let result = array.append(123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),FINI_TEST.length + 1); + assert_eq!(array.size(),FINI_TEST.size + FINI_TEST.entsize); + + let result = array.at(array.len() - 1); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + + #[test] + fn test_write_init_array_prepend() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", INIT_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),INIT_TEST.length); + assert_eq!(array.size(),INIT_TEST.size); + + let result = array.prepend(123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),INIT_TEST.length + 1); + assert_eq!(array.size(),INIT_TEST.size + INIT_TEST.entsize); + + let result = array.at(0); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + + #[test] + fn test_write_fini_array_prepend() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", FINI_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),FINI_TEST.length); + assert_eq!(array.size(),FINI_TEST.size); + + let result = array.prepend(123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),FINI_TEST.length + 1); + assert_eq!(array.size(),FINI_TEST.size + FINI_TEST.entsize); + + let result = array.at(0); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + + #[test] + fn test_write_init_array_insert() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", INIT_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),INIT_TEST.length); + assert_eq!(array.size(),INIT_TEST.size); + + let result = array.insert(3,123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),INIT_TEST.length + 1); + assert_eq!(array.size(),INIT_TEST.size + INIT_TEST.entsize); + + let result = array.at(3); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + + #[test] + fn test_write_fini_array_insert() { + let mut section = section!("assets/libqscintilla2/libqscintilla2_qt5.so.15.0.0", FINI_TEST.index); + + let result = ArrayMut::try_from(&mut section); + assert!(result.is_ok()); + + let mut array = result.unwrap(); + + assert_eq!(array.len(),FINI_TEST.length); + assert_eq!(array.size(),FINI_TEST.size); + + let result = array.insert(1,123.into()); + assert!(result.is_ok()); + + assert_eq!(array.len(),FINI_TEST.length + 1); + assert_eq!(array.size(),FINI_TEST.size + FINI_TEST.entsize); + + let result = array.at(1); + assert!(result.is_ok()); + + let item = result.unwrap(); + assert_eq!(item.value(),123); + } + } \ No newline at end of file diff --git a/src/utilities.rs b/src/utilities.rs index a96085b..d9cf1fe 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -46,7 +46,7 @@ pub mod tests { name: ".fini_array", address: 3811960, offset: 3807864, - index: 0, + index: 22, size: 8, length: 1, entsize: 8, @@ -57,7 +57,7 @@ pub mod tests { name: ".init_array", address: 3811048, offset: 3806952, - index: 0, + index: 21, size: 912, length: 114, entsize: 8, @@ -112,7 +112,7 @@ pub mod tests { name: ".shstrtab", address: 0, offset: 287172, - index: 0, + index: 27, size: 263, length: 26, entsize: 0, From 13892cc07f74d819953a864dcf914b7b908a9071 Mon Sep 17 00:00:00 2001 From: Michael House Date: Wed, 6 Sep 2023 11:47:35 -0500 Subject: [PATCH 3/3] Updated exports --- src/tables/mod.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/tables/mod.rs b/src/tables/mod.rs index 62824e9..0053c10 100644 --- a/src/tables/mod.rs +++ b/src/tables/mod.rs @@ -1,6 +1,6 @@ //! Various types of tables and associated table items //! -//! Each table type can be created (using TryFrom) from an appropriate section header +//! Each table type can be created (using TryFrom) from an appropriate section //! struct. TryFrom will fail if the section isn't the correct type (e.g. non-SHT_SYMTAB //! section header cannot be converted into a `Table` struct). @@ -25,5 +25,15 @@ pub use items::{ pub use table::{ Table, TableMut, - TableView + TableView, + Array, + ArrayMut, + SymbolTable, + SymbolTableMut, + RelTable, + RelTableMut, + RelaTable, + RelaTableMut, + StringTable, + StringTableMut, }; \ No newline at end of file