[all-commits] [llvm/llvm-project] 879f76: [BOLT] Fix shifted DWARF inline-scope ranges; trac...

Rafael Auler via All-commits all-commits at lists.llvm.org
Thu Jul 2 15:50:00 PDT 2026


  Branch: refs/heads/users/rafaelauler/fix-dbginfo-scopes
  Home:   https://github.com/llvm/llvm-project
  Commit: 879f762ed59c6f4efcada0441bf16cda7cd7417d
      https://github.com/llvm/llvm-project/commit/879f762ed59c6f4efcada0441bf16cda7cd7417d
  Author: Rafael Auler <rafaelauler at fb.com>
  Date:   2026-07-02 (Thu, 02 Jul 2026)

  Changed paths:
    M bolt/include/bolt/Core/BinaryContext.h
    M bolt/include/bolt/Core/BinaryFunction.h
    M bolt/lib/Core/BinaryContext.cpp
    M bolt/lib/Core/BinaryEmitter.cpp
    M bolt/lib/Core/BinaryFunction.cpp
    M bolt/lib/Rewrite/RewriteInstance.cpp
    A bolt/test/X86/dwarf-inline-range-plt-shift.s

  Log Message:
  -----------
  [BOLT] Fix shifted DWARF inline-scope ranges; track scope boundaries

Summary:
BOLT updated DWARF lexical-scope ranges (DW_TAG_inlined_subroutine /
lexical_block low_pc/high_pc and DW_AT_ranges) via
translateInputToOutputRange(), which mapped a boundary using its input
offset relative to the start of the containing basic block:

  OutAddr = BB.getOutputAddressRange().first + (InputOffset - BB.getOffset())

This assumes intra-block byte offsets are preserved input->output. Any
pass that changes instruction sizes within a block ahead of a scope
boundary breaks that assumption. With --plt=all, each `call foo at PLT`
(5 bytes, e8+rel32) is rewritten to `call *foo at GOT(%rip)` (6 bytes,
ff 15+rel32); N such calls before a boundary shift its emitted low_pc/
high_pc N bytes too early, onto the preceding instruction. The range
stays within the parent so `llvm-dwarfdump --verify` does not catch it;
symbolizers then attribute samples on those instructions to the wrong
inlined frames.

Fix is to resolve scope-range boundaries through the precise per-instruction
input-to-output AddressMap (the same map BAT already uses) instead of
input-relative block offsets. Boundary instructions are arbitrary (not
just calls/branches), so they are normally absent from that map; to make
them resolvable, disassembly now keeps an offset for the boundary
instructions (only the boundaries, to keep the AddressMap small) and
those offsets are emitted as AddressMap entries whenever an address map
is required (requiresAddressMap(), which includes --update-debug-sections
via requiresPreciseAddressMap()), not only under BAT.

Boundary collection (BinaryContext::collectDebugScopeBoundaries) runs in
readDebugInfo() after preprocessDebugInfo(). It streams the DIEs of the
CUs that will be updated directly from the already-loaded DWARFContext
with DWARFDebugInfoEntry::extractFast, decoding one DIE at a time into a
single reusable entry, so no DIE forest is materialized and no second
DWARF context is created. For split DWARF the .dwo DIEs are already
extracted by preprocessDWODebugInfo(), so the cached array is reused
instead. Boundaries are stored per function in a sorted, deduplicated
vector (BinaryFunction::DebugScopeBoundaryOffsets), queried during
disassembly with a monotonic cursor, and freed once the function is
disassembled, so the feature adds no global state.

The behavior is on by default and can be disabled with
--accurate-debug-ranges=0, which falls back to the old block-relative
mapping.

Test on big binaries with split dwarf, -lite=0:
                                wall                Max RSS
      -accurate-debug-ranges=0  1070.1s             94.91
      -accurate-debug-ranges=1  1173.0s             100.07
      delta                     +102.9s             +5.16   (+4.6% CPU,
                                                             +5.4% RSS)

Test on big binaries with split dwarf, lite=1:
      -accurate-debug-ranges=0  433.9s              83.23
      -accurate-debug-ranges=1  434.7s              83.79   (+0.7% RSS)

    --time-rewrite shows the boundary-collection phase itself is cheap:
    "read debug ranges" is 5.8s of 4960s total user time on one binary
    (0.1%) and 18.8s of 6307s on another binary; the feature's
    cost is dominated by emitting/translating the extra AddressMap entries,
    not by collection.



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list