summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
authorWill Wilson <will@indefiant.com>2018-09-24 15:28:03 +0000
committerWill Wilson <will@indefiant.com>2018-09-24 15:28:03 +0000
commit58898a8566a462780711073bfceb165d84cc0f73 (patch)
tree6658ae99a546435161477137fc800e9abfec6f6a /lld
parent146603d6841611b649999eda9fb868ce848ebebd (diff)
[lld-link] Generalize handling of /debug and /debug:{none,full,fastlink,ghash,symtab}
Implement final argument precedence if multiple /debug arguments are passed on the command-line to match expected link.exe behavior. Support /debug:none and emit warning for /debug:fastlink with automatic fallback to /debug:full. Emit error if last /debug:option is unknown. Emit warning if last /debugtype:option is unknown. https://reviews.llvm.org/D50404
Diffstat (limited to 'lld')
-rw-r--r--lld/COFF/Driver.cpp91
-rw-r--r--lld/COFF/Options.td5
-rw-r--r--lld/test/COFF/debug-fastlink.test12
-rw-r--r--lld/test/COFF/invalid-debug-type.test3
-rw-r--r--lld/test/COFF/invalid-debug.test6
-rw-r--r--lld/test/COFF/pdb-options.test5
6 files changed, 92 insertions, 30 deletions
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index b2fe804bce6..15ed19ba07b 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -508,26 +508,65 @@ static std::string createResponseFile(const opt::InputArgList &Args,
return Data.str();
}
-static unsigned getDefaultDebugType(const opt::InputArgList &Args) {
- unsigned DebugTypes = static_cast<unsigned>(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<DebugKind>(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<unsigned>(DebugType::None);
+
+ if (auto *A = Args.getLastArg(OPT_debugtype)) {
+ SmallVector<StringRef, 3> Types;
+ A->getSpelling().split(Types, ',', /*KeepEmpty=*/false);
+
+ for (StringRef Type : Types) {
+ unsigned V = StringSwitch<unsigned>(Type.lower())
+ .Case("cv", static_cast<unsigned>(DebugType::CV))
+ .Case("pdata", static_cast<unsigned>(DebugType::PData))
+ .Case("fixup", static_cast<unsigned>(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<unsigned>(DebugType::CV);
if (Args.hasArg(OPT_driver))
DebugTypes |= static_cast<unsigned>(DebugType::PData);
if (Args.hasArg(OPT_profile))
DebugTypes |= static_cast<unsigned>(DebugType::Fixup);
- return DebugTypes;
-}
-
-static unsigned parseDebugType(StringRef Arg) {
- SmallVector<StringRef, 3> Types;
- Arg.split(Types, ',', /*KeepEmpty=*/false);
- unsigned DebugTypes = static_cast<unsigned>(DebugType::None);
- for (StringRef Type : Types)
- DebugTypes |= StringSwitch<unsigned>(Type.lower())
- .Case("cv", static_cast<unsigned>(DebugType::CV))
- .Case("pdata", static_cast<unsigned>(DebugType::PData))
- .Case("fixup", static_cast<unsigned>(DebugType::Fixup))
- .Default(0);
return DebugTypes;
}
@@ -895,17 +934,19 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
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 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
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 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
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);
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 13947472054..f5dcd274089 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -85,7 +85,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<debug>;
+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 : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// 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">;
diff --git a/lld/test/COFF/debug-fastlink.test b/lld/test/COFF/debug-fastlink.test
new file mode 100644
index 00000000000..10b414195da
--- /dev/null
+++ b/lld/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
+
diff --git a/lld/test/COFF/invalid-debug-type.test b/lld/test/COFF/invalid-debug-type.test
index 10264180314..0fa40b0312b 100644
--- a/lld/test/COFF/invalid-debug-type.test
+++ b/lld/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
diff --git a/lld/test/COFF/invalid-debug.test b/lld/test/COFF/invalid-debug.test
new file mode 100644
index 00000000000..67f794f8b1b
--- /dev/null
+++ b/lld/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
diff --git a/lld/test/COFF/pdb-options.test b/lld/test/COFF/pdb-options.test
index 2bd1d920ee4..f0edc2f3bc7 100644
--- a/lld/test/COFF/pdb-options.test
+++ b/lld/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