Index: include/lldb/Host/Symbols.h =================================================================== --- include/lldb/Host/Symbols.h +++ include/lldb/Host/Symbols.h @@ -1,61 +0,0 @@ -//===-- Symbols.h -----------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef liblldb_Symbols_h_ -#define liblldb_Symbols_h_ - -#include - -#include "lldb/Utility/FileSpec.h" - -namespace lldb_private { - -class ArchSpec; -class ModuleSpec; -class UUID; - -class Symbols { -public: - //---------------------------------------------------------------------- - // Locate the executable file given a module specification. - // - // Locating the file should happen only on the local computer or using the - // current computers global settings. - //---------------------------------------------------------------------- - static 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 FileSpec LocateExecutableSymbolFile(const ModuleSpec &module_spec); - - static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, - const lldb_private::UUID *uuid, - const ArchSpec *arch); - - //---------------------------------------------------------------------- - // Locate the object and symbol file given a module specification. - // - // Locating the file can try to download the file from a corporate build - // repository, or using any other means necessary to locate both the - // unstripped object file and the debug symbols. The force_lookup argument - // controls whether the external program is called unconditionally to find - // the symbol file, or if the user's settings are checked to see if they've - // enabled the external program before calling. - // - //---------------------------------------------------------------------- - static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, - bool force_lookup = true); -}; - -} // namespace lldb_private - -#endif // liblldb_Symbols_h_ Index: include/lldb/Symbol/LocateSymbolFile.h =================================================================== --- include/lldb/Symbol/LocateSymbolFile.h +++ include/lldb/Symbol/LocateSymbolFile.h @@ -0,0 +1,61 @@ +//===-- Symbols.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Symbols_h_ +#define liblldb_Symbols_h_ + +#include + +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { + +class ArchSpec; +class ModuleSpec; +class UUID; + +class Symbols { +public: + //---------------------------------------------------------------------- + // Locate the executable file given a module specification. + // + // Locating the file should happen only on the local computer or using the + // current computers global settings. + //---------------------------------------------------------------------- + static 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 FileSpec LocateExecutableSymbolFile(const ModuleSpec &module_spec); + + static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, + const lldb_private::UUID *uuid, + const ArchSpec *arch); + + //---------------------------------------------------------------------- + // Locate the object and symbol file given a module specification. + // + // Locating the file can try to download the file from a corporate build + // repository, or using any other means necessary to locate both the + // unstripped object file and the debug symbols. The force_lookup argument + // controls whether the external program is called unconditionally to find + // the symbol file, or if the user's settings are checked to see if they've + // enabled the external program before calling. + // + //---------------------------------------------------------------------- + static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + bool force_lookup = true); +}; + +} // namespace lldb_private + +#endif // liblldb_Symbols_h_ Index: include/lldb/module.modulemap =================================================================== --- include/lldb/module.modulemap +++ include/lldb/module.modulemap @@ -48,7 +48,6 @@ module SocketAddress { header "Host/SocketAddress.h" export * } module Socket { header "Host/Socket.h" export * } module StringConvert { textual header "Host/StringConvert.h" export * } - module Symbols { header "Host/Symbols.h" export * } module TaskPool { header "Host/TaskPool.h" export * } module Terminal { header "Host/Terminal.h" export * } module ThreadLauncher { header "Host/ThreadLauncher.h" export * } Index: source/Commands/CommandObjectTarget.cpp =================================================================== --- source/Commands/CommandObjectTarget.cpp +++ source/Commands/CommandObjectTarget.cpp @@ -17,7 +17,6 @@ #include "lldb/DataFormatters/ValueObjectPrinter.h" #include "lldb/Host/OptionParser.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/Symbols.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" @@ -35,6 +34,7 @@ #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/FuncUnwinders.h" #include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" Index: source/Core/ModuleList.cpp =================================================================== --- source/Core/ModuleList.cpp +++ source/Core/ModuleList.cpp @@ -11,10 +11,10 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/FileSystem.h" -#include "lldb/Host/Symbols.h" #include "lldb/Interpreter/OptionValueFileSpec.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/VariableList.h" Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -44,7 +44,6 @@ common/SocketAddress.cpp common/Socket.cpp common/StringConvert.cpp - common/Symbols.cpp common/TaskPool.cpp common/TCPSocket.cpp common/Terminal.cpp @@ -95,7 +94,6 @@ add_subdirectory(macosx/objcxx) set(LLDBObjCLibs lldbHostMacOSXObjCXX) add_host_subdirectory(macosx - macosx/Symbols.cpp macosx/cfcpp/CFCBundle.cpp macosx/cfcpp/CFCData.cpp macosx/cfcpp/CFCMutableArray.cpp @@ -166,7 +164,6 @@ LINK_LIBS lldbCore - lldbSymbol lldbTarget lldbUtility ${EXTRA_LIBS} Index: source/Host/common/Symbols.cpp =================================================================== --- source/Host/common/Symbols.cpp +++ source/Host/common/Symbols.cpp @@ -1,383 +0,0 @@ -//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/Symbols.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Target/Target.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/DataBuffer.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/Timer.h" -#include "lldb/Utility/UUID.h" - -#include "llvm/Support/FileSystem.h" - -// From MacOSX system header "mach/machine.h" -typedef int cpu_type_t; -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 == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && - (arch == NULL || (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; - if (Symbols::DownloadObjectAndSymbolFile(mutable_mod_spec, 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 = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - const FileSpec &exec_fspec = module_spec.GetFileSpec(); - if (exec_fspec) { - if (::LookForDsymNextToExecutablePath (module_spec, exec_fspec, dsym_fspec)) { - if (log) { - log->Printf("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) { - log->Printf("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(); - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, - "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", - exec_fspec ? exec_fspec->GetFilename().AsCString("") : "", - arch ? arch->GetArchitectureName() : "", (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(); -} - -ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { - ModuleSpec result; - const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); - const ArchSpec *arch = module_spec.GetArchitecturePtr(); - const UUID *uuid = module_spec.GetUUIDPtr(); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", - exec_fspec ? exec_fspec->GetFilename().AsCString("") : "", - arch ? arch->GetArchitectureName() : "", (const void *)uuid); - - ModuleSpecList module_specs; - ModuleSpec matched_module_spec; - if (exec_fspec && - ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && - module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { - result.GetFileSpec() = exec_fspec; - } else { - LocateMacOSXFilesUsingDebugSymbols(module_spec, result); - } - return result; -} - -// Keep "symbols.enable-external-lookup" description in sync with this function. - -FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { - FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); - if (symbol_file_spec.IsAbsolute() && - FileSystem::Instance().Exists(symbol_file_spec)) - return symbol_file_spec; - - const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); - if (symbol_filename && symbol_filename[0]) { - FileSpecList debug_file_search_paths( - Target::GetDefaultDebugFileSearchPaths()); - - // 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); - - const 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 files; - std::string dirname = dirspec.GetPath(); - - files.push_back(dirname + "/" + symbol_filename); - files.push_back(dirname + "/.debug/" + symbol_filename); - files.push_back(dirname + "/.build-id/" + uuid_str); - - // 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_filename); - - 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); - assert(num_specs <= 1 && - "Symbol Vendor supports only a single architecture"); - if (num_specs == 1) { - ModuleSpec mspec; - if (specs.GetModuleSpecAtIndex(0, 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); -} - -#if !defined(__APPLE__) - -FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle, - const lldb_private::UUID *uuid, - const ArchSpec *arch) { - // FIXME - return FileSpec(); -} - -bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, - bool force_lookup) { - // Fill in the module_spec.GetFileSpec() for the object file and/or the - // module_spec.GetSymbolFileSpec() for the debug symbols file. - return false; -} - -#endif Index: source/Host/macosx/Symbols.cpp =================================================================== --- source/Host/macosx/Symbols.cpp +++ source/Host/macosx/Symbols.cpp @@ -1,654 +0,0 @@ -//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Host/Symbols.h" - -#include -#include - -#include - -#include "Host/macosx/cfcpp/CFCBundle.h" -#include "Host/macosx/cfcpp/CFCData.h" -#include "Host/macosx/cfcpp/CFCReleaser.h" -#include "Host/macosx/cfcpp/CFCString.h" -#include "lldb/Core/ModuleList.h" -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/Host.h" -#include "lldb/Symbol/ObjectFile.h" -#include "lldb/Utility/ArchSpec.h" -#include "lldb/Utility/CleanUp.h" -#include "lldb/Utility/DataBuffer.h" -#include "lldb/Utility/DataExtractor.h" -#include "lldb/Utility/Endian.h" -#include "lldb/Utility/Log.h" -#include "lldb/Utility/StreamString.h" -#include "lldb/Utility/Timer.h" -#include "lldb/Utility/UUID.h" -#include "mach/machine.h" - -#include "llvm/Support/FileSystem.h" - -using namespace lldb; -using namespace lldb_private; - -#if !defined(__arm__) && !defined(__arm64__) && \ - !defined(__aarch64__) // No DebugSymbols on the iOS devices -extern "C" { - -CFURLRef DBGCopyFullDSYMURLForUUID(CFUUIDRef uuid, CFURLRef exec_url); -CFDictionaryRef DBGCopyDSYMPropertyLists(CFURLRef dsym_url); -} -#endif - -int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, - ModuleSpec &return_module_spec) { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { - if (log) - log->Printf("Spotlight lookup for .dSYM bundles is disabled."); - return 0; - } - - return_module_spec = module_spec; - return_module_spec.GetFileSpec().Clear(); - return_module_spec.GetSymbolFileSpec().Clear(); - - int items_found = 0; - -#if !defined(__arm__) && !defined(__arm64__) && \ - !defined(__aarch64__) // No DebugSymbols on the iOS devices - - const UUID *uuid = module_spec.GetUUIDPtr(); - const ArchSpec *arch = module_spec.GetArchitecturePtr(); - - if (uuid && uuid->IsValid()) { - // Try and locate the dSYM file using DebugSymbols first - llvm::ArrayRef module_uuid = uuid->GetBytes(); - if (module_uuid.size() == 16) { - CFCReleaser 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 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 dsym_url( - ::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)) { - if (log) { - log->Printf("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 = - Symbols::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)) { - log->Printf("DebugSymbols framework returned dSYM path of %s for " - "UUID %s -- looking for an exec file", - path, uuid->GetAsString().c_str()); - } - } - - CFCReleaser dict( - ::DBGCopyDSYMPropertyLists(dsym_url.get())); - CFDictionaryRef uuid_dict = NULL; - if (dict.get()) { - CFCString uuid_cfstr(uuid->GetAsString().c_str()); - uuid_dict = static_cast( - ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); - } - if (uuid_dict) { - CFStringRef exec_cf_path = - static_cast(::CFDictionaryGetValue( - uuid_dict, CFSTR("DBGSymbolRichExecutable"))); - if (exec_cf_path && ::CFStringGetFileSystemRepresentation( - exec_cf_path, path, sizeof(path))) { - if (log) { - log->Printf("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; - } - } - } - - if (!success) { - // No dictionary, check near the dSYM bundle for an executable that - // matches... - 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'; - if (log) { - log->Printf("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 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; - if (log) { - log->Printf("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; - if (log) { - log->Printf("Executable binary %s next to dSYM is " - "compatible; using", - path); - } - } - break; - } - } - } - } - } - } - } - } -#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined - // (__aarch64__) - - return items_found; -} - -FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, - const lldb_private::UUID *uuid, - const ArchSpec *arch) { - char path[PATH_MAX]; - if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0) - return {}; - - ::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1); - - DIR *dirp = opendir(path); - if (!dirp) - return {}; - - // Make sure we close the directory before exiting this scope. - CleanUp cleanup_dir(closedir, dirp); - - FileSpec dsym_fspec; - dsym_fspec.GetDirectory().SetCString(path); - struct dirent *dp; - while ((dp = readdir(dirp)) != NULL) { - // Only search directories - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { - if (dp->d_namlen == 1 && dp->d_name[0] == '.') - continue; - - if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') - continue; - } - - if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) { - dsym_fspec.GetFilename().SetCString(dp->d_name); - ModuleSpecList module_specs; - if (ObjectFile::GetModuleSpecifications(dsym_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 == NULL || - (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && - (arch == NULL || - (spec.GetArchitecturePtr() && - spec.GetArchitecture().IsCompatibleMatch(*arch)))) { - return dsym_fspec; - } - } - } - } - } - - return {}; -} - -static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, - ModuleSpec &module_spec) { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - bool success = false; - if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) { - std::string str; - CFStringRef cf_str; - CFDictionaryRef cf_dict; - - cf_str = (CFStringRef)CFDictionaryGetValue( - (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - if (CFCString::FileSystemRepresentation(cf_str, str)) { - module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native); - FileSystem::Instance().Resolve(module_spec.GetFileSpec()); - if (log) { - log->Printf( - "From dsymForUUID plist: Symbol rich executable is at '%s'", - str.c_str()); - } - } - } - - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGDSYMPath")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - if (CFCString::FileSystemRepresentation(cf_str, str)) { - module_spec.GetSymbolFileSpec().SetFile(str.c_str(), - FileSpec::Style::native); - FileSystem::Instance().Resolve(module_spec.GetFileSpec()); - success = true; - if (log) { - log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str()); - } - } - } - - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGArchitecture")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - if (CFCString::FileSystemRepresentation(cf_str, str)) - module_spec.GetArchitecture().SetTriple(str.c_str()); - } - - std::string DBGBuildSourcePath; - std::string DBGSourcePath; - - // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. - // If DBGVersion 2, strip last two components of path remappings from - // entries to fix an issue with a specific set of - // DBGSourcePathRemapping entries that lldb worked - // with. - // If DBGVersion 3, trust & use the source path remappings as-is. - // - cf_dict = (CFDictionaryRef)CFDictionaryGetValue( - (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping")); - if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) { - // If we see DBGVersion with a value of 2 or higher, this is a new style - // DBGSourcePathRemapping dictionary - bool new_style_source_remapping_dictionary = false; - bool do_truncate_remapping_names = false; - std::string original_DBGSourcePath_value = DBGSourcePath; - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGVersion")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - std::string version; - CFCString::FileSystemRepresentation(cf_str, version); - if (!version.empty() && isdigit(version[0])) { - int version_number = atoi(version.c_str()); - if (version_number > 1) { - new_style_source_remapping_dictionary = true; - } - if (version_number == 2) { - do_truncate_remapping_names = true; - } - } - } - - CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict); - if (kv_pair_count > 0) { - CFStringRef *keys = - (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); - CFStringRef *values = - (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); - if (keys != nullptr && values != nullptr) { - CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict, - (const void **)keys, - (const void **)values); - } - for (CFIndex i = 0; i < kv_pair_count; i++) { - DBGBuildSourcePath.clear(); - DBGSourcePath.clear(); - if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) { - CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath); - } - if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) { - CFCString::FileSystemRepresentation(values[i], DBGSourcePath); - } - if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { - // In the "old style" DBGSourcePathRemapping dictionary, the - // DBGSourcePath values (the "values" half of key-value path pairs) - // were wrong. Ignore them and use the universal DBGSourcePath - // string from earlier. - if (new_style_source_remapping_dictionary && - !original_DBGSourcePath_value.empty()) { - DBGSourcePath = original_DBGSourcePath_value; - } - if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path(DBGSourcePath.c_str()); - FileSystem::Instance().Resolve(resolved_source_path); - DBGSourcePath = resolved_source_path.GetPath(); - } - // With version 2 of DBGSourcePathRemapping, we can chop off the - // last two filename parts from the source remapping and get a more - // general source remapping that still works. Add this as another - // option in addition to the full source path remap. - module_spec.GetSourceMappingList().Append( - ConstString(DBGBuildSourcePath.c_str()), - ConstString(DBGSourcePath.c_str()), true); - if (do_truncate_remapping_names) { - FileSpec build_path(DBGBuildSourcePath.c_str()); - FileSpec source_path(DBGSourcePath.c_str()); - build_path.RemoveLastPathComponent(); - build_path.RemoveLastPathComponent(); - source_path.RemoveLastPathComponent(); - source_path.RemoveLastPathComponent(); - module_spec.GetSourceMappingList().Append( - ConstString(build_path.GetPath().c_str()), - ConstString(source_path.GetPath().c_str()), true); - } - } - } - if (keys) - free(keys); - if (values) - free(values); - } - } - - - // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the - // source remappings list. - - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGBuildSourcePath")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); - } - - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGSourcePath")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); - } - - if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { - if (DBGSourcePath[0] == '~') { - FileSpec resolved_source_path(DBGSourcePath.c_str()); - FileSystem::Instance().Resolve(resolved_source_path); - DBGSourcePath = resolved_source_path.GetPath(); - } - module_spec.GetSourceMappingList().Append( - ConstString(DBGBuildSourcePath.c_str()), - ConstString(DBGSourcePath.c_str()), true); - } - } - return success; -} - -bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, - bool force_lookup) { - bool success = false; - const UUID *uuid_ptr = module_spec.GetUUIDPtr(); - const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); - - // It's expensive to check for the DBGShellCommands defaults setting, only do - // it once per lldb run and cache the result. - static bool g_have_checked_for_dbgshell_command = false; - static const char *g_dbgshell_command = NULL; - if (!g_have_checked_for_dbgshell_command) { - g_have_checked_for_dbgshell_command = true; - CFTypeRef defaults_setting = CFPreferencesCopyAppValue( - CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); - if (defaults_setting && - CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { - char cstr_buf[PATH_MAX]; - if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf, - sizeof(cstr_buf), kCFStringEncodingUTF8)) { - g_dbgshell_command = - strdup(cstr_buf); // this malloc'ed memory will never be freed - } - } - if (defaults_setting) { - CFRelease(defaults_setting); - } - } - - // When g_dbgshell_command is NULL, the user has not enabled the use of an - // external program to find the symbols, don't run it for them. - if (!force_lookup && g_dbgshell_command == NULL) { - return false; - } - - if (uuid_ptr || - (file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) { - static bool g_located_dsym_for_uuid_exe = false; - static bool g_dsym_for_uuid_exe_exists = false; - static char g_dsym_for_uuid_exe_path[PATH_MAX]; - if (!g_located_dsym_for_uuid_exe) { - g_located_dsym_for_uuid_exe = true; - const char *dsym_for_uuid_exe_path_cstr = - getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); - FileSpec dsym_for_uuid_exe_spec; - if (dsym_for_uuid_exe_path_cstr) { - dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, - FileSpec::Style::native); - FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec); - g_dsym_for_uuid_exe_exists = - FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); - } - - if (!g_dsym_for_uuid_exe_exists) { - dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", - FileSpec::Style::native); - g_dsym_for_uuid_exe_exists = - FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); - if (!g_dsym_for_uuid_exe_exists) { - long bufsize; - if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) { - char buffer[bufsize]; - struct passwd pwd; - struct passwd *tilde_rc = NULL; - // we are a library so we need to use the reentrant version of - // getpwnam() - if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 && - tilde_rc && tilde_rc->pw_dir) { - std::string dsymforuuid_path(tilde_rc->pw_dir); - dsymforuuid_path += "/bin/dsymForUUID"; - dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), - FileSpec::Style::native); - g_dsym_for_uuid_exe_exists = - FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); - } - } - } - } - if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) { - dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, - FileSpec::Style::native); - FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec); - g_dsym_for_uuid_exe_exists = - FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); - } - - if (g_dsym_for_uuid_exe_exists) - dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path, - sizeof(g_dsym_for_uuid_exe_path)); - } - if (g_dsym_for_uuid_exe_exists) { - std::string uuid_str; - char file_path[PATH_MAX]; - file_path[0] = '\0'; - - if (uuid_ptr) - uuid_str = uuid_ptr->GetAsString(); - - if (file_spec_ptr) - file_spec_ptr->GetPath(file_path, sizeof(file_path)); - - StreamString command; - if (!uuid_str.empty()) - command.Printf("%s --ignoreNegativeCache --copyExecutable %s", - g_dsym_for_uuid_exe_path, uuid_str.c_str()); - else if (file_path[0] != '\0') - command.Printf("%s --ignoreNegativeCache --copyExecutable %s", - g_dsym_for_uuid_exe_path, file_path); - - if (!command.GetString().empty()) { - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - int exit_status = -1; - int signo = -1; - std::string command_output; - if (log) { - if (!uuid_str.empty()) - log->Printf("Calling %s with UUID %s to find dSYM", - g_dsym_for_uuid_exe_path, uuid_str.c_str()); - else if (file_path[0] != '\0') - log->Printf("Calling %s with file %s to find dSYM", - g_dsym_for_uuid_exe_path, file_path); - } - Status error = Host::RunShellCommand( - command.GetData(), - NULL, // current working directory - &exit_status, // Exit status - &signo, // Signal int * - &command_output, // Command output - std::chrono::seconds( - 30), // Large timeout to allow for long dsym download times - false); // Don't run in a shell (we don't need shell expansion) - if (error.Success() && exit_status == 0 && !command_output.empty()) { - CFCData data(CFDataCreateWithBytesNoCopy( - NULL, (const UInt8 *)command_output.data(), command_output.size(), - kCFAllocatorNull)); - - CFCReleaser plist( - (CFDictionaryRef)::CFPropertyListCreateFromXMLData( - NULL, data.get(), kCFPropertyListImmutable, NULL)); - - if (plist.get() && - CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) { - if (!uuid_str.empty()) { - CFCString uuid_cfstr(uuid_str.c_str()); - CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue( - plist.get(), uuid_cfstr.get()); - success = - GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec); - } else { - const CFIndex num_values = ::CFDictionaryGetCount(plist.get()); - if (num_values > 0) { - std::vector keys(num_values, NULL); - std::vector values(num_values, NULL); - ::CFDictionaryGetKeysAndValues(plist.get(), NULL, - (const void **)&values[0]); - if (num_values == 1) { - return GetModuleSpecInfoFromUUIDDictionary(values[0], - module_spec); - } else { - for (CFIndex i = 0; i < num_values; ++i) { - ModuleSpec curr_module_spec; - if (GetModuleSpecInfoFromUUIDDictionary(values[i], - curr_module_spec)) { - if (module_spec.GetArchitecture().IsCompatibleMatch( - curr_module_spec.GetArchitecture())) { - module_spec = curr_module_spec; - return true; - } - } - } - } - } - } - } - } else { - if (log) { - if (!uuid_str.empty()) - log->Printf("Called %s on %s, no matches", - g_dsym_for_uuid_exe_path, uuid_str.c_str()); - else if (file_path[0] != '\0') - log->Printf("Called %s on %s, no matches", - g_dsym_for_uuid_exe_path, file_path); - } - } - } - } - } - return success; -} Index: source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp =================================================================== --- source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -15,8 +15,8 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" -#include "lldb/Host/Symbols.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/OperatingSystem.h" #include "lldb/Target/RegisterContext.h" Index: source/Plugins/Platform/MacOSX/PlatformDarwin.cpp =================================================================== --- source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -21,9 +21,9 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Host/Symbols.h" #include "lldb/Host/XML.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" Index: source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp =================================================================== --- source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -18,7 +18,6 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Host.h" -#include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/TCPSocket.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -28,6 +27,7 @@ #include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" Index: source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -41,7 +41,6 @@ #include "lldb/Host/PosixApi.h" #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/StringConvert.h" -#include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/XML.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -54,6 +53,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/Property.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" Index: source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -29,7 +29,6 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" -#include "lldb/Host/Symbols.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueProperties.h" @@ -42,6 +41,7 @@ #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/LineTable.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeMap.h" Index: source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp =================================================================== --- source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -15,7 +15,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" -#include "lldb/Host/Symbols.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" Index: source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp =================================================================== --- source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -15,8 +15,8 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Host/Host.h" -#include "lldb/Host/Symbols.h" #include "lldb/Host/XML.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" Index: source/Symbol/CMakeLists.txt =================================================================== --- source/Symbol/CMakeLists.txt +++ source/Symbol/CMakeLists.txt @@ -1,3 +1,9 @@ +set(LLVM_OPTIONAL_SOURCES LocateSymbolFileMacOSX.cpp) + +if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + set(PLATFORM_SOURCES LocateSymbolFileMacOSX.cpp) +endif() + add_lldb_library(lldbSymbol ArmUnwindInfo.cpp Block.cpp @@ -18,6 +24,7 @@ FuncUnwinders.cpp LineEntry.cpp LineTable.cpp + LocateSymbolFile.cpp ObjectFile.cpp Symbol.cpp SymbolContext.cpp @@ -34,6 +41,8 @@ VariableList.cpp VerifyDecl.cpp + ${PLATFORM_SOURCES} + LINK_LIBS clangAST clangBasic Index: source/Symbol/LocateSymbolFile.cpp =================================================================== --- source/Symbol/LocateSymbolFile.cpp +++ source/Symbol/LocateSymbolFile.cpp @@ -0,0 +1,388 @@ +//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/LocateSymbolFile.h" + +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" +#include "lldb/Utility/UUID.h" + +#include "llvm/Support/FileSystem.h" + +// From MacOSX system header "mach/machine.h" +typedef int cpu_type_t; +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 == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == NULL || (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; + if (Symbols::DownloadObjectAndSymbolFile(mutable_mod_spec, 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 = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + const FileSpec &exec_fspec = module_spec.GetFileSpec(); + if (exec_fspec) { + if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec, + dsym_fspec)) { + if (log) { + log->Printf("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) { + log->Printf("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(); + + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, + "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString("") : "", + arch ? arch->GetArchitectureName() : "", (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(); +} + +ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { + ModuleSpec result; + const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + const UUID *uuid = module_spec.GetUUIDPtr(); + static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); + Timer scoped_timer( + func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", + exec_fspec ? exec_fspec->GetFilename().AsCString("") : "", + arch ? arch->GetArchitectureName() : "", (const void *)uuid); + + ModuleSpecList module_specs; + ModuleSpec matched_module_spec; + if (exec_fspec && + ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && + module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { + result.GetFileSpec() = exec_fspec; + } else { + LocateMacOSXFilesUsingDebugSymbols(module_spec, result); + } + return result; +} + +// Keep "symbols.enable-external-lookup" description in sync with this function. + +FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { + FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); + if (symbol_file_spec.IsAbsolute() && + FileSystem::Instance().Exists(symbol_file_spec)) + return symbol_file_spec; + + const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); + if (symbol_filename && symbol_filename[0]) { + FileSpecList debug_file_search_paths( + Target::GetDefaultDebugFileSearchPaths()); + + // 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); + + const 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 files; + std::string dirname = dirspec.GetPath(); + + files.push_back(dirname + "/" + symbol_filename); + files.push_back(dirname + "/.debug/" + symbol_filename); + files.push_back(dirname + "/.build-id/" + uuid_str); + + // 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_filename); + + 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); + assert(num_specs <= 1 && + "Symbol Vendor supports only a single architecture"); + if (num_specs == 1) { + ModuleSpec mspec; + if (specs.GetModuleSpecAtIndex(0, 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); +} + +#if !defined(__APPLE__) + +FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle, + const lldb_private::UUID *uuid, + const ArchSpec *arch) { + // FIXME + return FileSpec(); +} + +bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + bool force_lookup) { + // Fill in the module_spec.GetFileSpec() for the object file and/or the + // module_spec.GetSymbolFileSpec() for the debug symbols file. + return false; +} + +#endif Index: source/Symbol/LocateSymbolFileMacOSX.cpp =================================================================== --- source/Symbol/LocateSymbolFileMacOSX.cpp +++ source/Symbol/LocateSymbolFileMacOSX.cpp @@ -0,0 +1,653 @@ +//===-- Symbols.cpp ---------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/LocateSymbolFile.h" + +#include +#include + +#include + +#include "Host/macosx/cfcpp/CFCBundle.h" +#include "Host/macosx/cfcpp/CFCData.h" +#include "Host/macosx/cfcpp/CFCReleaser.h" +#include "Host/macosx/cfcpp/CFCString.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/Host.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/CleanUp.h" +#include "lldb/Utility/DataBuffer.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" +#include "lldb/Utility/Timer.h" +#include "lldb/Utility/UUID.h" +#include "mach/machine.h" + +#include "llvm/Support/FileSystem.h" + +using namespace lldb; +using namespace lldb_private; + +#if !defined(__arm__) && !defined(__arm64__) && \ + !defined(__aarch64__) // No DebugSymbols on the iOS devices +extern "C" { + +CFURLRef DBGCopyFullDSYMURLForUUID(CFUUIDRef uuid, CFURLRef exec_url); +CFDictionaryRef DBGCopyDSYMPropertyLists(CFURLRef dsym_url); +} +#endif + +int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, + ModuleSpec &return_module_spec) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { + if (log) + log->Printf("Spotlight lookup for .dSYM bundles is disabled."); + return 0; + } + + return_module_spec = module_spec; + return_module_spec.GetFileSpec().Clear(); + return_module_spec.GetSymbolFileSpec().Clear(); + + int items_found = 0; + +#if !defined(__arm__) && !defined(__arm64__) && \ + !defined(__aarch64__) // No DebugSymbols on the iOS devices + + const UUID *uuid = module_spec.GetUUIDPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + + if (uuid && uuid->IsValid()) { + // Try and locate the dSYM file using DebugSymbols first + llvm::ArrayRef module_uuid = uuid->GetBytes(); + if (module_uuid.size() == 16) { + CFCReleaser 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 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 dsym_url( + ::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)) { + if (log) { + log->Printf("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 = + Symbols::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)) { + log->Printf("DebugSymbols framework returned dSYM path of %s for " + "UUID %s -- looking for an exec file", + path, uuid->GetAsString().c_str()); + } + } + + CFCReleaser dict( + ::DBGCopyDSYMPropertyLists(dsym_url.get())); + CFDictionaryRef uuid_dict = NULL; + if (dict.get()) { + CFCString uuid_cfstr(uuid->GetAsString().c_str()); + uuid_dict = static_cast( + ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); + } + if (uuid_dict) { + CFStringRef exec_cf_path = + static_cast(::CFDictionaryGetValue( + uuid_dict, CFSTR("DBGSymbolRichExecutable"))); + if (exec_cf_path && ::CFStringGetFileSystemRepresentation( + exec_cf_path, path, sizeof(path))) { + if (log) { + log->Printf("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; + } + } + } + + if (!success) { + // No dictionary, check near the dSYM bundle for an executable that + // matches... + 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'; + if (log) { + log->Printf("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 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; + if (log) { + log->Printf("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; + if (log) { + log->Printf("Executable binary %s next to dSYM is " + "compatible; using", + path); + } + } + break; + } + } + } + } + } + } + } + } +#endif // #if !defined (__arm__) && !defined (__arm64__) && !defined + // (__aarch64__) + + return items_found; +} + +FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, + const lldb_private::UUID *uuid, + const ArchSpec *arch) { + char path[PATH_MAX]; + if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0) + return {}; + + ::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1); + + DIR *dirp = opendir(path); + if (!dirp) + return {}; + + // Make sure we close the directory before exiting this scope. + CleanUp cleanup_dir(closedir, dirp); + + FileSpec dsym_fspec; + dsym_fspec.GetDirectory().SetCString(path); + struct dirent *dp; + while ((dp = readdir(dirp)) != NULL) { + // Only search directories + if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { + if (dp->d_namlen == 1 && dp->d_name[0] == '.') + continue; + + if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.') + continue; + } + + if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) { + dsym_fspec.GetFilename().SetCString(dp->d_name); + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(dsym_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 == NULL || + (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && + (arch == NULL || + (spec.GetArchitecturePtr() && + spec.GetArchitecture().IsCompatibleMatch(*arch)))) { + return dsym_fspec; + } + } + } + } + } + + return {}; +} + +static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, + ModuleSpec &module_spec) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + bool success = false; + if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) { + std::string str; + CFStringRef cf_str; + CFDictionaryRef cf_dict; + + cf_str = (CFStringRef)CFDictionaryGetValue( + (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) { + module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + if (log) { + log->Printf( + "From dsymForUUID plist: Symbol rich executable is at '%s'", + str.c_str()); + } + } + } + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGDSYMPath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) { + module_spec.GetSymbolFileSpec().SetFile(str.c_str(), + FileSpec::Style::native); + FileSystem::Instance().Resolve(module_spec.GetFileSpec()); + success = true; + if (log) { + log->Printf("From dsymForUUID plist: dSYM is at '%s'", str.c_str()); + } + } + } + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGArchitecture")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + if (CFCString::FileSystemRepresentation(cf_str, str)) + module_spec.GetArchitecture().SetTriple(str.c_str()); + } + + std::string DBGBuildSourcePath; + std::string DBGSourcePath; + + // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. + // If DBGVersion 2, strip last two components of path remappings from + // entries to fix an issue with a specific set of + // DBGSourcePathRemapping entries that lldb worked + // with. + // If DBGVersion 3, trust & use the source path remappings as-is. + // + cf_dict = (CFDictionaryRef)CFDictionaryGetValue( + (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping")); + if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) { + // If we see DBGVersion with a value of 2 or higher, this is a new style + // DBGSourcePathRemapping dictionary + bool new_style_source_remapping_dictionary = false; + bool do_truncate_remapping_names = false; + std::string original_DBGSourcePath_value = DBGSourcePath; + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGVersion")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + std::string version; + CFCString::FileSystemRepresentation(cf_str, version); + if (!version.empty() && isdigit(version[0])) { + int version_number = atoi(version.c_str()); + if (version_number > 1) { + new_style_source_remapping_dictionary = true; + } + if (version_number == 2) { + do_truncate_remapping_names = true; + } + } + } + + CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict); + if (kv_pair_count > 0) { + CFStringRef *keys = + (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); + CFStringRef *values = + (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); + if (keys != nullptr && values != nullptr) { + CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict, + (const void **)keys, + (const void **)values); + } + for (CFIndex i = 0; i < kv_pair_count; i++) { + DBGBuildSourcePath.clear(); + DBGSourcePath.clear(); + if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath); + } + if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(values[i], DBGSourcePath); + } + if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { + // In the "old style" DBGSourcePathRemapping dictionary, the + // DBGSourcePath values (the "values" half of key-value path pairs) + // were wrong. Ignore them and use the universal DBGSourcePath + // string from earlier. + if (new_style_source_remapping_dictionary && + !original_DBGSourcePath_value.empty()) { + DBGSourcePath = original_DBGSourcePath_value; + } + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); + } + // With version 2 of DBGSourcePathRemapping, we can chop off the + // last two filename parts from the source remapping and get a more + // general source remapping that still works. Add this as another + // option in addition to the full source path remap. + module_spec.GetSourceMappingList().Append( + ConstString(DBGBuildSourcePath.c_str()), + ConstString(DBGSourcePath.c_str()), true); + if (do_truncate_remapping_names) { + FileSpec build_path(DBGBuildSourcePath.c_str()); + FileSpec source_path(DBGSourcePath.c_str()); + build_path.RemoveLastPathComponent(); + build_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); + source_path.RemoveLastPathComponent(); + module_spec.GetSourceMappingList().Append( + ConstString(build_path.GetPath().c_str()), + ConstString(source_path.GetPath().c_str()), true); + } + } + } + if (keys) + free(keys); + if (values) + free(values); + } + } + + // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the + // source remappings list. + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGBuildSourcePath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); + } + + cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, + CFSTR("DBGSourcePath")); + if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { + CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); + } + + if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { + if (DBGSourcePath[0] == '~') { + FileSpec resolved_source_path(DBGSourcePath.c_str()); + FileSystem::Instance().Resolve(resolved_source_path); + DBGSourcePath = resolved_source_path.GetPath(); + } + module_spec.GetSourceMappingList().Append( + ConstString(DBGBuildSourcePath.c_str()), + ConstString(DBGSourcePath.c_str()), true); + } + } + return success; +} + +bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, + bool force_lookup) { + bool success = false; + const UUID *uuid_ptr = module_spec.GetUUIDPtr(); + const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); + + // It's expensive to check for the DBGShellCommands defaults setting, only do + // it once per lldb run and cache the result. + static bool g_have_checked_for_dbgshell_command = false; + static const char *g_dbgshell_command = NULL; + if (!g_have_checked_for_dbgshell_command) { + g_have_checked_for_dbgshell_command = true; + CFTypeRef defaults_setting = CFPreferencesCopyAppValue( + CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); + if (defaults_setting && + CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { + char cstr_buf[PATH_MAX]; + if (CFStringGetCString((CFStringRef)defaults_setting, cstr_buf, + sizeof(cstr_buf), kCFStringEncodingUTF8)) { + g_dbgshell_command = + strdup(cstr_buf); // this malloc'ed memory will never be freed + } + } + if (defaults_setting) { + CFRelease(defaults_setting); + } + } + + // When g_dbgshell_command is NULL, the user has not enabled the use of an + // external program to find the symbols, don't run it for them. + if (!force_lookup && g_dbgshell_command == NULL) { + return false; + } + + if (uuid_ptr || + (file_spec_ptr && FileSystem::Instance().Exists(*file_spec_ptr))) { + static bool g_located_dsym_for_uuid_exe = false; + static bool g_dsym_for_uuid_exe_exists = false; + static char g_dsym_for_uuid_exe_path[PATH_MAX]; + if (!g_located_dsym_for_uuid_exe) { + g_located_dsym_for_uuid_exe = true; + const char *dsym_for_uuid_exe_path_cstr = + getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE"); + FileSpec dsym_for_uuid_exe_spec; + if (dsym_for_uuid_exe_path_cstr) { + dsym_for_uuid_exe_spec.SetFile(dsym_for_uuid_exe_path_cstr, + FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec); + g_dsym_for_uuid_exe_exists = + FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); + } + + if (!g_dsym_for_uuid_exe_exists) { + dsym_for_uuid_exe_spec.SetFile("/usr/local/bin/dsymForUUID", + FileSpec::Style::native); + g_dsym_for_uuid_exe_exists = + FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); + if (!g_dsym_for_uuid_exe_exists) { + long bufsize; + if ((bufsize = sysconf(_SC_GETPW_R_SIZE_MAX)) != -1) { + char buffer[bufsize]; + struct passwd pwd; + struct passwd *tilde_rc = NULL; + // we are a library so we need to use the reentrant version of + // getpwnam() + if (getpwnam_r("rc", &pwd, buffer, bufsize, &tilde_rc) == 0 && + tilde_rc && tilde_rc->pw_dir) { + std::string dsymforuuid_path(tilde_rc->pw_dir); + dsymforuuid_path += "/bin/dsymForUUID"; + dsym_for_uuid_exe_spec.SetFile(dsymforuuid_path.c_str(), + FileSpec::Style::native); + g_dsym_for_uuid_exe_exists = + FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); + } + } + } + } + if (!g_dsym_for_uuid_exe_exists && g_dbgshell_command != NULL) { + dsym_for_uuid_exe_spec.SetFile(g_dbgshell_command, + FileSpec::Style::native); + FileSystem::Instance().Resolve(dsym_for_uuid_exe_spec); + g_dsym_for_uuid_exe_exists = + FileSystem::Instance().Exists(dsym_for_uuid_exe_spec); + } + + if (g_dsym_for_uuid_exe_exists) + dsym_for_uuid_exe_spec.GetPath(g_dsym_for_uuid_exe_path, + sizeof(g_dsym_for_uuid_exe_path)); + } + if (g_dsym_for_uuid_exe_exists) { + std::string uuid_str; + char file_path[PATH_MAX]; + file_path[0] = '\0'; + + if (uuid_ptr) + uuid_str = uuid_ptr->GetAsString(); + + if (file_spec_ptr) + file_spec_ptr->GetPath(file_path, sizeof(file_path)); + + StreamString command; + if (!uuid_str.empty()) + command.Printf("%s --ignoreNegativeCache --copyExecutable %s", + g_dsym_for_uuid_exe_path, uuid_str.c_str()); + else if (file_path[0] != '\0') + command.Printf("%s --ignoreNegativeCache --copyExecutable %s", + g_dsym_for_uuid_exe_path, file_path); + + if (!command.GetString().empty()) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + int exit_status = -1; + int signo = -1; + std::string command_output; + if (log) { + if (!uuid_str.empty()) + log->Printf("Calling %s with UUID %s to find dSYM", + g_dsym_for_uuid_exe_path, uuid_str.c_str()); + else if (file_path[0] != '\0') + log->Printf("Calling %s with file %s to find dSYM", + g_dsym_for_uuid_exe_path, file_path); + } + Status error = Host::RunShellCommand( + command.GetData(), + NULL, // current working directory + &exit_status, // Exit status + &signo, // Signal int * + &command_output, // Command output + std::chrono::seconds( + 30), // Large timeout to allow for long dsym download times + false); // Don't run in a shell (we don't need shell expansion) + if (error.Success() && exit_status == 0 && !command_output.empty()) { + CFCData data(CFDataCreateWithBytesNoCopy( + NULL, (const UInt8 *)command_output.data(), command_output.size(), + kCFAllocatorNull)); + + CFCReleaser plist( + (CFDictionaryRef)::CFPropertyListCreateFromXMLData( + NULL, data.get(), kCFPropertyListImmutable, NULL)); + + if (plist.get() && + CFGetTypeID(plist.get()) == CFDictionaryGetTypeID()) { + if (!uuid_str.empty()) { + CFCString uuid_cfstr(uuid_str.c_str()); + CFDictionaryRef uuid_dict = (CFDictionaryRef)CFDictionaryGetValue( + plist.get(), uuid_cfstr.get()); + success = + GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec); + } else { + const CFIndex num_values = ::CFDictionaryGetCount(plist.get()); + if (num_values > 0) { + std::vector keys(num_values, NULL); + std::vector values(num_values, NULL); + ::CFDictionaryGetKeysAndValues(plist.get(), NULL, + (const void **)&values[0]); + if (num_values == 1) { + return GetModuleSpecInfoFromUUIDDictionary(values[0], + module_spec); + } else { + for (CFIndex i = 0; i < num_values; ++i) { + ModuleSpec curr_module_spec; + if (GetModuleSpecInfoFromUUIDDictionary(values[i], + curr_module_spec)) { + if (module_spec.GetArchitecture().IsCompatibleMatch( + curr_module_spec.GetArchitecture())) { + module_spec = curr_module_spec; + return true; + } + } + } + } + } + } + } + } else { + if (log) { + if (!uuid_str.empty()) + log->Printf("Called %s on %s, no matches", + g_dsym_for_uuid_exe_path, uuid_str.c_str()); + else if (file_path[0] != '\0') + log->Printf("Called %s on %s, no matches", + g_dsym_for_uuid_exe_path, file_path); + } + } + } + } + } + return success; +} Index: unittests/Host/CMakeLists.txt =================================================================== --- unittests/Host/CMakeLists.txt +++ unittests/Host/CMakeLists.txt @@ -9,7 +9,6 @@ ProcessLaunchInfoTest.cpp SocketAddressTest.cpp SocketTest.cpp - SymbolsTest.cpp TaskPoolTest.cpp ) Index: unittests/Host/SymbolsTest.cpp =================================================================== --- unittests/Host/SymbolsTest.cpp +++ unittests/Host/SymbolsTest.cpp @@ -1,48 +0,0 @@ -//===-- SymbolsTest.cpp -----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" - -#include "lldb/Core/ModuleSpec.h" -#include "lldb/Host/FileSystem.h" -#include "lldb/Host/HostInfo.h" -#include "lldb/Host/Symbols.h" - -using namespace lldb_private; - -namespace { -class SymbolsTest : public ::testing::Test { -public: - void SetUp() override { - FileSystem::Initialize(); - HostInfo::Initialize(); - } - void TearDown() override { - HostInfo::Terminate(); - FileSystem::Terminate(); - } -}; -} // namespace - -TEST_F( - SymbolsTest, - TerminateLocateExecutableSymbolFileForUnknownExecutableAndUnknownSymbolFile) { - ModuleSpec module_spec; - FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec); - EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty()); -} - -TEST_F(SymbolsTest, - LocateExecutableSymbolFileForUnknownExecutableAndMissingSymbolFile) { - ModuleSpec module_spec; - // using a GUID here because the symbol file shouldn't actually exist on disk - module_spec.GetSymbolFileSpec().SetFile( - "4A524676-B24B-4F4E-968A-551D465EBAF1.so", FileSpec::Style::native); - FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec); - EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty()); -} Index: unittests/Symbol/CMakeLists.txt =================================================================== --- unittests/Symbol/CMakeLists.txt +++ unittests/Symbol/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_unittest(SymbolTests + LocateSymbolFileTest.cpp TestClangASTContext.cpp TestDWARFCallFrameInfo.cpp TestType.cpp Index: unittests/Symbol/LocateSymbolFileTest.cpp =================================================================== --- unittests/Symbol/LocateSymbolFileTest.cpp +++ unittests/Symbol/LocateSymbolFileTest.cpp @@ -0,0 +1,48 @@ +//===-- SymbolsTest.cpp -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "gtest/gtest.h" + +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/LocateSymbolFile.h" + +using namespace lldb_private; + +namespace { +class SymbolsTest : public ::testing::Test { +public: + void SetUp() override { + FileSystem::Initialize(); + HostInfo::Initialize(); + } + void TearDown() override { + HostInfo::Terminate(); + FileSystem::Terminate(); + } +}; +} // namespace + +TEST_F( + SymbolsTest, + TerminateLocateExecutableSymbolFileForUnknownExecutableAndUnknownSymbolFile) { + ModuleSpec module_spec; + FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec); + EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty()); +} + +TEST_F(SymbolsTest, + LocateExecutableSymbolFileForUnknownExecutableAndMissingSymbolFile) { + ModuleSpec module_spec; + // using a GUID here because the symbol file shouldn't actually exist on disk + module_spec.GetSymbolFileSpec().SetFile( + "4A524676-B24B-4F4E-968A-551D465EBAF1.so", FileSpec::Style::native); + FileSpec symbol_file_spec = Symbols::LocateExecutableSymbolFile(module_spec); + EXPECT_TRUE(symbol_file_spec.GetFilename().IsEmpty()); +}