summaryrefslogtreecommitdiff
path: root/lld/ELF
diff options
context:
space:
mode:
authorFangrui Song <i@maskray.me>2023-04-26 13:18:55 -0700
committerFangrui Song <i@maskray.me>2023-04-26 13:18:55 -0700
commit39c20a63b150053fcee5928be7ea1b3b0a51c9d4 (patch)
treea7ab7c4b0fad5f3798e97d6b51318d21316962bf /lld/ELF
parent65443f6f0a70f3ced43e688053cd6c1642d81ff6 (diff)
downloadllvm-39c20a63b150053fcee5928be7ea1b3b0a51c9d4.tar.gz
[ELF] Add --remap-inputs= and --remap-inputs-file=
--remap-inputs-file= can be specified multiple times, each naming a remap file that contains `from-glob=to-file` lines or `#`-led comments. ('=' is used a separator a la -fdebug-prefix-map=) --remap-inputs-file= can be used to: * replace an input file. E.g. `"*/libz.so=exp/libz.so"` can replace a resolved `-lz` without updating the input file list or (if used) a response file. When debugging an application where a bug is isolated to one single input file, this option gives a convenient way to test fixes. * remove an input file with `/dev/null` (changed to `NUL` on Windows), e.g. `"a.o=/dev/null"`. A build system may add unneeded dependencies. This option gives a convenient way to test the result removing some inputs. `--remap-inputs=a.o=aa.o` can be specified to provide one pattern without using an extra file. (bash/zsh process substitution is handy for specifying a pattern without using a remap file, e.g. `--remap-inputs-file=<(printf 'a.o=aa.o')`, but it may be unavailable in some systems. An extra file can be inconvenient for a build system.) Exact patterns are tested before wildcard patterns. In case of a tie, the first patterns wins. This is an implementation detail that users should not rely on. Co-authored-by: Marco Elver <elver@google.com> Link: https://discourse.llvm.org/t/rfc-support-exclude-inputs/70070 Reviewed By: melver, peter.smith Differential Revision: https://reviews.llvm.org/D148859
Diffstat (limited to 'lld/ELF')
-rw-r--r--lld/ELF/Config.h6
-rw-r--r--lld/ELF/Driver.cpp34
-rw-r--r--lld/ELF/DriverUtils.cpp1
-rw-r--r--lld/ELF/InputFiles.cpp23
-rw-r--r--lld/ELF/Options.td8
5 files changed, 72 insertions, 0 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index c446508dfa2f..9c9a49d9f20e 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -407,6 +407,12 @@ struct Config {
bool androidMemtagStack;
unsigned threadCount;
+
+ // If an input file equals a key, remap it to the value.
+ llvm::DenseMap<llvm::StringRef, llvm::StringRef> remapInputs;
+ // If an input file matches a wildcard pattern, remap it to the value.
+ llvm::SmallVector<std::pair<llvm::GlobPattern, llvm::StringRef>, 0>
+ remapInputsWildcards;
};
struct ConfigWrapper {
Config c;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 79f16a281df9..f235ffcbb955 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -1077,6 +1077,25 @@ static bool isValidReportString(StringRef arg) {
return arg == "none" || arg == "warning" || arg == "error";
}
+// Process a remap pattern 'from-glob=to-file'.
+static bool remapInputs(StringRef line, const Twine &location) {
+ SmallVector<StringRef, 0> fields;
+ line.split(fields, '=');
+ if (fields.size() != 2 || fields[1].empty()) {
+ error(location + ": parse error, not 'from-glob=to-file'");
+ return true;
+ }
+ if (!hasWildcard(fields[0]))
+ config->remapInputs[fields[0]] = fields[1];
+ else if (Expected<GlobPattern> pat = GlobPattern::create(fields[0]))
+ config->remapInputsWildcards.emplace_back(std::move(*pat), fields[1]);
+ else {
+ error(location + ": " + toString(pat.takeError()));
+ return true;
+ }
+ return false;
+}
+
// Initializes Config members by the command line options.
static void readConfigs(opt::InputArgList &args) {
errorHandler().verbose = args.hasArg(OPT_verbose);
@@ -1335,6 +1354,21 @@ static void readConfigs(opt::InputArgList &args) {
config->optEL = true;
}
+ for (opt::Arg *arg : args.filtered(OPT_remap_inputs)) {
+ StringRef value(arg->getValue());
+ remapInputs(value, arg->getSpelling());
+ }
+ for (opt::Arg *arg : args.filtered(OPT_remap_inputs_file)) {
+ StringRef filename(arg->getValue());
+ std::optional<MemoryBufferRef> buffer = readFile(filename);
+ if (!buffer)
+ continue;
+ // Parse 'from-glob=to-file' lines, ignoring #-led comments.
+ for (auto [lineno, line] : llvm::enumerate(args::getLines(*buffer)))
+ if (remapInputs(line, filename + ":" + Twine(lineno + 1)))
+ break;
+ }
+
for (opt::Arg *arg : args.filtered(OPT_shuffle_sections)) {
constexpr StringRef errPrefix = "--shuffle-sections=: ";
std::pair<StringRef, StringRef> kv = StringRef(arg->getValue()).split('=');
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index 254f4b722462..50e9f509bcb4 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -192,6 +192,7 @@ std::string elf::createResponseFile(const opt::InputArgList &args) {
case OPT_export_dynamic_symbol_list:
case OPT_just_symbols:
case OPT_library_path:
+ case OPT_remap_inputs_file:
case OPT_retain_symbols_file:
case OPT_rpath:
case OPT_script:
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index b7686e8e3ba9..b8291fb4307b 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -195,6 +195,29 @@ std::optional<MemoryBufferRef> elf::readFile(StringRef path) {
if (!config->chroot.empty() && path.startswith("/"))
path = saver().save(config->chroot + path);
+ bool remapped = false;
+ auto it = config->remapInputs.find(path);
+ if (it != config->remapInputs.end()) {
+ path = it->second;
+ remapped = true;
+ } else {
+ for (const auto &[pat, toFile] : config->remapInputsWildcards) {
+ if (pat.match(path)) {
+ path = toFile;
+ remapped = true;
+ break;
+ }
+ }
+ }
+ if (remapped) {
+ // Use /dev/null to indicate an input file that should be ignored. Change
+ // the path to NUL on Windows.
+#ifdef _WIN32
+ if (path == "/dev/null")
+ path = "NUL";
+#endif
+ }
+
log(path);
config->dependencyFiles.insert(llvm::CachedHashString(path));
diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td
index 5b3d9f6c40de..8f2a440fd67a 100644
--- a/lld/ELF/Options.td
+++ b/lld/ELF/Options.td
@@ -359,6 +359,14 @@ defm relax_gp: BB<"relax-gp",
"Enable global pointer relaxation",
"Disable global pointer relaxation (default)">;
+defm remap_inputs: EEq<"remap-inputs",
+ "Remap input files matching <from-glob> to <to-file>">,
+ MetaVarName<"<from-glob>=<to-file>">;
+
+def remap_inputs_file: JJ<"remap-inputs-file=">,
+ HelpText<"Each line contains 'from-glob=to-file'. An input file matching <from-glob> is remapped to <to-file>">,
+ MetaVarName<"<file>">;
+
defm reproduce:
EEq<"reproduce",
"Write tar file containing inputs and command to reproduce link">;