+2020-10-16  Nick Clifton  <nickc@redhat.com>
+
+       PR 26626
+       * ldmain.c (undefined_symbol): If an error handlign script is
+       available, call it.
+       * ldfile.c  (error_handling_script): Declare.
+       (ldfile_open_file): If a library cannot be found and an error
+       handling script is available, call it.
+       * ldmain.h  (error_handling_script): Prototype.
+       * ldlex.h (OPTION_ERROR_HANDLING_SCRIPT): Define.
+       * lexsup.c (ld_options): Add --error-handling-script.
+       (parse_args): Add support for --errror-handling-script.
+       * ld.texi: Document the new feature.
+       * configure.ac: Add --error-handling-script option to disable
+       support for the new feature.
+       * NEWS: Mention the new feature.
+       * config.in: Regenerate.
+       * configure: Regenerate.
+
 2020-10-16  Nelson Chu  <nelson.chu@sifive.com>
 
        * testsuite/ld-riscv-elf/ifunc-plt-got-overwrite.s: New testcase.
 
 -*- text -*-
 
+* Add --error-handling-script=<NAME> command line option to allow a helper
+  script to be invoked when an undefined symbol or a missing library is
+  encountered.  This option can be suppressed via the configure time
+  switch: --enable-error-handling-script=no.
+
 * Add -z x86-64-v[234] to the x86 ELF linker to mark x86-64-v[234] ISA
   level as needed.
 
 
 /* Define if you can safely include both <string.h> and <strings.h>. */
 #undef STRING_WITH_STRINGS
 
+/* Define to 1 if you want to support the --error-handling-script command line
+   option. */
+#undef SUPPORT_ERROR_HANDLING_SCRIPT
+
 /* Use b modifier when opening binary files? */
 #undef USE_BINARY_FOPEN
 
 
 enable_relro
 enable_textrel_check
 enable_separate_code
+enable_error_handling_script
 enable_default_hash_style
 enable_libctf
 enable_werror
   --enable-textrel-check=[yes|no|warning|error]
                           enable DT_TEXTREL check in ELF linker
   --enable-separate-code  enable -z separate-code in ELF linker by default
+  --enable-error-handling-script
+                          enable/disable support for the
+                          --error-handling-script option
   --enable-default-hash-style={sysv,gnu,both}
                           use this default hash style
   --enable-libctf         Handle .ctf type-info sections [default=yes]
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12042 "configure"
+#line 12046 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12148 "configure"
+#line 12152 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
 fi
 
 
+# Decide if --error-handling-script should be supported.
+ac_support_error_handling_script=unset
+# Check whether --enable-error-handling-script was given.
+if test "${enable_error_handling_script+set}" = set; then :
+  enableval=$enable_error_handling_script; case "${enableval}" in
+  yes) ac_support_error_handling_script=1 ;;
+  no)  ac_support_error_handling_script=0 ;;
+esac
+fi
+
+
 # Decide which "--hash-style" to use by default
 # Provide a configure time option to override our default.
 # Check whether --enable-default-hash-style was given.
 _ACEOF
 
 
+if test "${ac_support_error_handling_script}" = unset; then
+  ac_support_error_handling_script=1
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define SUPPORT_ERROR_HANDLING_SCRIPT $ac_support_error_handling_script
+_ACEOF
+
+
 
 cat >>confdefs.h <<_ACEOF
 #define DEFAULT_EMIT_SYSV_HASH $ac_default_emit_sysv_hash
 
   no) ac_default_ld_z_separate_code=0 ;;
 esac])
 
+# Decide if --error-handling-script should be supported.
+ac_support_error_handling_script=unset
+AC_ARG_ENABLE(error-handling-script,
+             AS_HELP_STRING([--enable-error-handling-script],
+             [enable/disable support for the --error-handling-script option]),
+[case "${enableval}" in
+  yes) ac_support_error_handling_script=1 ;;
+  no)  ac_support_error_handling_script=0 ;;
+esac])
+
 # Decide which "--hash-style" to use by default
 # Provide a configure time option to override our default.
 AC_ARG_ENABLE([default-hash-style],
   $ac_default_ld_z_separate_code,
   [Define to 1 if you want to enable -z separate-code in ELF linker by default.])
 
+if test "${ac_support_error_handling_script}" = unset; then
+  ac_support_error_handling_script=1
+fi
+AC_DEFINE_UNQUOTED(SUPPORT_ERROR_HANDLING_SCRIPT,
+  $ac_support_error_handling_script,
+  [Define to 1 if you want to support the --error-handling-script command line option.])
+
 AC_DEFINE_UNQUOTED([DEFAULT_EMIT_SYSV_HASH],
   [$ac_default_emit_sysv_hash],
   [Define to 1 if you want to emit sysv hash in the ELF linker by default.])
 
 appropriate memset function.
 @end itemize
 
