dougk created this revision. dougk added reviewers: chandlerc, jyknight. dougk added a subscriber: cfe-commits.
Both the Driver and the cc1 frontend play games with various combinations of 'g' group options. It would be nice if at least the frontend could be sane, leaving the decision of what OS favors dwarf version N totally in the driver's hands. As such, the Driver never passes a bare '-g' option nor lets the CompilerInvocation assume a default dwarf level. Instead, an explicit choices of debug info kind is conveyed from the driver directly into the CodeGen options, and similarly the dwarf level. At present this breaks hundreds of driver tests because they're looking for particular strings, but if people think this is the right way to do things, those tests can be fixed (and perhaps there's a genuine breakage or two, which must be fixed). http://reviews.llvm.org/D13221 Files: include/clang/Driver/Options.td include/clang/Driver/ToolChain.h lib/Driver/ToolChains.h lib/Driver/Tools.cpp lib/Frontend/CompilerInvocation.cpp
Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -393,37 +393,47 @@ Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; } - if (Args.hasArg(OPT_gline_tables_only)) { - Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); - } else if (Args.hasArg(OPT_g_Flag) || Args.hasArg(OPT_gdwarf_2) || - Args.hasArg(OPT_gdwarf_3) || Args.hasArg(OPT_gdwarf_4)) { - bool Default = false; - // Until dtrace (via CTF) and LLDB can deal with distributed debug info, - // Darwin and FreeBSD default to standalone/full debug info. - if (llvm::Triple(TargetOpts.Triple).isOSDarwin() || - llvm::Triple(TargetOpts.Triple).isOSFreeBSD()) - Default = true; - - if (Args.hasFlag(OPT_fstandalone_debug, OPT_fno_standalone_debug, Default)) - Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); - else - Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); + // There are three levels of user-requestable debug info (aside from "none", + // and not counting "location tracking only" which isn't user-requested). + // Use the last of the flags that set any of the three interesting levels. + // In the Driver, "limit-debug-info" is synonymous with "no-standalone-debug", + // but the "no" option name is very confusing as part of a multiway switch. + // Read "limit_debug_info" as "LimitedDebugInfo" and it makes perfect sense. + if (Arg *A = Args.getLastArg(OPT_fstandalone_debug, OPT_flimit_debug_info, + OPT_gline_tables_only)) { + enum CodeGenOptions::DebugInfoKind Kind; + switch (A->getOption().getID()) { + case OPT_fstandalone_debug: + Kind = CodeGenOptions::FullDebugInfo; + break; + case OPT_flimit_debug_info: + Kind = CodeGenOptions::LimitedDebugInfo; + break; + default: + Kind = CodeGenOptions::DebugLineTablesOnly; + break; + } + Opts.setDebugInfo(Kind); } - Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); - if (Args.hasArg(OPT_gcodeview)) { - Opts.EmitCodeView = true; - Opts.DwarfVersion = 0; - } else if (Opts.getDebugInfo() != CodeGenOptions::NoDebugInfo) { - // Default Dwarf version is 4 if we are generating debug information. - Opts.DwarfVersion = 4; + // Dwarf Version is one of {0,2,3,4}. There is no explicit flag for 0. + // It is the assumed default regardless of whether debug info was requested, + // so the driver had better pick one if debug info is to be produced. + if (Arg *A = Args.getLastArg(OPT_gdwarf_4, OPT_gdwarf_3, OPT_gdwarf_2)) { + switch (A->getOption().getID()) { + case OPT_gdwarf_2: + Opts.DwarfVersion = 2; + break; + case OPT_gdwarf_3: + Opts.DwarfVersion = 3; + break; + default: + Opts.DwarfVersion = 4; + break; + } } + Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); + Opts.EmitCodeView = Args.hasArg(OPT_gcodeview); Opts.SplitDwarfFile = Args.getLastArgValue(OPT_split_dwarf_file); - if (Args.hasArg(OPT_gdwarf_2)) - Opts.DwarfVersion = 2; - else if (Args.hasArg(OPT_gdwarf_3)) - Opts.DwarfVersion = 3; - else if (Args.hasArg(OPT_gdwarf_4)) - Opts.DwarfVersion = 4; Opts.DebugTypeExtRefs = Args.hasArg(OPT_dwarf_ext_refs); if (const Arg *A = Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -24,6 +24,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" +#include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -3797,43 +3798,70 @@ : "-"); } - // Use the last option from "-g" group. "-gline-tables-only" and "-gdwarf-x" - // are preserved, all other debug options are substituted with "-g". + // The 'g' groups options involve a somewhat intricate sequence of decisions + // about what to pass from the driver to the frontend, but by the time they + // reach cc1 they've been factored into two well-defined orthogonal choices: + // * what level of debug info to generate + // * what dwarf version to write + // This avoids having to monkey around further in cc1 other than to disable + // codeview if not running in a Windows environment. Perhaps even that + // decision should be made in the driver as well though. + enum CodeGenOptions::DebugInfoKind DebugInfoKind = + CodeGenOptions::NoDebugInfo; + unsigned DwarfVersion = 0; + Args.ClaimAllArgs(options::OPT_g_Group); Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { + // 'g1' and 'line tables' are synonymous, but not specified as aliases + // in Options.td - perhaps they should be. if ((A->getOption().matches(options::OPT_gline_tables_only) || A->getOption().matches(options::OPT_g1)) && + // If you say "-gline-tables-only -gsplit-dwarf", the split-dwarf wins. + // It is not a g_Group option, hence this extra test. (!SplitDwarfArg || A->getIndex() > SplitDwarfArg->getIndex())) { + DebugInfoKind = CodeGenOptions::DebugLineTablesOnly; // FIXME: we should support specifying dwarf version with // -gline-tables-only. - CmdArgs.push_back("-gline-tables-only"); - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); + // But: Does the preceding FIXME mean that only the option parser + // was busted, or that the emitter can't handle it? This is not clear. + // At any rate, the new logic should have a much better time + // at fixing this, if in fact it is fundamentally non-broken. + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); SplitDwarfArg = nullptr; } else if (A->getOption().matches(options::OPT_gdwarf_2) || A->getOption().matches(options::OPT_gdwarf_3) || A->getOption().matches(options::OPT_gdwarf_4)) { - A->render(Args, CmdArgs); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + switch (A->getOption().getID()) { + case options::OPT_gdwarf_2: + DwarfVersion = 2; + break; + case options::OPT_gdwarf_3: + DwarfVersion = 3; + break; + default: + DwarfVersion = 4; + break; + } } else if (!A->getOption().matches(options::OPT_g0) && !A->getOption().matches(options::OPT_ggdb0)) { - // Default is dwarf-2 for Darwin, OpenBSD, FreeBSD and Solaris. - const llvm::Triple &Triple = getToolChain().getTriple(); - if (Triple.isOSDarwin() || Triple.getOS() == llvm::Triple::OpenBSD || - Triple.getOS() == llvm::Triple::FreeBSD || - Triple.getOS() == llvm::Triple::Solaris) - CmdArgs.push_back("-gdwarf-2"); - else - CmdArgs.push_back("-g"); + // Some 'g' group option other than one expressly disabling debug info + // must have been the final (winning) one. They're all equivalent. + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); } } // Forward -gcodeview. - Args.AddLastArg(CmdArgs, options::OPT_gcodeview); + if (Args.hasArg(options::OPT_gcodeview)) { + CmdArgs.push_back("-gcodeview"); + // With codeview, if an explicit choice of gdwarf was not made, then + // DwarfVersion is reset to 0 so that both kinds of info are not emitted. + if (!Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4)) + DwarfVersion = 0; + } // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); @@ -3843,20 +3871,59 @@ // FIXME: Move backend command line options to the module. if (Args.hasArg(options::OPT_gmodules)) { - CmdArgs.push_back("-g"); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; CmdArgs.push_back("-dwarf-ext-refs"); CmdArgs.push_back("-fmodule-format=obj"); } // -gsplit-dwarf should turn on -g and enable the backend dwarf // splitting and extraction. // FIXME: Currently only works on Linux. if (getToolChain().getTriple().isOSLinux() && SplitDwarfArg) { - CmdArgs.push_back("-g"); + DebugInfoKind = CodeGenOptions::LimitedDebugInfo; CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-split-dwarf=Enable"); } + // After we've dealt with all combinations of things that could + // make DebugInfoKind be other than None or DebugLineTablesOnly, + // figure out if we need to "upgrade" it to standalone debug info. + // We parse these two '-f' options whether or not they will be used, + // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" + bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, + options::OPT_fno_standalone_debug, + getToolChain().GetDefaultStandaloneDebug()); + if (DebugInfoKind == CodeGenOptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = CodeGenOptions::FullDebugInfo; + + // Now, if DebugInfoKind is not None, emit the CC1 option for it. + switch (DebugInfoKind) { + case CodeGenOptions::DebugLineTablesOnly: + CmdArgs.push_back("-gline-tables-only"); + break; + case CodeGenOptions::LimitedDebugInfo: + CmdArgs.push_back("-flimit-debug-info"); + break; + case CodeGenOptions::FullDebugInfo: + CmdArgs.push_back("-fstandalone-debug"); + break; + default: + break; + } + switch (DwarfVersion) { + case 2: + CmdArgs.push_back("-gdwarf-2"); + break; + case 3: + CmdArgs.push_back("-gdwarf-3"); + break; + case 4: + CmdArgs.push_back("-gdwarf-4"); + break; + default: + break; + } + // -ggnu-pubnames turns on gnu style pubnames in the backend. if (Args.hasArg(options::OPT_ggnu_pubnames)) { CmdArgs.push_back("-backend-option"); @@ -4219,8 +4286,6 @@ // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); - Args.AddLastArg(CmdArgs, options::OPT_fstandalone_debug); - Args.AddLastArg(CmdArgs, options::OPT_fno_standalone_debug); Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); // Emulated TLS is enabled by default on Android, and can be enabled manually // with -femulated-tls. Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -508,6 +508,12 @@ void AddLinkARCArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // Darwin defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + /// } private: @@ -564,6 +570,8 @@ const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; @@ -615,6 +623,7 @@ unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { return 2; } + unsigned GetDefaultDwarfVersion() const override { return 2; } protected: Tool *buildAssembler() const override; @@ -661,6 +670,10 @@ bool UseSjLjExceptions() const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // FreeBSD defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } protected: Tool *buildAssembler() const override; Index: include/clang/Driver/ToolChain.h =================================================================== --- include/clang/Driver/ToolChain.h +++ include/clang/Driver/ToolChain.h @@ -279,6 +279,16 @@ /// compile unit information. virtual bool UseDwarfDebugFlags() const { return false; } + // Return the DWARF version to emit, in the absence of arguments + // to the contrary. + virtual unsigned GetDefaultDwarfVersion() const { return 4; } + + // True if the driver should assume "-fstandalone-debug" + // in the absence of an option specifying otherwise, + // provided that debugging was requested in the first place. + // i.e. a value of 'true' does not imply that debugging is wanted. + virtual bool GetDefaultStandaloneDebug() const { return false; } + /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. virtual bool UseSjLjExceptions() const { return false; } Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -989,7 +989,8 @@ HelpText<"Emit full debug info for all types used by the program">; def fno_standalone_debug : Flag<["-"], "fno-standalone-debug">, Group<f_Group>, Flags<[CC1Option]>, HelpText<"Limit debug information produced to reduce size of debug binary">; -def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>; +def flimit_debug_info : Flag<["-"], "flimit-debug-info">, Alias<fno_standalone_debug>, + Flags<[CC1Option]>; def fno_limit_debug_info : Flag<["-"], "fno-limit-debug-info">, Alias<fstandalone_debug>; def fstrict_aliasing : Flag<["-"], "fstrict-aliasing">, Group<f_Group>, Flags<[DriverOption, CoreOption]>;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits