Skip to content

Commit

Permalink
Merge pull request #52 from mjhouse/development
Browse files Browse the repository at this point in the history
Add helper methods and data to symbols
  • Loading branch information
mjhouse authored Oct 11, 2023
2 parents d35fd25 + 8096bc9 commit fb940c6
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 43 deletions.
93 changes: 57 additions & 36 deletions src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ impl Binary {
width
)?;

self.process();
self.process()?;
Ok(self.size())
}

Expand Down Expand Up @@ -200,52 +200,61 @@ impl Binary {
.ok_or(Error::NotFound)
}

pub fn symbols(&self) -> Vec<Symbol> {
self.symbol_tables()
pub fn symbols(&self) -> Result<Vec<Symbol>> {

let mut symbols = self
.symbol_tables()
.iter()
.flat_map(SymbolTable::items)
.flatten()
.collect()
}
.collect::<Vec<Symbol>>();

for symbol in symbols.iter_mut() {

if (symbol.is_object() ||
symbol.is_function() ||
symbol.is_section()) &&
!symbol.is_weak() &&
symbol.has_section()
{
let section = symbol.section(self)?;

// get an offset into the section
let offset = symbol
.value()
.saturating_sub(section
.address() as u64);

// get a slice of bytes the size of the symbol
let data = section
.slice(
offset as usize,
symbol.size() as usize)?;

// add them to the symbol
symbol.set_data(data);

}
}

pub fn functions(&self) -> Vec<Function> {
self.symbols()
.into_iter()
.flat_map(|f| self
.symbol_name(f.name())
.map(|s| (f,s)))
.flat_map(|(v,s)| Function::try_from(v)
.map(|f| {
let address = f.address() as usize;
let size = f.size() as usize;

f
.with_name(s)
.with_body(&self.data(address,size))
}))
.collect()
Ok(symbols)
}

pub fn functions_ex(&self) -> Result<Vec<Function>> {
pub fn functions(&self) -> Result<Vec<Function>> {

let mut functions = self
.symbols()
.symbols()?
.into_iter()
.filter_map(|s| Function::try_from(s).ok())
.collect::<Vec<Function>>();

for function in functions.iter_mut() {

let section_index = function.section();
let name_index = function.symbol().name();

let section = self.section(section_index)?;
let name = self.symbol_name(name_index)?;

function.set_body_from(
&section.data(),
section.offset())?;
// get the function name
let index = function.symbol().name();
let name = self.symbol_name(index)?;

// set the function name
function.set_name(name)

}
Expand Down Expand Up @@ -316,8 +325,6 @@ impl Updateable for Binary {

#[cfg(test)]
mod tests {
use crate::tables::{StringTable, SymbolTable};

use super::*;

#[test]
Expand Down Expand Up @@ -360,7 +367,10 @@ mod tests {
let path = "assets/libvpf/libvpf.so.4.1";
let binary = Binary::load(path).unwrap();

let symbols = binary.symbols();
let result = binary.symbols();
assert!(result.is_ok());

let symbols = result.unwrap();
assert_eq!(symbols.len(),294);

let index = symbols[1].name();
Expand All @@ -369,14 +379,25 @@ mod tests {

let name = result.unwrap();
assert_eq!(name, "__ctype_toupper_loc".to_string());

let index = symbols[78].name();
let result = binary.symbol_name(index);
assert!(result.is_ok());

let name = result.unwrap();
assert_eq!(name, "NOPROJ".to_string());
}

#[test]
fn test_get_functions() {
let path = "assets/libvpf/libvpf.so.4.1";
let binary = Binary::load(path).unwrap();

let functions = binary.functions();
let result = binary.functions();

assert!(result.is_ok());

let functions = result.unwrap();
assert_eq!(functions.len(),280);

let function1 = &functions[80];
Expand Down
1 change: 1 addition & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub use constants::{
PHType,
SHType,
SHFlags,
SHIndex,
STBind,
STType,
STVisibility,
Expand Down
17 changes: 11 additions & 6 deletions src/functions/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::symbols::{Symbol,SymbolInfo};
#[derive(Default)]
pub struct Function {
name: String,
body: Vec<u8>,
symbol: Symbol
}

Expand Down Expand Up @@ -41,16 +40,15 @@ impl Function {

/// Get the function body
pub fn body(&self) -> &[u8] {
&self.body
self.symbol.data()
}

/// Set the function body
///
/// Also updates the size of the symbol to reflect
/// the size of the given body.
pub fn set_body(&mut self, body: &[u8]) {
self.body = body.into();
self.set_size(body.len());
self.symbol.set_data(body);
}

/// Extract the function body from section data
Expand Down Expand Up @@ -305,6 +303,7 @@ impl Function {

/// Write the symbol entry to the beginning of the given data
fn write_symbol(&self, data: &mut [u8]) -> Result<()> {
assert!(self.symbol.is_function());
self.symbol.write(data)
}

Expand All @@ -316,7 +315,8 @@ impl Function {
let start = self.start(offset);
let end = self.end(offset);
if start <= end && end <= data.len() {
data[start..end].copy_from_slice(&self.body);
let body = self.body();
data[start..end].copy_from_slice(body);
Ok(())
}
else {
Expand All @@ -325,11 +325,16 @@ impl Function {
}

/// Finish and validate the new function
pub fn build(mut self) -> Result<Self> {
pub fn build(self) -> Result<Self> {

// ensure that the symbol is valid
self.symbol.validate()?;

// ensure that the symbol is a function
if !self.symbol.is_function() {
return Err(Error::WrongTypeError);
}

Ok(self)
}

Expand Down
4 changes: 4 additions & 0 deletions src/section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ impl Section {
self.body_size() / self.entity_size()
}

pub fn address(&self) -> usize {
self.header.address() as usize
}

pub fn offset(&self) -> usize {
self.header.offset()
}
Expand Down
120 changes: 119 additions & 1 deletion src/symbols/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use num_enum::TryFromPrimitive;

use crate::{Binary, Section};
use crate::errors::Result;
use crate::common::{
Width,
Layout,
Item,
ranges::*, STType, STBind, STVisibility
ranges::*, STType, STBind, STVisibility, SHIndex, FromBytes, IntoBytes
};
use crate::symbols::SymbolInfo;
use crate::tables::TableItem;
Expand All @@ -17,6 +20,7 @@ pub struct Symbol {
st_info: Item<u8,u8,SymbolInfo>,
st_other: Item<u8>,
st_shndx: Item<u16,u16>,
data: Vec<u8>,
}

impl Symbol {
Expand All @@ -30,9 +34,20 @@ impl Symbol {
st_info: Item::new(ST_INFO),
st_other: Item::new(ST_OTHER),
st_shndx: Item::new(ST_SHNDX),
data: Vec::new(),
}
}

/// Get a section reference for the symbol
pub fn section<'a>(&self, binary: &'a Binary) -> Result<&'a Section> {
binary.section(self.shndx() as usize)
}

/// Get a mutable section reference for the symbol
pub fn section_mut<'a>(&self, binary: &'a mut Binary) -> Result<&'a mut Section> {
binary.section_mut(self.shndx() as usize)
}

/// Get the 'st_name' field (name *index*) of the symbol
pub fn name(&self) -> usize {
self.st_name.get()
Expand Down Expand Up @@ -65,6 +80,33 @@ impl Symbol {
self
}

/// Get the data of the symbol
pub fn data(&self) -> &[u8] {
&self.data
}

/// Get the data of the symbol as a value
pub fn data_as<T: FromBytes>(&self) -> Result<T> {
T::from_bytes(self.data(), self.layout())
}

/// Get the data of the symbol mutably
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data
}

/// Set the symbol data and update the `st_size` field
pub fn set_data(&mut self, data: &[u8]) {
self.data = data.into();
self.set_size(data.len() as u64);
}

/// Builder method to set the function data
pub fn with_data(mut self, data: &[u8]) -> Self {
self.set_data(data);
self
}

/// Get the 'st_size' field of the symbol
pub fn size(&self) -> u64 {
self.st_size.get()
Expand Down Expand Up @@ -244,6 +286,63 @@ impl Symbol {
Ok(())
}

/// Returns true if the symbol is a function
pub fn is_function(&self) -> bool {
self.kind() == STType::STT_FUNC
}

/// Returns true if the symbol is an object
pub fn is_object(&self) -> bool {
self.kind() == STType::STT_OBJECT
}

/// Returns true if the symbol is a section
pub fn is_section(&self) -> bool {
self.kind() == STType::STT_SECTION
}

/// Returns true if the symbol is a file
pub fn is_file(&self) -> bool {
self.kind() == STType::STT_FILE
}

/// Returns true if the symbol is common
pub fn is_common(&self) -> bool {
self.kind() == STType::STT_COMMON
}

/// Returns true if the symbol is TLS
pub fn is_tls(&self) -> bool {
self.kind() == STType::STT_TLS
}

/// Returns true if the symbol is global
pub fn is_global(&self) -> bool {
self.bind() == STBind::STB_GLOBAL
}

/// Returns true if the symbol is local
pub fn is_local(&self) -> bool {
self.bind() == STBind::STB_LOCAL
}

/// Returns true if the symbol is weak
pub fn is_weak(&self) -> bool {
self.bind() == STBind::STB_WEAK
}

/// Returns true if the section index isn't
/// a reserved value
pub fn has_section(&self) -> bool {
// TODO: handle SHN_XINDEX situation
let v = self.value() as u32;
v != SHIndex::SHN_UNDEF.into() &&
v != SHIndex::SHN_BEFORE.into() &&
v != SHIndex::SHN_AFTER.into() &&
v != SHIndex::SHN_ABS.into() &&
v != SHIndex::SHN_COMMON.into()
}

}

impl TableItem for Symbol {
Expand Down Expand Up @@ -636,4 +735,23 @@ mod tests {
assert!(result.is_ok());
assert_eq!(symbol.size(),maximum);
}

#[test]
fn test_data_symbol_read() {
let path = "assets/libvpf/libvpf.so.4.1";
let binary = Binary::load(path).unwrap();

let result = binary.symbols();
assert!(result.is_ok());

let symbols = result.unwrap();

let result = symbols[78].data_as::<String>();
assert!(result.is_ok());

let string = result.unwrap();
let value = string.trim_matches(char::from(0));
assert_eq!(value.trim(), "Decimal Degrees".to_string());
}

}

0 comments on commit fb940c6

Please sign in to comment.