Skip to content

debug: preserve O0 variable locations - #2235

Draft
cpunion wants to merge 4 commits into
xgo-dev:mainfrom
cpunion:codex/linux-amd64-dwarf-locations-20260730
Draft

debug: preserve O0 variable locations#2235
cpunion wants to merge 4 commits into
xgo-dev:mainfrom
cpunion:codex/linux-amd64-dwarf-locations-20260730

Conversation

@cpunion

@cpunion cpunion commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Fixes #2206.

Problem

With -O0 -ldflags=-w=false on Linux/amd64, LLDB could list variables but fail to read scalar parameters at the first body breakpoint. An updated local aggregate could also show a stale value even when reading the same object through a pointer showed the new value.

Fix

  • Rebased onto xgo-dev/llgo e82e95fbe and give non-address-backed parameters stable O0 homes.
  • Refresh those homes at SSA debug assignments and clear !dbg from the compiler-generated stores, so they do not add source stepping sites.
  • Keep address-backed variables attached to their real storage with dbg.declare; do not replace them with aggregate value snapshots.
  • Preserve the existing dbg.value path for optimized builds, including aggregate parameters.

Validation

  • Local focused O0/O2 metadata tests: cl/TestCompileDebugMetadata, ssa/TestDebugParameterHomes pass.
  • macOS/arm64 LLDB 1703: 241/241 LLGo variable assertions pass, including marker/fallback checks.
  • Linux/amd64 focused parameter-home test passes.
  • Full cl and ssa package tests pass after refreshing the strict CHECK-NEXT IR expectations for stable parameter homes. The previous generic Go LLVM19 failure was caused by this PR’s expected O0 debug-IR changes, not by main; it is fixed at head 7d4908596.
  • CI at 7d4908596: 41 checks passed, 1 release check skipped by workflow policy, with no failures or cancellations; Codecov patch coverage is 96.61% (target 89.59%).

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: preserve O0 variable locations

The core mechanism is sound. At O0, diParam allocates a stable entry-block "home" and emits llvm.dbg.declare against it; later DebugRefs refresh that home via a location-less DIStore, so the debugger reads a live value from a fixed slot. The location save/clear/restore in withoutDebugLocation, entry-block dominance of the home alloca, the nil-map guards, and the debugAllocObjects/debugStableParams double-handling exclusion all check out. No blocking issues; findings below are minor/robustness.

Minor

  • ssa/di.go:673 — dead Load in doConstructDebugAddr. doConstructDebugAddr always emits dbgVal = b.Load(dbgPtr), but its only callers (DIValue at ssa/di.go:696 and now diParam via constructDebugAddr) discard dbgVal and the hardcoded exists=false. This PR extends the alloca/store/Load pattern to every parameter home, so an unused Load is now emitted per param in O0 IR — pure overhead that isn't cleaned up at O0. Consider dropping the Load (and the unused dbgVal/exists return values) since no caller uses them. Debug-build only.

  • cmd/internal/lldb/llgo_plugin.py — unguarded runtime state / value parsing. print_all_variables and print_go_expression walk target → process → thread → frame after _require_supported_target with no frame.IsValid()/process-state check, so invoking llgo vars / llgo print with a loaded-but-not-launched target yields empty/garbage output instead of a clear "no running process" message. Several int(x.GetValue(), 16) calls in format_slice / get_indexed_value / format_string, and the parts[i+1] / int(part[1:-1]) indexing in evaluate_expression, are unguarded against None/non-hex values and malformed tokens, which raise uncaught TypeError/ValueError/IndexError and abort the command. Low severity (interactive input), but worth hardening.

  • cmd/internal/lldb/lldb.go — LLDB version regex on Apple toolchains. parseLLDBMajor captures the first integer from the --version string against minimumLLDBVersion = 18. On macOS, Apple LLDB reports a build number (e.g. lldb-1700.x), so the check passes only coincidentally rather than validating the underlying LLVM major. Works today; consider special-casing or documenting the Apple lldb-<build> format.

Verified as non-issues: the stable.value/block short-circuit and the p.bvals[iv] missing→return path in debugRef match the existing DIValue semantics; debugStableParams is seeded only when DIParamWithHome returns a non-nil home (O0 only); the moved runtest.sh now passes LLDB commands via an argv array instead of eval, closing the earlier injection pattern; comments in internal/debuginfo/builder.go and the lldbtest/README.md are accurate after the move.

