Skip to content

Commit 0586ff9

Browse files
committed
Always add unique section symbols for data sections
1 parent 579f386 commit 0586ff9

File tree

1 file changed

+56
-17
lines changed

1 file changed

+56
-17
lines changed

objdiff-core/src/obj/read.rs

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::{
1515
diff::DiffObjConfig,
1616
obj::{
1717
FlowAnalysisResult, Object, Relocation, RelocationFlags, Section, SectionData, SectionFlag,
18-
SectionKind, Symbol, SymbolFlag, SymbolKind,
18+
SectionKind, Symbol, SymbolFlag, SymbolFlagSet, SymbolKind,
1919
split_meta::{SPLITMETA_SECTION, SplitMeta},
2020
},
2121
util::{align_data_slice_to, align_u64_to, read_u16, read_u32},
@@ -50,9 +50,10 @@ fn map_symbol(
5050
let section_name = section.name().context("Failed to process section name")?;
5151
name = format!("[{section_name}]");
5252
// For section symbols, set the size to zero. If the size is non-zero, it will be included
53-
// in the diff. The size inference logic below will set the size back to the section size
54-
// for data sections, thus acting as a placeholder symbol to allow diffing an entire section
55-
// at once.
53+
// in the diff. Most of the time, this is duplicative, given that we'll have function or
54+
// object symbols that cover the same range. In the case of an empty section, the size
55+
// inference logic below will set the size back to the section size, thus acting as a
56+
// placeholder symbol.
5657
size = 0;
5758
}
5859

@@ -109,7 +110,7 @@ fn map_symbols(
109110
split_meta: Option<&SplitMeta>,
110111
) -> Result<(Vec<Symbol>, Vec<usize>)> {
111112
let symbol_count = obj_file.symbols().count();
112-
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count);
113+
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count + obj_file.sections().count());
113114
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
114115
for obj_symbol in obj_file.symbols() {
115116
if symbol_indices.len() <= obj_symbol.index().0 {
@@ -126,6 +127,52 @@ fn map_symbols(
126127
Ok((symbols, symbol_indices))
127128
}
128129

130+
/// Add an extra fake symbol to the start of each data section in order to allow the user to diff
131+
/// all of the data in the section at once by clicking on this fake symbol at the top of the list.
132+
fn add_section_symbols(sections: &[Section], symbols: &mut Vec<Symbol>) {
133+
for (section_idx, section) in sections.iter().enumerate() {
134+
if section.kind != SectionKind::Data {
135+
continue;
136+
}
137+
138+
// Instead of naming the fake section symbol after `section.name` (e.g. ".data") we use
139+
// `section.id` (e.g. ".data-0") so that it is unique when multiple sections with the same
140+
// name exist and it also doesn't conflict with any real section symbols from the object.
141+
let name = if section.flags.contains(SectionFlag::Combined) {
142+
// For combined sections, `section.id` (e.g. ".data-combined") is inconsistent with
143+
// uncombined section IDs, so we add the "-0" suffix to the name to enable proper
144+
// pairing when one side had multiple sections combined and the other only had one
145+
// section to begin with.
146+
format!("[{}-0]", section.name)
147+
} else {
148+
format!("[{}]", section.id.clone())
149+
};
150+
151+
// `section.size` can include extra padding, so instead prefer using the address that the
152+
// last symbol ends at when there are any symbols in the section.
153+
let size = symbols
154+
.iter()
155+
.filter(|s| {
156+
s.section == Some(section_idx) && s.kind == SymbolKind::Object && s.size > 0
157+
})
158+
.map(|s| s.address + s.size)
159+
.max()
160+
.unwrap_or(section.size);
161+
162+
symbols.push(Symbol {
163+
name,
164+
demangled_name: None,
165+
address: 0,
166+
size,
167+
kind: SymbolKind::Section,
168+
section: Some(section_idx),
169+
flags: SymbolFlagSet::default() | SymbolFlag::Local,
170+
align: None,
171+
virtual_address: None,
172+
});
173+
}
174+
}
175+
129176
/// When inferring a symbol's size, we ignore symbols that start with specific prefixes. They are
130177
/// usually emitted as branch targets and do not represent the start of a function or object.
131178
fn is_local_label(symbol: &Symbol) -> bool {
@@ -208,18 +255,9 @@ fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Secti
208255
let next_address =
209256
next_symbol.map(|s| s.address).unwrap_or_else(|| section.address + section.size);
210257
let new_size = if symbol.kind == SymbolKind::Section && section.kind == SectionKind::Data {
211-
// For data section symbols, set their size to the section size. Then the user can diff
212-
// the entire section at once by clicking on the section symbol at the top.
213-
// `section.size` can include extra padding, so instead prefer using the address that
214-
// the last symbol ends at when there are symbols in the section.
215-
symbols
216-
.iter()
217-
.filter(|s| {
218-
s.section == Some(section_idx) && s.kind == SymbolKind::Object && s.size > 0
219-
})
220-
.map(|s| s.address + s.size)
221-
.max()
222-
.unwrap_or(section.size)
258+
// Data sections already have always-visible section symbols created by objdiff to allow
259+
// diffing them, so no need to unhide these.
260+
0
223261
} else if section.kind == SectionKind::Code {
224262
arch.infer_function_size(symbol, section, next_address)?
225263
} else {
@@ -954,6 +992,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
954992
if config.combine_data_sections || config.combine_text_sections {
955993
combine_sections(&mut sections, &mut symbols, config)?;
956994
}
995+
add_section_symbols(&sections, &mut symbols);
957996
arch.post_init(&sections, &symbols);
958997
let mut obj = Object {
959998
arch,

0 commit comments

Comments
 (0)