https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/214372

>From af4efebb900f77b2ea722d9debba054f08e92558 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Wed, 5 Aug 2026 12:42:25 -0700
Subject: [PATCH 1/2] [lldb] Split DynamicLoader binary loading into locate and
 load (NFCI)

LoadBinaryWithUUIDAndAddress both searched for a binary and registered
it with the Target. Split it into LocateBinaries, which only searches,
and LoadBinaryInTarget, which mutates the Target, with
LocateAndLoadBinary keeping the single binary case a one-liner.

The eight binary parameters and the results of the search are bundled in
a new BinarySpec struct, and both entry points return an llvm::Expected.

NFC, except for some small improvements to the error handling because we
don't write to the async output stream directly (and fixed the newline).

The motivation is a follow-up that runs LocateBinaries in parallel on
the thread pool. NFC except for the error reporting.
---
 lldb/include/lldb/Target/DynamicLoader.h      | 180 ++++++----
 lldb/source/Core/DynamicLoader.cpp            | 313 ++++++++++--------
 .../ObjectFile/Mach-O/ObjectFileMachO.cpp     |  29 +-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  41 +--
 .../Process/mach-core/ProcessMachCore.cpp     |  67 ++--
 5 files changed, 377 insertions(+), 253 deletions(-)

diff --git a/lldb/include/lldb/Target/DynamicLoader.h 
b/lldb/include/lldb/Target/DynamicLoader.h
index e85036c2887d1..e5500a5f0a2f1 100644
--- a/lldb/include/lldb/Target/DynamicLoader.h
+++ b/lldb/include/lldb/Target/DynamicLoader.h
@@ -20,8 +20,12 @@
 #include "lldb/lldb-private-enumerations.h"
 #include "lldb/lldb-types.h"
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Error.h"
+
 #include <cstddef>
 #include <cstdint>
