Cleanup & move extab code into ppc arch

This commit is contained in:
Luke Street 2024-09-09 19:43:10 -06:00
parent c7e6394628
commit dcf209aac5
7 changed files with 207 additions and 186 deletions

View File

@ -41,6 +41,10 @@ pub trait ObjArch: Send + Sync {
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str>;
fn symbol_address(&self, symbol: &Symbol) -> u64 { symbol.address() }
// Downcast methods
#[cfg(feature = "ppc")]
fn ppc(&self) -> Option<&ppc::ObjArchPpc> { None }
}
pub struct ProcessCodeResult {
@ -48,7 +52,7 @@ pub struct ProcessCodeResult {
pub insts: Vec<ObjIns>,
}
pub fn new_arch(object: &object::File) -> Result<Box<dyn ObjArch>> {
pub fn new_arch(object: &File) -> Result<Box<dyn ObjArch>> {
Ok(match object.architecture() {
#[cfg(feature = "ppc")]
Architecture::PowerPc => Box::new(ppc::ObjArchPpc::new(object)?),

View File

@ -1,13 +1,17 @@
use std::{borrow::Cow, collections::BTreeMap};
use anyhow::{bail, Result};
use object::{elf, File, Relocation, RelocationFlags};
use anyhow::{bail, ensure, Result};
use cwextab::{decode_extab, ExceptionTableData};
use object::{
elf, File, Object, ObjectSection, ObjectSymbol, Relocation, RelocationFlags, RelocationTarget,
Symbol, SymbolKind,
};
use ppc750cl::{Argument, InsIter, GPR};
use crate::{
arch::{ObjArch, ProcessCodeResult},
diff::DiffObjConfig,
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, ObjSymbol},
};
// Relative relocation, can be Simm, Offset or BranchDest
@ -22,10 +26,13 @@ fn is_rel_abs_arg(arg: &Argument) -> bool {
fn is_offset_arg(arg: &Argument) -> bool { matches!(arg, Argument::Offset(_)) }
pub struct ObjArchPpc {}
pub struct ObjArchPpc {
/// Exception info
pub extab: Option<BTreeMap<usize, ExceptionInfo>>,
}
impl ObjArchPpc {
pub fn new(_file: &File) -> Result<Self> { Ok(Self {}) }
pub fn new(file: &File) -> Result<Self> { Ok(Self { extab: decode_exception_info(file)? }) }
}
impl ObjArch for ObjArchPpc {
@ -178,6 +185,14 @@ impl ObjArch for ObjArchPpc {
_ => Cow::Owned(format!("<{flags:?}>")),
}
}
fn ppc(&self) -> Option<&ObjArchPpc> { Some(self) }
}
impl ObjArchPpc {
pub fn extab_for_symbol(&self, symbol: &ObjSymbol) -> Option<&ExceptionInfo> {
symbol.original_index.and_then(|i| self.extab.as_ref()?.get(&i))
}
}
fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
@ -208,3 +223,128 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
};
Ok(())
}
#[derive(Debug, Clone)]
pub struct ExtabSymbolRef {
pub original_index: usize,
pub name: String,
pub demangled_name: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ExceptionInfo {
pub eti_symbol: ExtabSymbolRef,
pub etb_symbol: ExtabSymbolRef,
pub data: ExceptionTableData,
pub dtors: Vec<ExtabSymbolRef>,
}
fn decode_exception_info(file: &File<'_>) -> Result<Option<BTreeMap<usize, ExceptionInfo>>> {
let Some(extab_section) = file.section_by_name("extab") else {
return Ok(None);
};
let Some(extabindex_section) = file.section_by_name("extabindex") else {
return Ok(None);
};
let mut result = BTreeMap::new();
let extab_relocations = extab_section.relocations().collect::<BTreeMap<u64, Relocation>>();
let extabindex_relocations =
extabindex_section.relocations().collect::<BTreeMap<u64, Relocation>>();
for extabindex in file.symbols().filter(|symbol| {
symbol.section_index() == Some(extabindex_section.index())
&& symbol.kind() == SymbolKind::Data
}) {
if extabindex.size() != 12 {
log::warn!("Invalid extabindex entry size {}", extabindex.size());
continue;
}
// Each extabindex entry has two relocations:
// - 0x0: The function that the exception table is for
// - 0x8: The relevant entry in extab section
let Some(extab_func_reloc) = extabindex_relocations.get(&extabindex.address()) else {
log::warn!("Failed to find function relocation for extabindex entry");
continue;
};
let Some(extab_reloc) = extabindex_relocations.get(&(extabindex.address() + 8)) else {
log::warn!("Failed to find extab relocation for extabindex entry");
continue;
};
// Resolve the function and extab symbols
let Some(extab_func) = relocation_symbol(file, extab_func_reloc)? else {
log::warn!("Failed to find function symbol for extabindex entry");
continue;
};
let extab_func_name = extab_func.name()?;
let Some(extab) = relocation_symbol(file, extab_reloc)? else {
log::warn!("Failed to find extab symbol for extabindex entry");
continue;
};
let extab_start_addr = extab.address() - extab_section.address();
let extab_end_addr = extab_start_addr + extab.size();
// All relocations in the extab section are dtors
let mut dtors: Vec<ExtabSymbolRef> = vec![];
for (_, reloc) in extab_relocations.range(extab_start_addr..extab_end_addr) {
let Some(symbol) = relocation_symbol(file, reloc)? else {
log::warn!("Failed to find symbol for extab relocation");
continue;
};
dtors.push(make_symbol_ref(&symbol)?);
}
// Decode the extab data
let Some(extab_data) = extab_section.data_range(extab_start_addr, extab.size())? else {
log::warn!("Failed to get extab data for function {}", extab_func_name);
continue;
};
let data = match decode_extab(extab_data) {
Some(decoded_data) => decoded_data,
None => {
log::warn!("Exception table decoding failed for function {}", extab_func_name);
return Ok(None);
}
};
//Add the new entry to the list
result.insert(extab_func.index().0, ExceptionInfo {
eti_symbol: make_symbol_ref(&extabindex)?,
etb_symbol: make_symbol_ref(&extab)?,
data,
dtors,
});
}
Ok(Some(result))
}
fn relocation_symbol<'data, 'file>(
file: &'file File<'data>,
relocation: &Relocation,
) -> Result<Option<Symbol<'data, 'file>>> {
let addend = relocation.addend();
match relocation.target() {
RelocationTarget::Symbol(idx) => {
ensure!(addend == 0, "Symbol relocations must have zero addend");
Ok(Some(file.symbol_by_index(idx)?))
}
RelocationTarget::Section(idx) => {
ensure!(addend >= 0, "Section relocations must have non-negative addend");
let addend = addend as u64;
Ok(file
.symbols()
.find(|symbol| symbol.section_index() == Some(idx) && symbol.address() == addend))
}
target => bail!("Unsupported relocation target: {target:?}"),
}
}
fn make_symbol_ref(symbol: &Symbol) -> Result<ExtabSymbolRef> {
let name = symbol.name()?.to_string();
let demangled_name = cwdemangle::demangle(&name, &cwdemangle::DemangleOptions::default());
Ok(ExtabSymbolRef { original_index: symbol.index().0, name, demangled_name })
}

View File

@ -3,7 +3,6 @@ pub mod split_meta;
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
use cwextab::*;
use filetime::FileTime;
use flagset::{flags, FlagSet};
use object::RelocationFlags;
@ -24,6 +23,9 @@ flags! {
Weak,
Common,
Hidden,
/// Has extra data associated with the symbol
/// (e.g. exception table entry)
HasExtra,
}
}
#[derive(Debug, Copy, Clone, Default)]
@ -114,9 +116,6 @@ pub struct ObjIns {
pub struct ObjSymbol {
pub name: String,
pub demangled_name: Option<String>,
pub has_extab: bool,
pub extab_name: Option<String>,
pub extabindex_name: Option<String>,
pub address: u64,
pub section_address: u64,
pub size: u64,
@ -125,13 +124,8 @@ pub struct ObjSymbol {
pub addend: i64,
/// Original virtual address (from .note.split section)
pub virtual_address: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct ObjExtab {
pub func: ObjSymbol,
pub data: ExceptionTableData,
pub dtors: Vec<ObjSymbol>,
/// Original index in object symbol table
pub original_index: Option<usize>,
}
pub struct ObjInfo {
@ -141,8 +135,6 @@ pub struct ObjInfo {
pub sections: Vec<ObjSection>,
/// Common BSS symbols
pub common: Vec<ObjSymbol>,
/// Exception tables
pub extab: Option<Vec<ObjExtab>>,
/// Split object metadata (.note.split section)
pub split_meta: Option<SplitMeta>,
}

View File

@ -1,15 +1,14 @@
use std::{collections::HashSet, fs, io::Cursor, mem::size_of, path::Path};
use anyhow::{anyhow, bail, ensure, Context, Result};
use cwextab::decode_extab;
use filetime::FileTime;
use flagset::Flags;
use object::{
endian::LittleEndian as LE,
pe::{ImageAuxSymbolFunctionBeginEnd, ImageLinenumber},
read::coff::{CoffFile, CoffHeader, ImageSymbol},
Architecture, BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget,
SectionIndex, SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
BinaryFormat, File, Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionIndex,
SectionKind, Symbol, SymbolIndex, SymbolKind, SymbolScope, SymbolSection,
};
use crate::{
@ -17,8 +16,7 @@ use crate::{
diff::DiffObjConfig,
obj::{
split_meta::{SplitMeta, SPLITMETA_SECTION},
ObjExtab, ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet,
ObjSymbolFlags,
ObjInfo, ObjReloc, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags,
},
util::{read_u16, read_u32},
};
@ -60,6 +58,13 @@ fn to_obj_symbol(
if obj_file.format() == BinaryFormat::Elf && symbol.scope() == SymbolScope::Linkage {
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::Hidden);
}
if arch
.ppc()
.and_then(|a| a.extab.as_ref())
.map_or(false, |e| e.contains_key(&symbol.index().0))
{
flags = ObjSymbolFlagSet(flags.0 | ObjSymbolFlags::HasExtra);
}
let address = arch.symbol_address(symbol);
let section_address = if let Some(section) =
symbol.section_index().and_then(|idx| obj_file.section_by_index(idx).ok())
@ -76,9 +81,6 @@ fn to_obj_symbol(
Ok(ObjSymbol {
name: name.to_string(),
demangled_name,
has_extab: false,
extab_name: None,
extabindex_name: None,
address,
section_address,
size: symbol.size(),
@ -86,6 +88,7 @@ fn to_obj_symbol(
flags,
addend,
virtual_address,
original_index: Some(symbol.index().0),
})
}
@ -168,9 +171,6 @@ fn symbols_by_section(
result.push(ObjSymbol {
name: format!("[{}]", section.name),
demangled_name: None,
has_extab: false,
extab_name: None,
extabindex_name: None,
address: 0,
section_address: 0,
size: section.size,
@ -178,6 +178,7 @@ fn symbols_by_section(
flags: Default::default(),
addend: 0,
virtual_address: None,
original_index: None,
});
}
Ok(result)
@ -195,111 +196,6 @@ fn common_symbols(
.collect::<Result<Vec<ObjSymbol>>>()
}
fn section_by_name<'a>(sections: &'a mut [ObjSection], name: &str) -> Option<&'a mut ObjSection> {
sections.iter_mut().find(|section| section.name == name)
}
fn exception_tables(
sections: &mut [ObjSection],
obj_file: &File<'_>,
) -> Result<Option<Vec<ObjExtab>>> {
//PowerPC only
if obj_file.architecture() != Architecture::PowerPc {
return Ok(None);
}
//Find the extab/extabindex sections
let extab_section = match section_by_name(sections, "extab") {
Some(section) => section.clone(),
None => {
return Ok(None);
}
};
let extabindex_section = match section_by_name(sections, "extabindex") {
Some(section) => section.clone(),
None => {
return Ok(None);
}
};
let text_section = match section_by_name(sections, ".text") {
Some(section) => section,
None => bail!(".text section is somehow missing, this should not happen"),
};
let mut result: Vec<ObjExtab> = vec![];
let extab_symbol_count = extab_section.symbols.len();
let extabindex_symbol_count = extabindex_section.symbols.len();
let extab_reloc_count = extab_section.relocations.len();
let table_count = extab_symbol_count;
let mut extab_reloc_index: usize = 0;
//Make sure that the number of symbols in the extab/extabindex section matches. If not, exit early
if extab_symbol_count != extabindex_symbol_count {
bail!("Extab/Extabindex symbol counts do not match");
}
//Convert the extab/extabindex section data
//Go through each extabindex entry
for i in 0..table_count {
let extabindex = &extabindex_section.symbols[i];
/* Get the function symbol and extab symbol from the extabindex relocations array. Each extabindex
entry has two relocations (the first for the function, the second for the extab entry) */
let extab_func = extabindex_section.relocations[i * 2].target.clone();
let extab = &extabindex_section.relocations[(i * 2) + 1].target;
let extab_start_addr = extab.address;
let extab_end_addr = extab_start_addr + extab.size;
//Find the function in the text section, and set the has extab flag
for i in 0..text_section.symbols.len() {
let func = &mut text_section.symbols[i];
if func.name == extab_func.name {
func.has_extab = true;
func.extab_name = Some(extab.name.clone());
func.extabindex_name = Some(extabindex.name.clone());
}
}
/* Iterate through the list of extab relocations, continuing until we hit a relocation
that isn't within the current extab symbol. Get the target dtor function symbol from
each relocation used, and add them to the list. */
let mut dtors: Vec<ObjSymbol> = vec![];
while extab_reloc_index < extab_reloc_count {
let extab_reloc = &extab_section.relocations[extab_reloc_index];
//If the current entry is past the current extab table, stop here
if extab_reloc.address >= extab_end_addr {
break;
}
//Otherwise, the current relocation is used by the current table
dtors.push(extab_reloc.target.clone());
//Go to the next entry
extab_reloc_index += 1;
}
//Decode the extab data
let start_index = extab_start_addr as usize;
let end_index = extab_end_addr as usize;
let extab_data = extab_section.data[start_index..end_index].try_into().unwrap();
let data = match decode_extab(extab_data) {
Some(decoded_data) => decoded_data,
None => {
log::warn!("Exception table decoding failed for function {}", extab_func.name);
return Ok(None);
}
};
//Add the new entry to the list
let entry = ObjExtab { func: extab_func, data, dtors };
result.push(entry);
}
Ok(Some(result))
}
fn find_section_symbol(
arch: &dyn ObjArch,
obj_file: &File<'_>,
@ -335,9 +231,6 @@ fn find_section_symbol(
Ok(ObjSymbol {
name: name.to_string(),
demangled_name: None,
has_extab: false,
extab_name: None,
extabindex_name: None,
address: offset,
section_address: address - section.address(),
size: 0,
@ -345,6 +238,7 @@ fn find_section_symbol(
flags: Default::default(),
addend: offset_addr as i64,
virtual_address: None,
original_index: None,
})
}
@ -615,9 +509,6 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
Ok(ObjSymbol {
name: symbol.name,
demangled_name: symbol.demangled_name,
has_extab: symbol.has_extab,
extab_name: symbol.extab_name,
extabindex_name: symbol.extabindex_name,
address: (symbol.address as i64 + address_change).try_into()?,
section_address: (symbol.section_address as i64 + address_change).try_into()?,
size: symbol.size,
@ -629,6 +520,7 @@ fn update_combined_symbol(symbol: ObjSymbol, address_change: i64) -> Result<ObjS
} else {
None
},
original_index: symbol.original_index,
})
}
@ -740,8 +632,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<ObjInfo> {
}
line_info(&obj_file, &mut sections, data)?;
let common = common_symbols(arch.as_ref(), &obj_file, split_meta.as_ref())?;
let extab = exception_tables(&mut sections, &obj_file)?;
Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, extab, split_meta })
Ok(ObjInfo { arch, path: None, timestamp: None, sections, common, split_meta })
}
pub fn has_function(obj_path: &Path, symbol_name: &str) -> Result<bool> {

View File

@ -1,4 +1,3 @@
#![warn(clippy::all, rust_2018_idioms)]
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
mod app;

View File

@ -1,8 +1,9 @@
use egui::{Align, Layout, ScrollArea, Ui, Vec2};
use egui_extras::{Size, StripBuilder};
use objdiff_core::{
arch::ppc::ExceptionInfo,
diff::ObjDiff,
obj::{ObjExtab, ObjInfo, ObjSymbol, SymbolRef},
obj::{ObjInfo, ObjSymbol, SymbolRef},
};
use time::format_description;
@ -22,7 +23,7 @@ fn find_symbol(obj: &ObjInfo, selected_symbol: &SymbolRefByName) -> Option<Symbo
None
}
fn decode_extab(extab: &ObjExtab) -> String {
fn decode_extab(extab: &ExceptionInfo) -> String {
let mut text = String::from("");
let mut dtor_names: Vec<&str> = vec![];
@ -42,18 +43,8 @@ fn decode_extab(extab: &ObjExtab) -> String {
text
}
fn find_extab_entry(obj: &ObjInfo, symbol: &ObjSymbol) -> Option<ObjExtab> {
if let Some(extab_array) = &obj.extab {
for extab_entry in extab_array {
if extab_entry.func.name == symbol.name {
return Some(extab_entry.clone());
}
}
} else {
return None;
}
None
fn find_extab_entry<'a>(obj: &'a ObjInfo, symbol: &ObjSymbol) -> Option<&'a ExceptionInfo> {
obj.arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol))
}
fn extab_text_ui(
@ -65,7 +56,7 @@ fn extab_text_ui(
let (_section, symbol) = obj.0.section_symbol(symbol_ref);
if let Some(extab_entry) = find_extab_entry(&obj.0, symbol) {
let text = decode_extab(&extab_entry);
let text = decode_extab(extab_entry);
ui.colored_label(appearance.replace_color, &text);
return Some(());
}

View File

@ -6,6 +6,7 @@ use egui::{
};
use egui_extras::{Size, StripBuilder};
use objdiff_core::{
arch::ObjArch,
diff::{ObjDiff, ObjSymbolDiff},
obj::{ObjInfo, ObjSection, ObjSectionKind, ObjSymbol, ObjSymbolFlags, SymbolRef},
};
@ -60,7 +61,6 @@ pub struct SymbolViewState {
pub reverse_fn_order: bool,
pub disable_reverse_fn_order: bool,
pub show_hidden_symbols: bool,
pub queue_extab_decode: bool,
}
impl DiffViewState {
@ -138,9 +138,11 @@ pub fn match_color_for_symbol(match_percent: f32, appearance: &Appearance) -> Co
fn symbol_context_menu_ui(
ui: &mut Ui,
state: &mut SymbolViewState,
arch: &dyn ObjArch,
symbol: &ObjSymbol,
section: Option<&ObjSection>,
) {
) -> Option<View> {
let mut ret = None;
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
@ -162,20 +164,22 @@ fn symbol_context_menu_ui(
}
}
if let Some(section) = section {
if symbol.has_extab && ui.button("Decode exception table").clicked() {
state.queue_extab_decode = true;
let has_extab = arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol)).is_some();
if has_extab && ui.button("Decode exception table").clicked() {
state.selected_symbol = Some(SymbolRefByName {
symbol_name: symbol.name.clone(),
demangled_symbol_name: symbol.demangled_name.clone(),
section_name: section.name.clone(),
});
ret = Some(View::ExtabDiff);
ui.close_menu();
}
}
});
ret
}
fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) {
fn symbol_hover_ui(ui: &mut Ui, arch: &dyn ObjArch, symbol: &ObjSymbol, appearance: &Appearance) {
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
@ -193,26 +197,24 @@ fn symbol_hover_ui(ui: &mut Ui, symbol: &ObjSymbol, appearance: &Appearance) {
if let Some(address) = symbol.virtual_address {
ui.colored_label(appearance.replace_color, format!("Virtual address: {:#x}", address));
}
if symbol.has_extab {
if let (Some(extab_name), Some(extabindex_name)) =
(&symbol.extab_name, &symbol.extabindex_name)
{
ui.colored_label(
appearance.highlight_color,
format!("Extab Symbol: {}", extab_name),
);
ui.colored_label(
appearance.highlight_color,
format!("Extabindex Symbol: {}", extabindex_name),
);
}
if let Some(extab) = arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol)) {
ui.colored_label(
appearance.highlight_color,
format!("extab symbol: {}", &extab.etb_symbol.name),
);
ui.colored_label(
appearance.highlight_color,
format!("extabindex symbol: {}", &extab.eti_symbol.name),
);
}
});
}
#[must_use]
#[allow(clippy::too_many_arguments)]
fn symbol_ui(
ui: &mut Ui,
arch: &dyn ObjArch,
symbol: &ObjSymbol,
symbol_diff: &ObjSymbolDiff,
section: Option<&ObjSection>,
@ -245,6 +247,9 @@ fn symbol_ui(
if symbol.flags.0.contains(ObjSymbolFlags::Weak) {
write_text("w", appearance.text_color, &mut job, appearance.code_font.clone());
}
if symbol.flags.0.contains(ObjSymbolFlags::HasExtra) {
write_text("e", appearance.text_color, &mut job, appearance.code_font.clone());
}
if symbol.flags.0.contains(ObjSymbolFlags::Hidden) {
write_text(
"h",
@ -268,8 +273,10 @@ fn symbol_ui(
write_text(name, appearance.highlight_color, &mut job, appearance.code_font.clone());
let response = SelectableLabel::new(selected, job)
.ui(ui)
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, symbol, appearance));
response.context_menu(|ui| symbol_context_menu_ui(ui, state, symbol, section));
.on_hover_ui_at_pointer(|ui| symbol_hover_ui(ui, arch, symbol, appearance));
response.context_menu(|ui| {
ret = ret.or(symbol_context_menu_ui(ui, state, arch, symbol, section));
});
if response.clicked() {
if let Some(section) = section {
if section.kind == ObjSectionKind::Code {
@ -299,13 +306,6 @@ fn symbol_ui(
(None, None)
};
}
//If the decode extab context menu option was clicked, switch to the extab view
if state.queue_extab_decode {
ret = Some(View::ExtabDiff);
state.queue_extab_decode = false;
}
ret
}
@ -328,6 +328,7 @@ fn symbol_list_ui(
left: bool,
) -> Option<View> {
let mut ret = None;
let arch = obj.0.arch.as_ref();
ScrollArea::both().auto_shrink([false, false]).show(ui, |ui| {
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
@ -341,6 +342,7 @@ fn symbol_list_ui(
}
ret = ret.or(symbol_ui(
ui,
arch,
symbol,
symbol_diff,
None,
@ -391,6 +393,7 @@ fn symbol_list_ui(
}
ret = ret.or(symbol_ui(
ui,
arch,
symbol,
symbol_diff,
Some(section),
@ -408,6 +411,7 @@ fn symbol_list_ui(
}
ret = ret.or(symbol_ui(
ui,
arch,
symbol,
symbol_diff,
Some(section),