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 <jo...@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()); } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits