Skip to content

DynamicLoaderDarwin load images in parallel with preload #110646

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
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
Loading