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