Skip to content

Commit 311261d

Browse files
committed
feat(static): make symbols sortable by name or address
1 parent 09137d2 commit 311261d

File tree

3 files changed

+94
-21
lines changed

3 files changed

+94
-21
lines changed

src/elf/symbols.rs

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,27 @@ use elf::{
55
};
66
use std::io::{Error as IoError, ErrorKind as IoErrorKind};
77

8+
// Sorting criteria.
9+
#[derive(Clone, Debug, Default)]
10+
enum SortBy {
11+
/// Elf encounter order.
12+
#[default]
13+
None = 0,
14+
/// Name.
15+
Name = 1,
16+
/// Value.
17+
Value = 2,
18+
}
19+
820
/// ELF symbols wrapper.
921
#[derive(Clone, Debug, Default)]
1022
pub struct Symbols {
1123
/// Symbols.
1224
symbols: Vec<Symbol>,
1325
/// Symbol names.
1426
names: Vec<String>,
27+
/// Sort by.
28+
sort: SortBy,
1529
}
1630

1731
impl<'a> TryFrom<Option<(ParsingTable<'a, AnyEndian, Symbol>, StringTable<'a>)>> for Symbols {
@@ -36,37 +50,58 @@ impl<'a> TryFrom<Option<(ParsingTable<'a, AnyEndian, Symbol>, StringTable<'a>)>>
3650
.unwrap_or_else(|_| String::from("unknown"))
3751
})
3852
.collect(),
53+
sort: SortBy::default(),
3954
})
4055
}
4156
}
4257

4358
impl<'a> Property<'a> for Symbols {
4459
fn items(&self) -> Vec<Vec<String>> {
45-
self.symbols
60+
let mut indices: Vec<usize> = (0..self.symbols.len()).collect();
61+
match self.sort {
62+
SortBy::Name => {
63+
indices.sort_by(|&a, &b| self.names[a].cmp(&self.names[b]));
64+
}
65+
SortBy::Value => {
66+
indices.sort_by(|&a, &b| self.symbols[a].st_value.cmp(&self.symbols[b].st_value));
67+
}
68+
SortBy::None => {}
69+
}
70+
71+
indices
4672
.iter()
47-
.enumerate()
48-
.map(|(i, symbol)| {
49-
let name = self.names[i].to_string();
73+
.map(|&i| {
5074
vec![
51-
name,
52-
elf::to_str::st_symtype_to_string(symbol.st_symtype())
75+
self.names[i].to_string(),
76+
elf::to_str::st_symtype_to_string(self.symbols[i].st_symtype())
5377
.trim_start_matches("STT_")
5478
.to_string(),
55-
format!("{:#x}", symbol.st_value),
56-
symbol.st_size.to_string(),
57-
elf::to_str::st_bind_to_string(symbol.st_bind())
79+
format!("{:#x}", self.symbols[i].st_value),
80+
self.symbols[i].st_size.to_string(),
81+
elf::to_str::st_bind_to_string(self.symbols[i].st_bind())
5882
.trim_start_matches("STB_")
5983
.to_string(),
60-
elf::to_str::st_vis_to_string(symbol.st_vis())
84+
elf::to_str::st_vis_to_string(self.symbols[i].st_vis())
6185
.trim_start_matches("STV_")
6286
.to_string(),
63-
symbol.st_shndx.to_string(),
87+
self.symbols[i].st_shndx.to_string(),
6488
]
6589
})
6690
.collect()
6791
}
6892
}
6993

94+
impl Symbols {
95+
/// Cycle sorting criteria.
96+
pub fn cycle_sort(&mut self) {
97+
match self.sort {
98+
SortBy::None => self.sort = SortBy::Name,
99+
SortBy::Name => self.sort = SortBy::Value,
100+
SortBy::Value => self.sort = SortBy::None,
101+
}
102+
}
103+
}
104+
70105
/// ELF dynamic symbols wrapper.
71106
#[derive(Clone, Debug, Default)]
72107
pub struct DynamicSymbols {
@@ -76,6 +111,8 @@ pub struct DynamicSymbols {
76111
names: Vec<String>,
77112
/// Requirements.
78113
requirements: Vec<String>,
114+
/// Sort by.
115+
sort: SortBy,
79116
}
80117

81118
impl<'a>
@@ -131,33 +168,55 @@ impl<'a>
131168
.to_string()
132169
})
133170
.collect(),
171+
sort: SortBy::default(),
134172
})
135173
}
136174
}
137175

