[Lldb-commits] [lldb] [lldb] Move DownloadObjectAndSymbolFile to SymbolLocator plugin (PR #71267)

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Fri Nov 3 19:53:43 PDT 2023


https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/71267

This builds on top of the work started in c3a302d to convert LocateSymbolFile to a SymbolLocator plugin. This commit moves DownloadObjectAndSymbolFile.

>From 8b237e9be1a17008b45d87596ee7384633d78f71 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Fri, 3 Nov 2023 14:21:24 -0700
Subject: [PATCH] [lldb] Move DownloadObjectAndSymbolFile to SymbolLocator
 plugin

This builds on top of the work started in c3a302d to convert
LocateSymbolFile to a SymbolLocator plugin. This commit moves
DownloadObjectAndSymbolFile.
---
 lldb/include/lldb/Core/PluginManager.h        |   7 +
 lldb/include/lldb/Symbol/LocateSymbolFile.h   |  14 -
 lldb/include/lldb/lldb-private-interfaces.h   |   4 +
 lldb/source/API/SBTarget.cpp                  |   6 +-
 lldb/source/Commands/CommandObjectTarget.cpp  |   5 +-
 lldb/source/Core/DynamicLoader.cpp            |   4 +-
 lldb/source/Core/PluginManager.cpp            |  22 +-
 .../DynamicLoaderDarwinKernel.cpp             |   4 +-
 .../DynamicLoaderFreeBSDKernel.cpp            |   3 +-
 .../Process/MacOSX-Kernel/ProcessKDP.cpp      |   4 +-
 .../SymbolLocatorDebugSymbols.cpp             | 365 +++++++++-
 .../DebugSymbols/SymbolLocatorDebugSymbols.h  |  12 +
 .../Default/SymbolLocatorDefault.cpp          |  10 +-
 .../Default/SymbolLocatorDefault.h            |  12 +
 lldb/source/Symbol/CMakeLists.txt             |  10 -
 lldb/source/Symbol/LocateSymbolFile.cpp       |  23 +-
 lldb/source/Symbol/LocateSymbolFileMacOSX.cpp | 649 ------------------
 17 files changed, 446 insertions(+), 708 deletions(-)
 delete mode 100644 lldb/source/Symbol/LocateSymbolFileMacOSX.cpp

diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index 50f0662f4bb2b95..318f8b63c251a19 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -353,6 +353,8 @@ class PluginManager {
           nullptr,
       SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file =
           nullptr,
+      SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file =
+          nullptr,
       SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle = nullptr);
 
   static bool UnregisterPlugin(SymbolLocatorCreateInstance create_callback);
@@ -366,6 +368,11 @@ class PluginManager {
   LocateExecutableSymbolFile(const ModuleSpec &module_spec,
                              const FileSpecList &default_search_paths);
 
+  static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
+                                          Status &error,
+                                          bool force_lookup = true,
+                                          bool copy_executable = true);
+
   static FileSpec FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec,
                                          const UUID *uuid,
                                          const ArchSpec *arch);
diff --git a/lldb/include/lldb/Symbol/LocateSymbolFile.h b/lldb/include/lldb/Symbol/LocateSymbolFile.h
index 3c0f069c27f8dd6..9247814a9e2ab22 100644
--- a/lldb/include/lldb/Symbol/LocateSymbolFile.h
+++ b/lldb/include/lldb/Symbol/LocateSymbolFile.h
@@ -24,20 +24,6 @@ class UUID;
 
 class Symbols {
 public:
-  // Locate the object and symbol file given a module specification.
-  //
-  // Locating the file can try to download the file from a corporate build
-  // repository, or using any other means necessary to locate both the
-  // unstripped object file and the debug symbols. The force_lookup argument
-  // controls whether the external program is called unconditionally to find
-  // the symbol file, or if the user's settings are checked to see if they've
-  // enabled the external program before calling.
-  //
-  static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
-                                          Status &error,
-                                          bool force_lookup = true,
-                                          bool copy_executable = true);
-
   /// Locate the symbol file for the given UUID on a background thread. This
   /// function returns immediately. Under the hood it uses the debugger's
   /// thread pool to call DownloadObjectAndSymbolFile. If a symbol file is
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index 4c324a721029075..65181dec644e20d 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -96,6 +96,10 @@ typedef std::optional<FileSpec> (*SymbolLocatorFindSymbolFileInBundle)(
     const FileSpec &dsym_bundle_fspec, const UUID *uuid, const ArchSpec *arch);
 typedef std::optional<FileSpec> (*SymbolLocatorLocateExecutableSymbolFile)(
     const ModuleSpec &module_spec, const FileSpecList &default_search_paths);
