@@ -15,7 +15,7 @@ use crate::{
15
15
diff:: DiffObjConfig ,
16
16
obj:: {
17
17
FlowAnalysisResult , Object , Relocation , RelocationFlags , Section , SectionData , SectionFlag ,
18
- SectionKind , Symbol , SymbolFlag , SymbolKind ,
18
+ SectionKind , Symbol , SymbolFlag , SymbolFlagSet , SymbolKind ,
19
19
split_meta:: { SPLITMETA_SECTION , SplitMeta } ,
20
20
} ,
21
21
util:: { align_data_slice_to, align_u64_to, read_u16, read_u32} ,
@@ -50,9 +50,10 @@ fn map_symbol(
50
50
let section_name = section. name ( ) . context ( "Failed to process section name" ) ?;
51
51
name = format ! ( "[{section_name}]" ) ;
52
52
// 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.
56
57
size = 0 ;
57
58
}
58
59
@@ -109,7 +110,7 @@ fn map_symbols(
109
110
split_meta : Option < & SplitMeta > ,
110
111
) -> Result < ( Vec < Symbol > , Vec < usize > ) > {
111
112
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 ( ) ) ;
113
114
let mut symbol_indices = Vec :: < usize > :: with_capacity ( symbol_count + 1 ) ;
114
115
for obj_symbol in obj_file. symbols ( ) {
115
116
if symbol_indices. len ( ) <= obj_symbol. index ( ) . 0 {
@@ -126,6 +127,52 @@ fn map_symbols(
126
127
Ok ( ( symbols, symbol_indices) )
127
128
}
128
129
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
+
129
176
/// When inferring a symbol's size, we ignore symbols that start with specific prefixes. They are
130
177
/// usually emitted as branch targets and do not represent the start of a function or object.
131
178
fn is_local_label ( symbol : & Symbol ) -> bool {
@@ -208,18 +255,9 @@ fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Secti
208
255
let next_address =
209
256
next_symbol. map ( |s| s. address ) . unwrap_or_else ( || section. address + section. size ) ;
210
257
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
223
261
} else if section. kind == SectionKind :: Code {
224
262
arch. infer_function_size ( symbol, section, next_address) ?
225
263
} else {
@@ -954,6 +992,7 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
954
992
if config. combine_data_sections || config. combine_text_sections {
955
993
combine_sections ( & mut sections, & mut symbols, config) ?;
956
994
}
995
+ add_section_symbols ( & sections, & mut symbols) ;
957
996
arch. post_init ( & sections, & symbols) ;
958
997
let mut obj = Object {
959
998
arch,
0 commit comments