Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -508,26 +508,65 @@ return Data.str(); } -static unsigned getDefaultDebugType(const opt::InputArgList &Args) { - unsigned DebugTypes = static_cast(DebugType::CV); +enum class DebugKind { Unknown, None, Full, FastLink, GHash, Dwarf, Symtab }; + +static DebugKind parseDebugKind(const opt::InputArgList &Args) { + auto *A = Args.getLastArg(OPT_debug, OPT_debug_opt); + if (!A) + return DebugKind::None; + if (A->getNumValues() == 0) + return DebugKind::Full; + + DebugKind Debug = StringSwitch(A->getValue()) + .CaseLower("none", DebugKind::None) + .CaseLower("full", DebugKind::Full) + .CaseLower("fastlink", DebugKind::FastLink) + // LLD extensions + .CaseLower("ghash", DebugKind::GHash) + .CaseLower("dwarf", DebugKind::Dwarf) + .CaseLower("symtab", DebugKind::Symtab) + .Default(DebugKind::Unknown); + + if (Debug == DebugKind::FastLink) { + warn("/debug:fastlink unsupported; using /debug:full"); + return DebugKind::Full; + } + if (Debug == DebugKind::Unknown) { + error("/debug: unknown option: " + Twine(A->getValue())); + return DebugKind::None; + } + return Debug; +} + +static unsigned parseDebugTypes(const opt::InputArgList &Args) { + unsigned DebugTypes = static_cast(DebugType::None); + + if (auto *A = Args.getLastArg(OPT_debugtype)) { + SmallVector Types; + A->getSpelling().split(Types, ',', /*KeepEmpty=*/false); + + for (StringRef Type : Types) { + unsigned V = StringSwitch(Type.lower()) + .Case("cv", static_cast(DebugType::CV)) + .Case("pdata", static_cast(DebugType::PData)) + .Case("fixup", static_cast(DebugType::Fixup)) + .Default(0); + if (V == 0) { + warn("/debugtype: unknown option: " + Twine(A->getValue())); + continue; + } + DebugTypes |= V; + } + return DebugTypes; + } + + // Default debug types + DebugTypes = static_cast(DebugType::CV); if (Args.hasArg(OPT_driver)) DebugTypes |= static_cast(DebugType::PData); if (Args.hasArg(OPT_profile)) DebugTypes |= static_cast(DebugType::Fixup); - return DebugTypes; -} -static unsigned parseDebugType(StringRef Arg) { - SmallVector Types; - Arg.split(Types, ',', /*KeepEmpty=*/false); - - unsigned DebugTypes = static_cast(DebugType::None); - for (StringRef Type : Types) - DebugTypes |= StringSwitch(Type.lower()) - .Case("cv", static_cast(DebugType::CV)) - .Case("pdata", static_cast(DebugType::PData)) - .Case("fixup", static_cast(DebugType::Fixup)) - .Default(0); return DebugTypes; } @@ -895,17 +934,19 @@ Config->ForceMultiple = true; // Handle /debug - if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { + DebugKind Debug = parseDebugKind(Args); + if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf || + Debug == DebugKind::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 /debugtype + Config->DebugTypes = parseDebugTypes(Args); + // Handle /pdb - bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); + bool ShouldCreatePDB = + (Debug == DebugKind::Full || Debug == DebugKind::GHash); if (ShouldCreatePDB) { if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = Arg->getValue(); @@ -1026,7 +1067,7 @@ Config->Implib = Arg->getValue(); // Handle /opt. - bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile); + bool DoGC = Debug == DebugKind::None || Args.hasArg(OPT_profile); unsigned ICFLevel = Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on unsigned TailMerge = 1; @@ -1170,9 +1211,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 = Debug == DebugKind::Dwarf; + Config->DebugGHashes = Debug == DebugKind::GHash; + Config->DebugSymtab = Debug == DebugKind::Symtab; Config->MapFile = getMapFile(Args); Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -85,7 +85,7 @@ HelpText<"Use module-definition file">; def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; -def debug_full : F<"debug:full">, Alias; +def debug_opt : P<"debug", "Embed a symbol table in the image with option">; 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">; @@ -142,9 +142,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-type.test =================================================================== --- test/COFF/invalid-debug-type.test +++ test/COFF/invalid-debug-type.test @@ -1,5 +1,6 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: lld-link /debug /debugtype:invalid /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: %t1.obj %t2.obj +# RUN: %t1.obj %t2.obj 2>&1 | FileCheck %s +# CHECK: /debugtype: unknown option: invalid \ No newline at end of file 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