[Lldb-commits] [lldb] [lldb] Move LocateExecutableSymbolFile to SymbolLocator plugin (PR #71266)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Fri Nov 3 19:37:51 PDT 2023
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/71266
This builds on top of the work started in c3a302d to convert LocateSymbolFile to a SymbolLocator plugin. This commit moves LocateExecutableSymbolFile.
>From e77c1245a5c3ca69c9f04d44c2be5304e08449e1 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 3 Nov 2023 14:02:13 -0700
Subject: [PATCH] [lldb] Move LocateExecutableSymbolFile to SymbolLocator
plugin
This builds on top of the work started in c3a302d to convert
LocateSymbolFile to a SymbolLocator plugin. This commit moves
LocateExecutableSymbolFile.
---
lldb/include/lldb/Core/PluginManager.h | 6 +
lldb/include/lldb/Symbol/LocateSymbolFile.h | 8 -
lldb/include/lldb/lldb-private-interfaces.h | 2 +
lldb/source/Core/DynamicLoader.cpp | 2 +-
lldb/source/Core/PluginManager.cpp | 20 +-
.../Process/MacOSX-Kernel/ProcessKDP.cpp | 4 +-
.../SymbolFile/DWARF/SymbolFileDWARF.cpp | 2 +-
.../SymbolLocatorDebugSymbols.cpp | 428 +++++++++++++++++-
.../DebugSymbols/SymbolLocatorDebugSymbols.h | 8 +
.../Default/SymbolLocatorDefault.cpp | 148 +++++-
.../Default/SymbolLocatorDefault.h | 8 +
.../SymbolVendor/ELF/SymbolVendorELF.cpp | 2 +-
.../MacOSX/SymbolVendorMacOSX.cpp | 4 +-
.../PECOFF/SymbolVendorPECOFF.cpp | 2 +-
.../SymbolVendor/wasm/SymbolVendorWasm.cpp | 2 +-
lldb/source/Symbol/LocateSymbolFile.cpp | 342 --------------
.../PECOFF/dwarf-gnu-debuglink-i686.yaml | 7 +-
.../unittests/Symbol/LocateSymbolFileTest.cpp | 5 +-
18 files changed, 630 insertions(+), 370 deletions(-)
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index b69aff9e00651bb..50f0662f4bb2b95 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -351,6 +351,8 @@ class PluginManager {
SymbolLocatorCreateInstance create_callback,
SymbolLocatorLocateExecutableObjectFile locate_executable_object_file =
nullptr,
+ SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file =
+ nullptr,
SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle = nullptr);
static bool UnregisterPlugin(SymbolLocatorCreateInstance create_callback);
@@ -360,6 +362,10 @@ class PluginManager {
static ModuleSpec LocateExecutableObjectFile(const ModuleSpec &module_spec);
+ static FileSpec
+ LocateExecutableSymbolFile(const ModuleSpec &module_spec,
+ const FileSpecList &default_search_paths);
+
static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
const UUID *uuid,
const ArchSpec *arch);
diff --git a/lldb/include/lldb/Symbol/LocateSymbolFile.h b/lldb/include/lldb/Symbol/LocateSymbolFile.h
index 03d3d9a2d440edf..3c0f069c27f8dd6 100644
--- a/lldb/include/lldb/Symbol/LocateSymbolFile.h
+++ b/lldb/include/lldb/Symbol/LocateSymbolFile.h
@@ -24,14 +24,6 @@ class UUID;
class Symbols {
public:
- // Locate the symbol file given a module specification.
- //
- // Locating the file should happen only on the local computer or using the
- // current computers global settings.
- static FileSpec
- LocateExecutableSymbolFile(const ModuleSpec &module_spec,
- const FileSpecList &default_search_paths);
-
// Locate the object and symbol file given a module specification.
//
// Locating the file can try to download the file from a corporate build
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index faf85833fe9f9e3..4c324a721029075 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -94,6 +94,8 @@ typedef std::optional<ModuleSpec> (*SymbolLocatorLocateExecutableObjectFile)(
const ModuleSpec &module_spec);
typedef std::optional<FileSpec> (*SymbolLocatorFindSymbolFileInBundle)(
const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch);
+typedef std::optional<FileSpec> (*SymbolLocatorLocateExecutableSymbolFile)(
+ const ModuleSpec &module_spec, const FileSpecList &default_search_paths);
typedef bool (*BreakpointHitCallback)(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index 7751fd70dedd730..efed29da0835ebf 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -219,7 +219,7 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
if (!module_sp) {
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
module_spec.GetSymbolFileSpec() =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
ModuleSpec objfile_module_spec =
PluginManager::LocateExecutableObjectFile(module_spec);
module_spec.GetFileSpec() = objfile_module_spec.GetFileSpec();
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 85c6b1d948a2d85..810e487f723de06 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1089,13 +1089,16 @@ struct SymbolLocatorInstance
llvm::StringRef name, llvm::StringRef description,
CallbackType create_callback,
SymbolLocatorLocateExecutableObjectFile locate_executable_object_file,
+ SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file,
SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle)
: PluginInstance<SymbolLocatorCreateInstance>(name, description,
create_callback),
locate_executable_object_file(locate_executable_object_file),
+ locate_executable_symbol_file(locate_executable_symbol_file),
find_symbol_file_in_bundle(find_symbol_file_in_bundle) {}
SymbolLocatorLocateExecutableObjectFile locate_executable_object_file;
+ SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file;
SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle;
};
typedef PluginInstances<SymbolLocatorInstance> SymbolLocatorInstances;
@@ -1109,10 +1112,11 @@ bool PluginManager::RegisterPlugin(
llvm::StringRef name, llvm::StringRef description,
SymbolLocatorCreateInstance create_callback,
SymbolLocatorLocateExecutableObjectFile locate_executable_object_file,
+ SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file,
SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle) {
return GetSymbolLocatorInstances().RegisterPlugin(
name, description, create_callback, locate_executable_object_file,
- find_symbol_file_in_bundle);
+ locate_executable_symbol_file, find_symbol_file_in_bundle);
}
bool PluginManager::UnregisterPlugin(
@@ -1139,6 +1143,20 @@ PluginManager::LocateExecutableObjectFile(const ModuleSpec &module_spec) {
return {};
}
+FileSpec PluginManager::LocateExecutableSymbolFile(
+ const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
+ auto &instances = GetSymbolLocatorInstances().GetInstances();
+ for (auto &instance : instances) {
+ if (instance.locate_executable_symbol_file) {
+ std::optional<FileSpec> result = instance.locate_executable_symbol_file(
+ module_spec, default_search_paths);
+ if (result)
+ return *result;
+ }
+ }
+ return {};
+}
+
FileSpec PluginManager::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
const UUID *uuid,
const ArchSpec *arch) {
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index 93d8e9bf75f52ea..9af544b31d89649 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -278,8 +278,8 @@ Status ProcessKDP::DoConnectRemote(llvm::StringRef remote_url) {
FileSpecList search_paths =
Target::GetDefaultDebugFileSearchPaths();
module_spec.GetSymbolFileSpec() =
- Symbols::LocateExecutableSymbolFile(module_spec,
- search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec,
+ search_paths);
if (module_spec.GetSymbolFileSpec()) {
ModuleSpec executable_module_spec =
PluginManager::LocateExecutableObjectFile(module_spec);
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 63b2c3a0c883097..122ab57e06ad9d7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -4329,7 +4329,7 @@ const std::shared_ptr<SymbolFileDWARFDwo> &SymbolFileDWARF::GetDwpSymbolFile() {
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dwp_filespec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (FileSystem::Instance().Exists(dwp_filespec)) {
DataBufferSP dwp_file_data_sp;
lldb::offset_t dwp_file_data_offset = 0;
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
index 217080bfd3ef3b1..2c57ef8b6a54ea0 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
@@ -65,7 +65,8 @@ SymbolLocatorDebugSymbols::SymbolLocatorDebugSymbols() : SymbolLocator() {}
void SymbolLocatorDebugSymbols::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
- LocateExecutableObjectFile, FindSymbolFileInBundle);
+ LocateExecutableObjectFile, LocateExecutableSymbolFile,
+ FindSymbolFileInBundle);
}
void SymbolLocatorDebugSymbols::Terminate() {
@@ -363,3 +364,428 @@ std::optional<FileSpec> SymbolLocatorDebugSymbols::FindSymbolFileInBundle(
return {};
}
+
+static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
+ const ArchSpec *arch,
+ const lldb_private::UUID *uuid) {
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) {
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i) {
+ bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
+ UNUSED_IF_ASSERT_DISABLED(got_spec);
+ assert(got_spec);
+ if ((uuid == nullptr || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == nullptr ||
+ (spec.GetArchitecturePtr() &&
+ spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+// Given a binary exec_fspec, and a ModuleSpec with an architecture/uuid,
+// return true if there is a matching dSYM bundle next to the exec_fspec,
+// and return that value in dsym_fspec.
+// If there is a .dSYM.yaa compressed archive next to the exec_fspec,
+// call through Symbols::DownloadObjectAndSymbolFile to download the
+// expanded/uncompressed dSYM and return that filepath in dsym_fspec.
+static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec,
+ const FileSpec &exec_fspec,
+ FileSpec &dsym_fspec) {
+ ConstString filename = exec_fspec.GetFilename();
+ FileSpec dsym_directory = exec_fspec;
+ dsym_directory.RemoveLastPathComponent();
+
+ std::string dsym_filename = filename.AsCString();
+ dsym_filename += ".dSYM";
+ dsym_directory.AppendPathComponent(dsym_filename);
+ dsym_directory.AppendPathComponent("Contents");
+ dsym_directory.AppendPathComponent("Resources");
+ dsym_directory.AppendPathComponent("DWARF");
+
+ if (FileSystem::Instance().Exists(dsym_directory)) {
+
+ // See if the binary name exists in the dSYM DWARF
+ // subdir.
+ dsym_fspec = dsym_directory;
+ dsym_fspec.AppendPathComponent(filename.AsCString());
+ if (FileSystem::Instance().Exists(dsym_fspec) &&
+ FileAtPathContainsArchAndUUID(dsym_fspec, mod_spec.GetArchitecturePtr(),
+ mod_spec.GetUUIDPtr())) {
+ return true;
+ }
+
+ // See if we have "../CF.framework" - so we'll look for
+ // CF.framework.dSYM/Contents/Resources/DWARF/CF
+ // We need to drop the last suffix after '.' to match
+ // 'CF' in the DWARF subdir.
+ std::string binary_name(filename.AsCString());
+ auto last_dot = binary_name.find_last_of('.');
+ if (last_dot != std::string::npos) {
+ binary_name.erase(last_dot);
+ dsym_fspec = dsym_directory;
+ dsym_fspec.AppendPathComponent(binary_name);
+ if (FileSystem::Instance().Exists(dsym_fspec) &&
+ FileAtPathContainsArchAndUUID(dsym_fspec,
+ mod_spec.GetArchitecturePtr(),
+ mod_spec.GetUUIDPtr())) {
+ return true;
+ }
+ }
+ }
+
+ // See if we have a .dSYM.yaa next to this executable path.
+ FileSpec dsym_yaa_fspec = exec_fspec;
+ dsym_yaa_fspec.RemoveLastPathComponent();
+ std::string dsym_yaa_filename = filename.AsCString();
+ dsym_yaa_filename += ".dSYM.yaa";
+ dsym_yaa_fspec.AppendPathComponent(dsym_yaa_filename);
+
+ if (FileSystem::Instance().Exists(dsym_yaa_fspec)) {
+ ModuleSpec mutable_mod_spec = mod_spec;
+ Status error;
+ if (Symbols::DownloadObjectAndSymbolFile(mutable_mod_spec, error, true) &&
+ FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) {
+ dsym_fspec = mutable_mod_spec.GetSymbolFileSpec();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Given a ModuleSpec with a FileSpec and optionally uuid/architecture
+// filled in, look for a .dSYM bundle next to that binary. Returns true
+// if a .dSYM bundle is found, and that path is returned in the dsym_fspec
+// FileSpec.
+//
+// This routine looks a few directory layers above the given exec_path -
+// exec_path might be /System/Library/Frameworks/CF.framework/CF and the
+// dSYM might be /System/Library/Frameworks/CF.framework.dSYM.
+//
+// If there is a .dSYM.yaa compressed archive found next to the binary,
+// we'll call DownloadObjectAndSymbolFile to expand it into a plain .dSYM
+static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
+ FileSpec &dsym_fspec) {
+ Log *log = GetLog(LLDBLog::Host);
+ const FileSpec &exec_fspec = module_spec.GetFileSpec();
+ if (exec_fspec) {
+ if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec,
+ dsym_fspec)) {
+ if (log) {
+ LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
+ dsym_fspec.GetPath().c_str());
+ }
+ return true;
+ } else {
+ FileSpec parent_dirs = exec_fspec;
+
+ // Remove the binary name from the FileSpec
+ parent_dirs.RemoveLastPathComponent();
+
+ // Add a ".dSYM" name to each directory component of the path,
+ // stripping off components. e.g. we may have a binary like
+ // /S/L/F/Foundation.framework/Versions/A/Foundation and
+ // /S/L/F/Foundation.framework.dSYM
+ //
+ // so we'll need to start with
+ // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the
+ // "A", and if that doesn't exist, strip off the "A" and try it again
+ // with "Versions", etc., until we find a dSYM bundle or we've
+ // stripped off enough path components that there's no need to
+ // continue.
+
+ for (int i = 0; i < 4; i++) {
+ // Does this part of the path have a "." character - could it be a
+ // bundle's top level directory?
+ const char *fn = parent_dirs.GetFilename().AsCString();
+ if (fn == nullptr)
+ break;
+ if (::strchr(fn, '.') != nullptr) {
+ if (::LookForDsymNextToExecutablePath(module_spec, parent_dirs,
+ dsym_fspec)) {
+ if (log) {
+ LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
+ dsym_fspec.GetPath().c_str());
+ }
+ return true;
+ }
+ }
+ parent_dirs.RemoveLastPathComponent();
+ }
+ }
+ }
+ dsym_fspec.Clear();
+ return false;
+}
+
+static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
+ ModuleSpec &return_module_spec) {
+ Log *log = GetLog(LLDBLog::Host);
+ if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
+ LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
+ return 0;
+ }
+
+ return_module_spec = module_spec;
+ return_module_spec.GetFileSpec().Clear();
+ return_module_spec.GetSymbolFileSpec().Clear();
+
+ const UUID *uuid = module_spec.GetUUIDPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+
+ int items_found = 0;
+
+ if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
+ g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
+ void *handle = dlopen(
+ "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (handle) {
+ g_dlsym_DBGCopyFullDSYMURLForUUID =
+ (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle,
+ "DBGCopyFullDSYMURLForUUID");
+ g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym(
+ handle, "DBGCopyDSYMPropertyLists");
+ }
+ }
+
+ if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
+ g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
+ return items_found;
+ }
+
+ if (uuid && uuid->IsValid()) {
+ // Try and locate the dSYM file using DebugSymbols first
+ llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
+ if (module_uuid.size() == 16) {
+ CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
+ NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
+ module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
+ module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
+ module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
+
+ if (module_uuid_ref.get()) {
+ CFCReleaser<CFURLRef> exec_url;
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ if (exec_fspec) {
+ char exec_cf_path[PATH_MAX];
+ if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
+ exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
+ NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
+ FALSE));
+ }
+
+ CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID(
+ module_uuid_ref.get(), exec_url.get()));
+ char path[PATH_MAX];
+
+ if (dsym_url.get()) {
+ if (::CFURLGetFileSystemRepresentation(
+ dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
+ LLDB_LOGF(log,
+ "DebugSymbols framework returned dSYM path of %s for "
+ "UUID %s -- looking for the dSYM",
+ path, uuid->GetAsString().c_str());
+ FileSpec dsym_filespec(path);
+ if (path[0] == '~')
+ FileSystem::Instance().Resolve(dsym_filespec);
+
+ if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
+ dsym_filespec = PluginManager::FindSymbolFileInBundle(
+ dsym_filespec, uuid, arch);
+ ++items_found;
+ } else {
+ ++items_found;
+ }
+ return_module_spec.GetSymbolFileSpec() = dsym_filespec;
+ }
+
+ bool success = false;
+ if (log) {
+ if (::CFURLGetFileSystemRepresentation(
+ dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
+ LLDB_LOGF(log,
+ "DebugSymbols framework returned dSYM path of %s for "
+ "UUID %s -- looking for an exec file",
+ path, uuid->GetAsString().c_str());
+ }
+ }
+
+ CFCReleaser<CFDictionaryRef> dict(
+ g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get()));
+ CFDictionaryRef uuid_dict = NULL;
+ if (dict.get()) {
+ CFCString uuid_cfstr(uuid->GetAsString().c_str());
+ uuid_dict = static_cast<CFDictionaryRef>(
+ ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
+ }
+
+ // Check to see if we have the file on the local filesystem.
+ if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
+ ModuleSpec exe_spec;
+ exe_spec.GetFileSpec() = module_spec.GetFileSpec();
+ exe_spec.GetUUID() = module_spec.GetUUID();
+ ModuleSP module_sp;
+ module_sp.reset(new Module(exe_spec));
+ if (module_sp && module_sp->GetObjectFile() &&
+ module_sp->MatchesModuleSpec(exe_spec)) {
+ success = true;
+ return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
+ LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
+ module_spec.GetFileSpec().GetPath().c_str(),
+ uuid->GetAsString().c_str());
+ ++items_found;
+ }
+ }
+
+ // Check if the requested image is in our shared cache.
+ if (!success) {
+ SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
+ module_spec.GetFileSpec().GetPath());
+
+ // If we found it and it has the correct UUID, let's proceed with
+ // creating a module from the memory contents.
+ if (image_info.uuid && (!module_spec.GetUUID() ||
+ module_spec.GetUUID() == image_info.uuid)) {
+ success = true;
+ return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
+ LLDB_LOGF(log,
+ "using binary from shared cache for filepath %s for "
+ "UUID %s",
+ module_spec.GetFileSpec().GetPath().c_str(),
+ uuid->GetAsString().c_str());
+ ++items_found;
+ }
+ }
+
+ // Use the DBGSymbolRichExecutable filepath if present
+ if (!success && uuid_dict) {
+ CFStringRef exec_cf_path =
+ static_cast<CFStringRef>(::CFDictionaryGetValue(
+ uuid_dict, CFSTR("DBGSymbolRichExecutable")));
+ if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
+ exec_cf_path, path, sizeof(path))) {
+ LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
+ path, uuid->GetAsString().c_str());
+ ++items_found;
+ FileSpec exec_filespec(path);
+ if (path[0] == '~')
+ FileSystem::Instance().Resolve(exec_filespec);
+ if (FileSystem::Instance().Exists(exec_filespec)) {
+ success = true;
+ return_module_spec.GetFileSpec() = exec_filespec;
+ }
+ }
+ }
+
+ // Look next to the dSYM for the binary file.
+ if (!success) {
+ if (::CFURLGetFileSystemRepresentation(
+ dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
+ char *dsym_extension_pos = ::strstr(path, ".dSYM");
+ if (dsym_extension_pos) {
+ *dsym_extension_pos = '\0';
+ LLDB_LOGF(log,
+ "Looking for executable binary next to dSYM "
+ "bundle with name with name %s",
+ path);
+ FileSpec file_spec(path);
+ FileSystem::Instance().Resolve(file_spec);
+ ModuleSpecList module_specs;
+ ModuleSpec matched_module_spec;
+ using namespace llvm::sys::fs;
+ switch (get_file_type(file_spec.GetPath())) {
+
+ case file_type::directory_file: // Bundle directory?
+ {
+ CFCBundle bundle(path);
+ CFCReleaser<CFURLRef> bundle_exe_url(
+ bundle.CopyExecutableURL());
+ if (bundle_exe_url.get()) {
+ if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
+ true, (UInt8 *)path,
+ sizeof(path) - 1)) {
+ FileSpec bundle_exe_file_spec(path);
+ FileSystem::Instance().Resolve(bundle_exe_file_spec);
+ if (ObjectFile::GetModuleSpecifications(
+ bundle_exe_file_spec, 0, 0, module_specs) &&
+ module_specs.FindMatchingModuleSpec(
+ module_spec, matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = bundle_exe_file_spec;
+ LLDB_LOGF(log,
+ "Executable binary %s next to dSYM is "
+ "compatible; using",
+ path);
+ }
+ }
+ }
+ } break;
+
+ case file_type::fifo_file: // Forget pipes
+ case file_type::socket_file: // We can't process socket files
+ case file_type::file_not_found: // File doesn't exist...
+ case file_type::status_error:
+ break;
+
+ case file_type::type_unknown:
+ case file_type::regular_file:
+ case file_type::symlink_file:
+ case file_type::block_file:
+ case file_type::character_file:
+ if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
+ module_specs) &&
+ module_specs.FindMatchingModuleSpec(module_spec,
+ matched_module_spec))
+
+ {
+ ++items_found;
+ return_module_spec.GetFileSpec() = file_spec;
+ LLDB_LOGF(log,
+ "Executable binary %s next to dSYM is "
+ "compatible; using",
+ path);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return items_found;
+}
+
+std::optional<FileSpec> SymbolLocatorDebugSymbols::LocateExecutableSymbolFile(
+ const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
+ const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
+ const ArchSpec *arch = module_spec.GetArchitecturePtr();
+ const UUID *uuid = module_spec.GetUUIDPtr();
+
+ LLDB_SCOPED_TIMERF(
+ "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
+ exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
+ arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
+
+ FileSpec symbol_fspec;
+ ModuleSpec dsym_module_spec;
+ // First try and find the dSYM in the same directory as the executable or in
+ // an appropriate parent directory
+ if (!LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec)) {
+ // We failed to easily find the dSYM above, so use DebugSymbols
+ LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec);
+ } else {
+ dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
+ }
+
+ return dsym_module_spec.GetSymbolFileSpec();
+}
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
index 256ac9372edd28f..72bd6de433dd706 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
@@ -38,6 +38,14 @@ class SymbolLocatorDebugSymbols : public SymbolLocator {
static std::optional<ModuleSpec>
LocateExecutableObjectFile(const ModuleSpec &module_spec);
+ // Locate the symbol file given a module specification.
+ //
+ // Locating the file should happen only on the local computer or using the
+ // current computers global settings.
+ static std::optional<FileSpec>
+ LocateExecutableSymbolFile(const ModuleSpec &module_spec,
+ const FileSpecList &default_search_paths);
+
static std::optional<FileSpec>
FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const UUID *uuid,
const ArchSpec *arch);
diff --git a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
index 4ccca5ca0f6a1e8..831b2b1ae0c4961 100644
--- a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
+++ b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
@@ -49,9 +49,9 @@ LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)
SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
void SymbolLocatorDefault::Initialize() {
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(), CreateInstance,
- LocateExecutableObjectFile);
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
+ LocateExecutableObjectFile, LocateExecutableSymbolFile);
}
void SymbolLocatorDefault::Terminate() {
@@ -88,3 +88,145 @@ std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile(
return {};
}
+
+// Keep "symbols.enable-external-lookup" description in sync with this function.
+std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile(
+ const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
+
+ FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
+ if (symbol_file_spec.IsAbsolute() &&
+ FileSystem::Instance().Exists(symbol_file_spec))
+ return symbol_file_spec;
+
+ Progress progress(llvm::formatv(
+ "Locating external symbol file for {0}",
+ module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")));
+
+ FileSpecList debug_file_search_paths = default_search_paths;
+
+ // Add module directory.
+ FileSpec module_file_spec = module_spec.GetFileSpec();
+ // We keep the unresolved pathname if it fails.
+ FileSystem::Instance().ResolveSymbolicLink(module_file_spec,
+ module_file_spec);
+
+ ConstString file_dir = module_file_spec.GetDirectory();
+ {
+ FileSpec file_spec(file_dir.AsCString("."));
+ FileSystem::Instance().Resolve(file_spec);
+ debug_file_search_paths.AppendIfUnique(file_spec);
+ }
+
+ if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
+
+ // Add current working directory.
+ {
+ FileSpec file_spec(".");
+ FileSystem::Instance().Resolve(file_spec);
+ debug_file_search_paths.AppendIfUnique(file_spec);
+ }
+
+#ifndef _WIN32
+#if defined(__NetBSD__)
+ // Add /usr/libdata/debug directory.
+ {
+ FileSpec file_spec("/usr/libdata/debug");
+ FileSystem::Instance().Resolve(file_spec);
+ debug_file_search_paths.AppendIfUnique(file_spec);
+ }
+#else
+ // Add /usr/lib/debug directory.
+ {
+ FileSpec file_spec("/usr/lib/debug");
+ FileSystem::Instance().Resolve(file_spec);
+ debug_file_search_paths.AppendIfUnique(file_spec);
+ }
+#endif
+#endif // _WIN32
+ }
+
+ std::string uuid_str;
+ const UUID &module_uuid = module_spec.GetUUID();
+ if (module_uuid.IsValid()) {
+ // Some debug files are stored in the .build-id directory like this:
+ // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
+ uuid_str = module_uuid.GetAsString("");
+ std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(),
+ ::tolower);
+ uuid_str.insert(2, 1, '/');
+ uuid_str = uuid_str + ".debug";
+ }
+
+ size_t num_directories = debug_file_search_paths.GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx) {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
+ FileSystem::Instance().Resolve(dirspec);
+ if (!FileSystem::Instance().IsDirectory(dirspec))
+ continue;
+
+ std::vector<std::string> files;
+ std::string dirname = dirspec.GetPath();
+
+ if (!uuid_str.empty())
+ files.push_back(dirname + "/.build-id/" + uuid_str);
+ if (symbol_file_spec.GetFilename()) {
+ files.push_back(dirname + "/" +
+ symbol_file_spec.GetFilename().GetCString());
+ files.push_back(dirname + "/.debug/" +
+ symbol_file_spec.GetFilename().GetCString());
+
+ // Some debug files may stored in the module directory like this:
+ // /usr/lib/debug/usr/lib/library.so.debug
+ if (!file_dir.IsEmpty())
+ files.push_back(dirname + file_dir.AsCString() + "/" +
+ symbol_file_spec.GetFilename().GetCString());
+ }
+
+ const uint32_t num_files = files.size();
+ for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
+ const std::string &filename = files[idx_file];
+ FileSpec file_spec(filename);
+ FileSystem::Instance().Resolve(file_spec);
+
+ if (llvm::sys::fs::equivalent(file_spec.GetPath(),
+ module_file_spec.GetPath()))
+ continue;
+
+ if (FileSystem::Instance().Exists(file_spec)) {
+ lldb_private::ModuleSpecList specs;
+ const size_t num_specs =
+ ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
+ ModuleSpec mspec;
+ bool valid_mspec = false;
+ if (num_specs == 2) {
+ // Special case to handle both i386 and i686 from ObjectFilePECOFF
+ ModuleSpec mspec2;
+ if (specs.GetModuleSpecAtIndex(0, mspec) &&
+ specs.GetModuleSpecAtIndex(1, mspec2) &&
+ mspec.GetArchitecture().GetTriple().isCompatibleWith(
+ mspec2.GetArchitecture().GetTriple())) {
+ valid_mspec = true;
+ }
+ }
+ if (!valid_mspec) {
+ assert(num_specs <= 1 &&
+ "Symbol Vendor supports only a single architecture");
+ if (num_specs == 1) {
+ if (specs.GetModuleSpecAtIndex(0, mspec)) {
+ valid_mspec = true;
+ }
+ }
+ }
+ if (valid_mspec) {
+ // Skip the uuids check if module_uuid is invalid. For example,
+ // this happens for *.dwp files since at the moment llvm-dwp
+ // doesn't output build ids, nor does binutils dwp.
+ if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
+ return file_spec;
+ }
+ }
+ }
+ }
+
+ return {};
+}
diff --git a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
index b1bb58ec298047a..99e0f0b1a78dc8c 100644
--- a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
+++ b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
@@ -37,6 +37,14 @@ class SymbolLocatorDefault : public SymbolLocator {
// current computers global settings.
static std::optional<ModuleSpec>
LocateExecutableObjectFile(const ModuleSpec &module_spec);
+
+ // Locate the symbol file given a module specification.
+ //
+ // Locating the file should happen only on the local computer or using the
+ // current computers global settings.
+ static std::optional<FileSpec>
+ LocateExecutableSymbolFile(const ModuleSpec &module_spec,
+ const FileSpecList &default_search_paths);
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
index 55a663bb1b9630d..cb61063151f1fdc 100644
--- a/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
+++ b/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
@@ -87,7 +87,7 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp,
module_spec.GetUUID() = uuid;
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dsym_fspec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (!dsym_fspec)
return nullptr;
diff --git a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
index 6008c582454a7ba..6fc9e40ba4a1285 100644
--- a/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
+++ b/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp
@@ -130,7 +130,7 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,
module_spec.GetUUID() = module_sp->GetUUID();
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
dsym_fspec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (module_spec.GetSourceMappingList().GetSize())
module_sp->GetSourceMappingList().Append(
module_spec.GetSourceMappingList(), true);
@@ -149,7 +149,7 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp,
FileSystem::Instance().GetByteSize(dsym_fspec),
dsym_file_data_sp, dsym_file_data_offset);
// Important to save the dSYM FileSpec so we don't call
- // Symbols::LocateExecutableSymbolFile a second time while trying to
+ // PluginManager::LocateExecutableSymbolFile a second time while trying to
// add the symbol ObjectFile to this Module.
if (dsym_objfile_sp && !module_sp->GetSymbolFileFileSpec()) {
module_sp->SetSymbolFileFileSpec(dsym_fspec);
diff --git a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
index 0f8d3108998da54..e4f4308d86c85a0 100644
--- a/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
+++ b/lldb/source/Plugins/SymbolVendor/PECOFF/SymbolVendorPECOFF.cpp
@@ -87,7 +87,7 @@ SymbolVendorPECOFF::CreateInstance(const lldb::ModuleSP &module_sp,
module_spec.GetUUID() = uuid;
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec dsym_fspec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (!dsym_fspec)
return nullptr;
diff --git a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
index 91b10ea64535d45..22ab7b001d3a84d 100644
--- a/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
+++ b/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp
@@ -87,7 +87,7 @@ SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp,
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec sym_fspec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
if (!sym_fspec)
return nullptr;
diff --git a/lldb/source/Symbol/LocateSymbolFile.cpp b/lldb/source/Symbol/LocateSymbolFile.cpp
index d9414ef93aa7135..17f5a090c71882d 100644
--- a/lldb/source/Symbol/LocateSymbolFile.cpp
+++ b/lldb/source/Symbol/LocateSymbolFile.cpp
@@ -35,348 +35,6 @@ typedef int cpu_subtype_t;
using namespace lldb;
using namespace lldb_private;
-#if defined(__APPLE__)
-
-// Forward declaration of method defined in source/Host/macosx/Symbols.cpp
-int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
- ModuleSpec &return_module_spec);
-
-#else
-
-int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
- ModuleSpec &return_module_spec) {
- // Cannot find MacOSX files using debug symbols on non MacOSX.
- return 0;
-}
-
-#endif
-
-static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
- const ArchSpec *arch,
- const lldb_private::UUID *uuid) {
- ModuleSpecList module_specs;
- if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) {
- ModuleSpec spec;
- for (size_t i = 0; i < module_specs.GetSize(); ++i) {
- bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
- UNUSED_IF_ASSERT_DISABLED(got_spec);
- assert(got_spec);
- if ((uuid == nullptr || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
- (arch == nullptr ||
- (spec.GetArchitecturePtr() &&
- spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
- return true;
- }
- }
- }
- return false;
-}
-
-// Given a binary exec_fspec, and a ModuleSpec with an architecture/uuid,
-// return true if there is a matching dSYM bundle next to the exec_fspec,
-// and return that value in dsym_fspec.
-// If there is a .dSYM.yaa compressed archive next to the exec_fspec,
-// call through Symbols::DownloadObjectAndSymbolFile to download the
-// expanded/uncompressed dSYM and return that filepath in dsym_fspec.
-
-static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec,
- const FileSpec &exec_fspec,
- FileSpec &dsym_fspec) {
- ConstString filename = exec_fspec.GetFilename();
- FileSpec dsym_directory = exec_fspec;
- dsym_directory.RemoveLastPathComponent();
-
- std::string dsym_filename = filename.AsCString();
- dsym_filename += ".dSYM";
- dsym_directory.AppendPathComponent(dsym_filename);
- dsym_directory.AppendPathComponent("Contents");
- dsym_directory.AppendPathComponent("Resources");
- dsym_directory.AppendPathComponent("DWARF");
-
- if (FileSystem::Instance().Exists(dsym_directory)) {
-
- // See if the binary name exists in the dSYM DWARF
- // subdir.
- dsym_fspec = dsym_directory;
- dsym_fspec.AppendPathComponent(filename.AsCString());
- if (FileSystem::Instance().Exists(dsym_fspec) &&
- FileAtPathContainsArchAndUUID(dsym_fspec, mod_spec.GetArchitecturePtr(),
- mod_spec.GetUUIDPtr())) {
- return true;
- }
-
- // See if we have "../CF.framework" - so we'll look for
- // CF.framework.dSYM/Contents/Resources/DWARF/CF
- // We need to drop the last suffix after '.' to match
- // 'CF' in the DWARF subdir.
- std::string binary_name(filename.AsCString());
- auto last_dot = binary_name.find_last_of('.');
- if (last_dot != std::string::npos) {
- binary_name.erase(last_dot);
- dsym_fspec = dsym_directory;
- dsym_fspec.AppendPathComponent(binary_name);
- if (FileSystem::Instance().Exists(dsym_fspec) &&
- FileAtPathContainsArchAndUUID(dsym_fspec,
- mod_spec.GetArchitecturePtr(),
- mod_spec.GetUUIDPtr())) {
- return true;
- }
- }
- }
-
- // See if we have a .dSYM.yaa next to this executable path.
- FileSpec dsym_yaa_fspec = exec_fspec;
- dsym_yaa_fspec.RemoveLastPathComponent();
- std::string dsym_yaa_filename = filename.AsCString();
- dsym_yaa_filename += ".dSYM.yaa";
- dsym_yaa_fspec.AppendPathComponent(dsym_yaa_filename);
-
- if (FileSystem::Instance().Exists(dsym_yaa_fspec)) {
- ModuleSpec mutable_mod_spec = mod_spec;
- Status error;
- if (Symbols::DownloadObjectAndSymbolFile(mutable_mod_spec, error, true) &&
- FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) {
- dsym_fspec = mutable_mod_spec.GetSymbolFileSpec();
- return true;
- }
- }
-
- return false;
-}
-
-// Given a ModuleSpec with a FileSpec and optionally uuid/architecture
-// filled in, look for a .dSYM bundle next to that binary. Returns true
-// if a .dSYM bundle is found, and that path is returned in the dsym_fspec
-// FileSpec.
-//
-// This routine looks a few directory layers above the given exec_path -
-// exec_path might be /System/Library/Frameworks/CF.framework/CF and the
-// dSYM might be /System/Library/Frameworks/CF.framework.dSYM.
-//
-// If there is a .dSYM.yaa compressed archive found next to the binary,
-// we'll call DownloadObjectAndSymbolFile to expand it into a plain .dSYM
-
-static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec,
- FileSpec &dsym_fspec) {
- Log *log = GetLog(LLDBLog::Host);
- const FileSpec &exec_fspec = module_spec.GetFileSpec();
- if (exec_fspec) {
- if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec,
- dsym_fspec)) {
- if (log) {
- LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
- dsym_fspec.GetPath().c_str());
- }
- return true;
- } else {
- FileSpec parent_dirs = exec_fspec;
-
- // Remove the binary name from the FileSpec
- parent_dirs.RemoveLastPathComponent();
-
- // Add a ".dSYM" name to each directory component of the path,
- // stripping off components. e.g. we may have a binary like
- // /S/L/F/Foundation.framework/Versions/A/Foundation and
- // /S/L/F/Foundation.framework.dSYM
- //
- // so we'll need to start with
- // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the
- // "A", and if that doesn't exist, strip off the "A" and try it again
- // with "Versions", etc., until we find a dSYM bundle or we've
- // stripped off enough path components that there's no need to
- // continue.
-
- for (int i = 0; i < 4; i++) {
- // Does this part of the path have a "." character - could it be a
- // bundle's top level directory?
- const char *fn = parent_dirs.GetFilename().AsCString();
- if (fn == nullptr)
- break;
- if (::strchr(fn, '.') != nullptr) {
- if (::LookForDsymNextToExecutablePath(module_spec, parent_dirs,
- dsym_fspec)) {
- if (log) {
- LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s",
- dsym_fspec.GetPath().c_str());
- }
- return true;
- }
- }
- parent_dirs.RemoveLastPathComponent();
- }
- }
- }
- dsym_fspec.Clear();
- return false;
-}
-
-static FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) {
- const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
- const ArchSpec *arch = module_spec.GetArchitecturePtr();
- const UUID *uuid = module_spec.GetUUIDPtr();
-
- LLDB_SCOPED_TIMERF(
- "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
- exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
- arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
-
- FileSpec symbol_fspec;
- ModuleSpec dsym_module_spec;
- // First try and find the dSYM in the same directory as the executable or in
- // an appropriate parent directory
- if (!LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec)) {
- // We failed to easily find the dSYM above, so use DebugSymbols
- LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec);
- } else {
- dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
- }
-
- return dsym_module_spec.GetSymbolFileSpec();
-}
-
-// Keep "symbols.enable-external-lookup" description in sync with this function.
-
-FileSpec
-Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec,
- const FileSpecList &default_search_paths) {
- FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
- if (symbol_file_spec.IsAbsolute() &&
- FileSystem::Instance().Exists(symbol_file_spec))
- return symbol_file_spec;
-
- Progress progress(llvm::formatv(
- "Locating external symbol file for {0}",
- module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")));
-
- FileSpecList debug_file_search_paths = default_search_paths;
-
- // Add module directory.
- FileSpec module_file_spec = module_spec.GetFileSpec();
- // We keep the unresolved pathname if it fails.
- FileSystem::Instance().ResolveSymbolicLink(module_file_spec,
- module_file_spec);
-
- ConstString file_dir = module_file_spec.GetDirectory();
- {
- FileSpec file_spec(file_dir.AsCString("."));
- FileSystem::Instance().Resolve(file_spec);
- debug_file_search_paths.AppendIfUnique(file_spec);
- }
-
- if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
-
- // Add current working directory.
- {
- FileSpec file_spec(".");
- FileSystem::Instance().Resolve(file_spec);
- debug_file_search_paths.AppendIfUnique(file_spec);
- }
-
-#ifndef _WIN32
-#if defined(__NetBSD__)
- // Add /usr/libdata/debug directory.
- {
- FileSpec file_spec("/usr/libdata/debug");
- FileSystem::Instance().Resolve(file_spec);
- debug_file_search_paths.AppendIfUnique(file_spec);
- }
-#else
- // Add /usr/lib/debug directory.
- {
- FileSpec file_spec("/usr/lib/debug");
- FileSystem::Instance().Resolve(file_spec);
- debug_file_search_paths.AppendIfUnique(file_spec);
- }
-#endif
-#endif // _WIN32
- }
-
- std::string uuid_str;
- const UUID &module_uuid = module_spec.GetUUID();
- if (module_uuid.IsValid()) {
- // Some debug files are stored in the .build-id directory like this:
- // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
- uuid_str = module_uuid.GetAsString("");
- std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(),
- ::tolower);
- uuid_str.insert(2, 1, '/');
- uuid_str = uuid_str + ".debug";
- }
-
- size_t num_directories = debug_file_search_paths.GetSize();
- for (size_t idx = 0; idx < num_directories; ++idx) {
- FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
- FileSystem::Instance().Resolve(dirspec);
- if (!FileSystem::Instance().IsDirectory(dirspec))
- continue;
-
- std::vector<std::string> files;
- std::string dirname = dirspec.GetPath();
-
- if (!uuid_str.empty())
- files.push_back(dirname + "/.build-id/" + uuid_str);
- if (symbol_file_spec.GetFilename()) {
- files.push_back(dirname + "/" +
- symbol_file_spec.GetFilename().GetCString());
- files.push_back(dirname + "/.debug/" +
- symbol_file_spec.GetFilename().GetCString());
-
- // Some debug files may stored in the module directory like this:
- // /usr/lib/debug/usr/lib/library.so.debug
- if (!file_dir.IsEmpty())
- files.push_back(dirname + file_dir.AsCString() + "/" +
- symbol_file_spec.GetFilename().GetCString());
- }
-
- const uint32_t num_files = files.size();
- for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
- const std::string &filename = files[idx_file];
- FileSpec file_spec(filename);
- FileSystem::Instance().Resolve(file_spec);
-
- if (llvm::sys::fs::equivalent(file_spec.GetPath(),
- module_file_spec.GetPath()))
- continue;
-
- if (FileSystem::Instance().Exists(file_spec)) {
- lldb_private::ModuleSpecList specs;
- const size_t num_specs =
- ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
- ModuleSpec mspec;
- bool valid_mspec = false;
- if (num_specs == 2) {
- // Special case to handle both i386 and i686 from ObjectFilePECOFF
- ModuleSpec mspec2;
- if (specs.GetModuleSpecAtIndex(0, mspec) &&
- specs.GetModuleSpecAtIndex(1, mspec2) &&
- mspec.GetArchitecture().GetTriple().isCompatibleWith(
- mspec2.GetArchitecture().GetTriple())) {
- valid_mspec = true;
- }
- }
- if (!valid_mspec) {
- assert(num_specs <= 1 &&
- "Symbol Vendor supports only a single architecture");
- if (num_specs == 1) {
- if (specs.GetModuleSpecAtIndex(0, mspec)) {
- valid_mspec = true;
- }
- }
- }
- if (valid_mspec) {
- // Skip the uuids check if module_uuid is invalid. For example,
- // this happens for *.dwp files since at the moment llvm-dwp
- // doesn't output build ids, nor does binutils dwp.
- if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
- return file_spec;
- }
- }
- }
- }
-
- return LocateExecutableSymbolFileDsym(module_spec);
-}
-
void Symbols::DownloadSymbolFileAsync(const UUID &uuid) {
if (!ModuleList::GetGlobalModuleListProperties().GetEnableBackgroundLookup())
return;
diff --git a/lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml b/lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
index a28a4f396d68d77..aa07830dad4d7f6 100644
--- a/lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
+++ b/lldb/test/Shell/ObjectFile/PECOFF/dwarf-gnu-debuglink-i686.yaml
@@ -2,10 +2,9 @@
# gnu-debuglink section to it linking to the unstripped version of the object
# file. The debug info shall be loaded from the gnu-debuglink reference.
#
-# This test is added to check that Symbols::LocateExecutableSymbolFile (in
-# LocateSymbolFile.cpp) can handle ObjectFilePECOFF::GetModuleSpecifications
-# returning two different module specs for MachineX86 -- "i386-pc-windows" and
-# "i686-pc-windows".
+# This test is added to check that LocateExecutableSymbolFile can handle
+# ObjectFilePECOFF::GetModuleSpecifications returning two different module
+# specs for MachineX86 -- "i386-pc-windows" and "i686-pc-windows".
# RUN: yaml2obj %s -o %t
# RUN: llvm-objcopy --strip-all --add-gnu-debuglink=%t %t %t.stripped
diff --git a/lldb/unittests/Symbol/LocateSymbolFileTest.cpp b/lldb/unittests/Symbol/LocateSymbolFileTest.cpp
index 268faeaf1dbbda3..d243a9df6e8a320 100644
--- a/lldb/unittests/Symbol/LocateSymbolFileTest.cpp
+++ b/lldb/unittests/Symbol/LocateSymbolFileTest.cpp
@@ -10,6 +10,7 @@
#include "TestingSupport/SubsystemRAII.h"
#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/LocateSymbolFile.h"
@@ -30,7 +31,7 @@ TEST_F(
ModuleSpec module_spec;
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec symbol_file_spec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
}
@@ -42,6 +43,6 @@ TEST_F(SymbolsTest,
"4A524676-B24B-4F4E-968A-551D465EBAF1.so", FileSpec::Style::native);
FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
FileSpec symbol_file_spec =
- Symbols::LocateExecutableSymbolFile(module_spec, search_paths);
+ PluginManager::LocateExecutableSymbolFile(module_spec, search_paths);
EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty());
}
More information about the lldb-commits
mailing list