Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -497,6 +497,27 @@ return Data.str(); } +enum class DebugGeneration { + Unknown, + None, + Full, + FastLink, + GHash, + Dwarf, + Symtab +}; + +static DebugGeneration parseDebugGeneration(StringRef Arg) { + return StringSwitch(Arg.lower()) + .Case("none", DebugGeneration::None) + .Case("full", DebugGeneration::Full) + .Case("fastlink", DebugGeneration::FastLink) + .Case("ghash", DebugGeneration::GHash) + .Case("dwarf", DebugGeneration::Dwarf) + .Case("symtab", DebugGeneration::Symtab) + .Default(DebugGeneration::Unknown); +} + static unsigned getDefaultDebugType(const opt::InputArgList &Args) { unsigned DebugTypes = static_cast(DebugType::CV); if (Args.hasArg(OPT_driver)) @@ -840,27 +861,44 @@ Config->Force = true; // Handle /debug - if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { - Config->Debug = true; - Config->Incremental = true; - if (auto *Arg = Args.getLastArg(OPT_debugtype)) - Config->DebugTypes = parseDebugType(Arg->getValue()); - else - Config->DebugTypes = getDefaultDebugType(Args); - } - - // Handle /pdb - bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); - if (ShouldCreatePDB) { - if (auto *Arg = Args.getLastArg(OPT_pdb)) - Config->PDBPath = Arg->getValue(); - if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) - Config->PDBAltPath = Arg->getValue(); - if (Args.hasArg(OPT_natvis)) - Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); + DebugGeneration DebugGen = DebugGeneration::None; + bool ShouldCreatePDB = false; + if (auto *DebugArg = Args.getLastArg(OPT_debug, OPT_debug_opt)) { + DebugGen = DebugGeneration::Full; + if (DebugArg->getNumValues() != 0) { + DebugGen = parseDebugGeneration(DebugArg->getValue()); + if (DebugGen == DebugGeneration::FastLink) { + warn("/debug:fastlink unsupported; using /debug:full"); + DebugGen = DebugGeneration::Full; + } else if (DebugGen == DebugGeneration::Unknown) + error("/debug: unknown option: " + Twine(DebugArg->getValue())); + } - if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) - Config->PDBSourcePath = Arg->getValue(); + if (DebugGen == DebugGeneration::Full || + DebugGen == DebugGeneration::Dwarf || + DebugGen == DebugGeneration::GHash) { + Config->Debug = true; + Config->Incremental = true; + if (auto *Arg = Args.getLastArg(OPT_debugtype)) + Config->DebugTypes = parseDebugType(Arg->getValue()); + else + Config->DebugTypes = getDefaultDebugType(Args); + + // Handle /pdb + ShouldCreatePDB = DebugGen == DebugGeneration::Full || + DebugGen == DebugGeneration::GHash; + if (ShouldCreatePDB) { + if (auto *Arg = Args.getLastArg(OPT_pdb)) + Config->PDBPath = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) + Config->PDBAltPath = Arg->getValue(); + if (Args.hasArg(OPT_natvis)) + Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); + + if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) + Config->PDBSourcePath = Arg->getValue(); + } + } } // Handle /noentry @@ -971,7 +1009,7 @@ Config->Implib = Arg->getValue(); // Handle /opt. - bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile); + bool DoGC = DebugGen == DebugGeneration::None || Args.hasArg(OPT_profile); unsigned ICFLevel = Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on unsigned TailMerge = 1; @@ -1109,9 +1147,9 @@ Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); Config->TerminalServerAware = !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); - Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf); - Config->DebugGHashes = Args.hasArg(OPT_debug_ghash); - Config->DebugSymtab = Args.hasArg(OPT_debug_symtab); + Config->DebugDwarf = DebugGen == DebugGeneration::Dwarf; + Config->DebugGHashes = DebugGen == DebugGeneration::GHash; + Config->DebugSymtab = DebugGen == DebugGeneration::Symtab; Config->MapFile = getMapFile(Args); Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -9,6 +9,12 @@ class P : Joined<["/", "-", "-?"], name#":">, HelpText; +// Flag that may take optional argument after ":". +multiclass POpt { + def NAME: F; + def NAME # _opt: P; +} + // Boolean flag which can be suffixed by ":no". Using it unsuffixed turns the // flag on and using it suffixed by ":no" turns it off. multiclass B { @@ -84,8 +90,7 @@ def deffile : Joined<["/", "-"], "def:">, HelpText<"Use module-definition file">; -def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; -def debug_full : F<"debug:full">, Alias; +defm debug : POpt<"debug", "Embed a symbol table in the image">; def debugtype : P<"debugtype", "Debug Info Options">; def dll : F<"dll">, HelpText<"Create a DLL">; def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; @@ -139,9 +144,6 @@ def help_q : Flag<["/?", "-?"], "">, Alias; // LLD extensions -def debug_ghash : F<"debug:ghash">; -def debug_dwarf : F<"debug:dwarf">; -def debug_symtab : F<"debug:symtab">; def export_all_symbols : F<"export-all-symbols">; def kill_at : F<"kill-at">; def lldmingw : F<"lldmingw">; Index: test/COFF/debug-fastlink.test =================================================================== --- test/COFF/debug-fastlink.test +++ test/COFF/debug-fastlink.test @@ -0,0 +1,12 @@ +# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj + +; If /DEBUG:FASTLINK is specified, /DEBUG:FULL is used instead +# RUN: rm -f %t.pdb +# RUN: lld-link /DEBUG /pdb:%t.pdb /DEBUG:FASTLINK /entry:main /nodefaultlib %t1.obj %t2.obj \ +# RUN: 2>&1 | FileCheck %s + +# CHECK: /debug:fastlink unsupported; using /debug:full + +# RUN: ls %t.pdb + Index: test/COFF/invalid-debug.test =================================================================== --- test/COFF/invalid-debug.test +++ test/COFF/invalid-debug.test @@ -0,0 +1,6 @@ +# RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj +# RUN: not lld-link /debug /debug:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ +# RUN: %t1.obj %t2.obj 2>&1 | FileCheck %s + +# CHECK: /debug: unknown option: invalid Index: test/COFF/pdb-options.test =================================================================== --- test/COFF/pdb-options.test +++ test/COFF/pdb-options.test @@ -6,6 +6,11 @@ # RUN: lld-link /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj # RUN: not ls %t.pdb +; If /DEBUG:NONE is specified after /DEBUG, /pdb is ignored. +# RUN: rm -f %t.pdb +# RUN: lld-link /DEBUG /pdb:%t.pdb /DEBUG:NONE /entry:main /nodefaultlib %t1.obj %t2.obj +# RUN: not ls %t.pdb + ; If /DEBUG and /pdb are specified, it uses the specified name. # RUN: lld-link /DEBUG /pdb:%t.pdb /entry:main /nodefaultlib %t1.obj %t2.obj # RUN: ls %t.pdb