15f757f3fSDimitry Andric //===-- SymbolLocatorDebugSymbols.cpp -------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #include "SymbolLocatorDebugSymbols.h" 105f757f3fSDimitry Andric 115f757f3fSDimitry Andric #include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" 125f757f3fSDimitry Andric #include "lldb/Core/Debugger.h" 135f757f3fSDimitry Andric #include "lldb/Core/Module.h" 145f757f3fSDimitry Andric #include "lldb/Core/ModuleList.h" 155f757f3fSDimitry Andric #include "lldb/Core/ModuleSpec.h" 165f757f3fSDimitry Andric #include "lldb/Core/PluginManager.h" 175f757f3fSDimitry Andric #include "lldb/Core/Progress.h" 185f757f3fSDimitry Andric #include "lldb/Core/Section.h" 195f757f3fSDimitry Andric #include "lldb/Host/FileSystem.h" 205f757f3fSDimitry Andric #include "lldb/Host/Host.h" 215f757f3fSDimitry Andric #include "lldb/Host/HostInfo.h" 225f757f3fSDimitry Andric #include "lldb/Symbol/ObjectFile.h" 235f757f3fSDimitry Andric #include "lldb/Target/Target.h" 245f757f3fSDimitry Andric #include "lldb/Utility/ArchSpec.h" 255f757f3fSDimitry Andric #include "lldb/Utility/DataBuffer.h" 265f757f3fSDimitry Andric #include "lldb/Utility/DataExtractor.h" 275f757f3fSDimitry Andric #include "lldb/Utility/LLDBLog.h" 285f757f3fSDimitry Andric #include "lldb/Utility/Log.h" 295f757f3fSDimitry Andric #include "lldb/Utility/StreamString.h" 305f757f3fSDimitry Andric #include "lldb/Utility/Timer.h" 315f757f3fSDimitry Andric #include "lldb/Utility/UUID.h" 325f757f3fSDimitry Andric 335f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h" 345f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h" 355f757f3fSDimitry Andric #include "llvm/Support/ThreadPool.h" 365f757f3fSDimitry Andric 375f757f3fSDimitry Andric #include "Host/macosx/cfcpp/CFCBundle.h" 385f757f3fSDimitry Andric #include "Host/macosx/cfcpp/CFCData.h" 395f757f3fSDimitry Andric #include "Host/macosx/cfcpp/CFCReleaser.h" 405f757f3fSDimitry Andric #include "Host/macosx/cfcpp/CFCString.h" 415f757f3fSDimitry Andric 425f757f3fSDimitry Andric #include "mach/machine.h" 435f757f3fSDimitry Andric 445f757f3fSDimitry Andric #include <CoreFoundation/CoreFoundation.h> 455f757f3fSDimitry Andric 465f757f3fSDimitry Andric #include <cstring> 475f757f3fSDimitry Andric #include <dirent.h> 485f757f3fSDimitry Andric #include <dlfcn.h> 495f757f3fSDimitry Andric #include <optional> 505f757f3fSDimitry Andric #include <pwd.h> 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric using namespace lldb; 535f757f3fSDimitry Andric using namespace lldb_private; 545f757f3fSDimitry Andric 555f757f3fSDimitry Andric static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID)( 565f757f3fSDimitry Andric CFUUIDRef uuid, CFURLRef exec_url) = nullptr; 575f757f3fSDimitry Andric static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) = 585f757f3fSDimitry Andric nullptr; 595f757f3fSDimitry Andric 605f757f3fSDimitry Andric LLDB_PLUGIN_DEFINE(SymbolLocatorDebugSymbols) 615f757f3fSDimitry Andric 625f757f3fSDimitry Andric SymbolLocatorDebugSymbols::SymbolLocatorDebugSymbols() : SymbolLocator() {} 635f757f3fSDimitry Andric 645f757f3fSDimitry Andric void SymbolLocatorDebugSymbols::Initialize() { 655f757f3fSDimitry Andric PluginManager::RegisterPlugin( 665f757f3fSDimitry Andric GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, 675f757f3fSDimitry Andric LocateExecutableObjectFile, LocateExecutableSymbolFile, 685f757f3fSDimitry Andric DownloadObjectAndSymbolFile, FindSymbolFileInBundle); 695f757f3fSDimitry Andric } 705f757f3fSDimitry Andric 715f757f3fSDimitry Andric void SymbolLocatorDebugSymbols::Terminate() { 725f757f3fSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 735f757f3fSDimitry Andric } 745f757f3fSDimitry Andric 755f757f3fSDimitry Andric llvm::StringRef SymbolLocatorDebugSymbols::GetPluginDescriptionStatic() { 765f757f3fSDimitry Andric return "DebugSymbols symbol locator."; 775f757f3fSDimitry Andric } 785f757f3fSDimitry Andric 795f757f3fSDimitry Andric SymbolLocator *SymbolLocatorDebugSymbols::CreateInstance() { 805f757f3fSDimitry Andric return new SymbolLocatorDebugSymbols(); 815f757f3fSDimitry Andric } 825f757f3fSDimitry Andric 835f757f3fSDimitry Andric std::optional<ModuleSpec> SymbolLocatorDebugSymbols::LocateExecutableObjectFile( 845f757f3fSDimitry Andric const ModuleSpec &module_spec) { 855f757f3fSDimitry Andric Log *log = GetLog(LLDBLog::Host); 865f757f3fSDimitry Andric if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { 875f757f3fSDimitry Andric LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled."); 885f757f3fSDimitry Andric return {}; 895f757f3fSDimitry Andric } 905f757f3fSDimitry Andric ModuleSpec return_module_spec; 915f757f3fSDimitry Andric return_module_spec = module_spec; 925f757f3fSDimitry Andric return_module_spec.GetFileSpec().Clear(); 935f757f3fSDimitry Andric return_module_spec.GetSymbolFileSpec().Clear(); 945f757f3fSDimitry Andric 955f757f3fSDimitry Andric const UUID *uuid = module_spec.GetUUIDPtr(); 965f757f3fSDimitry Andric const ArchSpec *arch = module_spec.GetArchitecturePtr(); 975f757f3fSDimitry Andric 985f757f3fSDimitry Andric int items_found = 0; 995f757f3fSDimitry Andric 1005f757f3fSDimitry Andric if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || 1015f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { 1025f757f3fSDimitry Andric void *handle = dlopen( 1035f757f3fSDimitry Andric "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", 1045f757f3fSDimitry Andric RTLD_LAZY | RTLD_LOCAL); 1055f757f3fSDimitry Andric if (handle) { 1065f757f3fSDimitry Andric g_dlsym_DBGCopyFullDSYMURLForUUID = 1075f757f3fSDimitry Andric (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle, 1085f757f3fSDimitry Andric "DBGCopyFullDSYMURLForUUID"); 1095f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym( 1105f757f3fSDimitry Andric handle, "DBGCopyDSYMPropertyLists"); 1115f757f3fSDimitry Andric } 1125f757f3fSDimitry Andric } 1135f757f3fSDimitry Andric 1145f757f3fSDimitry Andric if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || 1155f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { 1165f757f3fSDimitry Andric return {}; 1175f757f3fSDimitry Andric } 1185f757f3fSDimitry Andric 1195f757f3fSDimitry Andric if (uuid && uuid->IsValid()) { 1205f757f3fSDimitry Andric // Try and locate the dSYM file using DebugSymbols first 1215f757f3fSDimitry Andric llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes(); 1225f757f3fSDimitry Andric if (module_uuid.size() == 16) { 1235f757f3fSDimitry Andric CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes( 1245f757f3fSDimitry Andric NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3], 1255f757f3fSDimitry Andric module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7], 1265f757f3fSDimitry Andric module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11], 1275f757f3fSDimitry Andric module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15])); 1285f757f3fSDimitry Andric 1295f757f3fSDimitry Andric if (module_uuid_ref.get()) { 1305f757f3fSDimitry Andric CFCReleaser<CFURLRef> exec_url; 1315f757f3fSDimitry Andric const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 1325f757f3fSDimitry Andric if (exec_fspec) { 1335f757f3fSDimitry Andric char exec_cf_path[PATH_MAX]; 1345f757f3fSDimitry Andric if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) 1355f757f3fSDimitry Andric exec_url.reset(::CFURLCreateFromFileSystemRepresentation( 1365f757f3fSDimitry Andric NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path), 1375f757f3fSDimitry Andric FALSE)); 1385f757f3fSDimitry Andric } 1395f757f3fSDimitry Andric 1405f757f3fSDimitry Andric CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID( 1415f757f3fSDimitry Andric module_uuid_ref.get(), exec_url.get())); 1425f757f3fSDimitry Andric char path[PATH_MAX]; 1435f757f3fSDimitry Andric 1445f757f3fSDimitry Andric if (dsym_url.get()) { 1455f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 1465f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 1475f757f3fSDimitry Andric LLDB_LOGF(log, 1485f757f3fSDimitry Andric "DebugSymbols framework returned dSYM path of %s for " 1495f757f3fSDimitry Andric "UUID %s -- looking for the dSYM", 1505f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 1515f757f3fSDimitry Andric FileSpec dsym_filespec(path); 1525f757f3fSDimitry Andric if (path[0] == '~') 1535f757f3fSDimitry Andric FileSystem::Instance().Resolve(dsym_filespec); 1545f757f3fSDimitry Andric 1555f757f3fSDimitry Andric if (FileSystem::Instance().IsDirectory(dsym_filespec)) { 1565f757f3fSDimitry Andric dsym_filespec = PluginManager::FindSymbolFileInBundle( 1575f757f3fSDimitry Andric dsym_filespec, uuid, arch); 1585f757f3fSDimitry Andric ++items_found; 1595f757f3fSDimitry Andric } else { 1605f757f3fSDimitry Andric ++items_found; 1615f757f3fSDimitry Andric } 1625f757f3fSDimitry Andric return_module_spec.GetSymbolFileSpec() = dsym_filespec; 1635f757f3fSDimitry Andric } 1645f757f3fSDimitry Andric 1655f757f3fSDimitry Andric bool success = false; 1665f757f3fSDimitry Andric if (log) { 1675f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 1685f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 1695f757f3fSDimitry Andric LLDB_LOGF(log, 1705f757f3fSDimitry Andric "DebugSymbols framework returned dSYM path of %s for " 1715f757f3fSDimitry Andric "UUID %s -- looking for an exec file", 1725f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 1735f757f3fSDimitry Andric } 1745f757f3fSDimitry Andric } 1755f757f3fSDimitry Andric 1765f757f3fSDimitry Andric CFCReleaser<CFDictionaryRef> dict( 1775f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get())); 1785f757f3fSDimitry Andric CFDictionaryRef uuid_dict = NULL; 1795f757f3fSDimitry Andric if (dict.get()) { 1805f757f3fSDimitry Andric CFCString uuid_cfstr(uuid->GetAsString().c_str()); 1815f757f3fSDimitry Andric uuid_dict = static_cast<CFDictionaryRef>( 1825f757f3fSDimitry Andric ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); 1835f757f3fSDimitry Andric } 1845f757f3fSDimitry Andric 1855f757f3fSDimitry Andric // Check to see if we have the file on the local filesystem. 1865f757f3fSDimitry Andric if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { 1875f757f3fSDimitry Andric ModuleSpec exe_spec; 1885f757f3fSDimitry Andric exe_spec.GetFileSpec() = module_spec.GetFileSpec(); 1895f757f3fSDimitry Andric exe_spec.GetUUID() = module_spec.GetUUID(); 1905f757f3fSDimitry Andric ModuleSP module_sp; 1915f757f3fSDimitry Andric module_sp.reset(new Module(exe_spec)); 1925f757f3fSDimitry Andric if (module_sp && module_sp->GetObjectFile() && 1935f757f3fSDimitry Andric module_sp->MatchesModuleSpec(exe_spec)) { 1945f757f3fSDimitry Andric success = true; 1955f757f3fSDimitry Andric return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); 1965f757f3fSDimitry Andric LLDB_LOGF(log, "using original binary filepath %s for UUID %s", 1975f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath().c_str(), 1985f757f3fSDimitry Andric uuid->GetAsString().c_str()); 1995f757f3fSDimitry Andric ++items_found; 2005f757f3fSDimitry Andric } 2015f757f3fSDimitry Andric } 2025f757f3fSDimitry Andric 2035f757f3fSDimitry Andric // Check if the requested image is in our shared cache. 2045f757f3fSDimitry Andric if (!success) { 2055f757f3fSDimitry Andric SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo( 2065f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath()); 2075f757f3fSDimitry Andric 2085f757f3fSDimitry Andric // If we found it and it has the correct UUID, let's proceed with 2095f757f3fSDimitry Andric // creating a module from the memory contents. 2105f757f3fSDimitry Andric if (image_info.uuid && (!module_spec.GetUUID() || 2115f757f3fSDimitry Andric module_spec.GetUUID() == image_info.uuid)) { 2125f757f3fSDimitry Andric success = true; 2135f757f3fSDimitry Andric return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); 2145f757f3fSDimitry Andric LLDB_LOGF(log, 2155f757f3fSDimitry Andric "using binary from shared cache for filepath %s for " 2165f757f3fSDimitry Andric "UUID %s", 2175f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath().c_str(), 2185f757f3fSDimitry Andric uuid->GetAsString().c_str()); 2195f757f3fSDimitry Andric ++items_found; 2205f757f3fSDimitry Andric } 2215f757f3fSDimitry Andric } 2225f757f3fSDimitry Andric 2235f757f3fSDimitry Andric // Use the DBGSymbolRichExecutable filepath if present 2245f757f3fSDimitry Andric if (!success && uuid_dict) { 2255f757f3fSDimitry Andric CFStringRef exec_cf_path = 2265f757f3fSDimitry Andric static_cast<CFStringRef>(::CFDictionaryGetValue( 2275f757f3fSDimitry Andric uuid_dict, CFSTR("DBGSymbolRichExecutable"))); 2285f757f3fSDimitry Andric if (exec_cf_path && ::CFStringGetFileSystemRepresentation( 2295f757f3fSDimitry Andric exec_cf_path, path, sizeof(path))) { 2305f757f3fSDimitry Andric LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s", 2315f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 2325f757f3fSDimitry Andric ++items_found; 2335f757f3fSDimitry Andric FileSpec exec_filespec(path); 2345f757f3fSDimitry Andric if (path[0] == '~') 2355f757f3fSDimitry Andric FileSystem::Instance().Resolve(exec_filespec); 2365f757f3fSDimitry Andric if (FileSystem::Instance().Exists(exec_filespec)) { 2375f757f3fSDimitry Andric success = true; 2385f757f3fSDimitry Andric return_module_spec.GetFileSpec() = exec_filespec; 2395f757f3fSDimitry Andric } 2405f757f3fSDimitry Andric } 2415f757f3fSDimitry Andric } 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric // Look next to the dSYM for the binary file. 2445f757f3fSDimitry Andric if (!success) { 2455f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 2465f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 2475f757f3fSDimitry Andric char *dsym_extension_pos = ::strstr(path, ".dSYM"); 2485f757f3fSDimitry Andric if (dsym_extension_pos) { 2495f757f3fSDimitry Andric *dsym_extension_pos = '\0'; 2505f757f3fSDimitry Andric LLDB_LOGF(log, 2515f757f3fSDimitry Andric "Looking for executable binary next to dSYM " 2525f757f3fSDimitry Andric "bundle with name with name %s", 2535f757f3fSDimitry Andric path); 2545f757f3fSDimitry Andric FileSpec file_spec(path); 2555f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 2565f757f3fSDimitry Andric ModuleSpecList module_specs; 2575f757f3fSDimitry Andric ModuleSpec matched_module_spec; 2585f757f3fSDimitry Andric using namespace llvm::sys::fs; 2595f757f3fSDimitry Andric switch (get_file_type(file_spec.GetPath())) { 2605f757f3fSDimitry Andric 2615f757f3fSDimitry Andric case file_type::directory_file: // Bundle directory? 2625f757f3fSDimitry Andric { 2635f757f3fSDimitry Andric CFCBundle bundle(path); 2645f757f3fSDimitry Andric CFCReleaser<CFURLRef> bundle_exe_url( 2655f757f3fSDimitry Andric bundle.CopyExecutableURL()); 2665f757f3fSDimitry Andric if (bundle_exe_url.get()) { 2675f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(), 2685f757f3fSDimitry Andric true, (UInt8 *)path, 2695f757f3fSDimitry Andric sizeof(path) - 1)) { 2705f757f3fSDimitry Andric FileSpec bundle_exe_file_spec(path); 2715f757f3fSDimitry Andric FileSystem::Instance().Resolve(bundle_exe_file_spec); 2725f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications( 2735f757f3fSDimitry Andric bundle_exe_file_spec, 0, 0, module_specs) && 2745f757f3fSDimitry Andric module_specs.FindMatchingModuleSpec( 2755f757f3fSDimitry Andric module_spec, matched_module_spec)) 2765f757f3fSDimitry Andric 2775f757f3fSDimitry Andric { 2785f757f3fSDimitry Andric ++items_found; 2795f757f3fSDimitry Andric return_module_spec.GetFileSpec() = bundle_exe_file_spec; 2805f757f3fSDimitry Andric LLDB_LOGF(log, 2815f757f3fSDimitry Andric "Executable binary %s next to dSYM is " 2825f757f3fSDimitry Andric "compatible; using", 2835f757f3fSDimitry Andric path); 2845f757f3fSDimitry Andric } 2855f757f3fSDimitry Andric } 2865f757f3fSDimitry Andric } 2875f757f3fSDimitry Andric } break; 2885f757f3fSDimitry Andric 2895f757f3fSDimitry Andric case file_type::fifo_file: // Forget pipes 2905f757f3fSDimitry Andric case file_type::socket_file: // We can't process socket files 2915f757f3fSDimitry Andric case file_type::file_not_found: // File doesn't exist... 2925f757f3fSDimitry Andric case file_type::status_error: 2935f757f3fSDimitry Andric break; 2945f757f3fSDimitry Andric 2955f757f3fSDimitry Andric case file_type::type_unknown: 2965f757f3fSDimitry Andric case file_type::regular_file: 2975f757f3fSDimitry Andric case file_type::symlink_file: 2985f757f3fSDimitry Andric case file_type::block_file: 2995f757f3fSDimitry Andric case file_type::character_file: 3005f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, 3015f757f3fSDimitry Andric module_specs) && 3025f757f3fSDimitry Andric module_specs.FindMatchingModuleSpec(module_spec, 3035f757f3fSDimitry Andric matched_module_spec)) 3045f757f3fSDimitry Andric 3055f757f3fSDimitry Andric { 3065f757f3fSDimitry Andric ++items_found; 3075f757f3fSDimitry Andric return_module_spec.GetFileSpec() = file_spec; 3085f757f3fSDimitry Andric LLDB_LOGF(log, 3095f757f3fSDimitry Andric "Executable binary %s next to dSYM is " 3105f757f3fSDimitry Andric "compatible; using", 3115f757f3fSDimitry Andric path); 3125f757f3fSDimitry Andric } 3135f757f3fSDimitry Andric break; 3145f757f3fSDimitry Andric } 3155f757f3fSDimitry Andric } 3165f757f3fSDimitry Andric } 3175f757f3fSDimitry Andric } 3185f757f3fSDimitry Andric } 3195f757f3fSDimitry Andric } 3205f757f3fSDimitry Andric } 3215f757f3fSDimitry Andric } 3225f757f3fSDimitry Andric 3235f757f3fSDimitry Andric if (items_found) 3245f757f3fSDimitry Andric return return_module_spec; 3255f757f3fSDimitry Andric 3265f757f3fSDimitry Andric return {}; 3275f757f3fSDimitry Andric } 3285f757f3fSDimitry Andric 3295f757f3fSDimitry Andric std::optional<FileSpec> SymbolLocatorDebugSymbols::FindSymbolFileInBundle( 3305f757f3fSDimitry Andric const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch) { 3315f757f3fSDimitry Andric std::string dsym_bundle_path = dsym_bundle_fspec.GetPath(); 3325f757f3fSDimitry Andric llvm::SmallString<128> buffer(dsym_bundle_path); 3335f757f3fSDimitry Andric llvm::sys::path::append(buffer, "Contents", "Resources", "DWARF"); 3345f757f3fSDimitry Andric 3355f757f3fSDimitry Andric std::error_code EC; 3365f757f3fSDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs = 3375f757f3fSDimitry Andric FileSystem::Instance().GetVirtualFileSystem(); 3385f757f3fSDimitry Andric llvm::vfs::recursive_directory_iterator Iter(*vfs, buffer.str(), EC); 3395f757f3fSDimitry Andric llvm::vfs::recursive_directory_iterator End; 3405f757f3fSDimitry Andric for (; Iter != End && !EC; Iter.increment(EC)) { 3415f757f3fSDimitry Andric llvm::ErrorOr<llvm::vfs::Status> Status = vfs->status(Iter->path()); 3425f757f3fSDimitry Andric if (Status->isDirectory()) 3435f757f3fSDimitry Andric continue; 3445f757f3fSDimitry Andric 3455f757f3fSDimitry Andric FileSpec dsym_fspec(Iter->path()); 3465f757f3fSDimitry Andric ModuleSpecList module_specs; 3475f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) { 3485f757f3fSDimitry Andric ModuleSpec spec; 3495f757f3fSDimitry Andric for (size_t i = 0; i < module_specs.GetSize(); ++i) { 3505f757f3fSDimitry Andric bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); 3515f757f3fSDimitry Andric assert(got_spec); // The call has side-effects so can't be inlined. 3525f757f3fSDimitry Andric UNUSED_IF_ASSERT_DISABLED(got_spec); 3535f757f3fSDimitry Andric if ((uuid == nullptr || 3545f757f3fSDimitry Andric (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && 3555f757f3fSDimitry Andric (arch == nullptr || 3565f757f3fSDimitry Andric (spec.GetArchitecturePtr() && 3575f757f3fSDimitry Andric spec.GetArchitecture().IsCompatibleMatch(*arch)))) { 3585f757f3fSDimitry Andric return dsym_fspec; 3595f757f3fSDimitry Andric } 3605f757f3fSDimitry Andric } 3615f757f3fSDimitry Andric } 3625f757f3fSDimitry Andric } 3635f757f3fSDimitry Andric 3645f757f3fSDimitry Andric return {}; 3655f757f3fSDimitry Andric } 3665f757f3fSDimitry Andric 3675f757f3fSDimitry Andric static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, 3685f757f3fSDimitry Andric const ArchSpec *arch, 3695f757f3fSDimitry Andric const lldb_private::UUID *uuid) { 3705f757f3fSDimitry Andric ModuleSpecList module_specs; 3715f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) { 3725f757f3fSDimitry Andric ModuleSpec spec; 3735f757f3fSDimitry Andric for (size_t i = 0; i < module_specs.GetSize(); ++i) { 3745f757f3fSDimitry Andric bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); 3755f757f3fSDimitry Andric UNUSED_IF_ASSERT_DISABLED(got_spec); 3765f757f3fSDimitry Andric assert(got_spec); 3775f757f3fSDimitry Andric if ((uuid == nullptr || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && 3785f757f3fSDimitry Andric (arch == nullptr || 3795f757f3fSDimitry Andric (spec.GetArchitecturePtr() && 3805f757f3fSDimitry Andric spec.GetArchitecture().IsCompatibleMatch(*arch)))) { 3815f757f3fSDimitry Andric return true; 3825f757f3fSDimitry Andric } 3835f757f3fSDimitry Andric } 3845f757f3fSDimitry Andric } 3855f757f3fSDimitry Andric return false; 3865f757f3fSDimitry Andric } 3875f757f3fSDimitry Andric 3885f757f3fSDimitry Andric // Given a binary exec_fspec, and a ModuleSpec with an architecture/uuid, 3895f757f3fSDimitry Andric // return true if there is a matching dSYM bundle next to the exec_fspec, 3905f757f3fSDimitry Andric // and return that value in dsym_fspec. 3915f757f3fSDimitry Andric // If there is a .dSYM.yaa compressed archive next to the exec_fspec, 3925f757f3fSDimitry Andric // call through PluginManager::DownloadObjectAndSymbolFile to download the 3935f757f3fSDimitry Andric // expanded/uncompressed dSYM and return that filepath in dsym_fspec. 3945f757f3fSDimitry Andric static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec, 3955f757f3fSDimitry Andric const FileSpec &exec_fspec, 3965f757f3fSDimitry Andric FileSpec &dsym_fspec) { 3975f757f3fSDimitry Andric ConstString filename = exec_fspec.GetFilename(); 3985f757f3fSDimitry Andric FileSpec dsym_directory = exec_fspec; 3995f757f3fSDimitry Andric dsym_directory.RemoveLastPathComponent(); 4005f757f3fSDimitry Andric 4015f757f3fSDimitry Andric std::string dsym_filename = filename.AsCString(); 4025f757f3fSDimitry Andric dsym_filename += ".dSYM"; 4035f757f3fSDimitry Andric dsym_directory.AppendPathComponent(dsym_filename); 4045f757f3fSDimitry Andric dsym_directory.AppendPathComponent("Contents"); 4055f757f3fSDimitry Andric dsym_directory.AppendPathComponent("Resources"); 4065f757f3fSDimitry Andric dsym_directory.AppendPathComponent("DWARF"); 4075f757f3fSDimitry Andric 4085f757f3fSDimitry Andric if (FileSystem::Instance().Exists(dsym_directory)) { 4095f757f3fSDimitry Andric 4105f757f3fSDimitry Andric // See if the binary name exists in the dSYM DWARF 4115f757f3fSDimitry Andric // subdir. 4125f757f3fSDimitry Andric dsym_fspec = dsym_directory; 4135f757f3fSDimitry Andric dsym_fspec.AppendPathComponent(filename.AsCString()); 4145f757f3fSDimitry Andric if (FileSystem::Instance().Exists(dsym_fspec) && 4155f757f3fSDimitry Andric FileAtPathContainsArchAndUUID(dsym_fspec, mod_spec.GetArchitecturePtr(), 4165f757f3fSDimitry Andric mod_spec.GetUUIDPtr())) { 4175f757f3fSDimitry Andric return true; 4185f757f3fSDimitry Andric } 4195f757f3fSDimitry Andric 4205f757f3fSDimitry Andric // See if we have "../CF.framework" - so we'll look for 4215f757f3fSDimitry Andric // CF.framework.dSYM/Contents/Resources/DWARF/CF 4225f757f3fSDimitry Andric // We need to drop the last suffix after '.' to match 4235f757f3fSDimitry Andric // 'CF' in the DWARF subdir. 4245f757f3fSDimitry Andric std::string binary_name(filename.AsCString()); 4255f757f3fSDimitry Andric auto last_dot = binary_name.find_last_of('.'); 4265f757f3fSDimitry Andric if (last_dot != std::string::npos) { 4275f757f3fSDimitry Andric binary_name.erase(last_dot); 4285f757f3fSDimitry Andric dsym_fspec = dsym_directory; 4295f757f3fSDimitry Andric dsym_fspec.AppendPathComponent(binary_name); 4305f757f3fSDimitry Andric if (FileSystem::Instance().Exists(dsym_fspec) && 4315f757f3fSDimitry Andric FileAtPathContainsArchAndUUID(dsym_fspec, 4325f757f3fSDimitry Andric mod_spec.GetArchitecturePtr(), 4335f757f3fSDimitry Andric mod_spec.GetUUIDPtr())) { 4345f757f3fSDimitry Andric return true; 4355f757f3fSDimitry Andric } 4365f757f3fSDimitry Andric } 4375f757f3fSDimitry Andric } 4385f757f3fSDimitry Andric 4395f757f3fSDimitry Andric // See if we have a .dSYM.yaa next to this executable path. 4405f757f3fSDimitry Andric FileSpec dsym_yaa_fspec = exec_fspec; 4415f757f3fSDimitry Andric dsym_yaa_fspec.RemoveLastPathComponent(); 4425f757f3fSDimitry Andric std::string dsym_yaa_filename = filename.AsCString(); 4435f757f3fSDimitry Andric dsym_yaa_filename += ".dSYM.yaa"; 4445f757f3fSDimitry Andric dsym_yaa_fspec.AppendPathComponent(dsym_yaa_filename); 4455f757f3fSDimitry Andric 4465f757f3fSDimitry Andric if (FileSystem::Instance().Exists(dsym_yaa_fspec)) { 4475f757f3fSDimitry Andric ModuleSpec mutable_mod_spec = mod_spec; 4485f757f3fSDimitry Andric Status error; 4495f757f3fSDimitry Andric if (PluginManager::DownloadObjectAndSymbolFile(mutable_mod_spec, error, 4505f757f3fSDimitry Andric true) && 4515f757f3fSDimitry Andric FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) { 4525f757f3fSDimitry Andric dsym_fspec = mutable_mod_spec.GetSymbolFileSpec(); 4535f757f3fSDimitry Andric return true; 4545f757f3fSDimitry Andric } 4555f757f3fSDimitry Andric } 4565f757f3fSDimitry Andric 4575f757f3fSDimitry Andric return false; 4585f757f3fSDimitry Andric } 4595f757f3fSDimitry Andric 4605f757f3fSDimitry Andric // Given a ModuleSpec with a FileSpec and optionally uuid/architecture 4615f757f3fSDimitry Andric // filled in, look for a .dSYM bundle next to that binary. Returns true 4625f757f3fSDimitry Andric // if a .dSYM bundle is found, and that path is returned in the dsym_fspec 4635f757f3fSDimitry Andric // FileSpec. 4645f757f3fSDimitry Andric // 4655f757f3fSDimitry Andric // This routine looks a few directory layers above the given exec_path - 4665f757f3fSDimitry Andric // exec_path might be /System/Library/Frameworks/CF.framework/CF and the 4675f757f3fSDimitry Andric // dSYM might be /System/Library/Frameworks/CF.framework.dSYM. 4685f757f3fSDimitry Andric // 4695f757f3fSDimitry Andric // If there is a .dSYM.yaa compressed archive found next to the binary, 4705f757f3fSDimitry Andric // we'll call DownloadObjectAndSymbolFile to expand it into a plain .dSYM 4715f757f3fSDimitry Andric static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, 4725f757f3fSDimitry Andric FileSpec &dsym_fspec) { 4735f757f3fSDimitry Andric Log *log = GetLog(LLDBLog::Host); 4745f757f3fSDimitry Andric const FileSpec &exec_fspec = module_spec.GetFileSpec(); 4755f757f3fSDimitry Andric if (exec_fspec) { 4765f757f3fSDimitry Andric if (::LookForDsymNextToExecutablePath(module_spec, exec_fspec, 4775f757f3fSDimitry Andric dsym_fspec)) { 4785f757f3fSDimitry Andric if (log) { 4795f757f3fSDimitry Andric LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s", 4805f757f3fSDimitry Andric dsym_fspec.GetPath().c_str()); 4815f757f3fSDimitry Andric } 4825f757f3fSDimitry Andric return true; 4835f757f3fSDimitry Andric } else { 4845f757f3fSDimitry Andric FileSpec parent_dirs = exec_fspec; 4855f757f3fSDimitry Andric 4865f757f3fSDimitry Andric // Remove the binary name from the FileSpec 4875f757f3fSDimitry Andric parent_dirs.RemoveLastPathComponent(); 4885f757f3fSDimitry Andric 4895f757f3fSDimitry Andric // Add a ".dSYM" name to each directory component of the path, 4905f757f3fSDimitry Andric // stripping off components. e.g. we may have a binary like 4915f757f3fSDimitry Andric // /S/L/F/Foundation.framework/Versions/A/Foundation and 4925f757f3fSDimitry Andric // /S/L/F/Foundation.framework.dSYM 4935f757f3fSDimitry Andric // 4945f757f3fSDimitry Andric // so we'll need to start with 4955f757f3fSDimitry Andric // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the 4965f757f3fSDimitry Andric // "A", and if that doesn't exist, strip off the "A" and try it again 4975f757f3fSDimitry Andric // with "Versions", etc., until we find a dSYM bundle or we've 4985f757f3fSDimitry Andric // stripped off enough path components that there's no need to 4995f757f3fSDimitry Andric // continue. 5005f757f3fSDimitry Andric 5015f757f3fSDimitry Andric for (int i = 0; i < 4; i++) { 5025f757f3fSDimitry Andric // Does this part of the path have a "." character - could it be a 5035f757f3fSDimitry Andric // bundle's top level directory? 5045f757f3fSDimitry Andric const char *fn = parent_dirs.GetFilename().AsCString(); 5055f757f3fSDimitry Andric if (fn == nullptr) 5065f757f3fSDimitry Andric break; 5075f757f3fSDimitry Andric if (::strchr(fn, '.') != nullptr) { 5085f757f3fSDimitry Andric if (::LookForDsymNextToExecutablePath(module_spec, parent_dirs, 5095f757f3fSDimitry Andric dsym_fspec)) { 5105f757f3fSDimitry Andric if (log) { 5115f757f3fSDimitry Andric LLDB_LOGF(log, "dSYM with matching UUID & arch found at %s", 5125f757f3fSDimitry Andric dsym_fspec.GetPath().c_str()); 5135f757f3fSDimitry Andric } 5145f757f3fSDimitry Andric return true; 5155f757f3fSDimitry Andric } 5165f757f3fSDimitry Andric } 5175f757f3fSDimitry Andric parent_dirs.RemoveLastPathComponent(); 5185f757f3fSDimitry Andric } 5195f757f3fSDimitry Andric } 5205f757f3fSDimitry Andric } 5215f757f3fSDimitry Andric dsym_fspec.Clear(); 5225f757f3fSDimitry Andric return false; 5235f757f3fSDimitry Andric } 5245f757f3fSDimitry Andric 5255f757f3fSDimitry Andric static int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, 5265f757f3fSDimitry Andric ModuleSpec &return_module_spec) { 5275f757f3fSDimitry Andric Log *log = GetLog(LLDBLog::Host); 5285f757f3fSDimitry Andric if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { 5295f757f3fSDimitry Andric LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled."); 5305f757f3fSDimitry Andric return 0; 5315f757f3fSDimitry Andric } 5325f757f3fSDimitry Andric 5335f757f3fSDimitry Andric return_module_spec = module_spec; 5345f757f3fSDimitry Andric return_module_spec.GetFileSpec().Clear(); 5355f757f3fSDimitry Andric return_module_spec.GetSymbolFileSpec().Clear(); 5365f757f3fSDimitry Andric 5375f757f3fSDimitry Andric const UUID *uuid = module_spec.GetUUIDPtr(); 5385f757f3fSDimitry Andric const ArchSpec *arch = module_spec.GetArchitecturePtr(); 5395f757f3fSDimitry Andric 5405f757f3fSDimitry Andric int items_found = 0; 5415f757f3fSDimitry Andric 5425f757f3fSDimitry Andric if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || 5435f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { 5445f757f3fSDimitry Andric void *handle = dlopen( 5455f757f3fSDimitry Andric "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols", 5465f757f3fSDimitry Andric RTLD_LAZY | RTLD_LOCAL); 5475f757f3fSDimitry Andric if (handle) { 5485f757f3fSDimitry Andric g_dlsym_DBGCopyFullDSYMURLForUUID = 5495f757f3fSDimitry Andric (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle, 5505f757f3fSDimitry Andric "DBGCopyFullDSYMURLForUUID"); 5515f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym( 5525f757f3fSDimitry Andric handle, "DBGCopyDSYMPropertyLists"); 5535f757f3fSDimitry Andric } 5545f757f3fSDimitry Andric } 5555f757f3fSDimitry Andric 5565f757f3fSDimitry Andric if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || 5575f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists == nullptr) { 5585f757f3fSDimitry Andric return items_found; 5595f757f3fSDimitry Andric } 5605f757f3fSDimitry Andric 5615f757f3fSDimitry Andric if (uuid && uuid->IsValid()) { 5625f757f3fSDimitry Andric // Try and locate the dSYM file using DebugSymbols first 5635f757f3fSDimitry Andric llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes(); 5645f757f3fSDimitry Andric if (module_uuid.size() == 16) { 5655f757f3fSDimitry Andric CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes( 5665f757f3fSDimitry Andric NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3], 5675f757f3fSDimitry Andric module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7], 5685f757f3fSDimitry Andric module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11], 5695f757f3fSDimitry Andric module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15])); 5705f757f3fSDimitry Andric 5715f757f3fSDimitry Andric if (module_uuid_ref.get()) { 5725f757f3fSDimitry Andric CFCReleaser<CFURLRef> exec_url; 5735f757f3fSDimitry Andric const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 5745f757f3fSDimitry Andric if (exec_fspec) { 5755f757f3fSDimitry Andric char exec_cf_path[PATH_MAX]; 5765f757f3fSDimitry Andric if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path))) 5775f757f3fSDimitry Andric exec_url.reset(::CFURLCreateFromFileSystemRepresentation( 5785f757f3fSDimitry Andric NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path), 5795f757f3fSDimitry Andric FALSE)); 5805f757f3fSDimitry Andric } 5815f757f3fSDimitry Andric 5825f757f3fSDimitry Andric CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID( 5835f757f3fSDimitry Andric module_uuid_ref.get(), exec_url.get())); 5845f757f3fSDimitry Andric char path[PATH_MAX]; 5855f757f3fSDimitry Andric 5865f757f3fSDimitry Andric if (dsym_url.get()) { 5875f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 5885f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 5895f757f3fSDimitry Andric LLDB_LOGF(log, 5905f757f3fSDimitry Andric "DebugSymbols framework returned dSYM path of %s for " 5915f757f3fSDimitry Andric "UUID %s -- looking for the dSYM", 5925f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 5935f757f3fSDimitry Andric FileSpec dsym_filespec(path); 5945f757f3fSDimitry Andric if (path[0] == '~') 5955f757f3fSDimitry Andric FileSystem::Instance().Resolve(dsym_filespec); 5965f757f3fSDimitry Andric 5975f757f3fSDimitry Andric if (FileSystem::Instance().IsDirectory(dsym_filespec)) { 5985f757f3fSDimitry Andric dsym_filespec = PluginManager::FindSymbolFileInBundle( 5995f757f3fSDimitry Andric dsym_filespec, uuid, arch); 6005f757f3fSDimitry Andric ++items_found; 6015f757f3fSDimitry Andric } else { 6025f757f3fSDimitry Andric ++items_found; 6035f757f3fSDimitry Andric } 6045f757f3fSDimitry Andric return_module_spec.GetSymbolFileSpec() = dsym_filespec; 6055f757f3fSDimitry Andric } 6065f757f3fSDimitry Andric 6075f757f3fSDimitry Andric bool success = false; 6085f757f3fSDimitry Andric if (log) { 6095f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 6105f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 6115f757f3fSDimitry Andric LLDB_LOGF(log, 6125f757f3fSDimitry Andric "DebugSymbols framework returned dSYM path of %s for " 6135f757f3fSDimitry Andric "UUID %s -- looking for an exec file", 6145f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 6155f757f3fSDimitry Andric } 6165f757f3fSDimitry Andric } 6175f757f3fSDimitry Andric 6185f757f3fSDimitry Andric CFCReleaser<CFDictionaryRef> dict( 6195f757f3fSDimitry Andric g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get())); 6205f757f3fSDimitry Andric CFDictionaryRef uuid_dict = NULL; 6215f757f3fSDimitry Andric if (dict.get()) { 6225f757f3fSDimitry Andric CFCString uuid_cfstr(uuid->GetAsString().c_str()); 6235f757f3fSDimitry Andric uuid_dict = static_cast<CFDictionaryRef>( 6245f757f3fSDimitry Andric ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get())); 6255f757f3fSDimitry Andric } 6265f757f3fSDimitry Andric 6275f757f3fSDimitry Andric // Check to see if we have the file on the local filesystem. 6285f757f3fSDimitry Andric if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { 6295f757f3fSDimitry Andric ModuleSpec exe_spec; 6305f757f3fSDimitry Andric exe_spec.GetFileSpec() = module_spec.GetFileSpec(); 6315f757f3fSDimitry Andric exe_spec.GetUUID() = module_spec.GetUUID(); 6325f757f3fSDimitry Andric ModuleSP module_sp; 6335f757f3fSDimitry Andric module_sp.reset(new Module(exe_spec)); 6345f757f3fSDimitry Andric if (module_sp && module_sp->GetObjectFile() && 6355f757f3fSDimitry Andric module_sp->MatchesModuleSpec(exe_spec)) { 6365f757f3fSDimitry Andric success = true; 6375f757f3fSDimitry Andric return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); 6385f757f3fSDimitry Andric LLDB_LOGF(log, "using original binary filepath %s for UUID %s", 6395f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath().c_str(), 6405f757f3fSDimitry Andric uuid->GetAsString().c_str()); 6415f757f3fSDimitry Andric ++items_found; 6425f757f3fSDimitry Andric } 6435f757f3fSDimitry Andric } 6445f757f3fSDimitry Andric 6455f757f3fSDimitry Andric // Check if the requested image is in our shared cache. 6465f757f3fSDimitry Andric if (!success) { 6475f757f3fSDimitry Andric SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo( 6485f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath()); 6495f757f3fSDimitry Andric 6505f757f3fSDimitry Andric // If we found it and it has the correct UUID, let's proceed with 6515f757f3fSDimitry Andric // creating a module from the memory contents. 6525f757f3fSDimitry Andric if (image_info.uuid && (!module_spec.GetUUID() || 6535f757f3fSDimitry Andric module_spec.GetUUID() == image_info.uuid)) { 6545f757f3fSDimitry Andric success = true; 6555f757f3fSDimitry Andric return_module_spec.GetFileSpec() = module_spec.GetFileSpec(); 6565f757f3fSDimitry Andric LLDB_LOGF(log, 6575f757f3fSDimitry Andric "using binary from shared cache for filepath %s for " 6585f757f3fSDimitry Andric "UUID %s", 6595f757f3fSDimitry Andric module_spec.GetFileSpec().GetPath().c_str(), 6605f757f3fSDimitry Andric uuid->GetAsString().c_str()); 6615f757f3fSDimitry Andric ++items_found; 6625f757f3fSDimitry Andric } 6635f757f3fSDimitry Andric } 6645f757f3fSDimitry Andric 6655f757f3fSDimitry Andric // Use the DBGSymbolRichExecutable filepath if present 6665f757f3fSDimitry Andric if (!success && uuid_dict) { 6675f757f3fSDimitry Andric CFStringRef exec_cf_path = 6685f757f3fSDimitry Andric static_cast<CFStringRef>(::CFDictionaryGetValue( 6695f757f3fSDimitry Andric uuid_dict, CFSTR("DBGSymbolRichExecutable"))); 6705f757f3fSDimitry Andric if (exec_cf_path && ::CFStringGetFileSystemRepresentation( 6715f757f3fSDimitry Andric exec_cf_path, path, sizeof(path))) { 6725f757f3fSDimitry Andric LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s", 6735f757f3fSDimitry Andric path, uuid->GetAsString().c_str()); 6745f757f3fSDimitry Andric ++items_found; 6755f757f3fSDimitry Andric FileSpec exec_filespec(path); 6765f757f3fSDimitry Andric if (path[0] == '~') 6775f757f3fSDimitry Andric FileSystem::Instance().Resolve(exec_filespec); 6785f757f3fSDimitry Andric if (FileSystem::Instance().Exists(exec_filespec)) { 6795f757f3fSDimitry Andric success = true; 6805f757f3fSDimitry Andric return_module_spec.GetFileSpec() = exec_filespec; 6815f757f3fSDimitry Andric } 6825f757f3fSDimitry Andric } 6835f757f3fSDimitry Andric } 6845f757f3fSDimitry Andric 6855f757f3fSDimitry Andric // Look next to the dSYM for the binary file. 6865f757f3fSDimitry Andric if (!success) { 6875f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation( 6885f757f3fSDimitry Andric dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) { 6895f757f3fSDimitry Andric char *dsym_extension_pos = ::strstr(path, ".dSYM"); 6905f757f3fSDimitry Andric if (dsym_extension_pos) { 6915f757f3fSDimitry Andric *dsym_extension_pos = '\0'; 6925f757f3fSDimitry Andric LLDB_LOGF(log, 6935f757f3fSDimitry Andric "Looking for executable binary next to dSYM " 6945f757f3fSDimitry Andric "bundle with name with name %s", 6955f757f3fSDimitry Andric path); 6965f757f3fSDimitry Andric FileSpec file_spec(path); 6975f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 6985f757f3fSDimitry Andric ModuleSpecList module_specs; 6995f757f3fSDimitry Andric ModuleSpec matched_module_spec; 7005f757f3fSDimitry Andric using namespace llvm::sys::fs; 7015f757f3fSDimitry Andric switch (get_file_type(file_spec.GetPath())) { 7025f757f3fSDimitry Andric 7035f757f3fSDimitry Andric case file_type::directory_file: // Bundle directory? 7045f757f3fSDimitry Andric { 7055f757f3fSDimitry Andric CFCBundle bundle(path); 7065f757f3fSDimitry Andric CFCReleaser<CFURLRef> bundle_exe_url( 7075f757f3fSDimitry Andric bundle.CopyExecutableURL()); 7085f757f3fSDimitry Andric if (bundle_exe_url.get()) { 7095f757f3fSDimitry Andric if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(), 7105f757f3fSDimitry Andric true, (UInt8 *)path, 7115f757f3fSDimitry Andric sizeof(path) - 1)) { 7125f757f3fSDimitry Andric FileSpec bundle_exe_file_spec(path); 7135f757f3fSDimitry Andric FileSystem::Instance().Resolve(bundle_exe_file_spec); 7145f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications( 7155f757f3fSDimitry Andric bundle_exe_file_spec, 0, 0, module_specs) && 7165f757f3fSDimitry Andric module_specs.FindMatchingModuleSpec( 7175f757f3fSDimitry Andric module_spec, matched_module_spec)) 7185f757f3fSDimitry Andric 7195f757f3fSDimitry Andric { 7205f757f3fSDimitry Andric ++items_found; 7215f757f3fSDimitry Andric return_module_spec.GetFileSpec() = bundle_exe_file_spec; 7225f757f3fSDimitry Andric LLDB_LOGF(log, 7235f757f3fSDimitry Andric "Executable binary %s next to dSYM is " 7245f757f3fSDimitry Andric "compatible; using", 7255f757f3fSDimitry Andric path); 7265f757f3fSDimitry Andric } 7275f757f3fSDimitry Andric } 7285f757f3fSDimitry Andric } 7295f757f3fSDimitry Andric } break; 7305f757f3fSDimitry Andric 7315f757f3fSDimitry Andric case file_type::fifo_file: // Forget pipes 7325f757f3fSDimitry Andric case file_type::socket_file: // We can't process socket files 7335f757f3fSDimitry Andric case file_type::file_not_found: // File doesn't exist... 7345f757f3fSDimitry Andric case file_type::status_error: 7355f757f3fSDimitry Andric break; 7365f757f3fSDimitry Andric 7375f757f3fSDimitry Andric case file_type::type_unknown: 7385f757f3fSDimitry Andric case file_type::regular_file: 7395f757f3fSDimitry Andric case file_type::symlink_file: 7405f757f3fSDimitry Andric case file_type::block_file: 7415f757f3fSDimitry Andric case file_type::character_file: 7425f757f3fSDimitry Andric if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0, 7435f757f3fSDimitry Andric module_specs) && 7445f757f3fSDimitry Andric module_specs.FindMatchingModuleSpec(module_spec, 7455f757f3fSDimitry Andric matched_module_spec)) 7465f757f3fSDimitry Andric 7475f757f3fSDimitry Andric { 7485f757f3fSDimitry Andric ++items_found; 7495f757f3fSDimitry Andric return_module_spec.GetFileSpec() = file_spec; 7505f757f3fSDimitry Andric LLDB_LOGF(log, 7515f757f3fSDimitry Andric "Executable binary %s next to dSYM is " 7525f757f3fSDimitry Andric "compatible; using", 7535f757f3fSDimitry Andric path); 7545f757f3fSDimitry Andric } 7555f757f3fSDimitry Andric break; 7565f757f3fSDimitry Andric } 7575f757f3fSDimitry Andric } 7585f757f3fSDimitry Andric } 7595f757f3fSDimitry Andric } 7605f757f3fSDimitry Andric } 7615f757f3fSDimitry Andric } 7625f757f3fSDimitry Andric } 7635f757f3fSDimitry Andric } 7645f757f3fSDimitry Andric 7655f757f3fSDimitry Andric return items_found; 7665f757f3fSDimitry Andric } 7675f757f3fSDimitry Andric 7685f757f3fSDimitry Andric std::optional<FileSpec> SymbolLocatorDebugSymbols::LocateExecutableSymbolFile( 7695f757f3fSDimitry Andric const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { 7705f757f3fSDimitry Andric const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 7715f757f3fSDimitry Andric const ArchSpec *arch = module_spec.GetArchitecturePtr(); 7725f757f3fSDimitry Andric const UUID *uuid = module_spec.GetUUIDPtr(); 7735f757f3fSDimitry Andric 7745f757f3fSDimitry Andric LLDB_SCOPED_TIMERF( 7755f757f3fSDimitry Andric "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", 7765f757f3fSDimitry Andric exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", 7775f757f3fSDimitry Andric arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 7785f757f3fSDimitry Andric 779*0fca6ea1SDimitry Andric Progress progress( 780*0fca6ea1SDimitry Andric "Locating external symbol file", 781*0fca6ea1SDimitry Andric module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")); 782*0fca6ea1SDimitry Andric 7835f757f3fSDimitry Andric FileSpec symbol_fspec; 7845f757f3fSDimitry Andric ModuleSpec dsym_module_spec; 7855f757f3fSDimitry Andric // First try and find the dSYM in the same directory as the executable or in 7865f757f3fSDimitry Andric // an appropriate parent directory 7875f757f3fSDimitry Andric if (!LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec)) { 7885f757f3fSDimitry Andric // We failed to easily find the dSYM above, so use DebugSymbols 7895f757f3fSDimitry Andric LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec); 7905f757f3fSDimitry Andric } else { 7915f757f3fSDimitry Andric dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; 7925f757f3fSDimitry Andric } 7935f757f3fSDimitry Andric 7945f757f3fSDimitry Andric return dsym_module_spec.GetSymbolFileSpec(); 7955f757f3fSDimitry Andric } 7965f757f3fSDimitry Andric 7975f757f3fSDimitry Andric static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, 7985f757f3fSDimitry Andric ModuleSpec &module_spec, 7995f757f3fSDimitry Andric Status &error, 8005f757f3fSDimitry Andric const std::string &command) { 8015f757f3fSDimitry Andric Log *log = GetLog(LLDBLog::Host); 8025f757f3fSDimitry Andric bool success = false; 8035f757f3fSDimitry Andric if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) { 8045f757f3fSDimitry Andric std::string str; 8055f757f3fSDimitry Andric CFStringRef cf_str; 8065f757f3fSDimitry Andric CFDictionaryRef cf_dict; 8075f757f3fSDimitry Andric 8085f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, 8095f757f3fSDimitry Andric CFSTR("DBGError")); 8105f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 8115f757f3fSDimitry Andric if (CFCString::FileSystemRepresentation(cf_str, str)) { 8125f757f3fSDimitry Andric std::string errorstr = command; 8135f757f3fSDimitry Andric errorstr += ":\n"; 8145f757f3fSDimitry Andric errorstr += str; 8155f757f3fSDimitry Andric error.SetErrorString(errorstr); 8165f757f3fSDimitry Andric } 8175f757f3fSDimitry Andric } 8185f757f3fSDimitry Andric 8195f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue( 8205f757f3fSDimitry Andric (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable")); 8215f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 8225f757f3fSDimitry Andric if (CFCString::FileSystemRepresentation(cf_str, str)) { 8235f757f3fSDimitry Andric module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native); 8245f757f3fSDimitry Andric FileSystem::Instance().Resolve(module_spec.GetFileSpec()); 8255f757f3fSDimitry Andric LLDB_LOGF(log, 8265f757f3fSDimitry Andric "From dsymForUUID plist: Symbol rich executable is at '%s'", 8275f757f3fSDimitry Andric str.c_str()); 8285f757f3fSDimitry Andric } 8295f757f3fSDimitry Andric } 8305f757f3fSDimitry Andric 8315f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, 8325f757f3fSDimitry Andric CFSTR("DBGDSYMPath")); 8335f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 8345f757f3fSDimitry Andric if (CFCString::FileSystemRepresentation(cf_str, str)) { 8355f757f3fSDimitry Andric module_spec.GetSymbolFileSpec().SetFile(str.c_str(), 8365f757f3fSDimitry Andric FileSpec::Style::native); 8375f757f3fSDimitry Andric FileSystem::Instance().Resolve(module_spec.GetFileSpec()); 8385f757f3fSDimitry Andric success = true; 8395f757f3fSDimitry Andric LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str()); 8405f757f3fSDimitry Andric } 8415f757f3fSDimitry Andric } 8425f757f3fSDimitry Andric 8435f757f3fSDimitry Andric std::string DBGBuildSourcePath; 8445f757f3fSDimitry Andric std::string DBGSourcePath; 8455f757f3fSDimitry Andric 8465f757f3fSDimitry Andric // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping. 8475f757f3fSDimitry Andric // If DBGVersion 2, strip last two components of path remappings from 8485f757f3fSDimitry Andric // entries to fix an issue with a specific set of 8495f757f3fSDimitry Andric // DBGSourcePathRemapping entries that lldb worked 8505f757f3fSDimitry Andric // with. 8515f757f3fSDimitry Andric // If DBGVersion 3, trust & use the source path remappings as-is. 8525f757f3fSDimitry Andric // 8535f757f3fSDimitry Andric cf_dict = (CFDictionaryRef)CFDictionaryGetValue( 8545f757f3fSDimitry Andric (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping")); 8555f757f3fSDimitry Andric if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) { 8565f757f3fSDimitry Andric // If we see DBGVersion with a value of 2 or higher, this is a new style 8575f757f3fSDimitry Andric // DBGSourcePathRemapping dictionary 8585f757f3fSDimitry Andric bool new_style_source_remapping_dictionary = false; 8595f757f3fSDimitry Andric bool do_truncate_remapping_names = false; 8605f757f3fSDimitry Andric std::string original_DBGSourcePath_value = DBGSourcePath; 8615f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, 8625f757f3fSDimitry Andric CFSTR("DBGVersion")); 8635f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 8645f757f3fSDimitry Andric std::string version; 8655f757f3fSDimitry Andric CFCString::FileSystemRepresentation(cf_str, version); 8665f757f3fSDimitry Andric if (!version.empty() && isdigit(version[0])) { 8675f757f3fSDimitry Andric int version_number = atoi(version.c_str()); 8685f757f3fSDimitry Andric if (version_number > 1) { 8695f757f3fSDimitry Andric new_style_source_remapping_dictionary = true; 8705f757f3fSDimitry Andric } 8715f757f3fSDimitry Andric if (version_number == 2) { 8725f757f3fSDimitry Andric do_truncate_remapping_names = true; 8735f757f3fSDimitry Andric } 8745f757f3fSDimitry Andric } 8755f757f3fSDimitry Andric } 8765f757f3fSDimitry Andric 8775f757f3fSDimitry Andric CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict); 8785f757f3fSDimitry Andric if (kv_pair_count > 0) { 8795f757f3fSDimitry Andric CFStringRef *keys = 8805f757f3fSDimitry Andric (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); 8815f757f3fSDimitry Andric CFStringRef *values = 8825f757f3fSDimitry Andric (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef)); 8835f757f3fSDimitry Andric if (keys != nullptr && values != nullptr) { 8845f757f3fSDimitry Andric CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict, 8855f757f3fSDimitry Andric (const void **)keys, 8865f757f3fSDimitry Andric (const void **)values); 8875f757f3fSDimitry Andric } 8885f757f3fSDimitry Andric for (CFIndex i = 0; i < kv_pair_count; i++) { 8895f757f3fSDimitry Andric DBGBuildSourcePath.clear(); 8905f757f3fSDimitry Andric DBGSourcePath.clear(); 8915f757f3fSDimitry Andric if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) { 8925f757f3fSDimitry Andric CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath); 8935f757f3fSDimitry Andric } 8945f757f3fSDimitry Andric if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) { 8955f757f3fSDimitry Andric CFCString::FileSystemRepresentation(values[i], DBGSourcePath); 8965f757f3fSDimitry Andric } 8975f757f3fSDimitry Andric if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { 8985f757f3fSDimitry Andric // In the "old style" DBGSourcePathRemapping dictionary, the 8995f757f3fSDimitry Andric // DBGSourcePath values (the "values" half of key-value path pairs) 9005f757f3fSDimitry Andric // were wrong. Ignore them and use the universal DBGSourcePath 9015f757f3fSDimitry Andric // string from earlier. 9025f757f3fSDimitry Andric if (new_style_source_remapping_dictionary && 9035f757f3fSDimitry Andric !original_DBGSourcePath_value.empty()) { 9045f757f3fSDimitry Andric DBGSourcePath = original_DBGSourcePath_value; 9055f757f3fSDimitry Andric } 9065f757f3fSDimitry Andric if (DBGSourcePath[0] == '~') { 9075f757f3fSDimitry Andric FileSpec resolved_source_path(DBGSourcePath.c_str()); 9085f757f3fSDimitry Andric FileSystem::Instance().Resolve(resolved_source_path); 9095f757f3fSDimitry Andric DBGSourcePath = resolved_source_path.GetPath(); 9105f757f3fSDimitry Andric } 9115f757f3fSDimitry Andric // With version 2 of DBGSourcePathRemapping, we can chop off the 9125f757f3fSDimitry Andric // last two filename parts from the source remapping and get a more 9135f757f3fSDimitry Andric // general source remapping that still works. Add this as another 9145f757f3fSDimitry Andric // option in addition to the full source path remap. 9155f757f3fSDimitry Andric module_spec.GetSourceMappingList().Append(DBGBuildSourcePath, 9165f757f3fSDimitry Andric DBGSourcePath, true); 9175f757f3fSDimitry Andric if (do_truncate_remapping_names) { 9185f757f3fSDimitry Andric FileSpec build_path(DBGBuildSourcePath.c_str()); 9195f757f3fSDimitry Andric FileSpec source_path(DBGSourcePath.c_str()); 9205f757f3fSDimitry Andric build_path.RemoveLastPathComponent(); 9215f757f3fSDimitry Andric build_path.RemoveLastPathComponent(); 9225f757f3fSDimitry Andric source_path.RemoveLastPathComponent(); 9235f757f3fSDimitry Andric source_path.RemoveLastPathComponent(); 9245f757f3fSDimitry Andric module_spec.GetSourceMappingList().Append( 9255f757f3fSDimitry Andric build_path.GetPath(), source_path.GetPath(), true); 9265f757f3fSDimitry Andric } 9275f757f3fSDimitry Andric } 9285f757f3fSDimitry Andric } 9295f757f3fSDimitry Andric if (keys) 9305f757f3fSDimitry Andric free(keys); 9315f757f3fSDimitry Andric if (values) 9325f757f3fSDimitry Andric free(values); 9335f757f3fSDimitry Andric } 9345f757f3fSDimitry Andric } 9355f757f3fSDimitry Andric 9365f757f3fSDimitry Andric // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the 9375f757f3fSDimitry Andric // source remappings list. 9385f757f3fSDimitry Andric 9395f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, 9405f757f3fSDimitry Andric CFSTR("DBGBuildSourcePath")); 9415f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 9425f757f3fSDimitry Andric CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath); 9435f757f3fSDimitry Andric } 9445f757f3fSDimitry Andric 9455f757f3fSDimitry Andric cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, 9465f757f3fSDimitry Andric CFSTR("DBGSourcePath")); 9475f757f3fSDimitry Andric if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { 9485f757f3fSDimitry Andric CFCString::FileSystemRepresentation(cf_str, DBGSourcePath); 9495f757f3fSDimitry Andric } 9505f757f3fSDimitry Andric 9515f757f3fSDimitry Andric if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) { 9525f757f3fSDimitry Andric if (DBGSourcePath[0] == '~') { 9535f757f3fSDimitry Andric FileSpec resolved_source_path(DBGSourcePath.c_str()); 9545f757f3fSDimitry Andric FileSystem::Instance().Resolve(resolved_source_path); 9555f757f3fSDimitry Andric DBGSourcePath = resolved_source_path.GetPath(); 9565f757f3fSDimitry Andric } 9575f757f3fSDimitry Andric module_spec.GetSourceMappingList().Append(DBGBuildSourcePath, 9585f757f3fSDimitry Andric DBGSourcePath, true); 9595f757f3fSDimitry Andric } 9605f757f3fSDimitry Andric } 9615f757f3fSDimitry Andric return success; 9625f757f3fSDimitry Andric } 9635f757f3fSDimitry Andric 9645f757f3fSDimitry Andric /// It's expensive to check for the DBGShellCommands defaults setting. Only do 9655f757f3fSDimitry Andric /// it once per lldb run and cache the result. 9665f757f3fSDimitry Andric static llvm::StringRef GetDbgShellCommand() { 9675f757f3fSDimitry Andric static std::once_flag g_once_flag; 9685f757f3fSDimitry Andric static std::string g_dbgshell_command; 9695f757f3fSDimitry Andric std::call_once(g_once_flag, [&]() { 9705f757f3fSDimitry Andric CFTypeRef defaults_setting = CFPreferencesCopyAppValue( 9715f757f3fSDimitry Andric CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols")); 9725f757f3fSDimitry Andric if (defaults_setting && 9735f757f3fSDimitry Andric CFGetTypeID(defaults_setting) == CFStringGetTypeID()) { 9745f757f3fSDimitry Andric char buffer[PATH_MAX]; 9755f757f3fSDimitry Andric if (CFStringGetCString((CFStringRef)defaults_setting, buffer, 9765f757f3fSDimitry Andric sizeof(buffer), kCFStringEncodingUTF8)) { 9775f757f3fSDimitry Andric g_dbgshell_command = buffer; 9785f757f3fSDimitry Andric } 9795f757f3fSDimitry Andric } 9805f757f3fSDimitry Andric if (defaults_setting) { 9815f757f3fSDimitry Andric CFRelease(defaults_setting); 9825f757f3fSDimitry Andric } 9835f757f3fSDimitry Andric }); 9845f757f3fSDimitry Andric return g_dbgshell_command; 9855f757f3fSDimitry Andric } 9865f757f3fSDimitry Andric 9875f757f3fSDimitry Andric /// Get the dsymForUUID executable and cache the result so we don't end up 9885f757f3fSDimitry Andric /// stat'ing the binary over and over. 9895f757f3fSDimitry Andric static FileSpec GetDsymForUUIDExecutable() { 9905f757f3fSDimitry Andric // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the 9915f757f3fSDimitry Andric // test suite to override the dsymForUUID location. Because we must be able 9925f757f3fSDimitry Andric // to change the value within a single test, don't bother caching it. 9935f757f3fSDimitry Andric if (const char *dsymForUUID_env = 9945f757f3fSDimitry Andric getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) { 9955f757f3fSDimitry Andric FileSpec dsymForUUID_executable(dsymForUUID_env); 9965f757f3fSDimitry Andric FileSystem::Instance().Resolve(dsymForUUID_executable); 9975f757f3fSDimitry Andric if (FileSystem::Instance().Exists(dsymForUUID_executable)) 9985f757f3fSDimitry Andric return dsymForUUID_executable; 9995f757f3fSDimitry Andric } 10005f757f3fSDimitry Andric 10015f757f3fSDimitry Andric static std::once_flag g_once_flag; 10025f757f3fSDimitry Andric static FileSpec g_dsymForUUID_executable; 10035f757f3fSDimitry Andric std::call_once(g_once_flag, [&]() { 10045f757f3fSDimitry Andric // Try the DBGShellCommand. 10055f757f3fSDimitry Andric llvm::StringRef dbgshell_command = GetDbgShellCommand(); 10065f757f3fSDimitry Andric if (!dbgshell_command.empty()) { 10075f757f3fSDimitry Andric g_dsymForUUID_executable = FileSpec(dbgshell_command); 10085f757f3fSDimitry Andric FileSystem::Instance().Resolve(g_dsymForUUID_executable); 10095f757f3fSDimitry Andric if (FileSystem::Instance().Exists(g_dsymForUUID_executable)) 10105f757f3fSDimitry Andric return; 10115f757f3fSDimitry Andric } 10125f757f3fSDimitry Andric 10135f757f3fSDimitry Andric // Try dsymForUUID in /usr/local/bin 10145f757f3fSDimitry Andric { 10155f757f3fSDimitry Andric g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID"); 10165f757f3fSDimitry Andric if (FileSystem::Instance().Exists(g_dsymForUUID_executable)) 10175f757f3fSDimitry Andric return; 10185f757f3fSDimitry Andric } 10195f757f3fSDimitry Andric 10205f757f3fSDimitry Andric // We couldn't find the dsymForUUID binary. 10215f757f3fSDimitry Andric g_dsymForUUID_executable = {}; 10225f757f3fSDimitry Andric }); 10235f757f3fSDimitry Andric return g_dsymForUUID_executable; 10245f757f3fSDimitry Andric } 10255f757f3fSDimitry Andric 10265f757f3fSDimitry Andric bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile( 10275f757f3fSDimitry Andric ModuleSpec &module_spec, Status &error, bool force_lookup, 10285f757f3fSDimitry Andric bool copy_executable) { 10295f757f3fSDimitry Andric const UUID *uuid_ptr = module_spec.GetUUIDPtr(); 10305f757f3fSDimitry Andric const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); 10315f757f3fSDimitry Andric 10325f757f3fSDimitry Andric // If \a dbgshell_command is set, the user has specified 10335f757f3fSDimitry Andric // forced symbol lookup via that command. We'll get the 10345f757f3fSDimitry Andric // path back from GetDsymForUUIDExecutable() later. 10355f757f3fSDimitry Andric llvm::StringRef dbgshell_command = GetDbgShellCommand(); 10365f757f3fSDimitry Andric 10375f757f3fSDimitry Andric // If forced lookup isn't set, by the user's \a dbgshell_command or 10385f757f3fSDimitry Andric // by the \a force_lookup argument, exit this method. 10395f757f3fSDimitry Andric if (!force_lookup && dbgshell_command.empty()) 10405f757f3fSDimitry Andric return false; 10415f757f3fSDimitry Andric 10425f757f3fSDimitry Andric // We need a UUID or valid existing FileSpec. 10435f757f3fSDimitry Andric if (!uuid_ptr && 10445f757f3fSDimitry Andric (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr))) 10455f757f3fSDimitry Andric return false; 10465f757f3fSDimitry Andric 10475f757f3fSDimitry Andric // We need a dsymForUUID binary or an equivalent executable/script. 10485f757f3fSDimitry Andric FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable(); 10495f757f3fSDimitry Andric if (!dsymForUUID_exe_spec) 10505f757f3fSDimitry Andric return false; 10515f757f3fSDimitry Andric 1052*0fca6ea1SDimitry Andric // Create the dsymForUUID command. 10535f757f3fSDimitry Andric const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath(); 10545f757f3fSDimitry Andric const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : ""; 1055*0fca6ea1SDimitry Andric 1056*0fca6ea1SDimitry Andric std::string lookup_arg = uuid_str; 1057*0fca6ea1SDimitry Andric if (lookup_arg.empty()) 1058*0fca6ea1SDimitry Andric lookup_arg = file_spec_ptr ? file_spec_ptr->GetPath() : ""; 1059*0fca6ea1SDimitry Andric if (lookup_arg.empty()) 1060*0fca6ea1SDimitry Andric return false; 1061*0fca6ea1SDimitry Andric 1062*0fca6ea1SDimitry Andric StreamString command; 1063*0fca6ea1SDimitry Andric command << dsymForUUID_exe_path << " --ignoreNegativeCache "; 1064*0fca6ea1SDimitry Andric if (copy_executable) 1065*0fca6ea1SDimitry Andric command << "--copyExecutable "; 1066*0fca6ea1SDimitry Andric command << lookup_arg; 1067*0fca6ea1SDimitry Andric 1068*0fca6ea1SDimitry Andric // Log and report progress. 1069*0fca6ea1SDimitry Andric std::string lookup_desc; 1070*0fca6ea1SDimitry Andric if (uuid_ptr && file_spec_ptr) 1071*0fca6ea1SDimitry Andric lookup_desc = 1072*0fca6ea1SDimitry Andric llvm::formatv("{0} ({1})", file_spec_ptr->GetFilename().GetString(), 1073*0fca6ea1SDimitry Andric uuid_ptr->GetAsString()); 1074*0fca6ea1SDimitry Andric else if (uuid_ptr) 1075*0fca6ea1SDimitry Andric lookup_desc = uuid_ptr->GetAsString(); 1076*0fca6ea1SDimitry Andric else if (file_spec_ptr) 1077*0fca6ea1SDimitry Andric lookup_desc = file_spec_ptr->GetFilename().GetString(); 10785f757f3fSDimitry Andric 10795f757f3fSDimitry Andric Log *log = GetLog(LLDBLog::Host); 1080*0fca6ea1SDimitry Andric LLDB_LOG(log, "Calling {0} for {1} to find dSYM: {2}", dsymForUUID_exe_path, 1081*0fca6ea1SDimitry Andric lookup_desc, command.GetString()); 10825f757f3fSDimitry Andric 1083*0fca6ea1SDimitry Andric Progress progress("Downloading symbol file for", lookup_desc); 10845f757f3fSDimitry Andric 10855f757f3fSDimitry Andric // Invoke dsymForUUID. 10865f757f3fSDimitry Andric int exit_status = -1; 10875f757f3fSDimitry Andric int signo = -1; 10885f757f3fSDimitry Andric std::string command_output; 10895f757f3fSDimitry Andric error = Host::RunShellCommand( 10905f757f3fSDimitry Andric command.GetData(), 10915f757f3fSDimitry Andric FileSpec(), // current working directory 10925f757f3fSDimitry Andric &exit_status, // Exit status 10935f757f3fSDimitry Andric &signo, // Signal int * 10945f757f3fSDimitry Andric &command_output, // Command output 10955f757f3fSDimitry Andric std::chrono::seconds( 10965f757f3fSDimitry Andric 640), // Large timeout to allow for long dsym download times 10975f757f3fSDimitry Andric false); // Don't run in a shell (we don't need shell expansion) 10985f757f3fSDimitry Andric 10995f757f3fSDimitry Andric if (error.Fail() || exit_status != 0 || command_output.empty()) { 11005f757f3fSDimitry Andric LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')", 11015f757f3fSDimitry Andric command.GetData(), exit_status, error.AsCString(), 11025f757f3fSDimitry Andric command_output.c_str()); 11035f757f3fSDimitry Andric return false; 11045f757f3fSDimitry Andric } 11055f757f3fSDimitry Andric 11065f757f3fSDimitry Andric CFCData data( 11075f757f3fSDimitry Andric CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(), 11085f757f3fSDimitry Andric command_output.size(), kCFAllocatorNull)); 11095f757f3fSDimitry Andric 11105f757f3fSDimitry Andric CFCReleaser<CFDictionaryRef> plist( 11115f757f3fSDimitry Andric (CFDictionaryRef)::CFPropertyListCreateWithData( 11125f757f3fSDimitry Andric NULL, data.get(), kCFPropertyListImmutable, NULL, NULL)); 11135f757f3fSDimitry Andric 11145f757f3fSDimitry Andric if (!plist.get()) { 11155f757f3fSDimitry Andric LLDB_LOGF(log, "'%s' failed: output is not a valid plist", 11165f757f3fSDimitry Andric command.GetData()); 11175f757f3fSDimitry Andric return false; 11185f757f3fSDimitry Andric } 11195f757f3fSDimitry Andric 11205f757f3fSDimitry Andric if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) { 11215f757f3fSDimitry Andric LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary", 11225f757f3fSDimitry Andric command.GetData()); 11235f757f3fSDimitry Andric return false; 11245f757f3fSDimitry Andric } 11255f757f3fSDimitry Andric 11265f757f3fSDimitry Andric if (!uuid_str.empty()) { 11275f757f3fSDimitry Andric CFCString uuid_cfstr(uuid_str.c_str()); 11285f757f3fSDimitry Andric CFDictionaryRef uuid_dict = 11295f757f3fSDimitry Andric (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get()); 11305f757f3fSDimitry Andric return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error, 11315f757f3fSDimitry Andric command.GetData()); 11325f757f3fSDimitry Andric } 11335f757f3fSDimitry Andric 11345f757f3fSDimitry Andric if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) { 11355f757f3fSDimitry Andric std::vector<CFStringRef> keys(num_values, NULL); 11365f757f3fSDimitry Andric std::vector<CFDictionaryRef> values(num_values, NULL); 11375f757f3fSDimitry Andric ::CFDictionaryGetKeysAndValues(plist.get(), NULL, 11385f757f3fSDimitry Andric (const void **)&values[0]); 11395f757f3fSDimitry Andric if (num_values == 1) { 11405f757f3fSDimitry Andric return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error, 11415f757f3fSDimitry Andric command.GetData()); 11425f757f3fSDimitry Andric } 11435f757f3fSDimitry Andric 11445f757f3fSDimitry Andric for (CFIndex i = 0; i < num_values; ++i) { 11455f757f3fSDimitry Andric ModuleSpec curr_module_spec; 11465f757f3fSDimitry Andric if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec, 11475f757f3fSDimitry Andric error, command.GetData())) { 11485f757f3fSDimitry Andric if (module_spec.GetArchitecture().IsCompatibleMatch( 11495f757f3fSDimitry Andric curr_module_spec.GetArchitecture())) { 11505f757f3fSDimitry Andric module_spec = curr_module_spec; 11515f757f3fSDimitry Andric return true; 11525f757f3fSDimitry Andric } 11535f757f3fSDimitry Andric } 11545f757f3fSDimitry Andric } 11555f757f3fSDimitry Andric } 11565f757f3fSDimitry Andric 11575f757f3fSDimitry Andric return false; 11585f757f3fSDimitry Andric } 1159