[lld] cfc3226 - Provide a hook to customize missing library error handling
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 3 02:06:15 PST 2020
Author: serge-sans-paille
Date: 2020-11-03T11:01:29+01:00
New Revision: cfc32267e27f77211ee5eb6e30c52ab2c7740e6e
URL: https://github.com/llvm/llvm-project/commit/cfc32267e27f77211ee5eb6e30c52ab2c7740e6e
DIFF: https://github.com/llvm/llvm-project/commit/cfc32267e27f77211ee5eb6e30c52ab2c7740e6e.diff
LOG: Provide a hook to customize missing library error handling
Make it possible for lld users to provide a custom script that would help to
find missing libraries. A possible scenario could be:
% clang /tmp/a.c -fuse-ld=lld -loauth -Wl,--error-handling-script=/tmp/addLibrary.py
unable to find library -loauth
looking for relevant packages to provides that library
liboauth-0.9.7-4.el7.i686
liboauth-devel-0.9.7-4.el7.i686
liboauth-0.9.7-4.el7.x86_64
liboauth-devel-0.9.7-4.el7.x86_64
pix-1.6.1-3.el7.x86_64
Where addLibrary would be called with the missing library name as first argument
(in that case addLibrary.py oauth)
Differential Revision: https://reviews.llvm.org/D87758
Added:
lld/test/ELF/error-handling-script-linux.test
lld/test/ELF/error-handling-script-windows.bat
Modified:
lld/Common/ErrorHandler.cpp
lld/ELF/Driver.cpp
lld/ELF/Options.td
lld/docs/ReleaseNotes.rst
lld/docs/index.rst
lld/docs/ld.lld.1
lld/include/lld/Common/ErrorHandler.h
lld/test/ELF/lit.local.cfg
Removed:
################################################################################
diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp
index 3c3609e00743..4d6a039b8959 100644
--- a/lld/Common/ErrorHandler.cpp
+++ b/lld/Common/ErrorHandler.cpp
@@ -16,6 +16,7 @@
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Process.h"
+#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
#include <regex>
@@ -226,6 +227,50 @@ void ErrorHandler::error(const Twine &msg) {
exitLld(1);
}
+void ErrorHandler::error(const Twine &msg, ErrorTag tag,
+ ArrayRef<StringRef> args) {
+ if (errorHandlingScript.empty()) {
+ error(msg);
+ return;
+ }
+ SmallVector<StringRef, 4> scriptArgs;
+ scriptArgs.push_back(errorHandlingScript);
+ switch (tag) {
+ case ErrorTag::LibNotFound:
+ scriptArgs.push_back("missing-lib");
+ break;
+ default:
+ llvm_unreachable("unsupported ErrorTag");
+ }
+ scriptArgs.insert(scriptArgs.end(), args.begin(), args.end());
+ int res = llvm::sys::ExecuteAndWait(errorHandlingScript, scriptArgs);
+ if (res == 0) {
+ return error(msg);
+ } else {
+ // Temporarily disable error limit to make sure the two calls to error(...)
+ // only count as one.
+ uint64_t currentErrorLimit = errorLimit;
+ errorLimit = 0;
+ error(msg);
+ errorLimit = currentErrorLimit;
+ --errorCount;
+
+ switch (res) {
+ case -1:
+ error("error handling script '" + errorHandlingScript +
+ "' failed to execute");
+ break;
+ case -2:
+ error("error handling script '" + errorHandlingScript +
+ "' crashed or timeout");
+ break;
+ default:
+ error("error handling script '" + errorHandlingScript +
+ "' exited with code " + Twine(res));
+ }
+ }
+}
+
void ErrorHandler::fatal(const Twine &msg) {
error(msg);
exitLld(1);
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 30575f66d017..fbc5e44baa05 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -286,7 +286,7 @@ void LinkerDriver::addLibrary(StringRef name) {
if (Optional<std::string> path = searchLibrary(name))
addFile(*path, /*withLOption=*/true);
else
- error("unable to find library -l" + name);
+ error("unable to find library -l" + name, ErrorTag::LibNotFound, {name});
}
// This function is called on startup. We need this for LTO since
@@ -944,6 +944,10 @@ static void readConfigs(opt::InputArgList &args) {
config->enableNewDtags =
args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true);
config->entry = args.getLastArgValue(OPT_entry);
+
+ errorHandler().errorHandlingScript =
+ args.getLastArgValue(OPT_error_handling_script);
+
config->executeOnly =
args.hasFlag(OPT_execute_only, OPT_no_execute_only, false);
config->exportDynamic =
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 9f1fbd15caf7..37d6fda03893 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -179,6 +179,9 @@ defm error_limit:
def error_unresolved_symbols: F<"error-unresolved-symbols">,
HelpText<"Report unresolved symbols as errors">;
+defm error_handling_script: EEq<"error-handling-script",
+ "Specify an error handling script">;
+
defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">;
defm execute_only: BB<"execute-only",
diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst
index f50c3064f474..e0b17ca3e030 100644
--- a/lld/docs/ReleaseNotes.rst
+++ b/lld/docs/ReleaseNotes.rst
@@ -24,7 +24,8 @@ Non-comprehensive list of changes in this release
ELF Improvements
----------------
-* ...
+* ``--error-handling-script`` is added to allow for user-defined handlers upon
+ missing libraries. (`D87758 <https://reviews.llvm.org/D87758>`_)
Breaking changes
----------------
diff --git a/lld/docs/index.rst b/lld/docs/index.rst
index 900ad8219fe0..40da6d77cca8 100644
--- a/lld/docs/index.rst
+++ b/lld/docs/index.rst
@@ -174,6 +174,7 @@ document soon.
WebAssembly
windows_support
missingkeyfunction
+ error_handling_script
Partitions
ReleaseNotes
ELF/linker_script
diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1
index 5edeaf85f93f..0de278ac3b2d 100644
--- a/lld/docs/ld.lld.1
+++ b/lld/docs/ld.lld.1
@@ -181,6 +181,17 @@ Maximum number of errors to emit before stopping.
A value of zero indicates that there is no limit.
.It Fl -error-unresolved-symbols
Report unresolved symbols as errors.
+.It Fl -error-handing-script Ns = Ns Ar script_path
+Call script
+.Ar script_path
+upon some error, with
+.Ar tag
+as first argument, and an extra parameter as second argument. The script is
+expected to return 0 on success. Any other value is considered a generic error.
+.Ar tag
+may be
+.Cm missing-lib
+followed by the name of the missing library.
.It Fl -execute-only
Mark executable sections unreadable.
This option is currently only supported on AArch64.
diff --git a/lld/include/lld/Common/ErrorHandler.h b/lld/include/lld/Common/ErrorHandler.h
index 79a5940823bd..64f363014400 100644
--- a/lld/include/lld/Common/ErrorHandler.h
+++ b/lld/include/lld/Common/ErrorHandler.h
@@ -89,11 +89,14 @@ extern llvm::raw_ostream *stderrOS;
llvm::raw_ostream &outs();
llvm::raw_ostream &errs();
+enum class ErrorTag { LibNotFound };
+
class ErrorHandler {
public:
uint64_t errorCount = 0;
uint64_t errorLimit = 20;
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
+ StringRef errorHandlingScript;
StringRef logName = "lld";
bool exitEarly = true;
bool fatalWarnings = false;
@@ -103,6 +106,7 @@ class ErrorHandler {
std::function<void()> cleanupCallback;
void error(const Twine &msg);
+ void error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args);
LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg);
void log(const Twine &msg);
void message(const Twine &msg);
@@ -126,6 +130,9 @@ class ErrorHandler {
ErrorHandler &errorHandler();
inline void error(const Twine &msg) { errorHandler().error(msg); }
+inline void error(const Twine &msg, ErrorTag tag, ArrayRef<StringRef> args) {
+ errorHandler().error(msg, tag, args);
+}
inline LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &msg) {
errorHandler().fatal(msg);
}
diff --git a/lld/test/ELF/error-handling-script-linux.test b/lld/test/ELF/error-handling-script-linux.test
new file mode 100755
index 000000000000..c499680ee6df
--- /dev/null
+++ b/lld/test/ELF/error-handling-script-linux.test
@@ -0,0 +1,17 @@
+#!/bin/sh
+# REQUIRES: x86
+# UNSUPPORTED: system-windows
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t0.o
+# RUN: not ld.lld -o /dev/null -lidontexist --error-handling-script=%s %t0.o 2>&1 |\
+# RUN: FileCheck --check-prefix=CHECK-LIB %s
+# RUN: not ld.lld -o /dev/null -lidontexist --error-handling-script=%s.nope %t0.o 2>&1 |\
+# RUN: FileCheck --check-prefix=CHECK-SCRIPT-DOES-NOT-EXIST -DFILE=%s.nope %s
+
+# CHECK-LIB: script: info: called with missing-lib idontexist
+# CHECK-LIB-NEXT: ld.lld: error: unable to find library -lidontexist
+
+# CHECK-SCRIPT-DOES-NOT-EXIST: ld.lld: error: unable to find library -lidontexist
+# CHECK-SCRIPT-DOES-NOT-EXIST-NEXT: ld.lld: error: error handling script '[[FILE]]' failed to execute
+
+echo "script: info: called with $*"
diff --git a/lld/test/ELF/error-handling-script-windows.bat b/lld/test/ELF/error-handling-script-windows.bat
new file mode 100644
index 000000000000..64c4e95f043c
--- /dev/null
+++ b/lld/test/ELF/error-handling-script-windows.bat
@@ -0,0 +1,15 @@
+:: REQUIRES: x86, system-windows
+:: RUN: echo | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t0.o
+:: RUN: not ld.lld -o /dev/null -lidontexist --error-handling-script=%s %t0.o 2>&1 |\
+:: RUN: FileCheck --check-prefix=CHECK-LIB %s
+:: RUN: not ld.lld -o /dev/null -lidontexist --error-handling-script=%s.nope %t0.o 2>&1 |\
+:: RUN: FileCheck --check-prefix=CHECK-SCRIPT-DOES-NOT-EXIST -DFILE=%s.nope %s
+::
+:: CHECK-LIB: script: info: called with missing-lib idontexist
+:: CHECK-LIB-NEXT: ld.lld: error: unable to find library -lidontexist
+
+:: CHECK-SCRIPT-DOES-NOT-EXIST: ld.lld: error: unable to find library -lidontexist
+:: CHECK-SCRIPT-DOES-NOT-EXIST-NEXT: ld.lld: error: error handling script '[[FILE]]' failed to execute
+
+ at echo off
+echo "script: info: called with %*"
diff --git a/lld/test/ELF/lit.local.cfg b/lld/test/ELF/lit.local.cfg
index 284077d687fa..98c97b66afba 100644
--- a/lld/test/ELF/lit.local.cfg
+++ b/lld/test/ELF/lit.local.cfg
@@ -1 +1 @@
-config.suffixes = ['.test', '.s', '.ll']
+config.suffixes = ['.test', '.s', '.ll', '.bat']
More information about the llvm-commits
mailing list