[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