Comment thread cmd/llgo/lldbtest/runtest.sh Outdated
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.61017% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cl/compile.go 92.30% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@cpunion

cpunion commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the #2235-specific review finding in 0d38ab340: constructDebugAddr now returns only the address, the unused O0 Load is gone, and TestDebugParameterHomes asserts that parameter homes emit stores without a load.

Validation after the change:

  • macOS/arm64 LLDB: 215/215 assertions plus marker/fallback checks
  • Linux/amd64: focused TestDebugParameterHomes pass
  • ssa coverage: 93.0%; the changed helper entry points are covered

The runtime-state/value-parsing and Apple version-detection notes concern the parent #2211 launcher/plugin changes, not this compiler-location patch. I am keeping them out of #2235 so this dependent PR stays focused.

@cpunion
cpunion force-pushed the codex/linux-amd64-dwarf-locations-20260730 branch from 0d38ab3 to 919cea3 Compare July 30, 2026 21:12
@cpunion cpunion changed the title [Based on #2211] debug: preserve O0 variable locations debug: preserve O0 variable locations Jul 30, 2026
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

LLGo baseline benchmarks

7d490859680d | workflow run | long-term charts

Program measurements

Platform Workload File size vs main Build vs main Run vs main
Linux cprintf 18544 B +0.0% 295.014 ms +3.5% (worse) 1.269 ms -6.8% (better)
Linux fmtprintf 1877280 B +0.0% (worse) 3.085 s +5.7% (worse) 3.380 ms -4.8% (better)
Linux println 68096 B +0.0% 299.816 ms +4.0% (worse) 1.634 ms -1.6% (better)
macOS cprintf 84672 B +0.0% 510.846 ms +38.3% (worse) 4.773 ms +56.9% (worse)
macOS fmtprintf 1888208 B +0.0% 4.628 s +64.8% (worse) 15.139 ms +9.3% (worse)
macOS println 121200 B +0.0% 468.253 ms +27.3% (worse) 4.986 ms +44.6% (worse)
Core language and compiler benchmarks
Platform Benchmark ns/op vs main
Linux BenchmarkLookupPCRandom 13.310 ns/op +8.7% (worse)
Linux BenchmarkMergeCompilerFlags 150.800 ns/op +4.4% (worse)
Linux BenchmarkMergeLinkerFlags 94.520 ns/op +0.6% (worse)
Linux BenchmarkChannelBuffered 33.690 ns/op -7.7% (better)
Linux BenchmarkChannelHandoff 26804 ns/op +10.3% (worse)
Linux BenchmarkDefer 49.140 ns/op +4.0% (worse)
Linux BenchmarkDirectCall 1.558 ns/op -11.3% (better)
Linux BenchmarkGlobalRead 1.557 ns/op -11.4% (better)
Linux BenchmarkGlobalWrite 2.487 ns/op -11.5% (better)
Linux BenchmarkGoroutine 31943 ns/op -9.6% (better)
Linux BenchmarkInterfaceCall 7.783 ns/op -17.3% (better)
Linux BenchmarkRuntimeGetG 1.868 ns/op -11.5% (better)
macOS BenchmarkLookupPCRandom 14.490 ns/op +20.5% (worse)
macOS BenchmarkMergeCompilerFlags 138.900 ns/op -8.2% (better)
macOS BenchmarkMergeLinkerFlags 94.760 ns/op +40.0% (worse)
macOS BenchmarkChannelBuffered 29.780 ns/op +36.3% (worse)
macOS BenchmarkChannelHandoff 7733 ns/op +26.9% (worse)
macOS BenchmarkDefer 42.150 ns/op +64.2% (worse)
macOS BenchmarkDirectCall 1.193 ns/op +26.4% (worse)
macOS BenchmarkGlobalRead 1.201 ns/op +27.5% (worse)
macOS BenchmarkGlobalWrite 1.184 ns/op +25.3% (worse)
macOS BenchmarkGoroutine 40709 ns/op +48.1% (worse)
macOS BenchmarkInterfaceCall 6.365 ns/op +55.8% (worse)
macOS BenchmarkRuntimeGetG 2.317 ns/op +22.5% (worse)

Compared only with the latest matching platform in the main series.

@cpunion
cpunion marked this pull request as draft August 3, 2026 02:50
@cpunion
cpunion force-pushed the codex/linux-amd64-dwarf-locations-20260730 branch from 919cea3 to 58a7933 Compare August 9, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

debug: preserve variable locations on Linux/amd64

1 participant