Skip to content

[lldb] Read swift metadata from symbol rich binary #3960

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
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
2 changes: 2 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ class TargetProperties : public Properties {
bool GetSwiftReadMetadataFromFileCache() const;

bool GetSwiftUseReflectionSymbols() const;

bool GetSwiftReadMetadataFromDSYM() const;

bool GetEnableAutoImportClangModules() const;

Expand Down
108 changes: 95 additions & 13 deletions lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address,

LLDB_LOGV(log, "[MemoryReader] asked to read {0} bytes at address {1:x}",
size, address.getAddressData());
if (readBytesFromSymbolObjectFile(address.getAddressData(), dest, size))
return true;

llvm::Optional<Address> maybeAddr =
resolveRemoteAddress(address.getAddressData());
Expand Down Expand Up @@ -349,10 +351,15 @@ void LLDBMemoryReader::popLocalBuffer() {
}

llvm::Optional<std::pair<uint64_t, uint64_t>>
LLDBMemoryReader::addModuleToAddressMap(ModuleSP module) {
LLDBMemoryReader::addModuleToAddressMap(ModuleSP module, bool register_symbol_obj_file) {
if (!readMetadataFromFileCacheEnabled())
return {};

assert(register_symbol_obj_file <=
m_process.GetTarget().GetSwiftReadMetadataFromDSYM() &&
"Trying to register symbol object file, but reading from it is "
"disabled!");

// The first available address is the mask, since subsequent images are mapped
// in ascending order, all of them will contain this mask.
uint64_t module_start_address = LLDB_FILE_ADDRESS_BIT;
Expand All @@ -374,7 +381,20 @@ LLDBMemoryReader::addModuleToAddressMap(ModuleSP module) {
"LLDB file address bit clashes with an obj-c bit!");
#endif

SectionList *section_list = module->GetObjectFile()->GetSectionList();
ObjectFile *object_file;
if (register_symbol_obj_file) {
auto *symbol_file = module->GetSymbolFile();
if (!symbol_file)
return {};
object_file = symbol_file->GetObjectFile();
} else {
object_file = module->GetObjectFile();
}

if (!object_file)
return {};

SectionList *section_list = object_file->GetSectionList();

auto section_list_size = section_list->GetSize();
if (section_list_size == 0)
Expand All @@ -391,22 +411,27 @@ LLDBMemoryReader::addModuleToAddressMap(ModuleSP module) {
// available after the end of the current image.
uint64_t next_module_start_address = llvm::alignTo(module_end_address, 8);
m_range_module_map.emplace_back(next_module_start_address, module);

if (register_symbol_obj_file)
m_modules_with_metadata_in_symbol_obj_file.insert(module);

return {{module_start_address, module_end_address}};
}

llvm::Optional<Address>
LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
Log *log = GetLog(LLDBLog::Types);
llvm::Optional<std::pair<uint64_t, lldb::ModuleSP>>
LLDBMemoryReader::getFileAddressAndModuleForTaggedAddress(
uint64_t tagged_address) const {
Log *log(GetLog(LLDBLog::Types));

if (!readMetadataFromFileCacheEnabled())
return Address(address);
return {};

// If the address contains our mask, this is an image we registered.
if (!(address & LLDB_FILE_ADDRESS_BIT))
return Address(address);
if (!(tagged_address & LLDB_FILE_ADDRESS_BIT))
return {};

// Dummy pair with the address we're looking for.
auto comparison_pair = std::make_pair(address, ModuleSP());
auto comparison_pair = std::make_pair(tagged_address, ModuleSP());

// Explicitly compare only the addresses, never the modules in the pairs.
auto pair_iterator = std::lower_bound(
Expand All @@ -418,7 +443,7 @@ LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
LLDB_LOG(log,
"[MemoryReader] Address {0:x} is larger than the upper bound "
"address of the mapped in modules",
address);
tagged_address);
return {};
}

Expand All @@ -427,15 +452,31 @@ LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
if (pair_iterator == m_range_module_map.begin())
// Since this is the first registered module,
// clearing the tag bit will give the virtual file address.
file_address = address & ~LLDB_FILE_ADDRESS_BIT;
file_address = tagged_address & ~LLDB_FILE_ADDRESS_BIT;
else
// The end of the previous section is the start of the current one.
file_address = address - std::prev(pair_iterator)->first;
file_address = tagged_address - std::prev(pair_iterator)->first;

LLDB_LOGV(log,
"[MemoryReader] Successfully resolved mapped address {0:x} into "
"file address {1:x}",
address, file_address);
tagged_address, file_address);
return {{file_address, module}};
}

llvm::Optional<Address>
LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
Log *log(GetLog(LLDBLog::Types));
auto maybe_pair = getFileAddressAndModuleForTaggedAddress(address);
if (!maybe_pair)
return Address(address);

uint64_t file_address = maybe_pair->first;
ModuleSP module = maybe_pair->second;

if (m_modules_with_metadata_in_symbol_obj_file.count(module))
return Address(address);

auto *object_file = module->GetObjectFile();
if (!object_file)
return {};
Expand All @@ -456,6 +497,47 @@ LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const {
return resolved;
}

bool LLDBMemoryReader::readBytesFromSymbolObjectFile(uint64_t address, uint8_t *dest,
uint64_t size) const {
Log *log(GetLog(LLDBLog::Types));

if (!m_process.GetTarget().GetSwiftReadMetadataFromDSYM())
return false;

auto maybe_pair = getFileAddressAndModuleForTaggedAddress(address);
if (!maybe_pair)
return false;

uint64_t file_address = maybe_pair->first;
ModuleSP module = maybe_pair->second;

if (!m_modules_with_metadata_in_symbol_obj_file.count(module))
return false;

auto *symbol_file = module->GetSymbolFile();
if (!symbol_file)
return false;

auto *object_file = symbol_file->GetObjectFile();
if (!object_file)
return false;

Address resolved(file_address, object_file->GetSectionList());
if (!resolved.IsSectionOffset()) {
LLDB_LOG(log,
"[MemoryReader] Could not make a real address out of file address "
"{0:x} and object file {1}",
file_address, object_file->GetFileSpec().GetFilename());
return false;
}

LLDB_LOGV(log, "[MemoryReader] Reading memory from symbol rich binary");

auto section = resolved.GetSection();
return object_file->ReadSectionData(section.get(), resolved.GetOffset(),
dest, size);
}

bool LLDBMemoryReader::readMetadataFromFileCacheEnabled() const {
auto &triple = m_process.GetTarget().GetArchitecture().GetTriple();

Expand Down
18 changes: 16 additions & 2 deletions lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,17 @@ class LLDBMemoryReader : public swift::remote::MemoryReader {
/// \return a pair of addresses indicating the start and end of this image in
/// the tagged address space. None on failure.
llvm::Optional<std::pair<uint64_t, uint64_t>>
addModuleToAddressMap(lldb::ModuleSP module);
addModuleToAddressMap(lldb::ModuleSP module, bool register_symbol_obj_file);

/// Returns whether the filecache optimization is enabled or not.
bool readMetadataFromFileCacheEnabled() const;

private:
/// Gets the file address and module that were mapped to a given tagged
/// address.
llvm::Optional<std::pair<uint64_t, lldb::ModuleSP>>
getFileAddressAndModuleForTaggedAddress(uint64_t tagged_address) const;

/// Resolves the address by either mapping a tagged address back to an LLDB
/// Address with section + offset, or, in case the address is not tagged,
/// constructing an LLDB address with just the offset.
Expand All @@ -60,6 +65,11 @@ class LLDBMemoryReader : public swift::remote::MemoryReader {
/// Address.
llvm::Optional<Address> resolveRemoteAddress(uint64_t address) const;

/// Reads memory from the symbol rich binary from the address into dest.
/// \return true if it was able to successfully read memory.
bool readBytesFromSymbolObjectFile(uint64_t address, uint8_t *dest,
uint64_t size) const;

private:
Process &m_process;
size_t m_max_read_amount;
Expand All @@ -77,6 +87,10 @@ class LLDBMemoryReader : public swift::remote::MemoryReader {
/// module's virtual address space.
std::vector<std::pair<uint64_t, lldb::ModuleSP>> m_range_module_map;

/// The set of modules where we should read memory from the symbol file's
/// object file instead of the main object file.
std::unordered_set<lldb::ModuleSP> m_modules_with_metadata_in_symbol_obj_file;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use an llvm::DenseSet<> but that's more out of habit.


/// The bit used to tag LLDB's virtual addresses as such. See \c
/// m_range_module_map.
const static uint64_t LLDB_FILE_ADDRESS_BIT = 0x2000000000000000;
Expand Down
63 changes: 53 additions & 10 deletions lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,30 +644,74 @@ bool SwiftLanguageRuntimeImpl::AddJitObjectFileToReflectionContext(
}

bool SwiftLanguageRuntimeImpl::AddObjectFileToReflectionContext(
ModuleSP module, ObjectFile &obj_file) {
ModuleSP module) {
auto obj_format_type =
module->GetArchitecture().GetTriple().getObjectFormat();
module->GetArchitecture().GetTriple().getObjectFormat();

auto obj_file_format = GetObjectFileFormat(obj_format_type);
if (!obj_file_format)
return false;

llvm::Optional<llvm::StringRef> maybe_segment_name =
obj_file_format->getSegmentName();
bool should_register_with_symbol_obj_file = [&]() -> bool {
if (!m_process.GetTarget().GetSwiftReadMetadataFromDSYM())
return false;
auto *symbol_file = module->GetSymbolFile();
if (!symbol_file)
return false;
auto *sym_obj_file = symbol_file->GetObjectFile();
if (!sym_obj_file)
return false;

llvm::Optional<llvm::StringRef> maybe_segment_name =
obj_file_format->getSymbolRichSegmentName();
if (!maybe_segment_name)
return false;

llvm::StringRef segment_name = *maybe_segment_name;

auto *section_list = sym_obj_file->GetSectionList();
auto segment_iter = llvm::find_if(*section_list, [&](auto segment) {
return segment->GetName() == segment_name.begin();
});

if (segment_iter == section_list->end())
return false;

auto *segment = segment_iter->get();

auto section_iter =
llvm::find_if(segment->GetChildren(), [&](auto section) {
return obj_file_format->sectionContainsReflectionData(
section->GetName().GetStringRef());
});
return section_iter != segment->GetChildren().end();
}();

llvm::Optional<llvm::StringRef> maybe_segment_name;
ObjectFile *object_file;
if (should_register_with_symbol_obj_file) {
maybe_segment_name = obj_file_format->getSymbolRichSegmentName();
object_file = module->GetSymbolFile()->GetObjectFile();
} else {
maybe_segment_name = obj_file_format->getSegmentName();
object_file = module->GetObjectFile();
}

if (!maybe_segment_name)
return false;

llvm::StringRef segment_name = *maybe_segment_name;

auto lldb_memory_reader = GetMemoryReader();
auto maybe_start_and_end =
lldb_memory_reader->addModuleToAddressMap(module);
auto maybe_start_and_end = lldb_memory_reader->addModuleToAddressMap(
module, should_register_with_symbol_obj_file);
if (!maybe_start_and_end)
return false;

uint64_t start_address, end_address;
std::tie(start_address, end_address) = *maybe_start_and_end;

auto *section_list = obj_file.GetSectionList();
auto *section_list = object_file->GetSectionList();
auto segment_iter = llvm::find_if(*section_list, [&](auto segment) {
return segment->GetName() == segment_name.begin();
});
Expand All @@ -680,8 +724,7 @@ bool SwiftLanguageRuntimeImpl::AddObjectFileToReflectionContext(
return m_reflection_ctx->addImage(
[&](swift::ReflectionSectionKind section_kind)
-> std::pair<swift::remote::RemoteRef<void>, uint64_t> {
auto section_name =
obj_file_format->getSectionName(section_kind);
auto section_name = obj_file_format->getSectionName(section_kind);
for (auto section : segment->GetChildren()) {
// Iterate over the sections until we find the reflection section we
// need.
Expand Down Expand Up @@ -764,7 +807,7 @@ bool SwiftLanguageRuntimeImpl::AddModuleToReflectionContext(
llvm::Optional<llvm::sys::MemoryBlock>(file_buffer));
} else if (read_from_file_cache &&
obj_file->GetPluginName().equals("mach-o")) {
if (!AddObjectFileToReflectionContext(module_sp, *obj_file))
if (!AddObjectFileToReflectionContext(module_sp))
m_reflection_ctx->addImage(swift::remote::RemoteAddress(load_ptr));
} else {
m_reflection_ctx->addImage(swift::remote::RemoteAddress(load_ptr));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ class SwiftLanguageRuntimeImpl {
/// the directly from the object file.
/// \return true on success.
bool AddObjectFileToReflectionContext(
lldb::ModuleSP module, ObjectFile &obj_file);
lldb::ModuleSP module);

/// Cache for the debug-info-originating type infos.
/// \{
Expand Down
11 changes: 11 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4194,6 +4194,17 @@ bool TargetProperties::GetSwiftUseReflectionSymbols() const {
return true;
}

bool TargetProperties::GetSwiftReadMetadataFromDSYM() const {
const Property *exp_property = m_collection_sp->GetPropertyAtIndex(
nullptr, false, ePropertyExperimental);
OptionValueProperties *exp_values =
exp_property->GetValue()->GetAsProperties();
if (exp_values)
return exp_values->GetPropertyAtIndexAsBoolean(
nullptr, ePropertySwiftReadMetadataFromDSYM, true);

return true;
}
ArchSpec TargetProperties::GetDefaultArchitecture() const {
OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch(
nullptr, ePropertyDefaultArch);
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ let Definition = "target_experimental" in {
def SwiftUseReflectionSymbols : Property<"swift-use-reflection-symbols", "Boolean">,
Global, DefaultTrue,
Desc<"if true, optimize the loading of Swift reflection metadata by making use of available symbols.">;
def SwiftReadMetadataFromDSYM: Property<"swift-read-metadata-from-dsym", "Boolean">,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's great that you made this switchable, but dsymutil only copies reflection metadata if the linker has stripped it, so there's little risk in pessimizing existing workflows with this feature.

DefaultFalse,
Desc<"Read Swift reflection metadata from the dsym instead of the process when possible">;
}

let Definition = "target" in {
Expand Down