+
+typedef bool (*SymbolLocatorDownloadObjectAndSymbolFile)(
+    ModuleSpec &module_spec, Status &error, bool force_lookup,
+    bool copy_executable);
 typedef bool (*BreakpointHitCallback)(void *baton,
                                       StoppointCallbackContext *context,
                                       lldb::user_id_t break_id,
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index a4a7ac338c20768..03134ff54fa46e9 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -38,6 +38,7 @@
 #include "lldb/Core/Disassembler.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
 #include "lldb/Core/SearchFilter.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Core/StructuredDataImpl.h"
@@ -1525,8 +1526,9 @@ lldb::SBModule SBTarget::AddModule(const SBModuleSpec &module_spec) {
                                                  true /* notify */));
     if (!sb_module.IsValid() && module_spec.m_opaque_up->GetUUID().IsValid()) {
       Status error;
-      if (Symbols::DownloadObjectAndSymbolFile(*module_spec.m_opaque_up, error,
-                                               /* force_lookup */ true)) {
+      if (PluginManager::DownloadObjectAndSymbolFile(*module_spec.m_opaque_up,
+                                                     error,
+                                                     /* force_lookup */ true)) {
         if (FileSystem::Instance().Exists(
                 module_spec.m_opaque_up->GetFileSpec())) {
           sb_module.SetSP(target_sp->GetOrCreateModule(*module_spec.m_opaque_up,
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index ca8484cc79d4054..180210d45b7e000 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/IOHandler.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Section.h"
 #include "lldb/Core/ValueObjectVariable.h"
 #include "lldb/DataFormatters/ValueObjectPrinter.h"
@@ -2801,7 +2802,7 @@ class CommandObjectTargetModulesAdd : public CommandObjectParsed {
           module_spec.GetSymbolFileSpec() =
               m_symbol_file.GetOptionValue().GetCurrentValue();
         Status error;
-        if (Symbols::DownloadObjectAndSymbolFile(module_spec, error)) {
+        if (PluginManager::DownloadObjectAndSymbolFile(module_spec, error)) {
           ModuleSP module_sp(
               target->GetOrCreateModule(module_spec, true /* notify */));
           if (module_sp) {
@@ -4497,7 +4498,7 @@ class CommandObjectTargetSymbolsAdd : public CommandObjectParsed {
   bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
                                    CommandReturnObject &result, bool &flush) {
     Status error;
-    if (Symbols::DownloadObjectAndSymbolFile(module_spec, error)) {
+    if (PluginManager::DownloadObjectAndSymbolFile(module_spec, error)) {
       if (module_spec.GetSymbolFileSpec())
         return AddModuleSymbols(m_exe_ctx.GetTargetPtr(), module_spec, flush,
                                 result);
diff --git a/lldb/source/Core/DynamicLoader.cpp b/lldb/source/Core/DynamicLoader.cpp
index efed29da0835ebf..f4baaf450ee97ac 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -232,8 +232,8 @@ ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
     // If we haven't found a binary, or we don't have a SymbolFile, see
     // if there is an external search tool that can find it.
     if (!module_sp || !module_sp->GetSymbolFileFileSpec()) {
-      Symbols::DownloadObjectAndSymbolFile(module_spec, error,
-                                           force_symbol_search);
+      PluginManager::DownloadObjectAndSymbolFile(module_spec, error,
+                                                 force_symbol_search);
       if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
         module_sp = std::make_shared<Module>(module_spec);
       } else if (force_symbol_search && error.AsCString("") &&
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index 810e487f723de06..23c06357e2f95f3 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1090,15 +1090,18 @@ struct SymbolLocatorInstance
       CallbackType create_callback,
       SymbolLocatorLocateExecutableObjectFile locate_executable_object_file,
       SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file,
+      SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file,
       SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle)
       : PluginInstance<SymbolLocatorCreateInstance>(name, description,
                                                     create_callback),
         locate_executable_object_file(locate_executable_object_file),
         locate_executable_symbol_file(locate_executable_symbol_file),
+        download_object_symbol_file(download_object_symbol_file),
         find_symbol_file_in_bundle(find_symbol_file_in_bundle) {}
 
   SymbolLocatorLocateExecutableObjectFile locate_executable_object_file;
   SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file;
+  SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file;
   SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle;
 };
 typedef PluginInstances<SymbolLocatorInstance> SymbolLocatorInstances;
@@ -1113,10 +1116,12 @@ bool PluginManager::RegisterPlugin(
     SymbolLocatorCreateInstance create_callback,
     SymbolLocatorLocateExecutableObjectFile locate_executable_object_file,
     SymbolLocatorLocateExecutableSymbolFile locate_executable_symbol_file,
+    SymbolLocatorDownloadObjectAndSymbolFile download_object_symbol_file,
     SymbolLocatorFindSymbolFileInBundle find_symbol_file_in_bundle) {
   return GetSymbolLocatorInstances().RegisterPlugin(
       name, description, create_callback, locate_executable_object_file,
-      locate_executable_symbol_file, find_symbol_file_in_bundle);
+      locate_executable_symbol_file, download_object_symbol_file,
+      find_symbol_file_in_bundle);
 }
 
 bool PluginManager::UnregisterPlugin(
@@ -1157,6 +1162,21 @@ FileSpec PluginManager::LocateExecutableSymbolFile(
   return {};
 }
 
+bool PluginManager::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
+                                                Status &error,
+                                                bool force_lookup,
+                                                bool copy_executable) {
+  auto &instances = GetSymbolLocatorInstances().GetInstances();
+  for (auto &instance : instances) {
+    if (instance.download_object_symbol_file) {
+      if (instance.download_object_symbol_file(module_spec, error, force_lookup,
+                                               copy_executable))
+        return true;
+    }
+  }
+  return false;
+}
+
 FileSpec PluginManager::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
                                                const UUID *uuid,
                                                const ArchSpec *arch) {
diff --git a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
index 5aeaf3ae24d7c7b..a255a3b9e760c94 100644
--- a/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp
@@ -798,8 +798,8 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule(
       Status kernel_search_error;
       if (IsKernel() &&
           (!m_module_sp || !m_module_sp->GetSymbolFileFileSpec())) {
-        if (Symbols::DownloadObjectAndSymbolFile(module_spec,
-                                                 kernel_search_error, true)) {
+        if (PluginManager::DownloadObjectAndSymbolFile(
+                module_spec, kernel_search_error, true)) {
           if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
             m_module_sp = std::make_shared<Module>(module_spec.GetFileSpec(),
                                                    target.GetArchitecture());
diff --git a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
index a1bf8efb064b614..8235cc7f1ba6445 100644
--- a/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
+++ b/lldb/source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp
@@ -345,7 +345,8 @@ bool DynamicLoaderFreeBSDKernel::KModImageInfo::LoadImageUsingMemoryModule(
       ModuleSpec module_spec(FileSpec(GetPath()), target.GetArchitecture());
       if (IsKernel()) {
         Status error;
-        if (Symbols::DownloadObjectAndSymbolFile(module_spec, error, true)) {
+        if (PluginManager::DownloadObjectAndSymbolFile(module_spec, error,
+                                                       true)) {
           if (FileSystem::Instance().Exists(module_spec.GetFileSpec()))
             m_module_sp = std::make_shared<Module>(module_spec.GetFileSpec(),
                                                    target.GetArchitecture());
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index 9af544b31d89649..d10069f17cbbe3b 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -292,8 +292,8 @@ Status ProcessKDP::DoConnectRemote(llvm::StringRef remote_url) {
               if (!module_spec.GetSymbolFileSpec() ||
                   !module_spec.GetSymbolFileSpec()) {
                 Status symbl_error;
-                Symbols::DownloadObjectAndSymbolFile(module_spec, symbl_error,
-                                                     true);
+                PluginManager::DownloadObjectAndSymbolFile(module_spec,
+                                                           symbl_error, true);
               }
 
               if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
index 2c57ef8b6a54ea0..fb94e5cb31d49bf 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.cpp
@@ -66,7 +66,7 @@ void SymbolLocatorDebugSymbols::Initialize() {
   PluginManager::RegisterPlugin(
       GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
       LocateExecutableObjectFile, LocateExecutableSymbolFile,
-      FindSymbolFileInBundle);
+      DownloadObjectAndSymbolFile, FindSymbolFileInBundle);
 }
 
 void SymbolLocatorDebugSymbols::Terminate() {
@@ -390,7 +390,7 @@ static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
 // return true if there is a matching dSYM bundle next to the exec_fspec,
 // and return that value in dsym_fspec.
 // If there is a .dSYM.yaa compressed archive next to the exec_fspec,
-// call through Symbols::DownloadObjectAndSymbolFile to download the
+// call through PluginManager::DownloadObjectAndSymbolFile to download the
 // expanded/uncompressed dSYM and return that filepath in dsym_fspec.
 static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec,
                                             const FileSpec &exec_fspec,
@@ -447,7 +447,8 @@ static bool LookForDsymNextToExecutablePath(const ModuleSpec &mod_spec,
   if (FileSystem::Instance().Exists(dsym_yaa_fspec)) {
     ModuleSpec mutable_mod_spec = mod_spec;
     Status error;
-    if (Symbols::DownloadObjectAndSymbolFile(mutable_mod_spec, error, true) &&
+    if (PluginManager::DownloadObjectAndSymbolFile(mutable_mod_spec, error,
+                                                   true) &&
         FileSystem::Instance().Exists(mutable_mod_spec.GetSymbolFileSpec())) {
       dsym_fspec = mutable_mod_spec.GetSymbolFileSpec();
       return true;
@@ -789,3 +790,361 @@ std::optional<FileSpec> SymbolLocatorDebugSymbols::LocateExecutableSymbolFile(
 
   return dsym_module_spec.GetSymbolFileSpec();
 }
+
+static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
+                                                ModuleSpec &module_spec,
+                                                Status &error,
+                                                const std::string &command) {
+  Log *log = GetLog(LLDBLog::Host);
+  bool success = false;
+  if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
+    std::string str;
+    CFStringRef cf_str;
+    CFDictionaryRef cf_dict;
+
+    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
+                                               CFSTR("DBGError"));
+    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+      if (CFCString::FileSystemRepresentation(cf_str, str)) {
+        std::string errorstr = command;
+        errorstr += ":\n";
+        errorstr += str;
+        error.SetErrorString(errorstr);
+      }
+    }
+
+    cf_str = (CFStringRef)CFDictionaryGetValue(
+        (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
+    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+      if (CFCString::FileSystemRepresentation(cf_str, str)) {
+        module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
+        FileSystem::Instance().Resolve(module_spec.GetFileSpec());
+        LLDB_LOGF(log,
+                  "From dsymForUUID plist: Symbol rich executable is at '%s'",
+                  str.c_str());
+      }
+    }
+
+    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
+                                               CFSTR("DBGDSYMPath"));
+    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+      if (CFCString::FileSystemRepresentation(cf_str, str)) {
+        module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
+                                                FileSpec::Style::native);
+        FileSystem::Instance().Resolve(module_spec.GetFileSpec());
+        success = true;
+        LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str());
+      }
+    }
+
+    std::string DBGBuildSourcePath;
+    std::string DBGSourcePath;
+
+    // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
+    // If DBGVersion 2, strip last two components of path remappings from
+    //                  entries to fix an issue with a specific set of
+    //                  DBGSourcePathRemapping entries that lldb worked
+    //                  with.
+    // If DBGVersion 3, trust & use the source path remappings as-is.
+    //
+    cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
+        (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
+    if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
+      // If we see DBGVersion with a value of 2 or higher, this is a new style
+      // DBGSourcePathRemapping dictionary
+      bool new_style_source_remapping_dictionary = false;
+      bool do_truncate_remapping_names = false;
+      std::string original_DBGSourcePath_value = DBGSourcePath;
+      cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
+                                                 CFSTR("DBGVersion"));
+      if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+        std::string version;
+        CFCString::FileSystemRepresentation(cf_str, version);
+        if (!version.empty() && isdigit(version[0])) {
+          int version_number = atoi(version.c_str());
+          if (version_number > 1) {
+            new_style_source_remapping_dictionary = true;
+          }
+          if (version_number == 2) {
+            do_truncate_remapping_names = true;
+          }
+        }
+      }
+
+      CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
+      if (kv_pair_count > 0) {
+        CFStringRef *keys =
+            (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
+        CFStringRef *values =
+            (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
+        if (keys != nullptr && values != nullptr) {
+          CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
+                                       (const void **)keys,
+                                       (const void **)values);
+        }
+        for (CFIndex i = 0; i < kv_pair_count; i++) {
+          DBGBuildSourcePath.clear();
+          DBGSourcePath.clear();
+          if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
+            CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
+          }
+          if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
+            CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
+          }
+          if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
+            // In the "old style" DBGSourcePathRemapping dictionary, the
+            // DBGSourcePath values (the "values" half of key-value path pairs)
+            // were wrong.  Ignore them and use the universal DBGSourcePath
+            // string from earlier.
+            if (new_style_source_remapping_dictionary &&
+                !original_DBGSourcePath_value.empty()) {
+              DBGSourcePath = original_DBGSourcePath_value;
+            }
+            if (DBGSourcePath[0] == '~') {
+              FileSpec resolved_source_path(DBGSourcePath.c_str());
+              FileSystem::Instance().Resolve(resolved_source_path);
+              DBGSourcePath = resolved_source_path.GetPath();
+            }
+            // With version 2 of DBGSourcePathRemapping, we can chop off the
+            // last two filename parts from the source remapping and get a more
+            // general source remapping that still works. Add this as another
+            // option in addition to the full source path remap.
+            module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
+                                                      DBGSourcePath, true);
+            if (do_truncate_remapping_names) {
+              FileSpec build_path(DBGBuildSourcePath.c_str());
+              FileSpec source_path(DBGSourcePath.c_str());
+              build_path.RemoveLastPathComponent();
+              build_path.RemoveLastPathComponent();
+              source_path.RemoveLastPathComponent();
+              source_path.RemoveLastPathComponent();
+              module_spec.GetSourceMappingList().Append(
+                  build_path.GetPath(), source_path.GetPath(), true);
+            }
+          }
+        }
+        if (keys)
+          free(keys);
+        if (values)
+          free(values);
+      }
+    }
+
+    // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
+    // source remappings list.
+
+    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
+                                               CFSTR("DBGBuildSourcePath"));
+    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+      CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
+    }
+
+    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
+                                               CFSTR("DBGSourcePath"));
+    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
+      CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
+    }
+
+    if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
+      if (DBGSourcePath[0] == '~') {
+        FileSpec resolved_source_path(DBGSourcePath.c_str());
+        FileSystem::Instance().Resolve(resolved_source_path);
+        DBGSourcePath = resolved_source_path.GetPath();
+      }
+      module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
+                                                DBGSourcePath, true);
+    }
+  }
+  return success;
+}
+
+/// It's expensive to check for the DBGShellCommands defaults setting. Only do
+/// it once per lldb run and cache the result.
+static llvm::StringRef GetDbgShellCommand() {
+  static std::once_flag g_once_flag;
+  static std::string g_dbgshell_command;
+  std::call_once(g_once_flag, [&]() {
+    CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
+        CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
+    if (defaults_setting &&
+        CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
+      char buffer[PATH_MAX];
+      if (CFStringGetCString((CFStringRef)defaults_setting, buffer,
+                             sizeof(buffer), kCFStringEncodingUTF8)) {
+        g_dbgshell_command = buffer;
+      }
+    }
+    if (defaults_setting) {
+      CFRelease(defaults_setting);
+    }
+  });
+  return g_dbgshell_command;
+}
+
+/// Get the dsymForUUID executable and cache the result so we don't end up
+/// stat'ing the binary over and over.
+static FileSpec GetDsymForUUIDExecutable() {
+  // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the
+  // test suite to override the dsymForUUID location. Because we must be able
+  // to change the value within a single test, don't bother caching it.
+  if (const char *dsymForUUID_env =
+          getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) {
+    FileSpec dsymForUUID_executable(dsymForUUID_env);
+    FileSystem::Instance().Resolve(dsymForUUID_executable);
+    if (FileSystem::Instance().Exists(dsymForUUID_executable))
+      return dsymForUUID_executable;
+  }
+
+  static std::once_flag g_once_flag;
+  static FileSpec g_dsymForUUID_executable;
+  std::call_once(g_once_flag, [&]() {
+    // Try the DBGShellCommand.
+    llvm::StringRef dbgshell_command = GetDbgShellCommand();
+    if (!dbgshell_command.empty()) {
+      g_dsymForUUID_executable = FileSpec(dbgshell_command);
+      FileSystem::Instance().Resolve(g_dsymForUUID_executable);
+      if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
+        return;
+    }
+
+    // Try dsymForUUID in /usr/local/bin
+    {
+      g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID");
+      if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
+        return;
+    }
+
+    // We couldn't find the dsymForUUID binary.
+    g_dsymForUUID_executable = {};
+  });
+  return g_dsymForUUID_executable;
+}
+
+bool SymbolLocatorDebugSymbols::DownloadObjectAndSymbolFile(
+    ModuleSpec &module_spec, Status &error, bool force_lookup,
+    bool copy_executable) {
+  const UUID *uuid_ptr = module_spec.GetUUIDPtr();
+  const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
+
+  // If \a dbgshell_command is set, the user has specified
+  // forced symbol lookup via that command.  We'll get the
+  // path back from GetDsymForUUIDExecutable() later.
+  llvm::StringRef dbgshell_command = GetDbgShellCommand();
+
+  // If forced lookup isn't set, by the user's \a dbgshell_command or
+  // by the \a force_lookup argument, exit this method.
+  if (!force_lookup && dbgshell_command.empty())
+    return false;
+
+  // We need a UUID or valid existing FileSpec.
+  if (!uuid_ptr &&
+      (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr)))
+    return false;
+
+  // We need a dsymForUUID binary or an equivalent executable/script.
+  FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable();
+  if (!dsymForUUID_exe_spec)
+    return false;
+
+  const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath();
+  const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : "";
+  const std::string file_path_str =
+      file_spec_ptr ? file_spec_ptr->GetPath() : "";
+
+  Log *log = GetLog(LLDBLog::Host);
+
+  // Create the dsymForUUID command.
+  StreamString command;
+  const char *copy_executable_arg = copy_executable ? "--copyExecutable " : "";
+  if (!uuid_str.empty()) {
+    command.Printf("%s --ignoreNegativeCache %s%s",
+                   dsymForUUID_exe_path.c_str(), copy_executable_arg,
+                   uuid_str.c_str());
+    LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s",
+              dsymForUUID_exe_path.c_str(), uuid_str.c_str(),
+              command.GetString().data());
+  } else if (!file_path_str.empty()) {
+    command.Printf("%s --ignoreNegativeCache %s%s",
+                   dsymForUUID_exe_path.c_str(), copy_executable_arg,
+                   file_path_str.c_str());
+    LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s",
+              dsymForUUID_exe_path.c_str(), file_path_str.c_str(),
+              command.GetString().data());
+  } else {
+    return false;
+  }
+
+  // Invoke dsymForUUID.
+  int exit_status = -1;
+  int signo = -1;
+  std::string command_output;
+  error = Host::RunShellCommand(
+      command.GetData(),
+      FileSpec(),      // current working directory
+      &exit_status,    // Exit status
+      &signo,          // Signal int *
+      &command_output, // Command output
+      std::chrono::seconds(
+          640), // Large timeout to allow for long dsym download times
+      false);   // Don't run in a shell (we don't need shell expansion)
+
+  if (error.Fail() || exit_status != 0 || command_output.empty()) {
+    LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')",
+              command.GetData(), exit_status, error.AsCString(),
+              command_output.c_str());
+    return false;
+  }
+
+  CFCData data(
+      CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(),
+                                  command_output.size(), kCFAllocatorNull));
+
+  CFCReleaser<CFDictionaryRef> plist(
+      (CFDictionaryRef)::CFPropertyListCreateWithData(
+          NULL, data.get(), kCFPropertyListImmutable, NULL, NULL));
+
+  if (!plist.get()) {
+    LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
+              command.GetData());
+    return false;
+  }
+
+  if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
+    LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary",
+              command.GetData());
+    return false;
+  }
+
+  if (!uuid_str.empty()) {
+    CFCString uuid_cfstr(uuid_str.c_str());
+    CFDictionaryRef uuid_dict =
+        (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get());
+    return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error,
+                                               command.GetData());
+  }
+
+  if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) {
+    std::vector<CFStringRef> keys(num_values, NULL);
+    std::vector<CFDictionaryRef> values(num_values, NULL);
+    ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
+                                   (const void **)&values[0]);
+    if (num_values == 1) {
+      return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error,
+                                                 command.GetData());
+    }
+
+    for (CFIndex i = 0; i < num_values; ++i) {
+      ModuleSpec curr_module_spec;
+      if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec,
+                                              error, command.GetData())) {
+        if (module_spec.GetArchitecture().IsCompatibleMatch(
+                curr_module_spec.GetArchitecture())) {
+          module_spec = curr_module_spec;
+          return true;
+        }
+      }
+    }
+  }
+
+  return false;
+}
diff --git a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
index 72bd6de433dd706..efbe68bc5dae84f 100644
--- a/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
+++ b/lldb/source/Plugins/SymbolLocator/DebugSymbols/SymbolLocatorDebugSymbols.h
@@ -46,6 +46,18 @@ class SymbolLocatorDebugSymbols : public SymbolLocator {
   LocateExecutableSymbolFile(const ModuleSpec &module_spec,
                              const FileSpecList &default_search_paths);
 
+  // Locate the object and symbol file given a module specification.
+  //
+  // Locating the file can try to download the file from a corporate build
+  // repository, or using any other means necessary to locate both the
+  // unstripped object file and the debug symbols. The force_lookup argument
+  // controls whether the external program is called unconditionally to find
+  // the symbol file, or if the user's settings are checked to see if they've
+  // enabled the external program before calling.
+  static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
+                                          Status &error, bool force_lookup,
+                                          bool copy_executable);
+
   static std::optional<FileSpec>
   FindSymbolFileInBundle(const FileSpec &dsym_bundle_fspec, const UUID *uuid,
                          const ArchSpec *arch);
