[lld/mac] Print dylib search details with --print-dylib-search or RC_TRACE_DYLIB_SEARCHING

For debugging dylib loading, it's useful to have some insight into what
the linker is doing.

ld64 has the undocumented RC_TRACE_DYLIB_SEARCHING env var
for this printing dylib search candidates.

This adds a flag --print-dylib-search to make lld print the seame information.
It's useful for users, but also for writing tests. The output is formatted
slightly differently than ld64, but we still support RC_TRACE_DYLIB_SEARCHING
to offer at least a compatible way to trigger this.

ld64 has both `-print_statistics` and `-trace_symbol_output` to enable
diagnostics output. I went with "print" since that seems like a more
straightforward name.

Differential Revision: https://reviews.llvm.org/D103985
This commit is contained in:
Nico Weber 2021-06-09 15:16:45 -04:00
parent 91f147792e
commit e87c095af3
6 changed files with 51 additions and 24 deletions

View File

@ -96,6 +96,7 @@ struct Configuration {
bool headerPadMaxInstallNames = false;
bool ltoNewPassManager = LLVM_ENABLE_NEW_PASS_MANAGER;
bool markDeadStrippableDylib = false;
bool printDylibSearch = false;
bool printEachFile = false;
bool printWhyLoad = false;
bool searchDylibsFirst = false;

View File

@ -1020,6 +1020,8 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
config->headerPadMaxInstallNames =
args.hasArg(OPT_headerpad_max_install_names);
config->printDylibSearch =
args.hasArg(OPT_print_dylib_search) || getenv("RC_TRACE_DYLIB_SEARCHING");
config->printEachFile = args.hasArg(OPT_t);
config->printWhyLoad = args.hasArg(OPT_why_load);
config->outputType = getOutputType(args);

View File

@ -81,11 +81,6 @@ public:
explicit DependencyTracker(llvm::StringRef path);
// Adds the given path to the set of not-found files.
inline void logFileNotFound(std::string path) {
if (active)
notFounds.insert(std::move(path));
}
inline void logFileNotFound(const Twine &path) {
if (active)
notFounds.insert(path.str());

View File

@ -176,20 +176,27 @@ std::string macho::createResponseFile(const InputArgList &args) {
return std::string(data.str());
}
Optional<std::string> macho::resolveDylibPath(StringRef path) {
static void searchedDylib(const Twine &path, bool found) {
if (config->printDylibSearch)
message("searched " + path + (found ? ", found " : ", not found"));
if (!found)
depTracker->logFileNotFound(path);
}
Optional<std::string> macho::resolveDylibPath(StringRef dylibPath) {
// TODO: if a tbd and dylib are both present, we should check to make sure
// they are consistent.
if (fs::exists(path))
return std::string(path);
else
depTracker->logFileNotFound(path);
bool dylibExists = fs::exists(dylibPath);
searchedDylib(dylibPath, dylibExists);
if (dylibExists)
return std::string(dylibPath);
SmallString<261> location = path;
path::replace_extension(location, ".tbd");
if (fs::exists(location))
return std::string(location);
else
depTracker->logFileNotFound(location);
SmallString<261> tbdPath = dylibPath;
path::replace_extension(tbdPath, ".tbd");
bool tbdExists = fs::exists(tbdPath);
searchedDylib(tbdPath, tbdExists);
if (tbdExists)
return std::string(tbdPath);
return {};
}
@ -249,10 +256,10 @@ macho::findPathCombination(const Twine &name,
path::append(base, name);
for (StringRef ext : extensions) {
Twine location = base + ext;
if (fs::exists(location))
bool exists = fs::exists(location);
searchedDylib(location, exists);
if (exists)
return saver.save(location.str());
else
depTracker->logFileNotFound(location);
}
}
return {};

View File

@ -49,8 +49,12 @@ def no_lto_legacy_pass_manager : Flag<["--"], "no-lto-legacy-pass-manager">,
def time_trace: Flag<["--"], "time-trace">, HelpText<"Record time trace">;
def time_trace_granularity_eq: Joined<["--"], "time-trace-granularity=">,
HelpText<"Minimum time granularity (in microseconds) traced by time profiler">;
def time_trace_file_eq: Joined<["--"], "time-trace-file=">, HelpText<"Specify time trace output file">;
def deduplicate_literals: Flag<["--"], "deduplicate-literals">, HelpText<"Enable literal deduplication">;
def time_trace_file_eq: Joined<["--"], "time-trace-file=">,
HelpText<"Specify time trace output file">;
def deduplicate_literals: Flag<["--"], "deduplicate-literals">,
HelpText<"Enable literal deduplication">;
def print_dylib_search: Flag<["--"], "print-dylib-search">,
HelpText<"Print which paths lld searched when trying to find dylibs">;
// This is a complete Options.td compiled from Apple's ld(1) manpage
// dated 2018-03-07 and cross checked with ld64 source code in repo

View File

@ -15,7 +15,8 @@
################ default, which is the same as -search_paths_first
# RUN: %lld -L%S/Inputs/MacOSX.sdk/usr/lib -o %t/test -Z \
# RUN: -L%tA -L%tD -L%t -lhello -lgoodbye -lSystem %t/test.o
# RUN: -L%tA -L%tD -L%t -lhello -lgoodbye -lSystem %t/test.o \
# RUN: --print-dylib-search | FileCheck --check-prefix=ARCHIVESEARCH -DPATH=%t %s
# RUN: llvm-objdump --macho --dylibs-used %t/test | FileCheck --check-prefix=ARCHIVE %s
################ Test all permutations of -L%t{A,D} with -search_paths_first
@ -33,8 +34,9 @@
# RUN: llvm-objdump --macho --dylibs-used %t/test | FileCheck --check-prefix=DYLIB %s
################ Test all permutations of -L%t{A,D} with -search_dylibs_first
# RUN: %lld -L%S/Inputs/MacOSX.sdk/usr/lib -o %t/test -Z \
# RUN: -L%tA -L%tD -L%t -lhello -lgoodbye -lSystem %t/test.o -search_dylibs_first
# RUN: env RC_TRACE_DYLIB_SEARCHING=1 %lld -L%S/Inputs/MacOSX.sdk/usr/lib -o %t/test -Z \
# RUN: -L%tA -L%tD -L%t -lhello -lgoodbye -lSystem %t/test.o -search_dylibs_first \
# RUN: | FileCheck --check-prefix=DYLIBSEARCH -DPATH=%t %s
# RUN: llvm-objdump --macho --dylibs-used %t/test | FileCheck --check-prefix=DYLIB %s
# RUN: %lld -L%S/Inputs/MacOSX.sdk/usr/lib -o %t/test -Z \
# RUN: -L%tD -L%tA -L%t -lhello -lgoodbye -lSystem %t/test.o -search_dylibs_first
@ -50,10 +52,26 @@
# DYLIB: @executable_path/libgoodbye.dylib
# DYLIB: /usr/lib/libSystem.dylib
# DYLIBSEARCH: searched {{.*}}/MacOSX.sdk/usr/lib{{[/\\]}}libhello.tbd, not found
# DYLIBSEARCH-NEXT: searched {{.*}}/MacOSX.sdk/usr/lib{{[/\\]}}libhello.dylib, not found
# DYLIBSEARCH-NEXT: searched [[PATH]]A{{[/\\]}}libhello.tbd, not found
# DYLIBSEARCH-NEXT: searched [[PATH]]A{{[/\\]}}libhello.dylib, not found
# DYLIBSEARCH: searched [[PATH]]{{[/\\]}}libhello.dylib, found
# DYLIBSEARCH: searched [[PATH]]D{{[/\\]}}libgoodbye.dylib, found
# ARCHIVE: @executable_path/libhello.dylib
# ARCHIVE-NOT: @executable_path/libgoodbye.dylib
# ARCHIVE: /usr/lib/libSystem.dylib
# ARCHIVESEARCH: searched {{.*}}/MacOSX.sdk/usr/lib{{[/\\]}}libhello.tbd, not found
# ARCHIVESEARCH-NEXT: searched {{.*}}/MacOSX.sdk/usr/lib{{[/\\]}}libhello.dylib, not found
# ARCHIVESEARCH-NEXT: searched {{.*}}/MacOSX.sdk/usr/lib{{[/\\]}}libhello.a, not found
# ARCHIVESEARCH-NEXT: searched [[PATH]]A{{[/\\]}}libhello.tbd, not found
# ARCHIVESEARCH-NEXT: searched [[PATH]]A{{[/\\]}}libhello.dylib, not found
# ARCHIVESEARCH-NEXT: searched [[PATH]]A{{[/\\]}}libhello.a, not found
# ARCHIVESEARCH: searched [[PATH]]{{[/\\]}}libhello.dylib, found
# ARCHIVESEARCH: searched [[PATH]]A{{[/\\]}}libgoodbye.a, found
.section __TEXT,__text
.global _main