138176
impl<'a> Property<'a> for DynamicSymbols {
139177
fn items(&self) -> Vec<Vec<String>> {
140-
self.symbols
178+
let mut indices: Vec<usize> = (0..self.symbols.len()).collect();
179+
match self.sort {
180+
SortBy::Name => {
181+
indices.sort_by(|&a, &b| self.names[a].cmp(&self.names[b]));
182+
}
183+
SortBy::Value => {
184+
indices.sort_by(|&a, &b| self.symbols[a].st_value.cmp(&self.symbols[b].st_value));
185+
}
186+
SortBy::None => {}
187+
}
188+
189+
indices
141190
.iter()
142-
.enumerate()
143-
.map(|(i, symbol)| {
191+
.map(|&i| {
144192
vec![
145193
self.names[i].to_string(),
146194
self.requirements[i].to_string(),
147-
elf::to_str::st_symtype_to_string(symbol.st_symtype())
195+
elf::to_str::st_symtype_to_string(self.symbols[i].st_symtype())
148196
.trim_start_matches("STT_")
149197
.to_string(),
150-
format!("{:#x}", symbol.st_value),
151-
symbol.st_size.to_string(),
152-
elf::to_str::st_bind_to_string(symbol.st_bind())
198+
format!("{:#x}", self.symbols[i].st_value),
199+
self.symbols[i].st_size.to_string(),
200+
elf::to_str::st_bind_to_string(self.symbols[i].st_bind())
153201
.trim_start_matches("STB_")
154202
.to_string(),
155-
elf::to_str::st_vis_to_string(symbol.st_vis())
203+
elf::to_str::st_vis_to_string(self.symbols[i].st_vis())
156204
.trim_start_matches("STV_")
157205
.to_string(),
158-
symbol.st_shndx.to_string(),
206+
self.symbols[i].st_shndx.to_string(),
159207
]
160208
})
161209
.collect()
162210
}
163211
}
212+
213+
impl DynamicSymbols {
214+
/// Cycle sorting criteria.
215+
pub fn cycle_sort(&mut self) {
216+
match self.sort {
217+
SortBy::None => self.sort = SortBy::Name,
218+
SortBy::Name => self.sort = SortBy::Value,
219+
SortBy::Value => self.sort = SortBy::None,
220+
}
221+
}
222+
}

src/tui/command.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ pub enum Command {
4141
Hexdump(HexdumpCommand),
4242
/// Trace system calls.
4343
TraceCalls,
44+
/// Sort items.
45+
Sort,
4446
/// Exit application.
4547
Exit,
4648
/// Do nothing.
@@ -101,6 +103,7 @@ impl From<KeyEvent> for Command {
101103
KeyCode::Char('o') => Self::OpenRepo,
102104
KeyCode::Char('r') => Self::TraceCalls,
103105
KeyCode::Char('s') => Self::HumanReadable,
106+
KeyCode::Char('S') => Self::Sort,
104107
_ => Self::Nothing,
105108
}
106109
}

src/tui/state.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,13 @@ impl<'a> State<'a> {
340340
self.analyzer.extract_strings(event_sender.clone());
341341
}
342342
}
343+
Command::Sort => {
344+
if self.tab == Tab::StaticAnalysis {
345+
self.analyzer.elf.symbols.cycle_sort();
346+
self.analyzer.elf.dynamic_symbols.cycle_sort();
347+
self.handle_tab()?;
348+
}
349+
}
343350
Command::Exit => {
344351
if self.show_details {
345352
self.show_details = false;
@@ -454,7 +461,11 @@ impl<'a> State<'a> {
454461
("/", "Search"),
455462
("h/j/k/l", "Scroll"),
456463
("n/p", "Toggle"),
457-
("s", "Readability"),
464+
if self.info_index == 0 || self.info_index == 1 {
465+
("s", "Readability")
466+
} else {
467+
("S", "Sort")
468+
},
458469
("Tab", "Next"),
459470
("q", "Quit"),
460471
],

0 commit comments

Comments
 (0)