diff --git a/src/elf/symbols.rs b/src/elf/symbols.rs index afa7726..a9957c6 100644 --- a/src/elf/symbols.rs +++ b/src/elf/symbols.rs @@ -5,6 +5,18 @@ 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 { @@ -12,6 +24,8 @@ pub struct Symbols { symbols: Vec, /// Symbol names. names: Vec, + /// Sort by. + sort: SortBy, } impl<'a> TryFrom, StringTable<'a>)>> for Symbols { @@ -36,37 +50,58 @@ impl<'a> TryFrom, StringTable<'a>)>> .unwrap_or_else(|_| String::from("unknown")) }) .collect(), + sort: SortBy::default(), }) } } impl<'a> Property<'a> for Symbols { fn items(&self) -> Vec> { - self.symbols + let mut indices: Vec = (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 { @@ -76,6 +111,8 @@ pub struct DynamicSymbols { names: Vec, /// Requirements. requirements: Vec, + /// Sort by. + sort: SortBy, } impl<'a> @@ -131,33 +168,55 @@ impl<'a> .to_string() }) .collect(), + sort: SortBy::default(), }) } } impl<'a> Property<'a> for DynamicSymbols { fn items(&self) -> Vec> { - self.symbols + let mut indices: Vec = (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, + } + } +} diff --git a/src/tui/command.rs b/src/tui/command.rs index 40ed641..e6d63ce 100644 --- a/src/tui/command.rs +++ b/src/tui/command.rs @@ -41,6 +41,8 @@ pub enum Command { Hexdump(HexdumpCommand), /// Trace system calls. TraceCalls, + /// Sort items. + Sort, /// Exit application. Exit, /// Do nothing. @@ -101,6 +103,7 @@ impl From for Command { KeyCode::Char('o') => Self::OpenRepo, KeyCode::Char('r') => Self::TraceCalls, KeyCode::Char('s') => Self::HumanReadable, + KeyCode::Char('S') => Self::Sort, _ => Self::Nothing, } } diff --git a/src/tui/state.rs b/src/tui/state.rs index 81707ce..7350a84 100644 --- a/src/tui/state.rs +++ b/src/tui/state.rs @@ -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; @@ -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"), ],