https://github.com/OCHyams updated https://github.com/llvm/llvm-project/pull/194860
>From c2eecc25d5663a2a0fe77816055cd8d38e0ce9ae Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams <[email protected]> Date: Thu, 2 Apr 2026 15:49:06 +0100 Subject: [PATCH 1/4] [dyndbg][Clang] Implement nested-ELF dynamic debugging support A clone of the module is compiled without optimisations and embedded into the to-be-optimised module using embedBufferInModule, similarly to how -ffat-lto-objects and -fembed-offload-object work. That unoptimised-code object is embedded in the optimised-code object in a section called .debug_llvm_dyndbg. The optimised ELF/module may be referred to as the "outer" ELF/module, and the unoptimized one the "inner" ELF/module. The outer module holds global data referred to by both modules and all calls in the inner module are to outer module functions. To facilitate this the outer module is modified, adding external-linkage aliases for local symbols. See https://discourse.llvm.org/t/90113 for more detail (including a diagram). --- clang/include/clang/Basic/CodeGenOptions.h | 3 + clang/include/clang/Basic/DebugOptions.def | 7 ++ .../clang/Basic/DiagnosticDriverKinds.td | 4 + .../clang/Basic/DiagnosticFrontendKinds.td | 4 + clang/include/clang/Options/Options.td | 18 ++++ clang/lib/CodeGen/BackendUtil.cpp | 85 +++++++++++++++++++ clang/lib/Driver/ToolChains/Clang.cpp | 27 ++++++ clang/lib/Frontend/CompilerInvocation.cpp | 6 ++ .../DynamicDebugging/EndToEnd/X86/globalopt.c | 24 ++++++ .../EndToEnd/X86/lit.local.cfg | 4 + .../X86/obj-emission-target/lit.local.cfg | 3 + .../X86/obj-emission-target/no-target.c | 14 +++ .../DynamicDebugging/EndToEnd/X86/section.c | 13 +++ .../attr-outer-no-specialization.c | 7 ++ .../attr-outer-tail-pad-unsupported.c | 9 ++ .../DynamicDebugging/attr-outer-tail-pad.c | 10 +++ .../DynamicDebugging/compiler-used.cpp | 37 ++++++++ clang/test/DebugInfo/DynamicDebugging/embed.c | 12 +++ .../DebugInfo/DynamicDebugging/inner-attrs.c | 25 ++++++ .../DynamicDebugging/symbols-functions.cpp | 33 +++++++ .../DynamicDebugging/symbols-globals.cpp | 72 ++++++++++++++++ .../symbols-internal-comdat.cpp | 27 ++++++ clang/test/Driver/dynamic-debugging-flags.c | 28 ++++++ clang/test/Misc/warning-flags.c | 4 +- 24 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg create mode 100644 clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg create mode 100644 clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp create mode 100644 clang/test/DebugInfo/DynamicDebugging/embed.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/inner-attrs.c create mode 100644 clang/test/DebugInfo/DynamicDebugging/symbols-functions.cpp create mode 100644 clang/test/DebugInfo/DynamicDebugging/symbols-globals.cpp create mode 100644 clang/test/DebugInfo/DynamicDebugging/symbols-internal-comdat.cpp create mode 100644 clang/test/Driver/dynamic-debugging-flags.c diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 9454f7672b7e1..5afc27beaa923 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -359,6 +359,9 @@ class CodeGenOptions : public CodeGenOptionsBase { /// Prefix to use for -save-temps output. std::string SaveTempsFilePrefix; + /// Prefix to use for -save-dynamic-debugging-temps output. + std::string SaveDynDbgTempsFilePrefix; + /// Name of file passed with -fcuda-include-gpubinary option to forward to /// CUDA runtime back-end for incorporating them into host-side object file. std::string CudaGpuBinaryFileName; diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def index 604e87e615a69..b2fa50a289da9 100644 --- a/clang/include/clang/Basic/DebugOptions.def +++ b/clang/include/clang/Basic/DebugOptions.def @@ -62,6 +62,13 @@ ENUM_DEBUGOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2, /// Whether or not to use Key Instructions to determine breakpoint locations. DEBUGOPT(DebugKeyInstructions, 1, 0, Benign) +/// Whether or not to use the Dynamic Debugging feature. +DEBUGOPT(DynamicDebugging, 1, 0, Benign) + +/// Flag for testing: discard the dynamic debugging debug module before codegen +/// if true. +DEBUGOPT(DiscardDynamicDebuggingDebugModule, 1, 0, Benign) + DEBUGOPT(DebugColumnInfo, 1, 0, Compatible) ///< Whether or not to use column information ///< in debug info. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ed6a9107002af..def5e194053d6 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -390,6 +390,10 @@ def err_drv_optimization_remark_format : Error< def err_drv_no_neon_modifier : Error<"[no]neon is not accepted as modifier, please use [no]simd instead">; def err_drv_invalid_omp_target : Error<"OpenMP target is invalid: '%0'">; def err_drv_incompatible_omp_arch : Error<"OpenMP target architecture '%0' pointer size is incompatible with host '%1'">; +def err_drv_dyndbg_lto : Error<"'-fdynamic-debugging' incompatible with '-flto'">; +def err_drv_dyndbg_incompatible : Error<"'-fdynamic-debugging' incompatible with '%0'">; +def err_drv_dyndbg_ir : Error<"'-fdynamic-debugging' incompatible with IR input">; +def warn_drv_dyndbg_req_debug : Warning<"'-fdynamic-debugging' ignored: requires debug info">; def err_drv_omp_host_target_not_supported : Error< "target '%0' is not a supported OpenMP host target">; def err_drv_expecting_fopenmp_with_fopenmp_targets : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 62b74574102e4..793f21e7ded57 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -508,4 +508,8 @@ def err_cir_to_cir_transform_failed : Error< def err_cir_verification_failed_pre_passes : Error< "CIR module verification error before running CIR-to-CIR passes">, DefaultFatal; + +def warn_dyndbg_unable_to_create_target : Warning< + "ignoring -fdynamic-debugging: unable to create target: '%0'">; } + diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 412683fd968b0..534c9b0542726 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5182,6 +5182,24 @@ defm key_instructions : BoolGOption<"key-instructions", " in some debuggers. DWARF only.">, BothFlags<[], [ClangOption, CLOption, CC1Option]>>, Group<g_flags_Group>; +defm dynamic_debugging : BoolOption<"f", "dynamic-debugging", + CodeGenOpts<"DynamicDebugging">, DefaultFalse, + NegFlag<SetFalse>, PosFlag<SetTrue, [], [], + "Enable Dynamic Debugging, which allows runtime switching between" + " optimized and unoptimized code in debuggers that support it." + " Specified optimization level affects only the optimized code." + " This flag inhibits interprocedural optimizations.">, + BothFlags<[], [ClangOption, CLOption, CC1Option]>>; +def save_dynamic_debugging_temps : Flag<["--"], "save-dynamic-debugging-temps">, + Visibility<[ClangOption, CLOption, CC1Option]>, + HelpText<"Compiler-debugging/testing option to save the intermediate" + " states of dynamic debugging in the same directory as the final" + " output file">; +def discard_dynamic_debugging_debug_module : Flag<["--"], "discard-dynamic-debugging-debug-module">, + MarshallingInfoFlag<CodeGenOpts<"DiscardDynamicDebuggingDebugModule">>, + Visibility<[CC1Option]>, + HelpText<"Compiler-debugging/testing option to discard the dynamic" + " debugging debug module before Clang codegen">; def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">; def help : Flag<["-", "--"], "help">, Visibility<[ClangOption, CC1Option, CC1AsOption, diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 5b8b4083c2ac0..22e77dfdbd643 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -90,6 +90,7 @@ #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/JumpThreading.h" #include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/DynamicDebugging.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include <limits> #include <memory> @@ -1471,6 +1472,90 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, } } + + bool EnableDynamicDebugging = CGOpts.DynamicDebugging; + // Disable dyndbg if the target isn't available as we're compiling to the + // inner module to object regardless of other options. (This may change). + if (EnableDynamicDebugging) { + std::string Error; + const llvm::Target *TheTarget = + TargetRegistry::lookupTarget(M->getTargetTriple(), Error); + if (!TheTarget) { + Diags.Report(diag::warn_dyndbg_unable_to_create_target) << Error; + EnableDynamicDebugging = false; + } + } + + if (EnableDynamicDebugging) { + /// Helper for saving the module(s) at various dyndbg stages. + auto SaveModule = [&](StringRef Name, llvm::Module &M) { + if (CGOpts.SaveDynDbgTempsFilePrefix == "") + return; + std::error_code EC; + std::string Path = + Twine(CGOpts.SaveDynDbgTempsFilePrefix + "." + Name + ".ll").str(); + raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::OF_None); + if (EC) { + // Copy -save-temps behaviour: this is a debugging option so we simply + // exit if there's an issue. + errs() << "failed to open " << Path << ": " << EC.message() << '\n'; + errs().flush(); + exit(1); + } + M.print(OS, nullptr); + }; + + // Compute a hash suffix for promoting static globals (once per TU). + std::string PromotionSuffix; + { + // LLVM's hash/hash_combine is not guaranteed to be stable. + MD5 Hash; + // Include args in the hash else preprocessor definitions used to alter + // the same source file compiled twice won't generate unique hashes. + Hash.update(CGOpts.CmdArgs); + for (auto *CU : M->debug_compile_units()) { + Hash.update(CU->getDirectory()); + Hash.update(CU->getFilename()); + } + + MD5::MD5Result Result; + Hash.final(Result); + PromotionSuffix = ".dyndbg." + utohexstr(Result.low()); + } + + SaveModule("dyndbg.0.input", *M); + // Modify M as needed and create an "unoptimized" clone. + auto UnoptM = prepareForDynamicDebugging(M, PromotionSuffix); + SaveModule("dyndbg.1.inner", *UnoptM); + + if (!CGOpts.DiscardDynamicDebuggingDebugModule) { + CodeGenOptions UnoptOpts = CGOpts; + UnoptOpts.OptimizationLevel = 0; + UnoptOpts.OptimizeSize = 0; + EmitAssemblyHelper AsmHelper(CI, UnoptOpts, UnoptM.get(), VFS); + + // Create a buffer and ostream for the inner ELF. + SmallVector<char, 0> UnoptBuf; + std::unique_ptr<llvm::raw_pwrite_stream> UnoptOS = + std::make_unique<llvm::raw_svector_ostream>(UnoptBuf); + + // Always run the full codegen pipeline (Backend_EmitObj). This causes + // assertion failures if there's no registered backend which is why we + // disable the feature if that's the case (see + // warn_dyndbg_unable_to_create_target above). + AsmHelper.emitAssembly(Backend_EmitObj, std::move(UnoptOS), BC); + assert(!UnoptBuf.empty() && "Expected emitAssembly to fill UnoptBuf"); + + // Inject the inner ELF into the outer module. + StringRef SR(UnoptBuf.data(), UnoptBuf.size()); + std::unique_ptr<MemoryBuffer> Buf = + MemoryBuffer::getMemBuffer(SR, "", false); + + llvm::embedBufferInModule(*M, *Buf, ".debug_llvm_dyndbg"); + } + SaveModule("dyndbg.2.outer", *M); + } + EmitAssemblyHelper AsmHelper(CI, CGOpts, M, VFS); AsmHelper.emitAssembly(Action, std::move(OS), BC); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 6b3654d4b2526..673486e633b80 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4665,6 +4665,30 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, options::OPT_gno_structor_decl_linkage_names, true)) CmdArgs.push_back("-gno-structor-decl-linkage-names"); + if (Args.hasFlag(options::OPT_fdynamic_debugging, + options::OPT_fno_dynamic_debugging, false)) { + // As this is an experimental feature we can afford to be strict about + // supported configurations. + if (!TC.getTriple().isX86()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_fdynamic_debugging)->getAsString(Args) + << T.getTriple(); + if (D.isUsingLTO()) + D.Diag(diag::err_drv_dyndbg_lto); + if (DwarfFission != DwarfFissionKind::None) + D.Diag(diag::err_drv_dyndbg_incompatible) + << Args.getLastArg(options::OPT_gsplit_dwarf)->getAsString(Args); + // There's no fundamental reason why IR input should be incompatible, but + // it would add some complexity, and reducing the test matrix is valuable. + if (IRInput) + D.Diag(diag::err_drv_dyndbg_ir); + + if (!EmitDwarf) + D.Diag(diag::warn_drv_dyndbg_req_debug); + else + CmdArgs.push_back("-fdynamic-debugging"); + } + if (EmitCodeView) { CmdArgs.push_back("-gcodeview"); @@ -5358,6 +5382,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.getLastArg(options::OPT_save_temps_EQ)) Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); + if (Args.getLastArg(options::OPT_save_dynamic_debugging_temps)) + Args.AddLastArg(CmdArgs, options::OPT_save_dynamic_debugging_temps); + auto *MemProfArg = Args.getLastArg(options::OPT_fmemory_profile, options::OPT_fmemory_profile_EQ, options::OPT_fno_memory_profile); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 748c36efefaed..2dc70798f1ff3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1670,6 +1670,9 @@ void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, if (Opts.SaveTempsFilePrefix == OutputFile) GenerateArg(Consumer, OPT_save_temps_EQ, "obj"); + if (!Opts.SaveDynDbgTempsFilePrefix.empty()) + GenerateArg(Consumer, OPT_save_dynamic_debugging_temps); + StringRef MemProfileBasename("memprof.profraw"); if (!Opts.MemoryProfileOutput.empty()) { if (Opts.MemoryProfileOutput == MemProfileBasename) { @@ -2004,6 +2007,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, .Case("obj", OutputFile) .Default(llvm::sys::path::filename(OutputFile).str()); + if (Arg *A = Args.getLastArg(OPT_save_dynamic_debugging_temps)) + Opts.SaveDynDbgTempsFilePrefix = OutputFile; + // The memory profile runtime appends the pid to make this name more unique. const char *MemProfileBasename = "memprof.profraw"; if (Args.hasArg(OPT_fmemory_profile_EQ)) { diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c new file mode 100644 index 0000000000000..4450bd8aae5e2 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/globalopt.c @@ -0,0 +1,24 @@ +// Check `a` and `d` have aliases while keeping their original symbols. +// GlobalOpt would usually replace these internal-linkage functions with +// their external-linkage aliases. That's currently prevented as a side effect +// of adding discardable functions to the compiler-used global. + +// RUN: %clang -cc1 %s -emit-obj -O3 -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown | llvm-nm - | FileCheck %s +// CHECK: t a +// CHECK: T a.dyndbg.[[hash:[A-Z0-9]+]] +// CHECK: T b +// CHECK: U c +// CHECK: t d +// CHECK: T d.dyndbg.[[hash]] +// CHECK: B g + +int g; +int c(); + +__attribute__((always_inline)) +static inline int d() { return c(); } + +__attribute__((always_inline)) +static int a() { return g; } + +int b() { return a() + d() ;} diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg new file mode 100644 index 0000000000000..bf8bd32700a9d --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/lit.local.cfg @@ -0,0 +1,4 @@ +# These tests require x86 in order to inspect the inner object. +# FIXME: These tests are quite broad. +if "x86-registered-target" not in config.available_features: + config.unsupported = True diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg new file mode 100644 index 0000000000000..d36760917851d --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/lit.local.cfg @@ -0,0 +1,3 @@ +# This test wants X86 support without aarch64 support. +if "x86-registered-target" not in config.available_features or "aarch64-registered-target" in config.available_features: + config.unsupported = True diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c new file mode 100644 index 0000000000000..b5af3a3b7ac9c --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/obj-emission-target/no-target.c @@ -0,0 +1,14 @@ +// Check we get a warning if -fdynamic-debugging is specified for an +// unsupported target. Dynamic debugging currently emits the inner module as +// an object regardless of output flags (e.g. -emit-llvm). + +// RUN: %clang -cc1 %s -emit-llvm -debug-info-kind=limited -fdynamic-debugging -o - -triple aarch64-unknown-unknown 2>&1 | FileCheck %s --check-prefix=WITHOUT_TARGET +// WITHOUT_TARGET: warning: ignoring -fdynamic-debugging: unable to create target: 'No available targets are compatible with triple "aarch64-unknown-unknown"' +// WITHOUT_TARGET-NOT: .debug_llvm_dyndbg + +// Prevent rotten green test by checking we do see .debug_llvm_dyndbg otherwise. +// RUN: %clang -cc1 %s -emit-obj -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown 2>&1 | FileCheck %s --check-prefix=WITH_TARGET +// WITH_TARGET-NOT: ignoring -fdynamic-debugging: +// WITH_TARGET: .debug_llvm_dyndbg + +int g; diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c new file mode 100644 index 0000000000000..2f0f9a95c199a --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c @@ -0,0 +1,13 @@ +// By default LLVM gives this section SHF_EXCLUDE, which we don't want. + +// RUN: %clang -cc1 %s -emit-obj -debug-info-kind=limited -fdynamic-debugging -o - -triple x86_64-unknown-unknown | llvm-readelf --section-details - \ +// RUN: | FileCheck %s +// [Nr] Name +// CHECK: .debug_llvm_dyndbg +// Type Address Off Size ES Lk Inf Al +// CHECK-NEXT: PROGBITS 0000000000000000 {{[0-9a-z]+}} {{[0-9a-z]+}} 00 0 0 1 +// Flags +// CHECK-NEXT: [0000000000000000]: {{$}} + +int g; +int b() { return g; } diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c new file mode 100644 index 0000000000000..94fe0b7499df0 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-no-specialization.c @@ -0,0 +1,7 @@ +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o - \ +// RUN: -emit-llvm --discard-dynamic-debugging-debug-module \ +// RUN: | FileCheck %s + +// CHECK: define dso_local i32 @f() #0 +// CHECK: attributes #0 = {{{.*}}"no-func-spec"{{.*}}} +int f() { return 0; } diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c new file mode 100644 index 0000000000000..5d03e43109725 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad-unsupported.c @@ -0,0 +1,9 @@ +// REQUIRES: !x86-registered-target +// This test should trip to remind that tail-padding support should be added +// for targets as dynamic debugging support is expanded. +// RUN: %clang -cc1 %s -triple %itanium_abi_triple -debug-info-kind=constructor -fdynamic-debugging -o - \ +// RUN: -emit-llvm --discard-dynamic-debugging-debug-module \ +// RUN: | FileCheck %s + +// CHECK: "tail-pad-to-size" +int f() { return 0; } diff --git a/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c new file mode 100644 index 0000000000000..045374a34b936 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/attr-outer-tail-pad.c @@ -0,0 +1,10 @@ +// RUN: %clang -cc1 %s -triple %itanium_abi_triple -debug-info-kind=constructor -fdynamic-debugging -o - \ +// RUN: -emit-llvm --discard-dynamic-debugging-debug-module \ +// RUN: | FileCheck %s --check-prefix=X86 + +/// FIXME: Add negative tests for other targets (if in doubt, don't tail-pad). + +/// Pad functions to minimum of 5 bytes for insertion of 32 rel jump. +// X86: define dso_local i32 @f() #0 +// X86: attributes #0 = {{{.*}}"tail-pad-to-size"="5"{{.*}}"tail-pad-value"="144"{{.*}}} +int f() { return 0; } diff --git a/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp b/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp new file mode 100644 index 0000000000000..25e1eec4bd84f --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/compiler-used.cpp @@ -0,0 +1,37 @@ +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t \ +// RUN: -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module +// RUN: FileCheck %s --check-prefix=OUTER < %t.dyndbg.2.outer.ll + +// Test discardable symbols are added to the @llvm.compiler.used global, +// which prevents them being discarded (including by globalopt replacing) them +// with their external linkage aliases. + +// OUTER: @llvm.compiler.used = appending global [[[#]] x ptr] +// OUTER-SAME: [ +// OUTER-SAME: ptr @__cxx_global_var_init, +// OUTER-SAME: ptr @_ZL12internal_funv, +// OUTER-SAME: ptr @_Z14internal_fun_2v, +// OUTER-SAME: ptr @_GLOBAL__sub_I_compiler_used.cpp, +// OUTER-SAME: ptr @_ZL12used_by_init, +// OUTER-SAME: ptr @odrweak, +// OUTER-SAME: ptr @_ZL8internal, +// OUTER-SAME: ptr @_ZZ14internal_fun_2vE8internal +// OUTER-SAME: ], +// OUTER-SAME: section "llvm.metadata" + +// 'external' has external linkage; it's not discardable if unused, so it +// doesn't need to be added to compiler-used. +int external = 1; +// 'odrweak' and 'internal' are both discardable and may be only referenced +// from the inner module, so we must keep them. +inline int odrweak = 2; +static int internal = 1; +// 'unused_internal' has internal linkage and is unused so we don't need to +// preserve it (it isn't referenced by the outer or inner module). +static int internal_fun() { static int unused_internal = 0; return 0; } +inline int internal_fun_2() { static int internal = 0; return internal; } + +// Use those globals so they're not omitted by Clang. Don't use [[gnu::used]] +// because that populates the compiler-used global. This global itself is +// unused in user code but it _is_ used in __cxx_global_var_init. +static int used_by_init = external + odrweak + internal + internal_fun() + internal_fun_2(); diff --git a/clang/test/DebugInfo/DynamicDebugging/embed.c b/clang/test/DebugInfo/DynamicDebugging/embed.c new file mode 100644 index 0000000000000..969c2b581f913 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/embed.c @@ -0,0 +1,12 @@ +// REQUIRES: x86-registered-target +// Requires X86 as this test runs the codegen pipeline for the debug module. +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t --save-dynamic-debugging-temps +// RUN: FileCheck %s < %t.dyndbg.2.outer.ll + +// Test that a dynamic debugging section is embedded in the outer module. Note +// that !exclude is ignored by LLVM as this section's flags are chosen based +// on its name. FIXME: We could introduce new metadata like !exclude to avoid +// the special casing in LLVM. +int e() { return 0; } + +// CHECK: @llvm.embedded.object = private constant {{.*}}, section ".debug_llvm_dyndbg", align 1, !exclude diff --git a/clang/test/DebugInfo/DynamicDebugging/inner-attrs.c b/clang/test/DebugInfo/DynamicDebugging/inner-attrs.c new file mode 100644 index 0000000000000..7f7cc849d7776 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/inner-attrs.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple %itanium_abi_triple %s -Os -debug-info-kind=constructor -fdynamic-debugging -o %t \ +// RUN: -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module +// RUN: FileCheck %s --check-prefix=INPUT < %t.dyndbg.0.input.ll +// RUN: FileCheck %s --check-prefix=INNER < %t.dyndbg.1.inner.ll + +/// always_inline should be removed from the inner module. +__attribute__((always_inline)) void a() { } +__attribute__((minsize)) void b() { } + +/// Confirm the input module has alwaysinline, minsize, optsize. +// INPUT: define dso_local void @a() #0 +// INPUT: define dso_local void @b() #1 +// INPUT: attributes #0 = { alwaysinline nounwind optsize " +// INPUT: attributes #1 = { minsize nounwind optsize " + +/// Check the inner module has noinline and optnone added to its copies of the +/// outer functions, removing alwaysinline, minsize, optsize. +// INNER: define dso_local void @__dyndbg.a() #0 +// INNER: define dso_local void @__dyndbg.b() #0 +// INNER: declare dso_local void @a() #1 +// INNER: declare dso_local void @b() #2 +// INNER: attributes #0 = { noinline nounwind optnone " +/// Inner's references to outer's functions keep their original attributes. +// INNER: attributes #1 = { alwaysinline nounwind optsize " +// INNER: attributes #2 = { minsize nounwind optsize " diff --git a/clang/test/DebugInfo/DynamicDebugging/symbols-functions.cpp b/clang/test/DebugInfo/DynamicDebugging/symbols-functions.cpp new file mode 100644 index 0000000000000..0a9c5a73153b5 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/symbols-functions.cpp @@ -0,0 +1,33 @@ +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t \ +// RUN: -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module +// RUN: FileCheck %s --check-prefix=INNER < %t.dyndbg.1.inner.ll +// RUN: FileCheck %s --check-prefix=OUTER < %t.dyndbg.2.outer.ll + +/// Test functions get expected linkage and names in the dyndbg inner +/// and outer modules. Each outer (to-be-optimized) function should have a +/// corresponding inner (unoptimized) version. +/// +/// The internal functions get external aliases in outer. + +// OUTER: $_Z7odrweakv = comdat any +// INNER: $__dyndbg._Z7odrweakv = comdat any + +/// Outer: as input. Inner: external reference, __dyndbg copy. +void external() {} +// OUTER-DAG: define dso_local void @_Z8externalv() +// INNER-DAG: declare dso_local void @_Z8externalv() +// INNER-DAG: define dso_local void @__dyndbg._Z8externalv() + +/// Outer: add external linkage alias. Inner: external reference to alias, +/// __dyndbg copy. +[[gnu::used]] static void internal() {} +// OUTER-DAG: @_ZL8internalv.dyndbg.[[hash:[0-9A-Z]+]] = hidden alias void (), ptr @_ZL8internalv +// OUTER-DAG: define internal void @_ZL8internalv() +// INNER-DAG: declare hidden void @_ZL8internalv.dyndbg.[[hash:[0-9A-Z]+]]() +// INNER-DAG: define hidden void @__dyndbg._ZL8internalv.dyndbg.[[hash]] + +/// Outer: as input. Inner: external reference, __dyndbg copy. +[[gnu::used]] inline void odrweak() {} +// OUTER-DAG: define linkonce_odr void @_Z7odrweakv() +// INNER-DAG: declare void @_Z7odrweakv() +// INNER-DAG: define linkonce_odr void @__dyndbg._Z7odrweakv() diff --git a/clang/test/DebugInfo/DynamicDebugging/symbols-globals.cpp b/clang/test/DebugInfo/DynamicDebugging/symbols-globals.cpp new file mode 100644 index 0000000000000..be299c0262665 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/symbols-globals.cpp @@ -0,0 +1,72 @@ +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t \ +// RUN: -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module +// RUN: FileCheck %s --check-prefix=INNER < %t.dyndbg.1.inner.ll +// RUN: FileCheck %s --check-prefix=OUTER < %t.dyndbg.2.outer.ll + +// Test global variables get expected linkage and names in the dyndbg inner +// and outer modules. Global data is stored in the outer module and referenced +// from the inner module. +// +// The external global variables are simply referenced by inner. +// +// The internal (static) global variables get external aliases in outer +// and those are referenced from inner. +// +// The internal functions _ZTW1d (thread-local wrapper routine for d) and +// _GLOBAL__sub_I_symbols_globals, __cxx_global_var_init are promoted too (get +// global aliases). + +int a = 1; +// OUTER-DAG: @a = global i32 1, align 4 +// INNER-DAG: @a = external global i32, align 4 + +extern int b; +// OUTER-DAG: @b = external global i32, align 4 +// INNER-DAG: @b = external global i32, align 4 + +inline int c = 2; +// OUTER-DAG: $c = comdat any +// OUTER-DAG: @c = linkonce_odr global i32 2, comdat, align 4 +// INNER-DAG: @c = external global i32, align 4 + +thread_local int d = 3; +// OUTER-DAG: @d = thread_local global i32 3, align 4 +// INNER-DAG: @d = external thread_local global i32, align 4 +// +// OUTER-DAG: $_ZTW1d = comdat any +// OUTER-DAG: define weak_odr hidden noundef ptr @_ZTW1d() #[[#]] comdat +// INNER-DAG: $__dyndbg._ZTW1d = comdat any +// INNER-DAG: declare hidden noundef ptr @_ZTW1d() +// INNER-DAG: define weak_odr hidden noundef ptr @__dyndbg._ZTW1d() #[[#]] comdat + +struct S { int a, b; float c, d; } e {0, 100, 4.f, 5.f}; +// OUTER-DAG: @e = global %struct.S { i32 0, i32 100, float 4.000000e+00, float 5.000000e+00 }, align 4 +// INNER-DAG: @e = external global %struct.S, align 4 + +inline S f {0, 100, 4.f, 5.f}; +// OUTER-DAG: $f = comdat any +// OUTER-DAG: @f = linkonce_odr global %struct.S { i32 0, i32 100, float 4.000000e+00, float 5.000000e+00 }, comdat, align 4 +// INNER-DAG: @f = external global %struct.S, align 4 + +int fun() { + static int g = 0; + return g; +} +// OUTER-DAG: @_ZZ3funvE1g = internal global i32 0, align 4 +// OUTER-DAG: @_ZZ3funvE1g.dyndbg.[[hash:[0-9A-Z]+]] = hidden alias i32, ptr @_ZZ3funvE1g +// INNER-DAG: @_ZZ3funvE1g.dyndbg.[[hash:[0-9A-Z]+]] = external hidden global i32, align 4 + +static int h = 1; +// OUTER-DAG: @_ZL1h = internal global i32 1, align 4 +// OUTER-DAG: @_ZL1h.dyndbg.[[hash]] = hidden alias i32, ptr @_ZL1h +// INNER-DAG: @_ZL1h.dyndbg.[[hash]] = external hidden global i32, align 4 + +__attribute__((nodebug)) int use = a + b + c + d + e.a + f.a + h; + +// OUTER-DAG: define internal void @__cxx_global_var_init() +// OUTER-DAG: @__cxx_global_var_init.dyndbg.[[hash]] = hidden alias void (), ptr @__cxx_global_var_init +// INNER-DAG: declare hidden void @__cxx_global_var_init.dyndbg.[[hash]]() + +// OUTER-DAG: define internal void @_GLOBAL__sub_I_symbols_globals.cpp() +// OUTER-DAG: @_GLOBAL__sub_I_symbols_globals.cpp.dyndbg.[[hash]] = hidden alias void (), ptr @_GLOBAL__sub_I_symbols_globals.cpp +// INNER-DAG: define hidden void @__dyndbg._GLOBAL__sub_I_symbols_globals.cpp.dyndbg.[[hash]]() #[[#]] diff --git a/clang/test/DebugInfo/DynamicDebugging/symbols-internal-comdat.cpp b/clang/test/DebugInfo/DynamicDebugging/symbols-internal-comdat.cpp new file mode 100644 index 0000000000000..515602b140821 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/symbols-internal-comdat.cpp @@ -0,0 +1,27 @@ +// RUN: %clang -cc1 -triple %itanium_abi_triple %s -debug-info-kind=limited -fdynamic-debugging -o %t \ +// RUN: -emit-llvm --save-dynamic-debugging-temps --discard-dynamic-debugging-debug-module +// RUN: FileCheck %s --check-prefix=INNER < %t.dyndbg.1.inner.ll --implicit-check-not=@__dyndbg._ZN1X5weirdE +// RUN: FileCheck %s --check-prefix=OUTER < %t.dyndbg.2.outer.ll + +/// Check that internal symbols in comdats, __cxx_global_var_init in this case, +/// are not promoted (no external alias is produced). +/// +/// --implicit-check-not=@__dyndbg._ZN1X5weirdE: +/// The innner cxx_global_var_init gets a comdat, '$__dyndbg._ZN1X5weirdE', but +/// unlike the one in the outer module, this one has no associated global data. + +// OUTER: @_ZN1X5weirdE = linkonce_odr global %struct.X zeroinitializer, comdat, align 4 +// INNER: @_ZN1X5weirdE = external global %struct.X, align 4 + +// OUTER: define internal void @__cxx_global_var_init() {{.*}} comdat($_ZN1X5weirdE) +// INNER: define internal void @__dyndbg.__cxx_global_var_init() {{.*}} comdat($__dyndbg._ZN1X5weirdE) +// INNER: declare dso_local void @__cxx_global_var_init() + +struct X { +public: + X(int a) : a(a) {} + int a; + static const X weird; +}; + +inline const X X::weird = X(5); diff --git a/clang/test/Driver/dynamic-debugging-flags.c b/clang/test/Driver/dynamic-debugging-flags.c new file mode 100644 index 0000000000000..bf58a4250c63b --- /dev/null +++ b/clang/test/Driver/dynamic-debugging-flags.c @@ -0,0 +1,28 @@ +// Only support x86_64 targets initially. +// RUN: not %clang -c -target aarch64-unknown-unknown -g -fdynamic-debugging -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-TARGET-ERR +// RUN: %clang -c -target x86_64-unknown-unknown -g -fdynamic-debugging -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-OK +// CHECK-TARGET-ERR: error: unsupported option '-fdynamic-debugging' for target 'aarch64-unknown-unknown' + +// Do not support LTO initially. +// RUN: not %clang -c -target x86_64-unknown-unknown -g -fdynamic-debugging -flto -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-LTO-ERR +// RUN: not %clang -c -target x86_64-unknown-unknown -g -fdynamic-debugging -flto=full -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-LTO-ERR +// RUN: not %clang -c -target x86_64-unknown-unknown -g -fdynamic-debugging -flto=thin -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-LTO-ERR +// RUN: %clang -c -target x86_64-unknown-unknown -g -fdynamic-debugging -flto -fno-lto -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-OK +// CHECK-LTO-ERR: clang: error: '-fdynamic-debugging' incompatible with '-flto' + +// Do not support split dwarf. +// RUN: not %clang -c -target x86_64-unknown-unknown -fdynamic-debugging -g -gsplit-dwarf -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-DWO-ERR +// RUN: %clang -c -target x86_64-unknown-unknown -fdynamic-debugging -g -gsplit-dwarf -gno-split-dwarf -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-OK +// CHECK-DWO-ERR: clang: error: '-fdynamic-debugging' incompatible with '-gsplit-dwarf' + +// Do not support llvm IR input. +// RUN: not %clang -c -target x86_64-unknown-unknown -fdynamic-debugging -gsplit-dwarf -### -o /dev/null -x ir %s 2>&1 | FileCheck %s -check-prefix=CHECK-LL-ERR +// CHECK-LL-ERR: clang: error: '-fdynamic-debugging' incompatible with IR input + +// Warning - requires debug info. +// RUN: %clang -c -target x86_64-unknown-unknown -fdynamic-debugging -gsplit-dwarf -### -o /dev/null %s 2>&1 | FileCheck %s -check-prefix=CHECK-DBG-WARN +// CHECK-DBG-WARN: clang: warning: '-fdynamic-debugging' ignored: requires debug info +// CHECK-DBG-WARN-NOT: -fdynamic-debugging + +// CHECK-OK-NOT: error: +// CHECK-OK-NOT: warning: diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c index 3dc4bb55aa69c..17128bb804964 100644 --- a/clang/test/Misc/warning-flags.c +++ b/clang/test/Misc/warning-flags.c @@ -18,7 +18,7 @@ This test serves two purposes: The list of warnings below should NEVER grow. It should gradually shrink to 0. -CHECK: Warnings without flags (56): +CHECK: Warnings without flags (58): CHECK-NEXT: ext_expected_semi_decl_list CHECK-NEXT: ext_missing_whitespace_after_macro_name @@ -42,7 +42,9 @@ CHECK-NEXT: warn_delete_array_type CHECK-NEXT: warn_double_const_requires_fp64 CHECK-NEXT: warn_drv_assuming_mfloat_abi_is CHECK-NEXT: warn_drv_clang_unsupported +CHECK-NEXT: warn_drv_dyndbg_req_debug CHECK-NEXT: warn_drv_pch_not_first_include +CHECK-NEXT: warn_dyndbg_unable_to_create_target CHECK-NEXT: warn_expected_qualified_after_typename CHECK-NEXT: warn_fe_backend_unsupported CHECK-NEXT: warn_fe_cc_log_diagnostics_failure >From e0de5fafc2da75c3fabe4bece9c18560f516269d Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams <[email protected]> Date: Wed, 29 Apr 2026 11:23:18 +0100 Subject: [PATCH 2/4] err on profile-instrumentation --- clang/include/clang/Basic/DiagnosticFrontendKinds.td | 3 +++ clang/lib/CodeGen/BackendUtil.cpp | 9 +++++++++ clang/test/DebugInfo/DynamicDebugging/profile-coverage.c | 7 +++++++ 3 files changed, 19 insertions(+) create mode 100644 clang/test/DebugInfo/DynamicDebugging/profile-coverage.c diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 793f21e7ded57..d624fcb7179cc 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -511,5 +511,8 @@ def err_cir_verification_failed_pre_passes : Error< def warn_dyndbg_unable_to_create_target : Warning< "ignoring -fdynamic-debugging: unable to create target: '%0'">; + +def err_dyndbg_no_instrumentation : Error< + "'-fdynamic-debugging' unsupported with instrumentation (PGO/code coverage)">; } diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 22e77dfdbd643..cf8dbeccdbee1 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1484,6 +1484,15 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, Diags.Report(diag::warn_dyndbg_unable_to_create_target) << Error; EnableDynamicDebugging = false; } + + // Instrumentation causes issues (parts of LLVM expect certain globals to + // have initializers). Intrinsics may already have been added to IR by now, + // so we can't just turn it off for the inner module (we'd have to strip + // them out / not clone them). TODO: Support instrumentation. + if (CGOpts.getProfileInstr() != driver::ProfileInstrKind::ProfileNone) { + Diags.Report(diag::err_dyndbg_no_instrumentation); + EnableDynamicDebugging = false; + } } if (EnableDynamicDebugging) { diff --git a/clang/test/DebugInfo/DynamicDebugging/profile-coverage.c b/clang/test/DebugInfo/DynamicDebugging/profile-coverage.c new file mode 100644 index 0000000000000..a896ea57a8b26 --- /dev/null +++ b/clang/test/DebugInfo/DynamicDebugging/profile-coverage.c @@ -0,0 +1,7 @@ +// Instrumentation from PGO/code coverage isn't supported yet for dyndbg. +// RUN: not %clang_cc1 %s -fprofile-instrument=clang -fdynamic-debugging -emit-llvm \ +// RUN: --discard-dynamic-debugging-debug-module 2>&1 \ +// RUN: | FileCheck %s +// CHECK: error: '-fdynamic-debugging' unsupported with instrumentation (PGO/code coverage) + +int b() { return 0; } >From 01897e2a2b45d2fe2455281418d4c2dca1b86aaf Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams <[email protected]> Date: Wed, 29 Apr 2026 12:51:31 +0100 Subject: [PATCH 3/4] [Clang] Disable dyndbg and sanitizer composition The approach taken is slightly more aggressive than needed. It doesn't allow -fsanitize=undefined -fno-sanitize=undefined for example. --- clang/lib/Driver/ToolChains/Clang.cpp | 4 ++++ clang/test/Driver/dynamic-debugging-flags.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 673486e633b80..962c5ea923990 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4683,6 +4683,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T, if (IRInput) D.Diag(diag::err_drv_dyndbg_ir); + // Disable composition with sanitizers for now. + if (auto *San = Args.getLastArg(options::OPT_fsanitize_EQ)) + D.Diag(diag::err_drv_dyndbg_incompatible) << San->getAsString(Args); + if (!EmitDwarf) D.Diag(diag::warn_drv_dyndbg_req_debug); else diff --git a/clang/test/Driver/dynamic-debugging-flags.c b/clang/test/Driver/dynamic-debugging-flags.c index bf58a4250c63b..dedc9509eeb3d 100644 --- a/clang/test/Driver/dynamic-debugging-flags.c +++ b/clang/test/Driver/dynamic-debugging-flags.c @@ -24,5 +24,9 @@ // CHECK-DBG-WARN: clang: warning: '-fdynamic-debugging' ignored: requires debug info // CHECK-DBG-WARN-NOT: -fdynamic-debugging +// Do not support sanitizers initially. +// RUN: not %clang -fsanitize=undefined -c -target x86_64-unknown-unknown -fdynamic-debugging -### -o /dev/null -x ir %s 2>&1 | FileCheck %s -check-prefix=CHECK-SAN-ERR +// CHECK-SAN-ERR: clang: error: '-fdynamic-debugging' incompatible with '-fsanitize=undefined' + // CHECK-OK-NOT: error: // CHECK-OK-NOT: warning: >From 5c819ffad91372ad72254352e37ff83f5ee0380e Mon Sep 17 00:00:00 2001 From: Orlando Cazalet-Hyams <[email protected]> Date: Thu, 7 May 2026 09:57:22 +0100 Subject: [PATCH 4/4] Align .debug_llvm_dyndbg to 8 bytes --- clang/lib/CodeGen/BackendUtil.cpp | 2 +- clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c | 2 +- clang/test/DebugInfo/DynamicDebugging/embed.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index cf8dbeccdbee1..70516e594d1b5 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -1560,7 +1560,7 @@ void clang::emitBackendOutput(CompilerInstance &CI, CodeGenOptions &CGOpts, std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(SR, "", false); - llvm::embedBufferInModule(*M, *Buf, ".debug_llvm_dyndbg"); + llvm::embedBufferInModule(*M, *Buf, ".debug_llvm_dyndbg", Align(8)); } SaveModule("dyndbg.2.outer", *M); } diff --git a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c index 2f0f9a95c199a..a6ae1e74457e4 100644 --- a/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c +++ b/clang/test/DebugInfo/DynamicDebugging/EndToEnd/X86/section.c @@ -5,7 +5,7 @@ // [Nr] Name // CHECK: .debug_llvm_dyndbg // Type Address Off Size ES Lk Inf Al -// CHECK-NEXT: PROGBITS 0000000000000000 {{[0-9a-z]+}} {{[0-9a-z]+}} 00 0 0 1 +// CHECK-NEXT: PROGBITS 0000000000000000 {{[0-9a-z]+}} {{[0-9a-z]+}} 00 0 0 8 // Flags // CHECK-NEXT: [0000000000000000]: {{$}} diff --git a/clang/test/DebugInfo/DynamicDebugging/embed.c b/clang/test/DebugInfo/DynamicDebugging/embed.c index 969c2b581f913..a621e05378196 100644 --- a/clang/test/DebugInfo/DynamicDebugging/embed.c +++ b/clang/test/DebugInfo/DynamicDebugging/embed.c @@ -9,4 +9,4 @@ // the special casing in LLVM. int e() { return 0; } -// CHECK: @llvm.embedded.object = private constant {{.*}}, section ".debug_llvm_dyndbg", align 1, !exclude +// CHECK: @llvm.embedded.object = private constant {{.*}}, section ".debug_llvm_dyndbg", align 8, !exclude _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
