@@ -1234,15 +1234,23 @@ impl<I: VCodeInst> VCode<I> {
12341234 inst_offsets : & [ CodeOffset ] ,
12351235 func_body_len : u32 ,
12361236 ) -> ValueLabelsRanges {
1237+ let mut value_labels_ranges: ValueLabelsRanges = HashMap :: new ( ) ;
1238+
1239+ // Add synthetic full-body entries from the debug-locals stack
1240+ // slot before processing regalloc2 output so that the
1241+ // regalloc2-based (narrower but potentially register-based)
1242+ // entries are appended after and can take precedence in the
1243+ // DWARF transform's range intersection logic.
1244+ self . add_debug_locals_slot_ranges ( & mut value_labels_ranges, func_body_len) ;
1245+
12371246 if self . debug_value_labels . is_empty ( ) {
1238- return ValueLabelsRanges :: default ( ) ;
1247+ return value_labels_ranges ;
12391248 }
12401249
12411250 if trace_log_enabled ! ( ) {
12421251 self . log_value_labels_ranges ( regalloc, inst_offsets) ;
12431252 }
12441253
1245- let mut value_labels_ranges: ValueLabelsRanges = HashMap :: new ( ) ;
12461254 for & ( label, from, to, alloc) in & regalloc. debug_locations {
12471255 let label = ValueLabel :: from_u32 ( label) ;
12481256 let ranges = value_labels_ranges. entry ( label) . or_insert_with ( || vec ! [ ] ) ;
@@ -1313,6 +1321,67 @@ impl<I: VCodeInst> VCode<I> {
13131321 value_labels_ranges
13141322 }
13151323
1324+ /// If a sized stack slot is marked with the debug-locals sentinel
1325+ /// key, add a full-body `ValueLocRange` for each Wasm local (and
1326+ /// for the vmctx pointer stored after all locals) so that DWARF
1327+ /// expressions can always find values at known CFA-relative offsets.
1328+ fn add_debug_locals_slot_ranges (
1329+ & self ,
1330+ value_labels_ranges : & mut ValueLabelsRanges ,
1331+ func_body_len : u32 ,
1332+ ) {
1333+ const DEBUG_LOCALS_KEY_SENTINEL : u64 = 0xDEBF_DEAD_0000_0000 ;
1334+ const VMCTX_LABEL : u32 = 0xffff_fffe ;
1335+ let offsets = self . abi . sized_stackslot_offsets ( ) ;
1336+ let keys = self . abi . sized_stackslot_keys ( ) ;
1337+ for ( slot, slot_offset) in offsets {
1338+ let Some ( key) = keys[ slot] else { continue } ;
1339+ let bits = key. bits ( ) ;
1340+ if bits & 0xFFFF_FFFF_0000_0000 != DEBUG_LOCALS_KEY_SENTINEL {
1341+ continue ;
1342+ }
1343+ let num_locals = ( bits & 0xFFFF_FFFF ) as u32 ;
1344+ let slot_base = * slot_offset as i64 ;
1345+ let slot_base_to_caller_sp =
1346+ self . abi . slot_base_to_caller_sp_offset ( ) as i64 ;
1347+ let caller_sp_to_cfa =
1348+ crate :: isa:: unwind:: systemv:: caller_sp_to_cfa_offset ( ) as i64 ;
1349+ let cfa_to_slot_base =
1350+ -( slot_base_to_caller_sp + caller_sp_to_cfa) + slot_base;
1351+
1352+ for i in 0 ..num_locals {
1353+ let label = ValueLabel :: from_u32 ( i) ;
1354+ let per_local_offset = ( i as i64 ) * 16 ;
1355+ let cfa_offset = cfa_to_slot_base + per_local_offset;
1356+ let loc = LabelValueLoc :: CFAOffset ( cfa_offset) ;
1357+
1358+ let ranges = value_labels_ranges
1359+ . entry ( label)
1360+ . or_insert_with ( || vec ! [ ] ) ;
1361+ ranges. push ( ValueLocRange {
1362+ loc,
1363+ start : 0 ,
1364+ end : func_body_len,
1365+ } ) ;
1366+ }
1367+
1368+ // Also add a synthetic range for vmctx (frame base / memory
1369+ // deref), stored at offset num_locals * 16 in the slot.
1370+ let vmctx_label = ValueLabel :: from_u32 ( VMCTX_LABEL ) ;
1371+ let vmctx_offset = ( num_locals as i64 ) * 16 ;
1372+ let vmctx_cfa = cfa_to_slot_base + vmctx_offset;
1373+ let vmctx_loc = LabelValueLoc :: CFAOffset ( vmctx_cfa) ;
1374+ let ranges = value_labels_ranges
1375+ . entry ( vmctx_label)
1376+ . or_insert_with ( || vec ! [ ] ) ;
1377+ ranges. push ( ValueLocRange {
1378+ loc : vmctx_loc,
1379+ start : 0 ,
1380+ end : func_body_len,
1381+ } ) ;
1382+ }
1383+ }
1384+
13161385 fn log_value_labels_ranges ( & self , regalloc : & regalloc2:: Output , inst_offsets : & [ CodeOffset ] ) {
13171386 debug_assert ! ( trace_log_enabled!( ) ) ;
13181387
0 commit comments