@@ -578,6 +578,9 @@ fn rewrite_debug_sections(
578578 // #319 inc 2: fix DW_AT_ranges lists (base-relative offsets that gimli
579579 // mis-routes through convert_address) from the read side.
580580 correct_die_ranges ( & mut write_dwarf, & read_dwarf, remap) ;
581+ // #319 inc 3: fix DW_AT_location lists (same base-relative offset bug as
582+ // ranges, plus sentinel-derailed decode) from the read side.
583+ correct_die_locations ( & mut write_dwarf, & read_dwarf, remap) ;
581584 // #144 inc 3: the synthetic `<meld-adapter>` unit rides the SAME
582585 // write as the remapped original units, so every cross-section
583586 // offset is computed in one shared offset space (appending
@@ -779,6 +782,127 @@ fn correct_die_ranges<R: gimli::read::Reader<Offset = usize>>(
779782 }
780783}
781784
785+ /// Rewrite every `DW_AT_location` **location list** to the fused layout
786+ /// (#319 inc 3). Location-list entries carry the same base-relative
787+ /// begin/end offsets as `.debug_ranges` (inc 2), so gimli mis-routes them
788+ /// through `convert_address` — the entry ranges land at garbage output
789+ /// offsets and, combined with the `0xFFFFFFFF`/`0xFFFFFFFE` sentinels,
790+ /// derail the whole list (`llvm-dwarfdump`: "Invalid DW_AT_location" /
791+ /// "Invalid DWARF expressions"). Fix it exactly like [`correct_die_ranges`]:
792+ /// resolve each list from the read side (`attr_locations`, base applied),
793+ /// `translate` the entry endpoints, and re-emit as `OffsetPair` relative to
794+ /// the output CU base — carrying the location **expression bytes verbatim**
795+ /// (WASM location expressions — `DW_OP_WASM_location`, `DW_OP_stack_value` —
796+ /// hold no code addresses; a data `DW_OP_addr` is unchanged under fusion,
797+ /// matching `convert_address`'s data passthrough). Bare exprloc
798+ /// `DW_AT_location`s are not lists (`attr_locations` → `None`) and are left
799+ /// to gimli. Unmappable entries are dropped; an emptied list deletes the
800+ /// attribute (LS-D-1).
801+ fn correct_die_locations < R : gimli:: read:: Reader < Offset = usize > > (
802+ write_dwarf : & mut gimli:: write:: Dwarf ,
803+ read_dwarf : & gimli:: read:: Dwarf < R > ,
804+ remap : & AddressRemap ,
805+ ) {
806+ use gimli:: constants:: { DW_AT_location , DW_AT_low_pc } ;
807+ use gimli:: write:: { Address , AttributeValue , Expression , Location , LocationList } ;
808+
809+ let mut headers = read_dwarf. units ( ) ;
810+ let mut unit_idx = 0usize ;
811+ while let Ok ( Some ( header) ) = headers. next ( ) {
812+ if unit_idx >= write_dwarf. units . count ( ) {
813+ break ;
814+ }
815+ let uid = write_dwarf. units . id ( unit_idx) ;
816+ unit_idx += 1 ;
817+ let unit = match read_dwarf. unit ( header) {
818+ Ok ( u) => u,
819+ Err ( _) => continue ,
820+ } ;
821+
822+ let out_cu_base = {
823+ let root = write_dwarf. units . get ( uid) . root ( ) ;
824+ match write_dwarf. units . get ( uid) . get ( root) . get ( DW_AT_low_pc ) {
825+ Some ( AttributeValue :: Address ( Address :: Constant ( a) ) ) => * a as u32 ,
826+ _ => continue ,
827+ }
828+ } ;
829+
830+ let write_ids = {
831+ let wunit = write_dwarf. units . get ( uid) ;
832+ let mut ids = Vec :: new ( ) ;
833+ write_dies_preorder ( wunit, wunit. root ( ) , & mut ids) ;
834+ ids
835+ } ;
836+
837+ let mut entries = unit. entries ( ) ;
838+ let mut wi = 0usize ;
839+ while let Ok ( Some ( ( _, entry) ) ) = entries. next_dfs ( ) {
840+ if wi >= write_ids. len ( ) {
841+ break ;
842+ }
843+ let die_id = write_ids[ wi] ;
844+ wi += 1 ;
845+
846+ let loc_attr = match entry. attr_value ( DW_AT_location ) {
847+ Ok ( Some ( v) ) => v,
848+ _ => continue ,
849+ } ;
850+ // `attr_locations` returns `None` for a bare exprloc (not a list).
851+ let mut locs = match read_dwarf. attr_locations ( & unit, loc_attr) {
852+ Ok ( Some ( l) ) => l,
853+ _ => continue ,
854+ } ;
855+
856+ let mut new_locs = Vec :: new ( ) ;
857+ let mut aborted = false ;
858+ while let Ok ( Some ( le) ) = locs. next ( ) {
859+ let ( Some ( ob) , Some ( oe) ) = (
860+ remap. translate ( le. range . begin as u32 ) ,
861+ remap. translate ( le. range . end as u32 ) ,
862+ ) else {
863+ continue ; // unmappable (dropped/tombstoned) entry → drop
864+ } ;
865+ if ob < out_cu_base || oe <= ob {
866+ continue ;
867+ }
868+ let bytes = match le. data . 0 . to_slice ( ) {
869+ Ok ( b) => b. into_owned ( ) ,
870+ Err ( _) => {
871+ aborted = true ;
872+ break ;
873+ }
874+ } ;
875+ new_locs. push ( Location :: OffsetPair {
876+ begin : ( ob - out_cu_base) as u64 ,
877+ end : ( oe - out_cu_base) as u64 ,
878+ data : Expression :: raw ( bytes) ,
879+ } ) ;
880+ }
881+ if aborted {
882+ continue ; // couldn't read an expression — leave gimli's output
883+ }
884+ if new_locs. is_empty ( ) {
885+ write_dwarf
886+ . units
887+ . get_mut ( uid)
888+ . get_mut ( die_id)
889+ . delete ( DW_AT_location ) ;
890+ } else {
891+ let lid = write_dwarf
892+ . units
893+ . get_mut ( uid)
894+ . locations
895+ . add ( LocationList ( new_locs) ) ;
896+ write_dwarf
897+ . units
898+ . get_mut ( uid)
899+ . get_mut ( die_id)
900+ . set ( DW_AT_location , AttributeValue :: LocationListRef ( lid) ) ;
901+ }
902+ }
903+ }
904+ }
905+
782906/// Top-level entry point for [`crate::DwarfHandling::Remap`].
783907///
784908/// Inspects the input components for `.debug_*` sections and, when
0 commit comments