+@kindex --error-handling-script=@var{scriptname}
+@item --error-handling-script=@var{scriptname}
+If this option is provided then the linker will invoke
+@var{scriptname} whenever an error is encountered.  Currently however
+only two kinds of error are supported: missing symbols and missing
+libraries.  Two arguments will be passed to script: the keyword
+``missing-symbol'' or `missing-lib'' and the @var{name} of the 
+missing symbol or library.  The intention is that the script will
+provide suggestions to the user as to where the symbol or library
+might be found.  After the script has finished then the normal linker
+error message will be displayed.
+
+The availability of this option is controlled by a configure time
+switch, so it may not be present in specific implementations.
+
 @kindex --no-undefined-version
 @item --no-undefined-version
 Normally when a symbol has an undefined version, the linker will ignore
 
               && IS_ABSOLUTE_PATH (entry->local_sym_name))
            einfo (_("%P: cannot find %s inside %s\n"),
                   entry->local_sym_name, ld_sysroot);
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+         else if (error_handling_script != NULL)
+           {
+             char *        argv[4];
+             const char *  res;
+             int           status, err;
+
+             argv[0] = error_handling_script;
+             argv[1] = "missing-lib";
+             argv[2] = (char *) entry->local_sym_name;
+             argv[3] = NULL;
+      
+             if (verbose)
+               einfo (_("%P: About to run error handling script '%s' with arguments: '%s' '%s'\n"),
+                      argv[0], argv[1], argv[2]);
+
+             res = pex_one (PEX_SEARCH, error_handling_script, argv,
+                            N_("error handling script"),
+                            NULL /* Send stdout to random, temp file.  */,
+                            NULL /* Write to stderr.  */,
+                            &status, &err);
+             if (res != NULL)
+               {
+                 einfo (_("%P: Failed to run error handling script '%s', reason: "),
+                        error_handling_script);
+                 /* FIXME: We assume here that errrno == err.  */
+                 perror (res);
+               }
+             else /* We ignore the return status of the script
+                     and always print the error message.  */
+               einfo (_("%P: cannot find %s\n"), entry->local_sym_name);
+           }
+#endif
          else
            einfo (_("%P: cannot find %s\n"), entry->local_sym_name);
 
                  break;
                }
            }
+
          entry->flags.missing_file = TRUE;
          input_flags.missing_file = TRUE;
        }
 
   OPTION_ALLOW_SHLIB_UNDEFINED,
   OPTION_NO_ALLOW_SHLIB_UNDEFINED,
   OPTION_ALLOW_MULTIPLE_DEFINITION,
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+  OPTION_ERROR_HANDLING_SCRIPT,
+#endif
   OPTION_NO_UNDEFINED_VERSION,
   OPTION_DEFAULT_SYMVER,
   OPTION_DEFAULT_IMPORTED_SYMVER,
 
   free (relpp);
 }
 
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+char * error_handling_script = NULL;
+#endif
+
 /* This is called when an undefined symbol is found.  */
 
 static void
       error_name = xstrdup (name);
     }
 
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+  if (error_handling_script != NULL
+      && error_count < MAX_ERRORS_IN_A_ROW)
+    {
+      char *        argv[4];
+      const char *  res;
+      int           status, err;
+
+      argv[0] = error_handling_script;
+      argv[1] = "missing-symbol";
+      argv[2] = (char *) name;
+      argv[3] = NULL;
+      
+      if (verbose)
+       einfo (_("%P: About to run error handling script '%s' with arguments: '%s' '%s'\n"),
+              argv[0], argv[1], argv[2]);
+
+      res = pex_one (PEX_SEARCH, error_handling_script, argv,
+                    N_("error handling script"),
+                    NULL /* Send stdout to random, temp file.  */,
+                    NULL /* Write to stderr.  */,
+                    &status, &err);
+      if (res != NULL)
+       {
+         einfo (_("%P: Failed to run error handling script '%s', reason: "),
+                error_handling_script);
+         /* FIXME: We assume here that errrno == err.  */
+         perror (res);
+       }
+      /* We ignore the return status of the script and
+        carry on to issue the normal error message.  */
+    }
+#endif /* SUPPORT_ERROR_HANDLING_SCRIPT */
+  
   if (section != NULL)
     {
       if (error_count < MAX_ERRORS_IN_A_ROW)
 
 extern const char *output_filename;
 extern struct bfd_link_info link_info;
 extern int overflow_cutoff_limit;
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+extern char *error_handling_script;
+#endif
 
 #define RELAXATION_DISABLED_BY_DEFAULT \
   (link_info.disable_target_specific_optimizations < 0)
 
   { {"allow-multiple-definition", no_argument, NULL,
      OPTION_ALLOW_MULTIPLE_DEFINITION},
     '\0', NULL, N_("Allow multiple definitions"), TWO_DASHES },
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+  { {"error-handling-script", required_argument, NULL,
+     OPTION_ERROR_HANDLING_SCRIPT},
+    '\0', N_("SCRIPT"), N_("Provide a script to help with undefined symbol errors"), TWO_DASHES},
+#endif
   { {"no-undefined-version", no_argument, NULL, OPTION_NO_UNDEFINED_VERSION},
     '\0', NULL, N_("Disallow undefined version"), TWO_DASHES },
   { {"default-symver", no_argument, NULL, OPTION_DEFAULT_SYMVER},
        case OPTION_ALLOW_MULTIPLE_DEFINITION:
          link_info.allow_multiple_definition = TRUE;
          break;
+
+#if SUPPORT_ERROR_HANDLING_SCRIPT
+       case OPTION_ERROR_HANDLING_SCRIPT:
+         /* FIXME: Should we warn if the script is being overridden by another ?
+            Or maybe they should be chained together ?  */
+         error_handling_script = optarg;
+         break;
+#endif
+
        case OPTION_NO_UNDEFINED_VERSION:
          link_info.allow_undefined_version = FALSE;
          break;