Index: docs/ClangCommandLineReference.rst =================================================================== --- docs/ClangCommandLineReference.rst +++ docs/ClangCommandLineReference.rst @@ -792,6 +792,10 @@ .. option:: -fparse-all-comments +.. option:: -frecord-gcc-switches, -fno-record-gcc-switches + +Generate a section .LLVM.command.line containing the clang driver command line + .. option:: -fsanitize-address-field-padding= Level of field padding for AddressSanitizer Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -161,6 +161,8 @@ HelpText<"The compilation directory to embed in the debug info.">; def dwarf_debug_flags : Separate<["-"], "dwarf-debug-flags">, HelpText<"The string to embed in the Dwarf debug flags record.">; +def record_command_line : Separate<["-"], "record-command-line">, + HelpText<"The string to embed in the .LLVM.command.line section.">; def compress_debug_sections : Flag<["-", "--"], "compress-debug-sections">, HelpText<"DWARF debug sections compression">; def compress_debug_sections_EQ : Joined<["-"], "compress-debug-sections=">, Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -797,6 +797,9 @@ HelpText<"Treat each comma separated argument in as a documentation comment block command">, MetaVarName<"">; def fparse_all_comments : Flag<["-"], "fparse-all-comments">, Group, Flags<[CC1Option]>; +def frecord_gcc_switches : Flag<["-"], "frecord-gcc-switches">, Group; +def fno_record_gcc_switches : Flag<["-"], "fno-record-gcc-switches">, + Group; def fcommon : Flag<["-"], "fcommon">, Group; def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group; def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">, Group, Index: include/clang/Frontend/CodeGenOptions.h =================================================================== --- include/clang/Frontend/CodeGenOptions.h +++ include/clang/Frontend/CodeGenOptions.h @@ -140,6 +140,10 @@ /// non-empty. std::string DwarfDebugFlags; + /// The string containing the commandline for the llvm.commandline metadata, + /// if non-empty. + std::string RecordCommandLine; + std::map DebugPrefixMap; /// The ABI to use for passing floating point arguments. Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1402,6 +1402,9 @@ /// Emit the Clang version as llvm.ident metadata. void EmitVersionIdentMetadata(); + /// Emit the Clang commandline as llvm.commandline metadata. + void EmitCommandLineMetadata(); + /// Emits target specific Metadata for global declarations. void EmitTargetMetadata(); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -587,6 +587,9 @@ if (getCodeGenOpts().EmitVersionIdentMetadata) EmitVersionIdentMetadata(); + if (!getCodeGenOpts().RecordCommandLine.empty()) + EmitCommandLineMetadata(); + EmitTargetMetadata(); } @@ -5189,6 +5192,16 @@ IdentMetadata->addOperand(llvm::MDNode::get(Ctx, IdentNode)); } +void CodeGenModule::EmitCommandLineMetadata() { + llvm::NamedMDNode *CommandLineMetadata = + TheModule.getOrInsertNamedMetadata("llvm.commandline"); + std::string CommandLine = getCodeGenOpts().RecordCommandLine; + llvm::LLVMContext &Ctx = TheModule.getContext(); + + llvm::Metadata *CommandLineNode[] = {llvm::MDString::get(Ctx, CommandLine)}; + CommandLineMetadata->addOperand(llvm::MDNode::get(Ctx, CommandLineNode)); +} + void CodeGenModule::EmitTargetMetadata() { // Warning, new MangledDeclNames may be appended within this loop. // We rely on MapVector insertions adding new elements to the end Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4985,14 +4985,18 @@ const char *Exec = D.getClangProgramPath(); - // Optionally embed the -cc1 level arguments into the debug info, for build - // analysis. + // Optionally embed the -cc1 level arguments into the debug info or a + // section, for build analysis. // Also record command line arguments into the debug info if // -grecord-gcc-switches options is set on. // By default, -gno-record-gcc-switches is set on and no recording. - if (TC.UseDwarfDebugFlags() || + auto GRecordSwitches = Args.hasFlag(options::OPT_grecord_gcc_switches, - options::OPT_gno_record_gcc_switches, false)) { + options::OPT_gno_record_gcc_switches, false); + auto FRecordSwitches = + Args.hasFlag(options::OPT_frecord_gcc_switches, + options::OPT_fno_record_gcc_switches, false); + if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) { ArgStringList OriginalArgs; for (const auto &Arg : Args) Arg->render(Args, OriginalArgs); @@ -5005,8 +5009,15 @@ Flags += " "; Flags += EscapedArg; } - CmdArgs.push_back("-dwarf-debug-flags"); - CmdArgs.push_back(Args.MakeArgString(Flags)); + auto FlagsArgString = Args.MakeArgString(Flags); + if (TC.UseDwarfDebugFlags() || GRecordSwitches) { + CmdArgs.push_back("-dwarf-debug-flags"); + CmdArgs.push_back(FlagsArgString); + } + if (FRecordSwitches) { + CmdArgs.push_back("-record-command-line"); + CmdArgs.push_back(FlagsArgString); + } } // Host-side cuda compilation receives all device-side outputs in a single Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -627,6 +627,7 @@ Args.hasFlag(OPT_ffine_grained_bitfield_accesses, OPT_fno_fine_grained_bitfield_accesses, false); Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags); + Opts.RecordCommandLine = Args.getLastArgValue(OPT_record_command_line); Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Index: test/Driver/clang_f_opts.c =================================================================== --- test/Driver/clang_f_opts.c +++ test/Driver/clang_f_opts.c @@ -538,3 +538,10 @@ // RUN: %clang -### -S -fomit-frame-pointer -fno-omit-frame-pointer -pg %s 2>&1 | FileCheck -check-prefix=CHECK-MIX-NO-OMIT-FP-PG %s // CHECK-NO-MIX-OMIT-FP-PG: '-fomit-frame-pointer' not allowed with '-pg' // CHECK-MIX-NO-OMIT-FP-PG-NOT: '-fomit-frame-pointer' not allowed with '-pg' + +// RUN: %clang -### -S -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -fno-record-gcc-switches -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -frecord-gcc-switches -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// CHECK-RECORD-GCC-SWITCHES: "-record-command-line" +// CHECK-NO-RECORD-GCC-SWITCHES-NOT: "-record-command-line"