+#include <string>
 namespace lldb_private {
 class ModuleList;
 class Process;
@@ -212,72 +216,132 @@ class DynamicLoader : public PluginInterface {
                                              lldb::addr_t base_addr,
                                              bool base_addr_is_offset);
 
-  /// Find/load a binary into lldb given a UUID and the address where it is
-  /// loaded in memory, or a slide to be applied to the file address.
-  /// May force an expensive search on the computer to find the binary by
-  /// UUID, should not be used for a large number of binaries - intended for
-  /// an environment where there may be one, or a few, binaries resident in
-  /// memory.
+  /// A binary to find and load into a Target, and the state that finding it
+  /// produces.
+  ///
+  /// Loading a binary is split into LocateBinaries and LoadBinaryInTarget so
+  /// that a caller with many binaries can search for all of them before adding
+  /// any of them to the Target.
+  struct BinarySpec {
+    /// Name of the binary, if available.  If no matching binary can be found 
on
+    /// the debug host, a module may be created out of live memory and given
+    /// this name.  If empty, a name is constructed from the address the binary
+    /// is loaded at.
+    std::string name;
+
+    /// UUID of the binary to be loaded.  May be empty, in which case, if a 
load
+    /// address is supplied, the binary is read out of memory to get a UUID to
+    /// look for.  There is a performance cost to doing this, it is not
+    /// preferable.
+    UUID uuid;
+
+    /// Address where the binary should be loaded, or read out of memory.  Or a
+    /// slide value, to be applied to the file addresses of the binary.
+    lldb::addr_t value = LLDB_INVALID_ADDRESS;
+
+    /// A flag indicating that \a value is an address, or an offset to be
+    /// applied to the file addresses.
+    bool value_is_offset = false;
+
+    /// Allow the search to do a possibly expensive external search for the
+    /// ObjectFile and/or SymbolFile.
+    bool force_symbol_search = false;
+
+    /// Whether ModulesDidLoad should be called once the binary has been added
+    /// to the Target.  A caller loading several binaries may prefer to batch
+    /// those up.
+    bool notify = false;
+
+    /// Whether the address of the binary should be set in the Target if it is
+    /// added.  A caller that wants to set the section addresses individually
+    /// leaves this clear, and is then responsible for setting the load address
+    /// for the binary or its segments in the Target.
+    bool set_address_in_target = false;
+
+    /// If no better binary image can be found, allow reading the binary out of
+    /// memory, if possible, and create the Module based on that.  May be slow
+    /// to read a binary out of memory, and for unusual environments, there may
+    /// be no symbols mapped in memory at all.
+    bool allow_memory_image_last_resort = false;
+
+    /// The module the binary was found as, or empty if it was not found.  It 
is
+    /// not registered with the Target until LoadBinaryInTarget.
+    lldb::ModuleSP module_sp;
+
+    /// The binary as it was read out of the process' memory, if it had to be,
+    /// so that it is not read a second time.
+    lldb::ModuleSP memory_module_sp;
+
+    /// What an external symbol server had to say about this binary.  The 
search
+    /// records it rather than reporting it, so that it reaches the user in the
+    /// caller's order.
+    Status error;
+  };
+
+  /// Find a binary and load it into a Target.
+  ///
+  /// Given a UUID, search for a binary and load it at the address provided, or
+  /// with the slide applied, or at the file address unslid.
+  ///
+  /// Given an address, try to read the binary out of memory, get the UUID, 
find
+  /// the file if possible and load it unslid, or add the memory module.
+  ///
+  /// May force an expensive search on the computer to find the binary by UUID.
+  /// To load more than one binary, use LocateBinaries and LoadBinaryInTarget.
+  ///
+  /// \param[in] process
+  ///     The process to add this binary to.
+  ///
+  /// \param[in,out] bin_spec
+  ///     The binary to find and load, with its input fields filled in by the
+  ///     caller.
+  ///
+  /// \return
+  ///     The module that was added to the Target, or an error saying why the
+  ///     binary could not be found and loaded.
+  static llvm::Expected<lldb::ModuleSP>
+  LocateAndLoadBinary(Process *process, BinarySpec &bin_spec);
+
+  /// Search for a batch of binaries, without mutating the Target.
+  ///
+  /// The entries are independent: a binary that cannot be found leaves its
+  /// BinarySpec::module_sp empty and has no effect on the others.  Nothing is
+  /// registered with the Target, see LoadBinaryInTarget.
+  ///
+  /// \param[in] process
+  ///     The process the binaries belong to.  Used to read a binary's header
+  ///     out of memory when its UUID isn't known, and otherwise only read 
from.
+  ///
+  /// \param[in,out] bin_specs
+  ///     The binaries to search for, with their input fields filled in by the
+  ///     caller.
+  static void LocateBinaries(Process *process,
+                             llvm::MutableArrayRef<BinarySpec> bin_specs);
+
+  /// Add a binary that LocateBinaries searched for to the Target, and set its
+  /// load address.
   ///
-  /// Given a UUID, search for a binary and load it at the address provided,
-  /// or with the slide applied, or at the file address unslid.
+  /// This mutates the Target and may read the process' memory, so it has to be
+  /// called for one binary at a time.  Call it in the caller's own order 
rather
+  /// than in the order the searches finished: the order decides the Target's
+  /// module order, which binary gets to set the Target's architecture, and the
+  /// order in which messages reach the user.
   ///
-  /// Given an address, try to read the binary out of memory, get the UUID,
-  /// find the file if possible and load it unslid, or add the memory module.
+  /// Whether a failure is worth telling the user about is left to the caller,
+  /// which knows whether it went looking for a binary that has to be there.  A
+  /// symbol server's word on a binary that was found anyway is reported here.
   ///
   /// \param[in] process
   ///     The process to add this binary to.
   ///
-  /// \param[in] name
-  ///     Name of the binary, if available.  If this method cannot find a
-  ///     matching binary on the debug host, it may create a memory module
-  ///     out of live memory, and the provided name will be used.  If an
-  ///     empty StringRef is provided, a name will be constructed for the 
module
-  ///     based on the address it is loaded at.
-  ///
-  /// \param[in] uuid
-  ///     UUID of the binary to be loaded.  UUID may be empty, and if a
-  ///     load address is supplied, will read the binary from memory, get
-  ///     a UUID and try to find a local binary.  There is a performance
-  ///     cost to doing this, it is not preferable.
-  ///
-  /// \param[in] value
-  ///     Address where the binary should be loaded, or read out of memory.
-  ///     Or a slide value, to be applied to the file addresses of the binary.
-  ///
-  /// \param[in] value_is_offset
-  ///     A flag indicating that \p value is an address, or an offset to
-  ///     be applied to the file addresses.
-  ///
-  /// \param[in] force_symbol_search
-  ///     Allow the search to do a possibly expensive external search for
-  ///     the ObjectFile and/or SymbolFile.
-  ///
-  /// \param[in] notify
-  ///     Whether ModulesDidLoad should be called when a binary has been added
-  ///     to the Target.  The caller may prefer to batch up these when loading
-  ///     multiple binaries.
-  ///
-  /// \param[in] set_address_in_target
-  ///     Whether the address of the binary should be set in the Target if it
-  ///     is added.  The caller may want to set the section addresses
-  ///     individually, instead of loading the binary the entire based on the
-  ///     start address or slide.  The caller is responsible for setting the
-  ///     load address for the binary or its segments in the Target if it 
passes
-  ///     true.
-  ///
-  /// \param[in] allow_memory_image_last_resort
-  ///     If no better binary image can be found, allow reading the binary
-  ///     out of memory, if possible, and create the Module based on that.
-  ///     May be slow to read a binary out of memory, and for unusual
-  ///     environments, may be no symbols mapped in memory at all.
+  /// \param[in,out] bin_spec
+  ///     A binary that LocateBinaries has searched for.
   ///
   /// \return
-  ///     Returns a shared pointer for the Module that has been added.
-  static lldb::ModuleSP LoadBinaryWithUUIDAndAddress(
-      Process *process, llvm::StringRef name, UUID uuid, lldb::addr_t value,
-      bool value_is_offset, bool force_symbol_search, bool notify,
-      bool set_address_in_target, bool allow_memory_image_last_resort);
+  ///     The module that was added to the Target, or an error saying why the
+  ///     binary could not be found and loaded.
+  static llvm::Expected<lldb::ModuleSP>
+  LoadBinaryInTarget(Process *process, BinarySpec &bin_spec);
 
   /// Get information about the shared cache for a process, if possible.
   ///
diff --git a/lldb/source/Core/DynamicLoader.cpp 
b/lldb/source/Core/DynamicLoader.cpp
index ac260607f6c86..96da588a0d644 100644
--- a/lldb/source/Core/DynamicLoader.cpp
+++ b/lldb/source/Core/DynamicLoader.cpp
@@ -26,8 +26,10 @@
 #include "lldb/lldb-private-interfaces.h"
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
 
 #include <memory>
+#include <string>
 
 #include <cassert>
 
@@ -211,172 +213,205 @@ static ModuleSP ReadUnnamedMemoryModule(Process 
*process, addr_t addr,
   return *module_sp_or_err;
 }
 
-ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(
-    Process *process, llvm::StringRef name, UUID uuid, addr_t value,
-    bool value_is_offset, bool force_symbol_search, bool notify,
-    bool set_address_in_target, bool allow_memory_image_last_resort) {
-  ModuleSP memory_module_sp;
-  ModuleSP module_sp;
-  PlatformSP platform_sp = process->GetTarget().GetPlatform();
-  Target &target = process->GetTarget();
-  Status error;
-
-  StreamString prog_str;
-  if (!name.empty()) {
-    prog_str << name.str() << " ";
+static std::string
+GetBinaryDescription(const DynamicLoader::BinarySpec &bin_spec) {
+  StreamString desc;
+  if (!bin_spec.name.empty())
+    desc << bin_spec.name << " ";
+  if (bin_spec.uuid.IsValid())
+    desc << bin_spec.uuid.GetAsString();
+  if (!bin_spec.value_is_offset && bin_spec.value != LLDB_INVALID_ADDRESS) {
+    desc << " at 0x";
+    desc.PutHex64(bin_spec.value);
   }
-  if (uuid.IsValid())
-    prog_str << uuid.GetAsString();
-  if (value_is_offset == 0 && value != LLDB_INVALID_ADDRESS) {
-    prog_str << " at 0x";
-    prog_str.PutHex64(value);
-  }
-
-  if (!uuid.IsValid() && !value_is_offset) {
-    memory_module_sp = ReadUnnamedMemoryModule(process, value, name);
+  return desc.GetString().str();
+}
 
-    if (memory_module_sp) {
-      uuid = memory_module_sp->GetUUID();
-      if (uuid.IsValid()) {
-        prog_str << " ";
-        prog_str << uuid.GetAsString();
-      }
-    }
+static std::string
+GetBinaryNotFoundMessage(const DynamicLoader::BinarySpec &bin_spec) {
+  StreamString msg;
+  msg << "Unable to find file";
+  if (!bin_spec.name.empty())
+    msg << " " << bin_spec.name;
+  if (bin_spec.uuid.IsValid())
+    msg << " with UUID " << bin_spec.uuid.GetAsString();
+  if (bin_spec.value != LLDB_INVALID_ADDRESS) {
+    if (bin_spec.value_is_offset)
+      msg.Printf(" with slide 0x%" PRIx64, bin_spec.value);
+    else
+      msg.Printf(" at address 0x%" PRIx64, bin_spec.value);
   }
+  return msg.GetString().str();
+}
+
+/// Search for a binary with a known UUID, and create a module for it.
+///
+/// Does not mutate the Target, but does read from it, and reaches the global
+/// shared module list, the symbol locator plugins, and a locate module 
callback
+/// the user may have installed.
+static void SearchForBinary(Target &target, DynamicLoader::BinarySpec 
&bin_spec,
+                            const FileSpecList &search_paths) {
   ModuleSpec module_spec;
   module_spec.SetTarget(target.shared_from_this());
-  module_spec.GetUUID() = uuid;
-  FileSpec name_filespec(name);
+  module_spec.GetUUID() = bin_spec.uuid;
+  FileSpec name_filespec(bin_spec.name);
   if (FileSystem::Instance().Exists(name_filespec))
     module_spec.GetFileSpec() = name_filespec;
 
-  if (uuid.IsValid()) {
-    Progress progress("Locating binary", prog_str.GetString().str());
-
-    // Has lldb already seen a module with this UUID?
-    // Or have external lookup enabled in DebugSymbols on macOS.
-    if (!module_sp)
-      error =
-          ModuleList::GetSharedModule(module_spec, module_sp, nullptr, 
nullptr);
-
-    // Can lldb's symbol/executable location schemes
-    // find an executable and symbol file.
-    if (!module_sp) {
-      FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
-      StatisticsMap symbol_locator_map;
-      module_spec.GetSymbolFileSpec() =
-          PluginManager::LocateExecutableSymbolFile(module_spec, search_paths,
-                                                    symbol_locator_map);
-      ModuleSpec objfile_module_spec =
-          PluginManager::LocateExecutableObjectFile(module_spec,
-                                                    symbol_locator_map);
-      module_spec.GetFileSpec() = objfile_module_spec.GetFileSpec();
-      if (FileSystem::Instance().Exists(module_spec.GetFileSpec()) &&
-          FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec())) {
-        module_sp = std::make_shared<Module>(module_spec);
-      }
+  // Has lldb already seen a module with this UUID?
+  // Or have external lookup enabled in DebugSymbols on macOS.
+  Status error = ModuleList::GetSharedModule(module_spec, bin_spec.module_sp,
+                                             nullptr, nullptr);
+
+  // Can lldb's symbol/executable location schemes find an executable and
+  // symbol file.
+  if (!bin_spec.module_sp) {
+    StatisticsMap symbol_locator_map;
+    module_spec.GetSymbolFileSpec() = 
PluginManager::LocateExecutableSymbolFile(
+        module_spec, search_paths, symbol_locator_map);
+    ModuleSpec objfile_module_spec = PluginManager::LocateExecutableObjectFile(
+        module_spec, symbol_locator_map);
+    module_spec.GetFileSpec() = objfile_module_spec.GetFileSpec();
+    if (FileSystem::Instance().Exists(module_spec.GetFileSpec()) &&
+        FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec())) {
+      bin_spec.module_sp = std::make_shared<Module>(module_spec);
+    }
 
-      if (module_sp) {
-        module_sp->GetSymbolLocatorStatistics().merge(symbol_locator_map);
-      }
+    if (bin_spec.module_sp) {
+      bin_spec.module_sp->GetSymbolLocatorStatistics().merge(
+          symbol_locator_map);
     }
+  }
 
-    // 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()) {
-      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("") &&
-                 error.AsCString("")[0] != '\0') {
-        *target.GetDebugger().GetAsyncErrorStream() << error.AsCString();
-      }
+  // 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 (!bin_spec.module_sp || !bin_spec.module_sp->GetSymbolFileFileSpec()) {
+    PluginManager::DownloadObjectAndSymbolFile(module_spec, error,
+                                               bin_spec.force_symbol_search);
+    if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
+      bin_spec.module_sp = std::make_shared<Module>(module_spec);
+    } else if (bin_spec.force_symbol_search && error.Fail()) {
+      bin_spec.error = std::move(error);
     }
+  }
+
+  // If we only found the executable, create a Module based on that.
+  if (!bin_spec.module_sp &&
+      FileSystem::Instance().Exists(module_spec.GetFileSpec()))
+    bin_spec.module_sp = std::make_shared<Module>(module_spec);
+}
 
-    // If we only found the executable, create a Module based on that.
-    if (!module_sp && FileSystem::Instance().Exists(module_spec.GetFileSpec()))
-      module_sp = std::make_shared<Module>(module_spec);
+static void FindBinaryUUIDInMemory(Process *process,
+                                   DynamicLoader::BinarySpec &bin_spec) {
+  bin_spec.memory_module_sp =
+      ReadUnnamedMemoryModule(process, bin_spec.value, bin_spec.name);
+  if (bin_spec.memory_module_sp)
+    bin_spec.uuid = bin_spec.memory_module_sp->GetUUID();
+}
+
+void DynamicLoader::LocateBinaries(
+    Process *process, llvm::MutableArrayRef<BinarySpec> bin_specs) {
+  Target &target = process->GetTarget();
+  const FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths();
+
+  for (BinarySpec &bin_spec : bin_specs) {
+    if (!bin_spec.uuid.IsValid() && !bin_spec.value_is_offset)
+      FindBinaryUUIDInMemory(process, bin_spec);
+    if (!bin_spec.uuid.IsValid())
+      continue;
+    Progress progress("Locating binary", GetBinaryDescription(bin_spec));
+    SearchForBinary(target, bin_spec, search_paths);
   }
+}
+
+llvm::Expected<ModuleSP>
+DynamicLoader::LoadBinaryInTarget(Process *process, BinarySpec &bin_spec) {
+  Target &target = process->GetTarget();
+
+  // The error belongs to this function now: every path below either reports it
+  // or folds it into the failure.
+  llvm::Error search_error = bin_spec.error.takeError();
 
   // If we couldn't find the binary anywhere else, as a last resort,
   // read it out of memory.
-  if (allow_memory_image_last_resort && !module_sp.get() &&
-      value != LLDB_INVALID_ADDRESS && !value_is_offset) {
-    if (!memory_module_sp)
-      memory_module_sp = ReadUnnamedMemoryModule(process, value, name);
-    if (memory_module_sp)
-      module_sp = memory_module_sp;
+  if (bin_spec.allow_memory_image_last_resort && !bin_spec.module_sp &&
+      bin_spec.value != LLDB_INVALID_ADDRESS && !bin_spec.value_is_offset) {
+    if (!bin_spec.memory_module_sp)
+      bin_spec.memory_module_sp =
+          ReadUnnamedMemoryModule(process, bin_spec.value, bin_spec.name);
+    if (bin_spec.memory_module_sp)
+      bin_spec.module_sp = bin_spec.memory_module_sp;
   }
 
   Log *log = GetLog(LLDBLog::DynamicLoader);
-  if (module_sp.get()) {
-    // Ensure the Target has an architecture set in case
-    // we need it while processing this binary/eh_frame/debug info.
-    if (!target.GetArchitecture().IsValid())
-      target.SetArchitecture(module_sp->GetArchitecture());
-    target.GetImages().AppendIfNeeded(module_sp, false);
-
-    bool changed = false;
-    if (set_address_in_target) {
-      if (module_sp->GetObjectFile()) {
-        if (value != LLDB_INVALID_ADDRESS) {
-          LLDB_LOGF(log,
-                    "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading "
-                    "binary %s UUID %s at %s 0x%" PRIx64,
-                    name.str().c_str(), uuid.GetAsString().c_str(),
-                    value_is_offset ? "offset" : "address", value);
-          module_sp->SetLoadAddress(target, value, value_is_offset, changed);
-        } else {
-          // No address/offset/slide, load the binary at file address,
-          // offset 0.
-          LLDB_LOGF(log,
-                    "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading "
-                    "binary %s UUID %s at file address",
-                    name.str().c_str(), uuid.GetAsString().c_str());
-          module_sp->SetLoadAddress(target, 0, true /* value_is_slide */,
-                                    changed);
-        }
+  if (!bin_spec.module_sp) {
+    std::string message = GetBinaryNotFoundMessage(bin_spec);
+    LLDB_LOG(log, "{0}", message);
+    llvm::Error error = llvm::createStringError(message);
+    if (search_error)
+      return llvm::joinErrors(std::move(search_error), std::move(error));
+    return std::move(error);
+  }
+
+  // A binary was found, but a symbol server may still have had something to 
say
+  // about its symbols.
+  if (search_error)
+    *target.GetDebugger().GetAsyncErrorStream()
+        << llvm::toString(std::move(search_error)) << "\n";
+
+  // Ensure the Target has an architecture set in case
+  // we need it while processing this binary/eh_frame/debug info.
+  if (!target.GetArchitecture().IsValid())
+    target.SetArchitecture(bin_spec.module_sp->GetArchitecture());
+  target.GetImages().AppendIfNeeded(bin_spec.module_sp, false);
+
+  bool changed = false;
+  if (bin_spec.set_address_in_target) {
+    if (bin_spec.module_sp->GetObjectFile()) {
+      if (bin_spec.value != LLDB_INVALID_ADDRESS) {
+        LLDB_LOGF(log,
+                  "DynamicLoader::LoadBinaryInTarget Loading "
+                  "binary %s UUID %s at %s 0x%" PRIx64,
+                  bin_spec.name.c_str(), bin_spec.uuid.GetAsString().c_str(),
+                  bin_spec.value_is_offset ? "offset" : "address",
+                  bin_spec.value);
+        bin_spec.module_sp->SetLoadAddress(target, bin_spec.value,
+                                           bin_spec.value_is_offset, changed);
       } else {
-        // In-memory image, load at its true address, offset 0.
+        // No address/offset/slide, load the binary at file address,
+        // offset 0.
         LLDB_LOGF(log,
-                  "DynamicLoader::LoadBinaryWithUUIDAndAddress Loading binary "
-                  "%s UUID %s from memory at address 0x%" PRIx64,
-                  name.str().c_str(), uuid.GetAsString().c_str(), value);
-        module_sp->SetLoadAddress(target, 0, true /* value_is_slide */,
-                                  changed);
+                  "DynamicLoader::LoadBinaryInTarget Loading "
+                  "binary %s UUID %s at file address",
+                  bin_spec.name.c_str(), bin_spec.uuid.GetAsString().c_str());
+        bin_spec.module_sp->SetLoadAddress(target, 0, true /* value_is_slide 
*/,
+                                           changed);
       }
+    } else {
+      // In-memory image, load at its true address, offset 0.
+      LLDB_LOGF(log,
+                "DynamicLoader::LoadBinaryInTarget Loading binary "
+                "%s UUID %s from memory at address 0x%" PRIx64,
+                bin_spec.name.c_str(), bin_spec.uuid.GetAsString().c_str(),
+                bin_spec.value);
+      bin_spec.module_sp->SetLoadAddress(target, 0, true /* value_is_slide */,
+                                         changed);
     }
+  }
 
-    if (notify) {
-      ModuleList added_module;
-      added_module.Append(module_sp, false);
-      target.ModulesDidLoad(added_module);
-    }
-  } else {
-    if (force_symbol_search) {
-      lldb::StreamUP s = target.GetDebugger().GetAsyncErrorStream();
-      s->PutCString("Unable to find file");
-      if (!name.empty())
-        s->Printf(" %s", name.str().c_str());
-      if (uuid.IsValid())
-        s->Printf(" with UUID %s", uuid.GetAsString().c_str());
-      if (value != LLDB_INVALID_ADDRESS) {
-        if (value_is_offset)
-          s->Printf(" with slide 0x%" PRIx64, value);
-        else
-          s->Printf(" at address 0x%" PRIx64, value);
-      }
-      s->PutCString("\n");
-    }
-    LLDB_LOGF(log,
-              "Unable to find binary %s with UUID %s and load it at "
-              "%s 0x%" PRIx64,
-              name.str().c_str(), uuid.GetAsString().c_str(),
-              value_is_offset ? "offset" : "address", value);
+  if (bin_spec.notify) {
+    ModuleList added_module;
+    added_module.Append(bin_spec.module_sp, false);
+    target.ModulesDidLoad(added_module);
   }
 
-  return module_sp;
+  return bin_spec.module_sp;
+}
+
+llvm::Expected<ModuleSP>
+DynamicLoader::LocateAndLoadBinary(Process *process, BinarySpec &bin_spec) {
+  LocateBinaries(process, bin_spec);
+  return LoadBinaryInTarget(process, bin_spec);
 }
 
 int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr,
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp 
b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 60b90309bee00..0ae87a8e77f90 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -6709,16 +6709,29 @@ bool 
ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
     // and can try to read load commands and find a UUID.
     if (image.uuid.IsValid() ||
         (!value_is_offset && value != LLDB_INVALID_ADDRESS)) {
-      const bool set_load_address = image.segment_load_addresses.size() == 0;
-      const bool notify = false;
+      DynamicLoader::BinarySpec bin_spec;
+      bin_spec.name = image.filename;
+      bin_spec.uuid = image.uuid;
+      bin_spec.value = value;
+      bin_spec.value_is_offset = value_is_offset;
+      bin_spec.force_symbol_search = image.currently_executing;
+      bin_spec.notify = false;
       // Userland Darwin binaries will have segment load addresses via
       // the `all image infos` LC_NOTE.
-      const bool allow_memory_image_last_resort =
-          image.segment_load_addresses.size();
-      module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
-          &process, image.filename, image.uuid, value, value_is_offset,
-          image.currently_executing, notify, set_load_address,
-          allow_memory_image_last_resort);
+      bin_spec.set_address_in_target = image.segment_load_addresses.empty();
+      bin_spec.allow_memory_image_last_resort =
+          !image.segment_load_addresses.empty();
+      if (llvm::Expected<ModuleSP> located =
+              DynamicLoader::LocateAndLoadBinary(&process, bin_spec)) {
+        module_sp = *located;
+      } else if (bin_spec.force_symbol_search) {
+        *process.GetTarget().GetDebugger().GetAsyncErrorStream()
+            << llvm::toString(located.takeError()) << "\n";
+      } else {
+        // A corefile image that isn't on this machine is routine, and
+        // LocateAndLoadBinary has already logged it.
+        llvm::consumeError(located.takeError());
+      }
     }
 
     // We have a ModuleSP to load in the Target.  Load it at the
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp 
b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 724e7f2e71bd8..1e2788b3c081b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1167,17 +1167,19 @@ void ProcessGDBRemote::LoadStubBinaries() {
   bool standalone_value_is_offset;
   if (m_gdb_comm.GetProcessStandaloneBinary(standalone_uuid, standalone_value,
                                             standalone_value_is_offset)) {
-    ModuleSP module_sp;
-
     if (standalone_uuid.IsValid()) {
-      const bool force_symbol_search = true;
-      const bool notify = true;
-      const bool set_address_in_target = true;
-      const bool allow_memory_image_last_resort = false;
-      DynamicLoader::LoadBinaryWithUUIDAndAddress(
-          this, "", standalone_uuid, standalone_value,
-          standalone_value_is_offset, force_symbol_search, notify,
-          set_address_in_target, allow_memory_image_last_resort);
+      DynamicLoader::BinarySpec bin_spec;
+      bin_spec.uuid = standalone_uuid;
+      bin_spec.value = standalone_value;
+      bin_spec.value_is_offset = standalone_value_is_offset;
+      bin_spec.force_symbol_search = true;
+      bin_spec.notify = true;
+      bin_spec.set_address_in_target = true;
+      llvm::Expected<ModuleSP> module =
+          DynamicLoader::LocateAndLoadBinary(this, bin_spec);
+      if (!module)
+        *GetTarget().GetDebugger().GetAsyncErrorStream()
+            << llvm::toString(module.takeError()) << "\n";
     }
   }
 
@@ -1191,8 +1193,6 @@ void ProcessGDBRemote::LoadStubBinaries() {
 
   std::vector<addr_t> bin_addrs = m_gdb_comm.GetProcessStandaloneBinaries();
   if (bin_addrs.size()) {
-    UUID uuid;
-    const bool value_is_slide = false;
     for (addr_t addr : bin_addrs) {
       const bool notify = true;
       // First see if this is a special platform
@@ -1204,14 +1204,17 @@ void ProcessGDBRemote::LoadStubBinaries() {
               .LoadPlatformBinaryAndSetup(this, addr, notify))
         continue;
 
-      const bool force_symbol_search = true;
-      const bool set_address_in_target = true;
-      const bool allow_memory_image_last_resort = false;
       // Second manually load this binary into the Target.
-      DynamicLoader::LoadBinaryWithUUIDAndAddress(
-          this, llvm::StringRef(), uuid, addr, value_is_slide,
-          force_symbol_search, notify, set_address_in_target,
-          allow_memory_image_last_resort);
+      DynamicLoader::BinarySpec bin_spec;
+      bin_spec.value = addr;
+      bin_spec.force_symbol_search = true;
+      bin_spec.notify = notify;
+      bin_spec.set_address_in_target = true;
+      llvm::Expected<ModuleSP> module =
+          DynamicLoader::LocateAndLoadBinary(this, bin_spec);
+      if (!module)
+        *GetTarget().GetDebugger().GetAsyncErrorStream()
+            << llvm::toString(module.takeError()) << "\n";
     }
   }
 }
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp 
b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index d0b9de0091511..91a977bb69bdc 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -262,17 +262,20 @@ bool ProcessMachCore::LoadBinaryViaLowmemUUID() {
                         uuid.GetAsString().c_str(), addr);
               // We have no address specified, only a UUID.  Load it at the 
file
               // address.
-              const bool value_is_offset = true;
-              const bool force_symbol_search = true;
-              const bool notify = true;
-              const bool set_address_in_target = true;
-              const bool allow_memory_image_last_resort = false;
-              if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
-                      this, llvm::StringRef(), uuid, 0, value_is_offset,
-                      force_symbol_search, notify, set_address_in_target,
-                      allow_memory_image_last_resort)) {
+              DynamicLoader::BinarySpec bin_spec;
+              bin_spec.uuid = uuid;
+              bin_spec.value = 0;
+              bin_spec.value_is_offset = true;
+              bin_spec.force_symbol_search = true;
+              bin_spec.notify = true;
+              bin_spec.set_address_in_target = true;
+              llvm::Expected<ModuleSP> module =
+                  DynamicLoader::LocateAndLoadBinary(this, bin_spec);
+              if (module)
                 m_dyld_plugin_name = 
DynamicLoaderStatic::GetPluginNameStatic();
-              }
+              else
+                *GetTarget().GetDebugger().GetAsyncErrorStream()
+                    << llvm::toString(module.takeError()) << "\n";
               // We found metadata saying which binary should be loaded; don't
               // try an exhaustive search.
               return true;
@@ -325,17 +328,20 @@ bool ProcessMachCore::LoadBinariesViaMetadata() {
       m_dyld_all_image_infos_addr = objfile_binary_value;
       m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic();
     } else {
-      const bool force_symbol_search = true;
-      const bool notify = true;
-      const bool set_address_in_target = true;
-      const bool allow_memory_image_last_resort = false;
-      if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
-              this, llvm::StringRef(), objfile_binary_uuid,
-              objfile_binary_value, objfile_binary_value_is_offset,
-              force_symbol_search, notify, set_address_in_target,
-              allow_memory_image_last_resort)) {
+      DynamicLoader::BinarySpec bin_spec;
+      bin_spec.uuid = objfile_binary_uuid;
+      bin_spec.value = objfile_binary_value;
+      bin_spec.value_is_offset = objfile_binary_value_is_offset;
+      bin_spec.force_symbol_search = true;
+      bin_spec.notify = true;
+      bin_spec.set_address_in_target = true;
+      llvm::Expected<ModuleSP> module =
+          DynamicLoader::LocateAndLoadBinary(this, bin_spec);
+      if (module)
         m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
-      }
+      else
+        *GetTarget().GetDebugger().GetAsyncErrorStream()
+            << llvm::toString(module.takeError()) << "\n";
     }
   }
 