diff --git a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
index 831b2b1ae0c4961..1a58ecb38cb84e8 100644
--- a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
+++ b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp
@@ -51,7 +51,8 @@ SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
 void SymbolLocatorDefault::Initialize() {
   PluginManager::RegisterPlugin(
       GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
-      LocateExecutableObjectFile, LocateExecutableSymbolFile);
+      LocateExecutableObjectFile, LocateExecutableSymbolFile,
+      DownloadObjectAndSymbolFile);
 }
 
 void SymbolLocatorDefault::Terminate() {
@@ -230,3 +231,10 @@ std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile(
 
   return {};
 }
+
+bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
+                                                       Status &error,
+                                                       bool force_lookup,
+                                                       bool copy_executable) {
+  return false;
+}
diff --git a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
index 99e0f0b1a78dc8c..7bf0a2ad4a5b130 100644
--- a/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
+++ b/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.h
@@ -45,6 +45,18 @@ class SymbolLocatorDefault : public SymbolLocator {
   static std::optional<FileSpec>
   LocateExecutableSymbolFile(const ModuleSpec &module_spec,
                              const FileSpecList &default_search_paths);
+
+  // Locate the object and symbol file given a module specification.
+  //
+  // Locating the file can try to download the file from a corporate build
+  // repository, or using any other means necessary to locate both the
+  // unstripped object file and the debug symbols. The force_lookup argument
+  // controls whether the external program is called unconditionally to find
+  // the symbol file, or if the user's settings are checked to see if they've
+  // enabled the external program before calling.
+  static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
+                                          Status &error, bool force_lookup,
+                                          bool copy_executable);
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Symbol/CMakeLists.txt b/lldb/source/Symbol/CMakeLists.txt
index cec49b8b2cb4b63..4de48097870e90e 100644
--- a/lldb/source/Symbol/CMakeLists.txt
+++ b/lldb/source/Symbol/CMakeLists.txt
@@ -1,11 +1,3 @@
-set(LLVM_OPTIONAL_SOURCES LocateSymbolFileMacOSX.cpp)
-
-if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
-  set(PLATFORM_SOURCES
-    LocateSymbolFileMacOSX.cpp
-    )
-endif()
-
 add_lldb_library(lldbSymbol NO_PLUGIN_DEPENDENCIES
   ArmUnwindInfo.cpp
   Block.cpp
@@ -40,8 +32,6 @@ add_lldb_library(lldbSymbol NO_PLUGIN_DEPENDENCIES
   Variable.cpp
   VariableList.cpp
 
-  ${PLATFORM_SOURCES}
-
   LINK_LIBS
     lldbCore
     lldbExpression
diff --git a/lldb/source/Symbol/LocateSymbolFile.cpp b/lldb/source/Symbol/LocateSymbolFile.cpp
index 17f5a090c71882d..06b113f89827186 100644
--- a/lldb/source/Symbol/LocateSymbolFile.cpp
+++ b/lldb/source/Symbol/LocateSymbolFile.cpp
@@ -12,6 +12,7 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleList.h"
 #include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
 #include "lldb/Core/Progress.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Symbol/ObjectFile.h"
@@ -28,10 +29,6 @@
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/ThreadPool.h"
 
-// From MacOSX system header "mach/machine.h"
-typedef int cpu_type_t;
-typedef int cpu_subtype_t;
-
 using namespace lldb;
 using namespace lldb_private;
 
@@ -52,9 +49,9 @@ void Symbols::DownloadSymbolFileAsync(const UUID &uuid) {
     Status error;
     ModuleSpec module_spec;
     module_spec.GetUUID() = uuid;
-    if (!Symbols::DownloadObjectAndSymbolFile(module_spec, error,
-                                              /*force_lookup=*/true,
-                                              /*copy_executable=*/false))
+    if (!PluginManager::DownloadObjectAndSymbolFile(module_spec, error,
+                                                    /*force_lookup=*/true,
+                                                    /*copy_executable=*/false))
       return;
 
     if (error.Fail())
@@ -63,15 +60,3 @@ void Symbols::DownloadSymbolFileAsync(const UUID &uuid) {
     Debugger::ReportSymbolChange(module_spec);
   });
 }
-
-#if !defined(__APPLE__)
-
-bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
-                                          Status &error, bool force_lookup,
-                                          bool copy_executable) {
-  // Fill in the module_spec.GetFileSpec() for the object file and/or the
-  // module_spec.GetSymbolFileSpec() for the debug symbols file.
-  return false;
-}
-
-#endif
diff --git a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp b/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp
deleted file mode 100644
index be0bb37bab5350b..000000000000000
--- a/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp
+++ /dev/null
@@ -1,649 +0,0 @@
-//===-- LocateSymbolFileMacOSX.cpp ----------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "lldb/Symbol/LocateSymbolFile.h"
-
-#include <dirent.h>
-#include <dlfcn.h>
-#include <pwd.h>
-
-#include <CoreFoundation/CoreFoundation.h>
-
-#include "Host/macosx/cfcpp/CFCBundle.h"
-#include "Host/macosx/cfcpp/CFCData.h"
-#include "Host/macosx/cfcpp/CFCReleaser.h"
-#include "Host/macosx/cfcpp/CFCString.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleList.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Host/Host.h"
-#include "lldb/Host/HostInfo.h"
-#include "lldb/Symbol/ObjectFile.h"
-#include "lldb/Utility/ArchSpec.h"
-#include "lldb/Utility/DataBuffer.h"
-#include "lldb/Utility/DataExtractor.h"
-#include "lldb/Utility/Endian.h"
-#include "lldb/Utility/LLDBLog.h"
-#include "lldb/Utility/Log.h"
-#include "lldb/Utility/StreamString.h"
-#include "lldb/Utility/Timer.h"
-#include "lldb/Utility/UUID.h"
-#include "mach/machine.h"
-
-#include "llvm/ADT/ScopeExit.h"
-#include "llvm/Support/FileSystem.h"
-
-using namespace lldb;
-using namespace lldb_private;
-
-static CFURLRef (*g_dlsym_DBGCopyFullDSYMURLForUUID)(
-    CFUUIDRef uuid, CFURLRef exec_url) = nullptr;
-static CFDictionaryRef (*g_dlsym_DBGCopyDSYMPropertyLists)(CFURLRef dsym_url) =
-    nullptr;
-
-int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
-                                       ModuleSpec &return_module_spec) {
-  Log *log = GetLog(LLDBLog::Host);
-  if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
-    LLDB_LOGF(log, "Spotlight lookup for .dSYM bundles is disabled.");
-    return 0;
-  }
-
-  return_module_spec = module_spec;
-  return_module_spec.GetFileSpec().Clear();
-  return_module_spec.GetSymbolFileSpec().Clear();
-
-  const UUID *uuid = module_spec.GetUUIDPtr();
-  const ArchSpec *arch = module_spec.GetArchitecturePtr();
-
-  int items_found = 0;
-
-  if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
-      g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
-    void *handle = dlopen(
-        "/System/Library/PrivateFrameworks/DebugSymbols.framework/DebugSymbols",
-        RTLD_LAZY | RTLD_LOCAL);
-    if (handle) {
-      g_dlsym_DBGCopyFullDSYMURLForUUID =
-          (CFURLRef(*)(CFUUIDRef, CFURLRef))dlsym(handle,
-                                                  "DBGCopyFullDSYMURLForUUID");
-      g_dlsym_DBGCopyDSYMPropertyLists = (CFDictionaryRef(*)(CFURLRef))dlsym(
-          handle, "DBGCopyDSYMPropertyLists");
-    }
-  }
-
-  if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr ||
-      g_dlsym_DBGCopyDSYMPropertyLists == nullptr) {
-    return items_found;
-  }
-
-  if (uuid && uuid->IsValid()) {
-    // Try and locate the dSYM file using DebugSymbols first
-    llvm::ArrayRef<uint8_t> module_uuid = uuid->GetBytes();
-    if (module_uuid.size() == 16) {
-      CFCReleaser<CFUUIDRef> module_uuid_ref(::CFUUIDCreateWithBytes(
-          NULL, module_uuid[0], module_uuid[1], module_uuid[2], module_uuid[3],
-          module_uuid[4], module_uuid[5], module_uuid[6], module_uuid[7],
-          module_uuid[8], module_uuid[9], module_uuid[10], module_uuid[11],
-          module_uuid[12], module_uuid[13], module_uuid[14], module_uuid[15]));
-
-      if (module_uuid_ref.get()) {
-        CFCReleaser<CFURLRef> exec_url;
-        const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
-        if (exec_fspec) {
-          char exec_cf_path[PATH_MAX];
-          if (exec_fspec->GetPath(exec_cf_path, sizeof(exec_cf_path)))
-            exec_url.reset(::CFURLCreateFromFileSystemRepresentation(
-                NULL, (const UInt8 *)exec_cf_path, strlen(exec_cf_path),
-                FALSE));
-        }
-
-        CFCReleaser<CFURLRef> dsym_url(g_dlsym_DBGCopyFullDSYMURLForUUID(
-            module_uuid_ref.get(), exec_url.get()));
-        char path[PATH_MAX];
-
-        if (dsym_url.get()) {
-          if (::CFURLGetFileSystemRepresentation(
-                  dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
-            LLDB_LOGF(log,
-                      "DebugSymbols framework returned dSYM path of %s for "
-                      "UUID %s -- looking for the dSYM",
-                      path, uuid->GetAsString().c_str());
-            FileSpec dsym_filespec(path);
-            if (path[0] == '~')
-              FileSystem::Instance().Resolve(dsym_filespec);
-
-            if (FileSystem::Instance().IsDirectory(dsym_filespec)) {
-              dsym_filespec = PluginManager::FindSymbolFileInBundle(
-                  dsym_filespec, uuid, arch);
-              ++items_found;
-            } else {
-              ++items_found;
-            }
-            return_module_spec.GetSymbolFileSpec() = dsym_filespec;
-          }
-
-          bool success = false;
-          if (log) {
-            if (::CFURLGetFileSystemRepresentation(
-                    dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
-              LLDB_LOGF(log,
-                        "DebugSymbols framework returned dSYM path of %s for "
-                        "UUID %s -- looking for an exec file",
-                        path, uuid->GetAsString().c_str());
-            }
-          }
-
-          CFCReleaser<CFDictionaryRef> dict(
-              g_dlsym_DBGCopyDSYMPropertyLists(dsym_url.get()));
-          CFDictionaryRef uuid_dict = NULL;
-          if (dict.get()) {
-            CFCString uuid_cfstr(uuid->GetAsString().c_str());
-            uuid_dict = static_cast<CFDictionaryRef>(
-                ::CFDictionaryGetValue(dict.get(), uuid_cfstr.get()));
-          }
-
-          // Check to see if we have the file on the local filesystem.
-          if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
-            ModuleSpec exe_spec;
-            exe_spec.GetFileSpec() = module_spec.GetFileSpec();
-            exe_spec.GetUUID() = module_spec.GetUUID();
-            ModuleSP module_sp;
-            module_sp.reset(new Module(exe_spec));
-            if (module_sp && module_sp->GetObjectFile() &&
-                module_sp->MatchesModuleSpec(exe_spec)) {
-              success = true;
-              return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
-              LLDB_LOGF(log, "using original binary filepath %s for UUID %s",
-                        module_spec.GetFileSpec().GetPath().c_str(),
-                        uuid->GetAsString().c_str());
-              ++items_found;
-            }
-          }
-
-          // Check if the requested image is in our shared cache.
-          if (!success) {
-            SharedCacheImageInfo image_info = HostInfo::GetSharedCacheImageInfo(
-                module_spec.GetFileSpec().GetPath());
-
-            // If we found it and it has the correct UUID, let's proceed with
-            // creating a module from the memory contents.
-            if (image_info.uuid && (!module_spec.GetUUID() ||
-                                    module_spec.GetUUID() == image_info.uuid)) {
-              success = true;
-              return_module_spec.GetFileSpec() = module_spec.GetFileSpec();
-              LLDB_LOGF(log,
-                        "using binary from shared cache for filepath %s for "
-                        "UUID %s",
-                        module_spec.GetFileSpec().GetPath().c_str(),
-                        uuid->GetAsString().c_str());
-              ++items_found;
-            }
-          }
-
-          // Use the DBGSymbolRichExecutable filepath if present
-          if (!success && uuid_dict) {
-            CFStringRef exec_cf_path =
-                static_cast<CFStringRef>(::CFDictionaryGetValue(
-                    uuid_dict, CFSTR("DBGSymbolRichExecutable")));
-            if (exec_cf_path && ::CFStringGetFileSystemRepresentation(
-                                    exec_cf_path, path, sizeof(path))) {
-              LLDB_LOGF(log, "plist bundle has exec path of %s for UUID %s",
-                        path, uuid->GetAsString().c_str());
-              ++items_found;
-              FileSpec exec_filespec(path);
-              if (path[0] == '~')
-                FileSystem::Instance().Resolve(exec_filespec);
-              if (FileSystem::Instance().Exists(exec_filespec)) {
-                success = true;
-                return_module_spec.GetFileSpec() = exec_filespec;
-              }
-            }
-          }
-
-          // Look next to the dSYM for the binary file.
-          if (!success) {
-            if (::CFURLGetFileSystemRepresentation(
-                    dsym_url.get(), true, (UInt8 *)path, sizeof(path) - 1)) {
-              char *dsym_extension_pos = ::strstr(path, ".dSYM");
-              if (dsym_extension_pos) {
-                *dsym_extension_pos = '\0';
-                LLDB_LOGF(log,
-                          "Looking for executable binary next to dSYM "
-                          "bundle with name with name %s",
-                          path);
-                FileSpec file_spec(path);
-                FileSystem::Instance().Resolve(file_spec);
-                ModuleSpecList module_specs;
-                ModuleSpec matched_module_spec;
-                using namespace llvm::sys::fs;
-                switch (get_file_type(file_spec.GetPath())) {
-
-                case file_type::directory_file: // Bundle directory?
-                {
-                  CFCBundle bundle(path);
-                  CFCReleaser<CFURLRef> bundle_exe_url(
-                      bundle.CopyExecutableURL());
-                  if (bundle_exe_url.get()) {
-                    if (::CFURLGetFileSystemRepresentation(bundle_exe_url.get(),
-                                                           true, (UInt8 *)path,
-                                                           sizeof(path) - 1)) {
-                      FileSpec bundle_exe_file_spec(path);
-                      FileSystem::Instance().Resolve(bundle_exe_file_spec);
-                      if (ObjectFile::GetModuleSpecifications(
-                              bundle_exe_file_spec, 0, 0, module_specs) &&
-                          module_specs.FindMatchingModuleSpec(
-                              module_spec, matched_module_spec))
-
-                      {
-                        ++items_found;
-                        return_module_spec.GetFileSpec() = bundle_exe_file_spec;
-                        LLDB_LOGF(log,
-                                  "Executable binary %s next to dSYM is "
-                                  "compatible; using",
-                                  path);
-                      }
-                    }
-                  }
-                } break;
-
-                case file_type::fifo_file:      // Forget pipes
-                case file_type::socket_file:    // We can't process socket files
-                case file_type::file_not_found: // File doesn't exist...
-                case file_type::status_error:
-                  break;
-
-                case file_type::type_unknown:
-                case file_type::regular_file:
-                case file_type::symlink_file:
-                case file_type::block_file:
-                case file_type::character_file:
-                  if (ObjectFile::GetModuleSpecifications(file_spec, 0, 0,
-                                                          module_specs) &&
-                      module_specs.FindMatchingModuleSpec(module_spec,
-                                                          matched_module_spec))
-
-                  {
-                    ++items_found;
-                    return_module_spec.GetFileSpec() = file_spec;
-                    LLDB_LOGF(log,
-                              "Executable binary %s next to dSYM is "
-                              "compatible; using",
-                              path);
-                  }
-                  break;
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  return items_found;
-}
-
-static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,
-                                                ModuleSpec &module_spec,
-                                                Status &error,
-                                                const std::string &command) {
-  Log *log = GetLog(LLDBLog::Host);
-  bool success = false;
-  if (uuid_dict != NULL && CFGetTypeID(uuid_dict) == CFDictionaryGetTypeID()) {
-    std::string str;
-    CFStringRef cf_str;
-    CFDictionaryRef cf_dict;
-
-    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
-                                               CFSTR("DBGError"));
-    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-      if (CFCString::FileSystemRepresentation(cf_str, str)) {
-        std::string errorstr = command;
-        errorstr += ":\n";
-        errorstr += str;
-        error.SetErrorString(errorstr);
-      }
-    }
-
-    cf_str = (CFStringRef)CFDictionaryGetValue(
-        (CFDictionaryRef)uuid_dict, CFSTR("DBGSymbolRichExecutable"));
-    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-      if (CFCString::FileSystemRepresentation(cf_str, str)) {
-        module_spec.GetFileSpec().SetFile(str.c_str(), FileSpec::Style::native);
-        FileSystem::Instance().Resolve(module_spec.GetFileSpec());
-        LLDB_LOGF(log,
-                  "From dsymForUUID plist: Symbol rich executable is at '%s'",
-                  str.c_str());
-      }
-    }
-
-    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
-                                               CFSTR("DBGDSYMPath"));
-    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-      if (CFCString::FileSystemRepresentation(cf_str, str)) {
-        module_spec.GetSymbolFileSpec().SetFile(str.c_str(),
-                                                FileSpec::Style::native);
-        FileSystem::Instance().Resolve(module_spec.GetFileSpec());
-        success = true;
-        LLDB_LOGF(log, "From dsymForUUID plist: dSYM is at '%s'", str.c_str());
-      }
-    }
-
-    std::string DBGBuildSourcePath;
-    std::string DBGSourcePath;
-
-    // If DBGVersion 1 or DBGVersion missing, ignore DBGSourcePathRemapping.
-    // If DBGVersion 2, strip last two components of path remappings from
-    //                  entries to fix an issue with a specific set of
-    //                  DBGSourcePathRemapping entries that lldb worked
-    //                  with.
-    // If DBGVersion 3, trust & use the source path remappings as-is.
-    //
-    cf_dict = (CFDictionaryRef)CFDictionaryGetValue(
-        (CFDictionaryRef)uuid_dict, CFSTR("DBGSourcePathRemapping"));
-    if (cf_dict && CFGetTypeID(cf_dict) == CFDictionaryGetTypeID()) {
-      // If we see DBGVersion with a value of 2 or higher, this is a new style
-      // DBGSourcePathRemapping dictionary
-      bool new_style_source_remapping_dictionary = false;
-      bool do_truncate_remapping_names = false;
-      std::string original_DBGSourcePath_value = DBGSourcePath;
-      cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
-                                                 CFSTR("DBGVersion"));
-      if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-        std::string version;
-        CFCString::FileSystemRepresentation(cf_str, version);
-        if (!version.empty() && isdigit(version[0])) {
-          int version_number = atoi(version.c_str());
-          if (version_number > 1) {
-            new_style_source_remapping_dictionary = true;
-          }
-          if (version_number == 2) {
-            do_truncate_remapping_names = true;
-          }
-        }
-      }
-
-      CFIndex kv_pair_count = CFDictionaryGetCount((CFDictionaryRef)uuid_dict);
-      if (kv_pair_count > 0) {
-        CFStringRef *keys =
-            (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
-        CFStringRef *values =
-            (CFStringRef *)malloc(kv_pair_count * sizeof(CFStringRef));
-        if (keys != nullptr && values != nullptr) {
-          CFDictionaryGetKeysAndValues((CFDictionaryRef)uuid_dict,
-                                       (const void **)keys,
-                                       (const void **)values);
-        }
-        for (CFIndex i = 0; i < kv_pair_count; i++) {
-          DBGBuildSourcePath.clear();
-          DBGSourcePath.clear();
-          if (keys[i] && CFGetTypeID(keys[i]) == CFStringGetTypeID()) {
-            CFCString::FileSystemRepresentation(keys[i], DBGBuildSourcePath);
-          }
-          if (values[i] && CFGetTypeID(values[i]) == CFStringGetTypeID()) {
-            CFCString::FileSystemRepresentation(values[i], DBGSourcePath);
-          }
-          if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
-            // In the "old style" DBGSourcePathRemapping dictionary, the
-            // DBGSourcePath values (the "values" half of key-value path pairs)
-            // were wrong.  Ignore them and use the universal DBGSourcePath
-            // string from earlier.
-            if (new_style_source_remapping_dictionary &&
-                !original_DBGSourcePath_value.empty()) {
-              DBGSourcePath = original_DBGSourcePath_value;
-            }
-            if (DBGSourcePath[0] == '~') {
-              FileSpec resolved_source_path(DBGSourcePath.c_str());
-              FileSystem::Instance().Resolve(resolved_source_path);
-              DBGSourcePath = resolved_source_path.GetPath();
-            }
-            // With version 2 of DBGSourcePathRemapping, we can chop off the
-            // last two filename parts from the source remapping and get a more
-            // general source remapping that still works. Add this as another
-            // option in addition to the full source path remap.
-            module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
-                                                      DBGSourcePath, true);
-            if (do_truncate_remapping_names) {
-              FileSpec build_path(DBGBuildSourcePath.c_str());
-              FileSpec source_path(DBGSourcePath.c_str());
-              build_path.RemoveLastPathComponent();
-              build_path.RemoveLastPathComponent();
-              source_path.RemoveLastPathComponent();
-              source_path.RemoveLastPathComponent();
-              module_spec.GetSourceMappingList().Append(
-                  build_path.GetPath(), source_path.GetPath(), true);
-            }
-          }
-        }
-        if (keys)
-          free(keys);
-        if (values)
-          free(values);
-      }
-    }
-
-    // If we have a DBGBuildSourcePath + DBGSourcePath pair, append them to the
-    // source remappings list.
-
-    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
-                                               CFSTR("DBGBuildSourcePath"));
-    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-      CFCString::FileSystemRepresentation(cf_str, DBGBuildSourcePath);
-    }
-
-    cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict,
-                                               CFSTR("DBGSourcePath"));
-    if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) {
-      CFCString::FileSystemRepresentation(cf_str, DBGSourcePath);
-    }
-
-    if (!DBGBuildSourcePath.empty() && !DBGSourcePath.empty()) {
-      if (DBGSourcePath[0] == '~') {
-        FileSpec resolved_source_path(DBGSourcePath.c_str());
-        FileSystem::Instance().Resolve(resolved_source_path);
-        DBGSourcePath = resolved_source_path.GetPath();
-      }
-      module_spec.GetSourceMappingList().Append(DBGBuildSourcePath,
-                                                DBGSourcePath, true);
-    }
-  }
-  return success;
-}
-
-/// It's expensive to check for the DBGShellCommands defaults setting. Only do
-/// it once per lldb run and cache the result.
-static llvm::StringRef GetDbgShellCommand() {
-  static std::once_flag g_once_flag;
-  static std::string g_dbgshell_command;
-  std::call_once(g_once_flag, [&]() {
-    CFTypeRef defaults_setting = CFPreferencesCopyAppValue(
-        CFSTR("DBGShellCommands"), CFSTR("com.apple.DebugSymbols"));
-    if (defaults_setting &&
-        CFGetTypeID(defaults_setting) == CFStringGetTypeID()) {
-      char buffer[PATH_MAX];
-      if (CFStringGetCString((CFStringRef)defaults_setting, buffer,
-                             sizeof(buffer), kCFStringEncodingUTF8)) {
-        g_dbgshell_command = buffer;
-      }
-    }
-    if (defaults_setting) {
-      CFRelease(defaults_setting);
-    }
-  });
-  return g_dbgshell_command;
-}
-
-/// Get the dsymForUUID executable and cache the result so we don't end up
-/// stat'ing the binary over and over.
-static FileSpec GetDsymForUUIDExecutable() {
-  // The LLDB_APPLE_DSYMFORUUID_EXECUTABLE environment variable is used by the
-  // test suite to override the dsymForUUID location. Because we must be able
-  // to change the value within a single test, don't bother caching it.
-  if (const char *dsymForUUID_env =
-          getenv("LLDB_APPLE_DSYMFORUUID_EXECUTABLE")) {
-    FileSpec dsymForUUID_executable(dsymForUUID_env);
-    FileSystem::Instance().Resolve(dsymForUUID_executable);
-    if (FileSystem::Instance().Exists(dsymForUUID_executable))
-      return dsymForUUID_executable;
-  }
-
-  static std::once_flag g_once_flag;
-  static FileSpec g_dsymForUUID_executable;
-  std::call_once(g_once_flag, [&]() {
-    // Try the DBGShellCommand.
-    llvm::StringRef dbgshell_command = GetDbgShellCommand();
-    if (!dbgshell_command.empty()) {
-      g_dsymForUUID_executable = FileSpec(dbgshell_command);
-      FileSystem::Instance().Resolve(g_dsymForUUID_executable);
-      if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
-        return;
-    }
-
-    // Try dsymForUUID in /usr/local/bin
-    {
-      g_dsymForUUID_executable = FileSpec("/usr/local/bin/dsymForUUID");
-      if (FileSystem::Instance().Exists(g_dsymForUUID_executable))
-        return;
-    }
-
-    // We couldn't find the dsymForUUID binary.
-    g_dsymForUUID_executable = {};
-  });
-  return g_dsymForUUID_executable;
-}
-
-bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
-                                          Status &error, bool force_lookup,
-                                          bool copy_executable) {
-  const UUID *uuid_ptr = module_spec.GetUUIDPtr();
-  const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr();
-
-  // If \a dbgshell_command is set, the user has specified
-  // forced symbol lookup via that command.  We'll get the
-  // path back from GetDsymForUUIDExecutable() later.
-  llvm::StringRef dbgshell_command = GetDbgShellCommand();
-
-  // If forced lookup isn't set, by the user's \a dbgshell_command or
-  // by the \a force_lookup argument, exit this method.
-  if (!force_lookup && dbgshell_command.empty())
-    return false;
-
-  // We need a UUID or valid existing FileSpec.
-  if (!uuid_ptr &&
-      (!file_spec_ptr || !FileSystem::Instance().Exists(*file_spec_ptr)))
-    return false;
-
-  // We need a dsymForUUID binary or an equivalent executable/script.
-  FileSpec dsymForUUID_exe_spec = GetDsymForUUIDExecutable();
-  if (!dsymForUUID_exe_spec)
-    return false;
-
-  const std::string dsymForUUID_exe_path = dsymForUUID_exe_spec.GetPath();
-  const std::string uuid_str = uuid_ptr ? uuid_ptr->GetAsString() : "";
-  const std::string file_path_str =
-      file_spec_ptr ? file_spec_ptr->GetPath() : "";
-
-  Log *log = GetLog(LLDBLog::Host);
-
-  // Create the dsymForUUID command.
-  StreamString command;
-  const char *copy_executable_arg = copy_executable ? "--copyExecutable " : "";
-  if (!uuid_str.empty()) {
-    command.Printf("%s --ignoreNegativeCache %s%s",
-                   dsymForUUID_exe_path.c_str(), copy_executable_arg,
-                   uuid_str.c_str());
-    LLDB_LOGF(log, "Calling %s with UUID %s to find dSYM: %s",
-              dsymForUUID_exe_path.c_str(), uuid_str.c_str(),
-              command.GetString().data());
-  } else if (!file_path_str.empty()) {
-    command.Printf("%s --ignoreNegativeCache %s%s",
-                   dsymForUUID_exe_path.c_str(), copy_executable_arg,
-                   file_path_str.c_str());
-    LLDB_LOGF(log, "Calling %s with file %s to find dSYM: %s",
-              dsymForUUID_exe_path.c_str(), file_path_str.c_str(),
-              command.GetString().data());
-  } else {
-    return false;
-  }
-
-  // Invoke dsymForUUID.
-  int exit_status = -1;
-  int signo = -1;
-  std::string command_output;
-  error = Host::RunShellCommand(
-      command.GetData(),
-      FileSpec(),      // current working directory
-      &exit_status,    // Exit status
-      &signo,          // Signal int *
-      &command_output, // Command output
-      std::chrono::seconds(
-          640), // Large timeout to allow for long dsym download times
-      false);   // Don't run in a shell (we don't need shell expansion)
-
-  if (error.Fail() || exit_status != 0 || command_output.empty()) {
-    LLDB_LOGF(log, "'%s' failed (exit status: %d, error: '%s', output: '%s')",
-              command.GetData(), exit_status, error.AsCString(),
-              command_output.c_str());
-    return false;
-  }
-
-  CFCData data(
-      CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)command_output.data(),
-                                  command_output.size(), kCFAllocatorNull));
-
-  CFCReleaser<CFDictionaryRef> plist(
-      (CFDictionaryRef)::CFPropertyListCreateWithData(
-          NULL, data.get(), kCFPropertyListImmutable, NULL, NULL));
-
-  if (!plist.get()) {
-    LLDB_LOGF(log, "'%s' failed: output is not a valid plist",
-              command.GetData());
-    return false;
-  }
-
-  if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) {
-    LLDB_LOGF(log, "'%s' failed: output plist is not a valid CFDictionary",
-              command.GetData());
-    return false;
-  }
-
-  if (!uuid_str.empty()) {
-    CFCString uuid_cfstr(uuid_str.c_str());
-    CFDictionaryRef uuid_dict =
-        (CFDictionaryRef)CFDictionaryGetValue(plist.get(), uuid_cfstr.get());
-    return GetModuleSpecInfoFromUUIDDictionary(uuid_dict, module_spec, error,
-                                               command.GetData());
-  }
-
-  if (const CFIndex num_values = ::CFDictionaryGetCount(plist.get())) {
-    std::vector<CFStringRef> keys(num_values, NULL);
-    std::vector<CFDictionaryRef> values(num_values, NULL);
-    ::CFDictionaryGetKeysAndValues(plist.get(), NULL,
-                                   (const void **)&values[0]);
-    if (num_values == 1) {
-      return GetModuleSpecInfoFromUUIDDictionary(values[0], module_spec, error,
-                                                 command.GetData());
-    }
-
-    for (CFIndex i = 0; i < num_values; ++i) {
-      ModuleSpec curr_module_spec;
-      if (GetModuleSpecInfoFromUUIDDictionary(values[i], curr_module_spec,
-                                              error, command.GetData())) {
-        if (module_spec.GetArchitecture().IsCompatibleMatch(
-                curr_module_spec.GetArchitecture())) {
-          module_spec = curr_module_spec;
-          return true;
-        }
-      }
-    }
-  }
-
-  return false;
-}



More information about the lldb-commits mailing list