Index: docs/ClangCommandLineReference.rst =================================================================== --- docs/ClangCommandLineReference.rst +++ docs/ClangCommandLineReference.rst @@ -792,6 +792,16 @@ .. option:: -fparse-all-comments +.. option:: -frecord-command-line, -frecord-gcc-switches, -fno-record-command-line, -fno-record-gcc-switches + +Generate a section named ".GCC.command.line" containing the clang driver +command-line. After linking, the section may contain multiple command lines, +which will be individually terminated by null bytes. Separate arguments within +a command line are combined with spaces; spaces and backslashes within an +argument are escaped with backslashes. This format differs from the format of +the equivalent section produced by GCC with the -frecord-gcc-switches flag. +This option is currently only supported on ELF targets. + .. option:: -fsanitize-address-field-padding= Level of field padding for AddressSanitizer @@ -2831,7 +2841,7 @@ .. option:: -gpubnames, -gno-pubnames -.. option:: -grecord-gcc-switches, -gno-record-gcc-switches +.. option:: -grecord-command-line, -grecord-gcc-switches, -gno-record-command-line, -gno-record-gcc-switches .. option:: -gsplit-dwarf Index: include/clang/Basic/CodeGenOptions.h =================================================================== --- include/clang/Basic/CodeGenOptions.h +++ include/clang/Basic/CodeGenOptions.h @@ -148,6 +148,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: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td +++ include/clang/Driver/CC1Options.td @@ -167,6 +167,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 @@ -799,6 +799,12 @@ 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_command_line : Flag<["-"], "frecord-command-line">, + Group; +def fno_record_command_line : Flag<["-"], "fno-record-command-line">, + Group; +def : Flag<["-"], "frecord-gcc-switches">, Alias; +def : Flag<["-"], "fno-record-gcc-switches">, Alias; def fcommon : Flag<["-"], "fcommon">, Group; def fcompile_resource_EQ : Joined<["-"], "fcompile-resource=">, Group; def fcomplete_member_pointers : Flag<["-"], "fcomplete-member-pointers">, Group, @@ -1854,9 +1860,12 @@ def gxcoff : Joined<["-"], "gxcoff">, Group, Flags<[Unsupported]>; def gvms : Joined<["-"], "gvms">, Group, Flags<[Unsupported]>; def gtoggle : Flag<["-"], "gtoggle">, Group, Flags<[Unsupported]>; -def grecord_gcc_switches : Flag<["-"], "grecord-gcc-switches">, Group; -def gno_record_gcc_switches : Flag<["-"], "gno-record-gcc-switches">, +def grecord_command_line : Flag<["-"], "grecord-command-line">, Group; +def gno_record_command_line : Flag<["-"], "gno-record-command-line">, + Group; +def : Flag<["-"], "grecord-gcc-switches">, Alias; +def : Flag<["-"], "gno-record-gcc-switches">, Alias; def gstrict_dwarf : Flag<["-"], "gstrict-dwarf">, Group; def gno_strict_dwarf : Flag<["-"], "gno-strict-dwarf">, Group; def gcolumn_info : Flag<["-"], "gcolumn-info">, Group, Flags<[CoreOption]>; Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1408,6 +1408,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 @@ -590,6 +590,9 @@ if (getCodeGenOpts().EmitVersionIdentMetadata) EmitVersionIdentMetadata(); + if (!getCodeGenOpts().RecordCommandLine.empty()) + EmitCommandLineMetadata(); + EmitTargetMetadata(); } @@ -5210,6 +5213,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 @@ -5063,14 +5063,22 @@ 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() || - Args.hasFlag(options::OPT_grecord_gcc_switches, - options::OPT_gno_record_gcc_switches, false)) { + auto GRecordSwitches = + Args.hasFlag(options::OPT_grecord_command_line, + options::OPT_gno_record_command_line, false); + auto FRecordSwitches = + Args.hasFlag(options::OPT_frecord_command_line, + options::OPT_fno_record_command_line, false); + if (FRecordSwitches && !Triple.isOSBinFormatELF()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << Args.getLastArg(options::OPT_frecord_command_line)->getAsString(Args) + << TripleStr; + if (TC.UseDwarfDebugFlags() || GRecordSwitches || FRecordSwitches) { ArgStringList OriginalArgs; for (const auto &Arg : Args) Arg->render(Args, OriginalArgs); @@ -5083,8 +5091,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 @@ -755,6 +755,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 @@ -542,3 +542,18 @@ // 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 -target x86_64-unknown-linux -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-gcc-switches -frecord-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-gcc-switches -fno-record-gcc-switches %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -fno-record-command-line -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES %s +// RUN: %clang -### -S -target x86_64-unknown-linux -frecord-command-line -fno-record-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-NO-RECORD-GCC-SWITCHES %s +// Test with a couple examples of non-ELF object file formats +// RUN: %clang -### -S -target x86_64-unknown-macosx -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES-ERROR %s +// RUN: %clang -### -S -target x86_64-unknown-windows -frecord-command-line %s 2>&1 | FileCheck -check-prefix=CHECK-RECORD-GCC-SWITCHES-ERROR %s +// CHECK-RECORD-GCC-SWITCHES: "-record-command-line" +// CHECK-NO-RECORD-GCC-SWITCHES-NOT: "-record-command-line" +// CHECK-RECORD-GCC-SWITCHES-ERROR: error: unsupported option '-frecord-command-line' for target Index: test/Driver/debug-options.c =================================================================== --- test/Driver/debug-options.c +++ test/Driver/debug-options.c @@ -157,6 +157,17 @@ // RUN: %clang -### -c -O3 -ffunction-sections -grecord-gcc-switches %s 2>&1 \ // | FileCheck -check-prefix=GRECORD_OPT %s // +// RUN: %clang -### -c -grecord-command-line %s 2>&1 \ +// | FileCheck -check-prefix=GRECORD %s +// RUN: %clang -### -c -gno-record-command-line %s 2>&1 \ +// | FileCheck -check-prefix=GNO_RECORD %s +// RUN: %clang -### -c -grecord-command-line -gno-record-command-line %s 2>&1 \ +// | FileCheck -check-prefix=GNO_RECORD %s/ +// RUN: %clang -### -c -grecord-command-line -o - %s 2>&1 \ +// | FileCheck -check-prefix=GRECORD_O %s +// RUN: %clang -### -c -O3 -ffunction-sections -grecord-command-line %s 2>&1 \ +// | FileCheck -check-prefix=GRECORD_OPT %s +// // RUN: %clang -### -c -gstrict-dwarf -gno-strict-dwarf %s 2>&1 \ // RUN: | FileCheck -check-prefix=GIGNORE %s //