Skip to content

Commit

Permalink
feat(static): make symbols sortable by name or address
Browse files Browse the repository at this point in the history
  • Loading branch information
XXMA16 committed Nov 10, 2024
1 parent 09137d2 commit 311261d
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 21 deletions.
99 changes: 79 additions & 20 deletions src/elf/symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,27 @@ use elf::{
};
use std::io::{Error as IoError, ErrorKind as IoErrorKind};

// Sorting criteria.
#[derive(Clone, Debug, Default)]
enum SortBy {
/// Elf encounter order.
#[default]
None = 0,
/// Name.
Name = 1,
/// Value.
Value = 2,
}

/// ELF symbols wrapper.
#[derive(Clone, Debug, Default)]
pub struct Symbols {
/// Symbols.
symbols: Vec<Symbol>,
/// Symbol names.
names: Vec<String>,
/// Sort by.
sort: SortBy,
}

impl<'a> TryFrom<Option<(ParsingTable<'a, AnyEndian, Symbol>, StringTable<'a>)>> for Symbols {
Expand All @@ -36,37 +50,58 @@ impl<'a> TryFrom<Option<(ParsingTable<'a, AnyEndian, Symbol>, StringTable<'a>)>>
.unwrap_or_else(|_| String::from("unknown"))
})
.collect(),
sort: SortBy::default(),
})
}
}

impl<'a> Property<'a> for Symbols {
fn items(&self) -> Vec<Vec<String>> {
self.symbols
let mut indices: Vec<usize> = (0..self.symbols.len()).collect();
match self.sort {
SortBy::Name => {
indices.sort_by(|&a, &b| self.names[a].cmp(&self.names[b]));
}
SortBy::Value => {
indices.sort_by(|&a, &b| self.symbols[a].st_value.cmp(&self.symbols[b].st_value));
}
SortBy::None => {}
}

indices
.iter()
.enumerate()
.map(|(i, symbol)| {
let name = self.names[i].to_string();
.map(|&i| {
vec![
name,
elf::to_str::st_symtype_to_string(symbol.st_symtype())
self.names[i].to_string(),
elf::to_str::st_symtype_to_string(self.symbols[i].st_symtype())
.trim_start_matches("STT_")
.to_string(),
format!("{:#x}", symbol.st_value),
symbol.st_size.to_string(),
elf::to_str::st_bind_to_string(symbol.st_bind())
format!("{:#x}", self.symbols[i].st_value),
self.symbols[i].st_size.to_string(),
elf::to_str::st_bind_to_string(self.symbols[i].st_bind())
.trim_start_matches("STB_")
.to_string(),
elf::to_str::st_vis_to_string(symbol.st_vis())
elf::to_str::st_vis_to_string(self.symbols[i].st_vis())
.trim_start_matches("STV_")
.to_string(),
symbol.st_shndx.to_string(),
self.symbols[i].st_shndx.to_string(),
]
})
.collect()
}
}

impl Symbols {
/// Cycle sorting criteria.
pub fn cycle_sort(&mut self) {
match self.sort {
SortBy::None => self.sort = SortBy::Name,
SortBy::Name => self.sort = SortBy::Value,
SortBy::Value => self.sort = SortBy::None,
}
}
}

/// ELF dynamic symbols wrapper.
#[derive(Clone, Debug, Default)]
pub struct DynamicSymbols {
Expand All @@ -76,6 +111,8 @@ pub struct DynamicSymbols {
names: Vec<String>,
/// Requirements.
requirements: Vec<String>,
/// Sort by.
sort: SortBy,
}

impl<'a>
Expand Down Expand Up @@ -131,33 +168,55 @@ impl<'a>
.to_string()
})
.collect(),
sort: SortBy::default(),
})
}
}

impl<'a> Property<'a> for DynamicSymbols {
fn items(&self) -> Vec<Vec<String>> {
self.symbols
let mut indices: Vec<usize> = (0..self.symbols.len()).collect();
match self.sort {
SortBy::Name => {
indices.sort_by(|&a, &b| self.names[a].cmp(&self.names[b]));
}
SortBy::Value => {
indices.sort_by(|&a, &b| self.symbols[a].st_value.cmp(&self.symbols[b].st_value));
}
SortBy::None => {}
}

indices
.iter()
.enumerate()
.map(|(i, symbol)| {
.map(|&i| {
vec![
self.names[i].to_string(),
self.requirements[i].to_string(),
elf::to_str::st_symtype_to_string(symbol.st_symtype())
elf::to_str::st_symtype_to_string(self.symbols[i].st_symtype())
.trim_start_matches("STT_")
.to_string(),
format!("{:#x}", symbol.st_value),
symbol.st_size.to_string(),
elf::to_str::st_bind_to_string(symbol.st_bind())
format!("{:#x}", self.symbols[i].st_value),
self.symbols[i].st_size.to_string(),
elf::to_str::st_bind_to_string(self.symbols[i].st_bind())
.trim_start_matches("STB_")
.to_string(),
elf::to_str::st_vis_to_string(symbol.st_vis())
elf::to_str::st_vis_to_string(self.symbols[i].st_vis())
.trim_start_matches("STV_")
.to_string(),
symbol.st_shndx.to_string(),
self.symbols[i].st_shndx.to_string(),
]
})
.collect()
}
}

impl DynamicSymbols {
/// Cycle sorting criteria.
pub fn cycle_sort(&mut self) {
match self.sort {
SortBy::None => self.sort = SortBy::Name,
SortBy::Name => self.sort = SortBy::Value,
SortBy::Value => self.sort = SortBy::None,
}
}
}
3 changes: 3 additions & 0 deletions src/tui/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub enum Command {
Hexdump(HexdumpCommand),
/// Trace system calls.
TraceCalls,
/// Sort items.
Sort,
/// Exit application.
Exit,
/// Do nothing.
Expand Down Expand Up @@ -101,6 +103,7 @@ impl From<KeyEvent> for Command {
KeyCode::Char('o') => Self::OpenRepo,
KeyCode::Char('r') => Self::TraceCalls,
KeyCode::Char('s') => Self::HumanReadable,
KeyCode::Char('S') => Self::Sort,
_ => Self::Nothing,
}
}
Expand Down
13 changes: 12 additions & 1 deletion src/tui/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,13 @@ impl<'a> State<'a> {
self.analyzer.extract_strings(event_sender.clone());
}
}
Command::Sort => {
if self.tab == Tab::StaticAnalysis {
self.analyzer.elf.symbols.cycle_sort();
self.analyzer.elf.dynamic_symbols.cycle_sort();
self.handle_tab()?;
}
}
Command::Exit => {
if self.show_details {
self.show_details = false;
Expand Down Expand Up @@ -454,7 +461,11 @@ impl<'a> State<'a> {
("/", "Search"),
("h/j/k/l", "Scroll"),
("n/p", "Toggle"),
("s", "Readability"),
if self.info_index == 0 || self.info_index == 1 {
("s", "Readability")
} else {
("S", "Sort")
},
("Tab", "Next"),
("q", "Quit"),
],
Expand Down

0 comments on commit 311261d

Please sign in to comment.