@@ -382,17 +388,20 @@ bool ProcessMachCore::LoadBinariesViaMetadata() {
     } else if (ident_uuid.IsValid()) {
       // We have no address specified, only a UUID.  Load it at the file
       // address.
-      const bool value_is_offset = false;
-      const bool force_symbol_search = true;
-      const bool notify = true;
-      const bool set_address_in_target = true;
-      const bool allow_memory_image_last_resort = false;
-      if (DynamicLoader::LoadBinaryWithUUIDAndAddress(
-              this, llvm::StringRef(), ident_uuid, ident_binary_addr,
-              value_is_offset, force_symbol_search, notify,
-              set_address_in_target, allow_memory_image_last_resort)) {
+      DynamicLoader::BinarySpec bin_spec;
+      bin_spec.uuid = ident_uuid;
+      bin_spec.value = ident_binary_addr;
+      bin_spec.force_symbol_search = true;
+      bin_spec.notify = true;
+      bin_spec.set_address_in_target = true;
+      llvm::Expected<ModuleSP> module =
+          DynamicLoader::LocateAndLoadBinary(this, bin_spec);
+      if (module) {
         found_binary_spec_in_metadata = true;
         m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic();
+      } else {
+        *GetTarget().GetDebugger().GetAsyncErrorStream()
+            << llvm::toString(module.takeError()) << "\n";
       }
     }
 

>From b8701cddd47713cff3825f0ef9f1dabb646e5d9c Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Wed, 5 Aug 2026 22:27:42 -0700
Subject: [PATCH 2/2] Address Jason's feedback

---
 lldb/include/lldb/Target/DynamicLoader.h | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/lldb/include/lldb/Target/DynamicLoader.h 
b/lldb/include/lldb/Target/DynamicLoader.h
index e5500a5f0a2f1..62307a9f9c2a2 100644
--- a/lldb/include/lldb/Target/DynamicLoader.h
+++ b/lldb/include/lldb/Target/DynamicLoader.h
@@ -254,7 +254,7 @@ class DynamicLoader : public PluginInterface {
 
     /// Whether the address of the binary should be set in the Target if it is
     /// added.  A caller that wants to set the section addresses individually
-    /// leaves this clear, and is then responsible for setting the load address
+    /// leaves this false, and is then responsible for setting the load address
     /// for the binary or its segments in the Target.
     bool set_address_in_target = false;
 
@@ -264,7 +264,7 @@ class DynamicLoader : public PluginInterface {
     /// be no symbols mapped in memory at all.
     bool allow_memory_image_last_resort = false;
 
-    /// The module the binary was found as, or empty if it was not found.  It 
is
+    /// The module found for the binary, or empty if it was not found.  It is
     /// not registered with the Target until LoadBinaryInTarget.
     lldb::ModuleSP module_sp;
 
@@ -305,8 +305,10 @@ class DynamicLoader : public PluginInterface {
   /// Search for a batch of binaries, without mutating the Target.
   ///
   /// The entries are independent: a binary that cannot be found leaves its
-  /// BinarySpec::module_sp empty and has no effect on the others.  Nothing is
-  /// registered with the Target, see LoadBinaryInTarget.
+  /// BinarySpec::module_sp empty and has no effect on the others.  Its
+  /// BinarySpec::memory_module_sp is set only when the binary's header had to
+  /// be read out of memory to get the UUID.  Nothing is registered with the
+  /// Target, see LoadBinaryInTarget.
   ///
   /// \param[in] process
   ///     The process the binaries belong to.  Used to read a binary's header

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to