Skip to content

Commit

Permalink
DynamicLoaderDarwin load images in parallel with preload (llvm#110646)
Browse files Browse the repository at this point in the history
This change enables `DynamicLoaderDarwin` to load modules in parallel
using the thread pool. This new behavior is controlled by a new setting
`plugin.dynamic-loader.darwin.experimental.enable-parallel-image-load`,
which is enabled by default. When disabled, DynamicLoaderDarwin will
load modules sequentially as before.
  • Loading branch information
DmT021 authored Oct 15, 2024
1 parent 3cab882 commit 5f2cf99
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 43 deletions.
13 changes: 13 additions & 0 deletions lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
lldb_tablegen(DynamicLoaderDarwinProperties.inc -gen-lldb-property-defs
SOURCE DynamicLoaderDarwinProperties.td
TARGET LLDBPluginDynamicLoaderDarwinPropertiesGen)

lldb_tablegen(DynamicLoaderDarwinPropertiesEnum.inc -gen-lldb-property-enum-defs
SOURCE DynamicLoaderDarwinProperties.td
TARGET LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)

add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
DynamicLoaderMacOSXDYLD.cpp
DynamicLoaderMacOS.cpp
DynamicLoaderDarwin.cpp
DynamicLoaderDarwinProperties.cpp

LINK_LIBS
lldbBreakpoint
Expand All @@ -16,3 +25,7 @@ add_lldb_library(lldbPluginDynamicLoaderMacOSXDYLD PLUGIN
Support
TargetParser
)

add_dependencies(lldbPluginDynamicLoaderMacOSXDYLD
LLDBPluginDynamicLoaderDarwinPropertiesGen
LLDBPluginDynamicLoaderDarwinPropertiesEnumGen)
102 changes: 72 additions & 30 deletions lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "DynamicLoaderDarwin.h"

#include "DynamicLoaderDarwinProperties.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
Expand All @@ -31,6 +32,7 @@
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
#include "llvm/Support/ThreadPool.h"

#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
Expand Down Expand Up @@ -77,6 +79,17 @@ void DynamicLoaderDarwin::DidLaunch() {
SetNotificationBreakpoint();
}

void DynamicLoaderDarwin::CreateSettings(lldb_private::Debugger &debugger) {
if (!PluginManager::GetSettingForDynamicLoaderPlugin(
debugger, DynamicLoaderDarwinProperties::GetSettingName())) {
const bool is_global_setting = true;
PluginManager::CreateSettingForDynamicLoaderPlugin(
debugger,
DynamicLoaderDarwinProperties::GetGlobal().GetValueProperties(),
"Properties for the DynamicLoaderDarwin plug-in.", is_global_setting);
}
}

// Clear out the state of this class.
void DynamicLoaderDarwin::Clear(bool clear_process) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
Expand All @@ -88,7 +101,7 @@ void DynamicLoaderDarwin::Clear(bool clear_process) {
}

ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
const ImageInfo &image_info, bool can_create, bool *did_create_ptr) {
if (did_create_ptr)
*did_create_ptr = false;

Expand Down Expand Up @@ -517,44 +530,43 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo(
return true;
}

void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
ImageInfo::collection &image_infos) {
void DynamicLoaderDarwin::UpdateSpecialBinariesFromPreloadedModules(
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
uint32_t exe_idx = UINT32_MAX;
uint32_t dyld_idx = UINT32_MAX;
Target &target = m_process->GetTarget();
Log *log = GetLog(LLDBLog::DynamicLoader);
ConstString g_dyld_sim_filename("dyld_sim");

ArchSpec target_arch = target.GetArchitecture();
const size_t image_infos_size = image_infos.size();
for (size_t i = 0; i < image_infos_size; i++) {
if (image_infos[i].header.filetype == llvm::MachO::MH_DYLINKER) {
const size_t images_size = images.size();
for (size_t i = 0; i < images_size; i++) {
const auto &image_info = images[i].first;
if (image_info.header.filetype == llvm::MachO::MH_DYLINKER) {
// In a "simulator" process we will have two dyld modules --
// a "dyld" that we want to keep track of, and a "dyld_sim" which
// we don't need to keep track of here. dyld_sim will have a non-macosx
// OS.
if (target_arch.GetTriple().getEnvironment() == llvm::Triple::Simulator &&
image_infos[i].os_type != llvm::Triple::OSType::MacOSX) {
image_info.os_type != llvm::Triple::OSType::MacOSX) {
continue;
}

dyld_idx = i;
}
if (image_infos[i].header.filetype == llvm::MachO::MH_EXECUTE) {
if (image_info.header.filetype == llvm::MachO::MH_EXECUTE) {
exe_idx = i;
}
}

// Set the target executable if we haven't found one so far.
if (exe_idx != UINT32_MAX && !target.GetExecutableModule()) {
const bool can_create = true;
ModuleSP exe_module_sp(FindTargetModuleForImageInfo(image_infos[exe_idx],
can_create, nullptr));
ModuleSP exe_module_sp = images[exe_idx].second;
if (exe_module_sp) {
LLDB_LOGF(log, "Found executable module: %s",
exe_module_sp->GetFileSpec().GetPath().c_str());
target.GetImages().AppendIfNeeded(exe_module_sp);
UpdateImageLoadAddress(exe_module_sp.get(), image_infos[exe_idx]);
UpdateImageLoadAddress(exe_module_sp.get(), images[exe_idx].first);
if (exe_module_sp.get() != target.GetExecutableModulePointer())
target.SetExecutableModule(exe_module_sp, eLoadDependentsNo);

Expand All @@ -581,14 +593,12 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos(
}

if (dyld_idx != UINT32_MAX) {
const bool can_create = true;
ModuleSP dyld_sp = FindTargetModuleForImageInfo(image_infos[dyld_idx],
can_create, nullptr);
ModuleSP dyld_sp = images[dyld_idx].second;
if (dyld_sp.get()) {
LLDB_LOGF(log, "Found dyld module: %s",
dyld_sp->GetFileSpec().GetPath().c_str());
target.GetImages().AppendIfNeeded(dyld_sp);
UpdateImageLoadAddress(dyld_sp.get(), image_infos[dyld_idx]);
UpdateImageLoadAddress(dyld_sp.get(), images[dyld_idx].first);
SetDYLDModule(dyld_sp);
}
}
Expand Down Expand Up @@ -642,26 +652,58 @@ ModuleSP DynamicLoaderDarwin::GetDYLDModule() {

void DynamicLoaderDarwin::ClearDYLDModule() { m_dyld_module_wp.reset(); }

std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>>
DynamicLoaderDarwin::PreloadModulesFromImageInfos(
const ImageInfo::collection &image_infos) {
const auto size = image_infos.size();
std::vector<std::pair<DynamicLoaderDarwin::ImageInfo, ModuleSP>> images(size);
auto LoadImage = [&](size_t i, ImageInfo::collection::const_iterator it) {
const auto &image_info = *it;
images[i] = std::make_pair(
image_info, FindTargetModuleForImageInfo(image_info, true, nullptr));
};
auto it = image_infos.begin();
bool is_parallel_load =
DynamicLoaderDarwinProperties::GetGlobal().GetEnableParallelImageLoad();
if (is_parallel_load) {
llvm::ThreadPoolTaskGroup taskGroup(Debugger::GetThreadPool());
for (size_t i = 0; i < size; ++i, ++it) {
taskGroup.async(LoadImage, i, it);
}
taskGroup.wait();
} else {
for (size_t i = 0; i < size; ++i, ++it) {
LoadImage(i, it);
}
}
return images;
}

bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
ImageInfo::collection &image_infos) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
auto images = PreloadModulesFromImageInfos(image_infos);
return AddModulesUsingPreloadedModules(images);
}

bool DynamicLoaderDarwin::AddModulesUsingPreloadedModules(
std::vector<std::pair<ImageInfo, ModuleSP>> &images) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Now add these images to the main list.
ModuleList loaded_module_list;
Log *log = GetLog(LLDBLog::DynamicLoader);
Target &target = m_process->GetTarget();
ModuleList &target_images = target.GetImages();

for (uint32_t idx = 0; idx < image_infos.size(); ++idx) {
for (uint32_t idx = 0; idx < images.size(); ++idx) {
auto &image_info = images[idx].first;
const auto &image_module_sp = images[idx].second;
if (log) {
LLDB_LOGF(log, "Adding new image at address=0x%16.16" PRIx64 ".",
image_infos[idx].address);
image_infos[idx].PutToLog(log);
image_info.address);
image_info.PutToLog(log);
}

m_dyld_image_infos.push_back(image_infos[idx]);

ModuleSP image_module_sp(
FindTargetModuleForImageInfo(image_infos[idx], true, nullptr));
m_dyld_image_infos.push_back(image_info);

if (image_module_sp) {
ObjectFile *objfile = image_module_sp->GetObjectFile();
Expand All @@ -673,7 +715,7 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
sections->FindSectionByName(commpage_dbstr).get();
if (commpage_section) {
ModuleSpec module_spec(objfile->GetFileSpec(),
image_infos[idx].GetArchitecture());
image_info.GetArchitecture());
module_spec.GetObjectName() = commpage_dbstr;
ModuleSP commpage_image_module_sp(
target_images.FindFirstModule(module_spec));
Expand All @@ -686,17 +728,17 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
if (!commpage_image_module_sp ||
commpage_image_module_sp->GetObjectFile() == nullptr) {
commpage_image_module_sp = m_process->ReadModuleFromMemory(
image_infos[idx].file_spec, image_infos[idx].address);
image_info.file_spec, image_info.address);
// Always load a memory image right away in the target in case
// we end up trying to read the symbol table from memory... The
// __LINKEDIT will need to be mapped so we can figure out where
// the symbol table bits are...
bool changed = false;
UpdateImageLoadAddress(commpage_image_module_sp.get(),
image_infos[idx]);
image_info);
target.GetImages().Append(commpage_image_module_sp);
if (changed) {
image_infos[idx].load_stop_id = m_process->GetStopID();
image_info.load_stop_id = m_process->GetStopID();
loaded_module_list.AppendIfNeeded(commpage_image_module_sp);
}
}
Expand All @@ -709,14 +751,14 @@ bool DynamicLoaderDarwin::AddModulesUsingImageInfos(
// address. We need to check this so we don't mention that all loaded
// shared libraries are newly loaded each time we hit out dyld breakpoint
// since dyld will list all shared libraries each time.
if (UpdateImageLoadAddress(image_module_sp.get(), image_infos[idx])) {
if (UpdateImageLoadAddress(image_module_sp.get(), image_info)) {
target_images.AppendIfNeeded(image_module_sp);
loaded_module_list.AppendIfNeeded(image_module_sp);
}

// To support macCatalyst and legacy iOS simulator,
// update the module's platform with the DYLD info.
ArchSpec dyld_spec = image_infos[idx].GetArchitecture();
ArchSpec dyld_spec = image_info.GetArchitecture();
auto &dyld_triple = dyld_spec.GetTriple();
if ((dyld_triple.getEnvironment() == llvm::Triple::MacABI &&
dyld_triple.getOS() == llvm::Triple::IOS) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {

std::optional<lldb_private::Address> GetStartAddress() override;

static void CreateSettings(lldb_private::Debugger &debugger);

protected:
void PrivateInitialize(lldb_private::Process *process);

Expand Down Expand Up @@ -174,7 +176,7 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {

bool UnloadModuleSections(lldb_private::Module *module, ImageInfo &info);

lldb::ModuleSP FindTargetModuleForImageInfo(ImageInfo &image_info,
lldb::ModuleSP FindTargetModuleForImageInfo(const ImageInfo &image_info,
bool can_create,
bool *did_create_ptr);

Expand All @@ -201,11 +203,18 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
lldb_private::StructuredData::ObjectSP image_details,
ImageInfo::collection &image_infos);

// If image_infos contains / may contain dyld or executable image, call this
// method
// to keep our internal record keeping of the special binaries up-to-date.
void
UpdateSpecialBinariesFromNewImageInfos(ImageInfo::collection &image_infos);
// Finds/loads modules for a given `image_infos` and returns pairs
// (ImageInfo, ModuleSP).
// Prefer using this method rather than calling `FindTargetModuleForImageInfo`
// directly as this method may load the modules in parallel.
std::vector<std::pair<ImageInfo, lldb::ModuleSP>>
PreloadModulesFromImageInfos(const ImageInfo::collection &image_infos);

// If `images` contains / may contain dyld or executable image, call this
// method to keep our internal record keeping of the special binaries
// up-to-date.
void UpdateSpecialBinariesFromPreloadedModules(
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);

// if image_info is a dyld binary, call this method
bool UpdateDYLDImageInfoFromNewImageInfo(ImageInfo &image_info);
Expand All @@ -215,6 +224,8 @@ class DynamicLoaderDarwin : public lldb_private::DynamicLoader {
void AddExecutableModuleIfInImageInfos(ImageInfo::collection &image_infos);

bool AddModulesUsingImageInfos(ImageInfo::collection &image_infos);
bool AddModulesUsingPreloadedModules(
std::vector<std::pair<ImageInfo, lldb::ModuleSP>> &images);

// Whether we should use the new dyld SPI to get shared library information,
// or read
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//===-- DynamicLoaderDarwinProperties.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 "DynamicLoaderDarwinProperties.h"

using namespace lldb_private;

#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
#include "DynamicLoaderDarwinProperties.inc"

enum {
#define LLDB_PROPERTIES_dynamicloaderdarwin_experimental
#include "DynamicLoaderDarwinPropertiesEnum.inc"
};

llvm::StringRef DynamicLoaderDarwinProperties::GetSettingName() {
static constexpr llvm::StringLiteral g_setting_name("darwin");
return g_setting_name;
}

DynamicLoaderDarwinProperties::ExperimentalProperties::ExperimentalProperties()
: Properties(std::make_shared<OptionValueProperties>(
GetExperimentalSettingsName())) {
m_collection_sp->Initialize(g_dynamicloaderdarwin_experimental_properties);
}

DynamicLoaderDarwinProperties::DynamicLoaderDarwinProperties()
: Properties(std::make_shared<OptionValueProperties>(GetSettingName())),
m_experimental_properties(std::make_unique<ExperimentalProperties>()) {
m_collection_sp->AppendProperty(
Properties::GetExperimentalSettingsName(),
"Experimental settings - setting these won't produce errors if the "
"setting is not present.",
true, m_experimental_properties->GetValueProperties());
}

bool DynamicLoaderDarwinProperties::GetEnableParallelImageLoad() const {
return m_experimental_properties->GetPropertyAtIndexAs<bool>(
ePropertyEnableParallelImageLoad,
g_dynamicloaderdarwin_experimental_properties
[ePropertyEnableParallelImageLoad]
.default_uint_value != 0);
}

DynamicLoaderDarwinProperties &DynamicLoaderDarwinProperties::GetGlobal() {
static DynamicLoaderDarwinProperties g_settings;
return g_settings;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- DynamicLoaderDarwinProperties.h -------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H

#include "lldb/Core/UserSettingsController.h"

namespace lldb_private {

class DynamicLoaderDarwinProperties : public Properties {
public:
class ExperimentalProperties : public Properties {
public:
ExperimentalProperties();
};
static llvm::StringRef GetSettingName();
static DynamicLoaderDarwinProperties &GetGlobal();
DynamicLoaderDarwinProperties();
~DynamicLoaderDarwinProperties() override = default;
bool GetEnableParallelImageLoad() const;

private:
std::unique_ptr<ExperimentalProperties> m_experimental_properties;
};

} // namespace lldb_private

#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERDARWINPROPERTIES_H
Loading

0 comments on commit 5f2cf99

Please sign in to comment.