Skip to content

debug: allow supported targets to retain DWARF - #2269

Draft
cpunion wants to merge 1 commit into
xgo-dev:mainfrom
cpunion:codex/debug-artifact-policy-2164-20260801
Draft

debug: allow supported targets to retain DWARF#2269
cpunion wants to merge 1 commit into
xgo-dev:mainfrom
cpunion:codex/debug-artifact-policy-2164-20260801

Conversation

@cpunion

@cpunion cpunion commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Part of #2164.

This is the dependency-tree root change. It keeps target debug-artifact policy explicit without pulling any dependent debugger frontend or runtime changes:

  • model DWARF retention and preserve/omit linker flags as target capabilities;
  • allow supported ELF and Wasm linkers to retain DWARF while preserving the existing default omission policy;
  • keep clang-driver and direct-linker arguments separate;
  • verify that a Cortex-M debug ELF retains DWARF and produces identical flashed .bin bytes to the stripped control.

Validation on the rebased root:

  • GOMAXPROCS=4 go test -timeout=2m ./internal/build -run '^(TestDwarfLinkerArgs|TestDwarfPreserveLinkerArgs|TestEffectiveOmitDWARF|TestShouldEmitDebugInfo|TestValidateLinkOptions|TestDwarfLinkerArgsSuppressNativeInputDWARF|TestTargetDWARFDoesNotChangeLoadableELF|TestCollectFingerprint|TestTargetTripleMethod)$'
  • GOMAXPROCS=4 go test -timeout=2m ./internal/crosscompile

The complete internal/build package has a pre-existing TestRunPrintfWithStdioNobuf hang; it was not used as a root validation gate. Dependent PRs will be submitted one layer at a time after this root is reviewed.

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cpunion
cpunion marked this pull request as ready for review August 3, 2026 01:24
@cpunion

cpunion commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Dependency audit: this root PR has no cpunion predecessor. xgo-dev/main already contains the relevant baseline PRs #2141 (DWARF foundation), #2211 (LLDB launcher/schema), and #2240 (strings/slices runtime views); none are duplicated here. The next cpunion layer (#112) depends on this PR and will not be submitted upstream until this root layer is accepted.

@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 summary

This is a clean, well-tested refactor of DWARF debug-info handling. Replacing the boolean AlwaysOmit with a typed DebugInfoCapability + CanRetain() and splitting PreserveLinkFlags/OmitLinkFlags reads clearly, and the change is backed by thorough unit tests plus a new end-to-end Cortex-M ELF test. No correctness regressions found across code-quality, performance, security, and documentation passes.

Confirmed as correct-by-design:

  • The -S vs -Wl,-S split is intentional: the use() wasm/native path links through the clang driver (-Wl,-S), while targetDebugInfoPolicy (via UseTarget, direct ld.lld/wasm-ld) uses bare -S.
  • Removing the unconditional -S from UseTarget ldflags is safe: omission still flows through OmitDWARFByDefaultdwarfLinkerArgs["-S"] for retainable targets, covered by the fixed target w test.
  • No security concerns: flags are hardcoded constants appended as argv elements (no shell/injection surface); test exec.Command calls use fixed tool names guarded by LookPath.

The findings below are all low-severity maintainability/documentation notes, left inline.

return policy
}

func targetDebugInfoPolicy(linker, llvmTarget string) DebugInfoPolicy {

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.

targetDebugInfoPolicy is only reached via UseTarget, and Use() routes every wasm/wasi target name to use() instead (crosscompile.go:753). All four wasm-ld target JSONs (wasm, wasm-unknown, wasip1, wasip2) start with those prefixes, so the wasm-ld branch here is never exercised by a real build — only by TestTargetDebugInfoPolicy. Not a bug, but worth a one-line comment noting that wasm/wasi are handled by use() and that this branch is currently test-only.

Separately, any unrecognized (linker, llvmTarget) combination silently falls through to DebugInfoUnavailable, which disables DWARF entirely for that target (via !CanRetain() in shouldEmitDebugInfo). Documenting that intentional fail-to-omit default would help the next person adding a target with a different linker.

return
}
export.DebugInfo.OmitLinkFlags = []string{"-Wl,-S"}
export.DebugInfo = DebugInfoPolicy{

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.

This wasm policy literal (PreserveLinkFlags: ["-gdwarf-4"], OmitLinkFlags: ["-Wl,-S"]) is identical to what nativeDebugInfoPolicy produces for darwin/linux. Both represent "link through the clang driver", so consider factoring a shared helper (e.g. driverDebugInfoPolicy()) so the -gdwarf-4 / -Wl,-S pairing lives in one place.

Note this also diverges from the wasm-ld branch in targetDebugInfoPolicy (line 88-90), which uses PreserveLinkFlags: nil / OmitLinkFlags: ["-S"] for the same wasm family — a second reason the flag choice tracks "clang driver vs direct linker invocation", not "linker type".

}

// dwarfPreserveLinkerArgs returns compiler-driver options needed while linking
// a debug artifact. Direct linkers such as ld.lld retain input DWARF without a

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.

The dichotomy here ("direct linkers such as ld.lld ... without a corresponding flag, while clang-compatible drivers accept -gdwarf-4") is slightly oversimplified: the wasm cross-compile path in crosscompile.go:365-368 assigns -gdwarf-4 even though it links with wasm-ld (a direct linker), because linking there goes through the clang driver. The real determinant is whether the invocation goes through the clang driver, not the linker type. Minor wording tweak would make the comment match all paths.

@cpunion
cpunion marked this pull request as draft August 3, 2026 02:50
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.

1 participant