@@ -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.
131178fn 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