From c9d2fabefdaef73a2f15e792b7a07afa864925bf Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Thu, 10 Jul 2025 11:25:22 -0700 Subject: [PATCH 1/6] [lldb] Use RemoteAddress's address space for the file cache optimization Now that RemoteAddress carries its address space, instead of using a high bit to turn on the filecache optimization, use that instead. This way we are guaranteed to not clash with any pointer authentication masks. rdar://148361743 (cherry picked from commit 99c31b75b1677de0446f9d41d83341c02f21c0b9) --- .../Swift/LLDBMemoryReader.cpp | 91 ++++++++----------- .../LanguageRuntime/Swift/LLDBMemoryReader.h | 19 ++-- .../Swift/SwiftLanguageRuntime.cpp | 4 +- 3 files changed, 45 insertions(+), 69 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp index 5ad007bb22b70..f8462bf1dc8e5 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp @@ -32,11 +32,6 @@ bool LLDBMemoryReader::queryDataLayout(DataLayoutQueryType type, void *inBuffer, return false; // The mask returned by the process masks out the non-addressable bits. uint64_t mask_pattern = ~ptrauth_mask; - // LLDBMemoryReader sets LLDB_FILE_ADDRESS_BIT to distinguish process - // addresses and file addresses that point into a reflection section on - // disk. Setting the bit in the mask ensures it isn't accidentally cleared - // by ptrauth stripping. - mask_pattern |= LLDB_FILE_ADDRESS_BIT; memcpy(outBuffer, &mask_pattern, m_process.GetAddressByteSize()); return true; } @@ -181,8 +176,7 @@ LLDBMemoryReader::resolvePointerAsSymbol(swift::remote::RemoteAddress address) { if (!target.GetSwiftUseReflectionSymbols()) return {}; - std::optional
maybeAddr = - resolveRemoteAddress(address.getRawAddress()); + std::optional
maybeAddr = remoteAddressToLLDBAddress(address); // This is not an assert, but should never happen. if (!maybeAddr) return {}; @@ -231,11 +225,14 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, // to a tagged address so further memory reads originating from it benefit // from the file-cache optimization. swift::remote::RemoteAbsolutePointer process_pointer{ - swift::remote::RemoteAddress{ - readValue, swift::remote::RemoteAddress::DefaultAddressSpace}}; + swift::remote::RemoteAddress{readValue, address.getAddressSpace()}}; - if (!readMetadataFromFileCacheEnabled()) + if (!readMetadataFromFileCacheEnabled()) { + assert(address.getAddressSpace() == + swift::remote::RemoteAddress::DefaultAddressSpace && + "Unexpected address space!"); return process_pointer; + } // Try to strip the pointer before checking if we have it mapped. auto strippedPointer = signedPointerStripper(process_pointer); @@ -271,10 +268,10 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, } // If the containing image is the first registered one, the image's tagged - // start address for it is the first tagged address. Otherwise, the previous - // pair's address is the start tagged address. + // start address for it is zero. Otherwise, the previous pair's address is the + // start of the new address. uint64_t start_tagged_address = pair_iterator == m_range_module_map.begin() - ? LLDB_FILE_ADDRESS_BIT + ? 0 : std::prev(pair_iterator)->first; auto *section_list = module_containing_pointer->GetSectionList(); @@ -298,8 +295,7 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, } swift::remote::RemoteAbsolutePointer tagged_pointer{ - swift::remote::RemoteAddress{ - tagged_address, swift::remote::RemoteAddress::DefaultAddressSpace}}; + swift::remote::RemoteAddress{tagged_address, LLDBAddressSpace}}; if (tagged_address != (uint64_t)signedPointerStripper(tagged_pointer) .getResolvedAddress() @@ -341,10 +337,10 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, LLDB_LOGV(log, "[MemoryReader] asked to read {0} bytes at address {1:x}", size, address.getRawAddress()); std::optional
maybeAddr = - resolveRemoteAddressFromSymbolObjectFile(address.getRawAddress()); + resolveRemoteAddressFromSymbolObjectFile(address); if (!maybeAddr) - maybeAddr = resolveRemoteAddress(address.getRawAddress()); + maybeAddr = remoteAddressToLLDBAddress(address); if (!maybeAddr) { LLDB_LOGV(log, "[MemoryReader] could not resolve address {0:x}", @@ -418,10 +414,10 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, address.getRawAddress()); std::optional
maybeAddr = - resolveRemoteAddressFromSymbolObjectFile(address.getRawAddress()); + resolveRemoteAddressFromSymbolObjectFile(address); if (!maybeAddr) - maybeAddr = resolveRemoteAddress(address.getRawAddress()); + maybeAddr = remoteAddressToLLDBAddress(address); if (!maybeAddr) { LLDB_LOGV(log, "[MemoryReader] could not resolve address {0:x}", @@ -461,7 +457,7 @@ bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, MemoryReaderLocalBufferHolder::~MemoryReaderLocalBufferHolder() { if (m_memory_reader) - m_memory_reader->popLocalBuffer(); + m_memory_reader->popLocalBuffer(); } MemoryReaderLocalBufferHolder @@ -490,12 +486,9 @@ LLDBMemoryReader::addModuleToAddressMap(ModuleSP module, "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; + uint64_t module_start_address = 0; if (!m_range_module_map.empty()) - // We map the images contiguously one after the other, all with the tag bit - // set. + // We map the images contiguously one after the other. // The address that maps the last module is exactly the address the new // module should start at. module_start_address = m_range_module_map.back().first; @@ -541,18 +534,6 @@ LLDBMemoryReader::addModuleToAddressMap(ModuleSP module, auto size = end_file_address - start_file_address; auto module_end_address = module_start_address + size; - if (module_end_address != - signedPointerStripper( - swift::remote::RemoteAbsolutePointer{swift::remote::RemoteAddress{ - module_end_address, - swift::reflection::RemoteAddress::DefaultAddressSpace}}) - .getResolvedAddress() - .getRawAddress()) { - LLDB_LOG(GetLog(LLDBLog::Types), - "[MemoryReader] module to address map ran into pointer " - "authentication mask!"); - return {}; - } // The address for the next image is the next pointer aligned address // available after the end of the current image. uint64_t next_module_start_address = llvm::alignTo(module_end_address, 8); @@ -566,18 +547,18 @@ LLDBMemoryReader::addModuleToAddressMap(ModuleSP module, std::optional> LLDBMemoryReader::getFileAddressAndModuleForTaggedAddress( - uint64_t tagged_address) const { + swift::remote::RemoteAddress tagged_address) const { Log *log(GetLog(LLDBLog::Types)); if (!readMetadataFromFileCacheEnabled()) return {}; - // If the address contains our mask, this is an image we registered. - if (!(tagged_address & LLDB_FILE_ADDRESS_BIT)) + if (tagged_address.getAddressSpace() != LLDBAddressSpace) return {}; // Dummy pair with the address we're looking for. - auto comparison_pair = std::make_pair(tagged_address, ModuleSP()); + auto comparison_pair = + std::make_pair(tagged_address.getRawAddress(), ModuleSP()); // Explicitly compare only the addresses, never the modules in the pairs. auto pair_iterator = std::lower_bound( @@ -589,7 +570,7 @@ LLDBMemoryReader::getFileAddressAndModuleForTaggedAddress( LLDB_LOG(log, "[MemoryReader] Address {0:x} is larger than the upper bound " "address of the mapped in modules", - tagged_address); + tagged_address.getRawAddress()); return {}; } @@ -601,14 +582,13 @@ LLDBMemoryReader::getFileAddressAndModuleForTaggedAddress( } uint64_t file_address; 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 = tagged_address & ~LLDB_FILE_ADDRESS_BIT; + file_address = tagged_address.getRawAddress(); else // The end of the previous section is the start of the current one. // We also need to add the first section's file address since we remove it // when constructing the range to module map. - file_address = tagged_address - std::prev(pair_iterator)->first; + file_address = + (tagged_address - std::prev(pair_iterator)->first).getRawAddress(); // We also need to add the module's file address, since we subtract it when // building the range to module map. @@ -620,27 +600,28 @@ std::optional LLDBMemoryReader::resolveRemoteAddress( swift::reflection::RemoteAddress address) const { std::optional
lldb_address = - LLDBMemoryReader::resolveRemoteAddress(address.getRawAddress()); + LLDBMemoryReader::remoteAddressToLLDBAddress(address); if (!lldb_address) return {}; lldb::addr_t addr = lldb_address->GetLoadAddress(&m_process.GetTarget()); if (addr != LLDB_INVALID_ADDRESS) - return swift::reflection::RemoteAddress(addr, swift::reflection::RemoteAddress::DefaultAddressSpace); + return swift::reflection::RemoteAddress( + addr, swift::reflection::RemoteAddress::DefaultAddressSpace); return {}; } -std::optional
-LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const { +std::optional
LLDBMemoryReader::remoteAddressToLLDBAddress( + swift::remote::RemoteAddress address) const { Log *log(GetLog(LLDBLog::Types)); auto maybe_pair = getFileAddressAndModuleForTaggedAddress(address); if (!maybe_pair) - return Address(address); + return Address(address.getRawAddress()); 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); + return Address(address.getRawAddress()); auto *object_file = module->GetObjectFile(); if (!object_file) @@ -656,7 +637,7 @@ LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const { LLDB_LOGV(log, "[MemoryReader] Successfully resolved mapped address {0:x} into " "file address {1:x}", - address, resolved.GetFileAddress()); + address.getRawAddress(), resolved.GetFileAddress()); return resolved; } auto *sec_list = module->GetSectionList(); @@ -700,7 +681,7 @@ LLDBMemoryReader::resolveRemoteAddress(uint64_t address) const { std::optional
LLDBMemoryReader::resolveRemoteAddressFromSymbolObjectFile( - uint64_t address) const { + swift::remote::RemoteAddress address) const { Log *log(GetLog(LLDBLog::Types)); if (!m_process.GetTarget().GetSwiftReadMetadataFromDSYM()) @@ -744,7 +725,7 @@ LLDBMemoryReader::resolveRemoteAddressFromSymbolObjectFile( LLDB_LOGV(log, "[MemoryReader] Successfully resolved mapped address {0:x} into " "file address {1:x} from symbol object file.", - address, file_address); + address.getRawAddress(), file_address); return resolved; } diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h index cd6d8a9bb3589..aa52ff047ecda 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h @@ -51,6 +51,7 @@ class MemoryReaderLocalBufferHolder { class LLDBMemoryReader : public swift::remote::MemoryReader { public: + static constexpr uint8_t LLDBAddressSpace = 1; LLDBMemoryReader(Process &p, std::function> - getFileAddressAndModuleForTaggedAddress(uint64_t tagged_address) const; + getFileAddressAndModuleForTaggedAddress( + swift::remote::RemoteAddress 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, @@ -114,12 +116,13 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { /// tagged address back, an Address with just an offset if the address was not /// tagged, and None if the address was tagged but we couldn't convert it back /// to an Address. - std::optional
resolveRemoteAddress(uint64_t address) const; + std::optional
+ remoteAddressToLLDBAddress(swift::remote::RemoteAddress address) const; /// Reads memory from the symbol rich binary from the address into dest. /// \return true if it was able to successfully read memory. - std::optional
- resolveRemoteAddressFromSymbolObjectFile(uint64_t address) const; + std::optional
resolveRemoteAddressFromSymbolObjectFile( + swift::remote::RemoteAddress address) const; Process &m_process; size_t m_max_read_amount; @@ -144,14 +147,6 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { /// The set of modules where we should read memory from the symbol file's /// object file instead of the main object file. llvm::SmallSet m_modules_with_metadata_in_symbol_obj_file; - - /// 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; - static_assert(LLDB_FILE_ADDRESS_BIT & SWIFT_ABI_X86_64_SWIFT_SPARE_BITS_MASK, - "LLDB file address bit not in spare bits mask!"); - static_assert(LLDB_FILE_ADDRESS_BIT & SWIFT_ABI_ARM64_SWIFT_SPARE_BITS_MASK, - "LLDB file address bit not in spare bits mask!"); }; } // namespace lldb_private #endif diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp index 691519f984e25..778e89a382c36 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.cpp @@ -727,8 +727,8 @@ std::optional SwiftLanguageRuntime::AddObjectFileToReflectionContext( assert(address <= end_address && "Address outside of range!"); swift::remote::RemoteRef remote_ref( - swift::remote::RemoteAddress( - address, swift::remote::RemoteAddress::DefaultAddressSpace), + swift::remote::RemoteAddress(address, + LLDBMemoryReader::LLDBAddressSpace), Buf); return {remote_ref, size}; } From 9d60dc7e346f0ac84574fded5ffcbfe5ed71701b Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 16 Jul 2025 21:25:54 -0700 Subject: [PATCH 2/6] [lldb] Add an extra optional did_read_live_memory to Target::ReadMemory Target::ReadMemory may or may not read live memory, but whether it did read from live memory or from the filecache is opaque to callers. Add an extra out parameter to indicate whether live memory was read or not. (cherry picked from commit c5c35e72da109c7afbe0c93746d28215537eb236) --- lldb/include/lldb/Target/Target.h | 7 +++++-- lldb/source/Target/Target.cpp | 5 ++++- lldb/unittests/Expression/DWARFExpressionTest.cpp | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index e0d30c2027b7c..dadd6d267bcf6 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -1204,11 +1204,14 @@ class Target : public std::enable_shared_from_this, // 2 - if there is a process, then read from memory // 3 - if there is no process, then read from the file cache // + // The optional did_read_live_memory parameter will be set true if live memory + // was read successfully. + // // The method is virtual for mocking in the unit tests. virtual size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, Status &error, bool force_live_memory = false, - lldb::addr_t *load_addr_ptr = nullptr); - + lldb::addr_t *load_addr_ptr = nullptr, + bool *did_read_live_memory = nullptr); size_t ReadCStringFromMemory(const Address &addr, std::string &out_str, Status &error, bool force_live_memory = false); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index b2a2896352e73..bf486d0faaffa 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2025,7 +2025,8 @@ size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, Status &error, bool force_live_memory, - lldb::addr_t *load_addr_ptr) { + lldb::addr_t *load_addr_ptr, + bool *did_read_live_memory) { error.Clear(); Address fixed_addr = addr; @@ -2124,6 +2125,8 @@ size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, if (bytes_read) { if (load_addr_ptr) *load_addr_ptr = load_addr; + if (did_read_live_memory) + *did_read_live_memory = true; return bytes_read; } } diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index fdc9bfae1876c..3c4c496889fca 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -111,7 +111,8 @@ class MockTarget : public Target { size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, Status &error, bool force_live_memory = false, - lldb::addr_t *load_addr_ptr = nullptr) /*override*/ { + lldb::addr_t *load_addr_ptr = nullptr, + bool *did_read_live_memory = nullptr) /*override*/ { auto expected_memory = this->ReadMemory(addr.GetOffset(), dst_len); if (!expected_memory) { llvm::consumeError(expected_memory.takeError()); From 8cf0a14702d7c8466206357d048daf52cd7c2081 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 16 Jul 2025 21:27:51 -0700 Subject: [PATCH 3/6] [lldb] Implement LLDBMemoryReader::readRemoteAddressImpl Use the new out parameter on Target::ReadMemory to set the correct remote address space in readRemoteAddressImpl. rdar://148361743 (cherry picked from commit decce2be7d98ff40a0046ce6395e860c5503c23c) --- .../Swift/LLDBMemoryReader.cpp | 60 +++++++++++++++---- .../LanguageRuntime/Swift/LLDBMemoryReader.h | 11 ++++ 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp index f8462bf1dc8e5..d3e7d565758f4 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp @@ -225,7 +225,8 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, // to a tagged address so further memory reads originating from it benefit // from the file-cache optimization. swift::remote::RemoteAbsolutePointer process_pointer{ - swift::remote::RemoteAddress{readValue, address.getAddressSpace()}}; + swift::remote::RemoteAddress{ + readValue, swift::remote::RemoteAddress::DefaultAddressSpace}}; if (!readMetadataFromFileCacheEnabled()) { assert(address.getAddressSpace() == @@ -314,6 +315,13 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, uint8_t *dest, uint64_t size) { + auto [success, _] = readBytesImpl(address, dest, size); + return success; +} + +std::pair +LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, + uint8_t *dest, uint64_t size) { Log *log = GetLog(LLDBLog::Types); if (m_local_buffer) { bool overflow = false; @@ -322,7 +330,7 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, if (overflow) { LLDB_LOGV(log, "[MemoryReader] address {0:x} + size {1} overflows", addr, size); - return false; + return {false, false}; } if (addr >= *m_local_buffer && end <= *m_local_buffer + m_local_buffer_size) { @@ -330,7 +338,7 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, // GetDynamicTypeAndAddress_Protocol() most likely no longer // hold. memcpy(dest, (void *)addr, size); - return true; + return {true, false}; } } @@ -345,7 +353,7 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, if (!maybeAddr) { LLDB_LOGV(log, "[MemoryReader] could not resolve address {0:x}", address.getRawAddress()); - return false; + return {false, false}; } auto addr = *maybeAddr; if (addr.IsSectionOffset()) { @@ -354,14 +362,15 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, if (object_file->GetType() == ObjectFile::Type::eTypeDebugInfo) { LLDB_LOGV(log, "[MemoryReader] Reading memory from symbol rich binary"); - return object_file->ReadSectionData(section.get(), addr.GetOffset(), dest, - size); + bool success = object_file->ReadSectionData(section.get(), + addr.GetOffset(), dest, size); + return {success, false}; } } if (size > m_max_read_amount) { LLDB_LOGV(log, "[MemoryReader] memory read exceeds maximum allowed size"); - return false; + return {false, false}; } Target &target(m_process.GetTarget()); Status error; @@ -369,15 +378,18 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, // address to section + offset. const bool force_live_memory = !readMetadataFromFileCacheEnabled() || !addr.IsSectionOffset(); - if (size > target.ReadMemory(addr, dest, size, error, force_live_memory)) { + bool did_read_live_memory = false; + if (size > target.ReadMemory(addr, dest, size, error, force_live_memory, + /*load_addr_ptr=*/nullptr, + &did_read_live_memory)) { LLDB_LOGV(log, "[MemoryReader] memory read returned fewer bytes than asked for"); - return false; + return {false, did_read_live_memory}; } if (error.Fail()) { LLDB_LOGV(log, "[MemoryReader] memory read returned error: {0}", error.AsCString()); - return false; + return {false, did_read_live_memory}; } auto format_data = [](auto dest, auto size) { @@ -391,7 +403,7 @@ bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, LLDB_LOGV(log, "[MemoryReader] memory read returned data: {0}", format_data(dest, size)); - return true; + return {true, did_read_live_memory}; } bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, @@ -596,6 +608,32 @@ LLDBMemoryReader::getFileAddressAndModuleForTaggedAddress( return {{file_address, module}}; } +bool LLDBMemoryReader::readRemoteAddressImpl( + swift::remote::RemoteAddress address, swift::remote::RemoteAddress &out, + std::size_t size) { + assert((size == 4 || size == 8) && + "Only 32 or 64 bit architectures are supported!"); + auto *dest = (uint8_t *)std::malloc(size); + auto defer = llvm::make_scope_exit([&] { free(dest); }); + + auto [success, did_read_live_memory] = readBytesImpl(address, dest, size); + if (!success) + return false; + + uint8_t addressSpace = did_read_live_memory + ? swift::remote::RemoteAddress::DefaultAddressSpace + : LLDBAddressSpace; + if (size == 4) + out = swift::remote::RemoteAddress(*reinterpret_cast(dest), + addressSpace); + else if (size == 8) + out = swift::remote::RemoteAddress(*reinterpret_cast(dest), + addressSpace); + else + return false; + return true; +} + std::optional LLDBMemoryReader::resolveRemoteAddress( swift::reflection::RemoteAddress address) const { diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h index aa52ff047ecda..901e4636561c6 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h @@ -98,6 +98,11 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { /// Returns whether the filecache optimization is enabled or not. bool readMetadataFromFileCacheEnabled() const; +protected: + bool readRemoteAddressImpl(swift::remote::RemoteAddress address, + swift::remote::RemoteAddress &out, + std::size_t integerSize) override; + private: friend MemoryReaderLocalBufferHolder; @@ -119,6 +124,12 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { std::optional
remoteAddressToLLDBAddress(swift::remote::RemoteAddress address) const; + /// Implementation detail of readBytes. Returns a pair where the first element + /// indicates whether the memory was read successfully, the second element + /// indicates whether live memory was read. + std::pair readBytesImpl(swift::remote::RemoteAddress address, + uint8_t *dest, uint64_t size); + /// Reads memory from the symbol rich binary from the address into dest. /// \return true if it was able to successfully read memory. std::optional
resolveRemoteAddressFromSymbolObjectFile( From 53a7e58f121ed54310e4f938919318044ea323ec Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 16 Jul 2025 21:46:47 -0700 Subject: [PATCH 4/6] [lldb] Enable filecache optz in 32 bit platforms (cherry picked from commit b7ac8fd9748de5bba69c6e5f9f38963833304ae9) --- .../Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp index d3e7d565758f4..ee7237c6c1ddc 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp @@ -768,11 +768,6 @@ LLDBMemoryReader::resolveRemoteAddressFromSymbolObjectFile( } bool LLDBMemoryReader::readMetadataFromFileCacheEnabled() const { - auto &triple = m_process.GetTarget().GetArchitecture().GetTriple(); - - // 32 doesn't have a flag bit we can reliably use, so reading from filecache - // is disabled on it. - return m_process.GetTarget().GetSwiftReadMetadataFromFileCache() && - triple.isArch64Bit(); + return m_process.GetTarget().GetSwiftReadMetadataFromFileCache(); } } // namespace lldb_private From e89bf497405c2700ba0ce02715352aae0248d2e8 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Fri, 18 Jul 2025 17:36:55 -0700 Subject: [PATCH 5/6] [NFC][lldb] Clean up LLDBMemoryReader changes. (cherry picked from commit cc4ab2cfea7338d9f055fd4dab592ec20d60ba68) --- .../Swift/LLDBMemoryReader.cpp | 65 +++++++++++-------- .../LanguageRuntime/Swift/LLDBMemoryReader.h | 8 ++- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp index ee7237c6c1ddc..ecf7f3a4caf9f 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp @@ -315,11 +315,11 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address, bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address, uint8_t *dest, uint64_t size) { - auto [success, _] = readBytesImpl(address, dest, size); - return success; + auto read_bytes_result = readBytesImpl(address, dest, size); + return read_bytes_result != ReadBytesResult::fail; } -std::pair +LLDBMemoryReader::ReadBytesResult LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, uint8_t *dest, uint64_t size) { Log *log = GetLog(LLDBLog::Types); @@ -330,7 +330,7 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, if (overflow) { LLDB_LOGV(log, "[MemoryReader] address {0:x} + size {1} overflows", addr, size); - return {false, false}; + return ReadBytesResult::fail; } if (addr >= *m_local_buffer && end <= *m_local_buffer + m_local_buffer_size) { @@ -338,7 +338,7 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, // GetDynamicTypeAndAddress_Protocol() most likely no longer // hold. memcpy(dest, (void *)addr, size); - return {true, false}; + return ReadBytesResult::success_from_file; } } @@ -353,7 +353,7 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, if (!maybeAddr) { LLDB_LOGV(log, "[MemoryReader] could not resolve address {0:x}", address.getRawAddress()); - return {false, false}; + return ReadBytesResult::fail; } auto addr = *maybeAddr; if (addr.IsSectionOffset()) { @@ -362,15 +362,16 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, if (object_file->GetType() == ObjectFile::Type::eTypeDebugInfo) { LLDB_LOGV(log, "[MemoryReader] Reading memory from symbol rich binary"); - bool success = object_file->ReadSectionData(section.get(), - addr.GetOffset(), dest, size); - return {success, false}; + if (object_file->ReadSectionData(section.get(), addr.GetOffset(), dest, + size)) + return ReadBytesResult::success_from_file; + return ReadBytesResult::fail; } } if (size > m_max_read_amount) { LLDB_LOGV(log, "[MemoryReader] memory read exceeds maximum allowed size"); - return {false, false}; + return ReadBytesResult::fail; } Target &target(m_process.GetTarget()); Status error; @@ -384,12 +385,12 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, &did_read_live_memory)) { LLDB_LOGV(log, "[MemoryReader] memory read returned fewer bytes than asked for"); - return {false, did_read_live_memory}; + return ReadBytesResult::fail; } if (error.Fail()) { LLDB_LOGV(log, "[MemoryReader] memory read returned error: {0}", error.AsCString()); - return {false, did_read_live_memory}; + return ReadBytesResult::fail; } auto format_data = [](auto dest, auto size) { @@ -403,7 +404,8 @@ LLDBMemoryReader::readBytesImpl(swift::remote::RemoteAddress address, LLDB_LOGV(log, "[MemoryReader] memory read returned data: {0}", format_data(dest, size)); - return {true, did_read_live_memory}; + return did_read_live_memory ? ReadBytesResult::success_from_memory + : ReadBytesResult::success_from_file; } bool LLDBMemoryReader::readString(swift::remote::RemoteAddress address, @@ -613,24 +615,31 @@ bool LLDBMemoryReader::readRemoteAddressImpl( std::size_t size) { assert((size == 4 || size == 8) && "Only 32 or 64 bit architectures are supported!"); - auto *dest = (uint8_t *)std::malloc(size); - auto defer = llvm::make_scope_exit([&] { free(dest); }); - - auto [success, did_read_live_memory] = readBytesImpl(address, dest, size); - if (!success) + if (size != 4 && size != 8) return false; - uint8_t addressSpace = did_read_live_memory - ? swift::remote::RemoteAddress::DefaultAddressSpace - : LLDBAddressSpace; - if (size == 4) - out = swift::remote::RemoteAddress(*reinterpret_cast(dest), - addressSpace); - else if (size == 8) - out = swift::remote::RemoteAddress(*reinterpret_cast(dest), - addressSpace); - else + uint64_t buf; + auto read_bytes_result = + readBytesImpl(address, reinterpret_cast(&buf), size); + + uint8_t addressSpace; + switch (read_bytes_result) { + case ReadBytesResult::success_from_file: + addressSpace = LLDBAddressSpace; + break; + case ReadBytesResult::success_from_memory: + addressSpace = swift::remote::RemoteAddress::DefaultAddressSpace; + break; + case ReadBytesResult::fail: return false; + } + ByteOrder byte_order = m_process.GetTarget().GetArchitecture().GetByteOrder(); + uint32_t byte_size = + m_process.GetTarget().GetArchitecture().GetAddressByteSize(); + DataExtractor extractor((const void *)&buf, size, byte_order, byte_size); + lldb::offset_t offset = 0; + auto data = extractor.GetMaxU64(&offset, size); + out = swift::remote::RemoteAddress(data, addressSpace); return true; } diff --git a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h index 901e4636561c6..2eef7c3bcec62 100644 --- a/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h +++ b/lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h @@ -51,6 +51,9 @@ class MemoryReaderLocalBufferHolder { class LLDBMemoryReader : public swift::remote::MemoryReader { public: + /// Besides address space 0 (the DefaultAddressSpace), subclasses are free to + /// use any address space for their own implementation purposes. LLDB uses + /// this address space to track file addresses it sends to RemoteInspection. static constexpr uint8_t LLDBAddressSpace = 1; LLDBMemoryReader(Process &p, @@ -124,11 +127,12 @@ class LLDBMemoryReader : public swift::remote::MemoryReader { std::optional
remoteAddressToLLDBAddress(swift::remote::RemoteAddress address) const; + enum class ReadBytesResult { fail, success_from_file, success_from_memory }; /// Implementation detail of readBytes. Returns a pair where the first element /// indicates whether the memory was read successfully, the second element /// indicates whether live memory was read. - std::pair readBytesImpl(swift::remote::RemoteAddress address, - uint8_t *dest, uint64_t size); + ReadBytesResult readBytesImpl(swift::remote::RemoteAddress address, + uint8_t *dest, uint64_t size); /// Reads memory from the symbol rich binary from the address into dest. /// \return true if it was able to successfully read memory. From bf890013b5710c847f76b7c6b1f13a47d0e43f12 Mon Sep 17 00:00:00 2001 From: Augusto Noronha Date: Wed, 23 Jul 2025 14:32:49 -0700 Subject: [PATCH 6/6] [lldb] Speed up check if C++ interop and embedded are enabled Previously, we were parsing every compile unit to look up the flags that indicate whether the current compile unit had C++ interop and/or embedded Swift enabled. Change that to parse only the compile unit we're interested in. rdar://153198051 (cherry picked from commit 1349b680dbd9cac4c8441d76934ef5ebd651a8a7) --- lldb/include/lldb/Symbol/SymbolFile.h | 9 +++ .../Swift/SwiftExpressionParser.cpp | 8 +- .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 75 +++++++++---------- .../TypeSystem/Swift/TypeSystemSwift.cpp | 21 +++--- .../TestSwiftForwardInteropExpressions.py | 6 +- .../expr/TestSwiftEmbeddedExpression.py | 6 ++ 6 files changed, 71 insertions(+), 54 deletions(-) diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 7594734e4946a..20e2d87ad252c 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -387,6 +387,15 @@ class SymbolFile : public PluginInterface { /// for this module have been changed. virtual void SectionFileAddressesChanged() = 0; + /// Looks for the compile option specified by \p option, and sets \p value to + /// it's value. For example, for a flag such as -foo=bar, looking up \p option + /// "-foo" will set \p value to "bar". For a standalone flag such as -baz, \p + /// value will be empty. + /// + /// If \p cu is set, only that compile unit is searched. Otherwise, every + /// compile unit is searched until the option is found or failure. + /// + /// Returns true if the option is found. virtual bool GetCompileOption(const char *option, std::string &value, CompileUnit *cu = nullptr) { value.clear(); diff --git a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp index 7914dbd565463..02e366c789f93 100644 --- a/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Swift/SwiftExpressionParser.cpp @@ -358,12 +358,12 @@ class LLDBExprNameLookup : public LLDBNameLookup { swift::Identifier getPreferredPrivateDiscriminator() override { if (m_sc.comp_unit) { if (lldb_private::Module *module = m_sc.module_sp.get()) { - if (lldb_private::SymbolFile *symbol_file = - module->GetSymbolFile()) { + if (lldb_private::SymbolFile *symbol_file = module->GetSymbolFile()) { std::string private_discriminator_string; if (symbol_file->GetCompileOption("-private-discriminator", - private_discriminator_string, - m_sc.comp_unit)) { + private_discriminator_string, + m_sc.comp_unit) && + !private_discriminator_string.empty()) { return m_source_file.getASTContext().getIdentifier( private_discriminator_string); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 5cb220bd4f42e..4c85e5481c7e0 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3109,6 +3109,36 @@ SymbolFileDWARF::FindDefinitionDIE(const DWARFDIE &die) { return result; } +namespace { +const char *GetFlags(const char *option, DWARFUnit *dwarf_cu) { + if (!dwarf_cu) + return nullptr; + + const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); + if (!die) + return nullptr; + + const char *flags = die.GetAttributeValueAsString(DW_AT_APPLE_flags, NULL); + if (!flags) + return nullptr; + + if (strstr(flags, option)) + return flags; + + return nullptr; +} +bool FindOptionInDWARFCU(const char *option, DWARFUnit *dwarf_cu, + std::string &value) { + const char *flags = GetFlags(option, dwarf_cu); + if (!flags) + return false; + + Args compiler_args(flags); + OptionParsing::GetOptionValueAsString(compiler_args, option, value); + return true; +} +} // namespace + bool SymbolFileDWARF::GetCompileOption(const char *option, std::string &value, CompileUnit *cu) { value.clear(); @@ -3118,52 +3148,19 @@ bool SymbolFileDWARF::GetCompileOption(const char *option, std::string &value, const uint32_t num_compile_units = GetNumCompileUnits(); if (cu) { - auto *dwarf_cu = - llvm::dyn_cast_or_null(GetDWARFCompileUnit(cu)); - - if (dwarf_cu) { + if (auto *dwarf_cu = + llvm::dyn_cast_or_null(GetDWARFCompileUnit(cu))) { // GetDWARFCompileUnit() only looks up by CU#. Make sure that // this is actually the correct SymbolFile by converting it // back to a CompileUnit. if (GetCompUnitForDWARFCompUnit(*dwarf_cu) != cu) return false; - - const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die) { - const char *flags = - die.GetAttributeValueAsString(DW_AT_APPLE_flags, NULL); - - if (flags) { - if (strstr(flags, option)) { - Args compiler_args(flags); - - return OptionParsing::GetOptionValueAsString(compiler_args, - option, value); - } - } - } + return FindOptionInDWARFCU(option, dwarf_cu, value); } } else { - for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) { - DWARFUnit *dwarf_cu = debug_info.GetUnitAtIndex(cu_idx); - - if (dwarf_cu) { - const DWARFBaseDIE die = dwarf_cu->GetUnitDIEOnly(); - if (die) { - const char *flags = - die.GetAttributeValueAsString(DW_AT_APPLE_flags, NULL); - - if (flags) { - if (strstr(flags, option)) { - Args compiler_args(flags); - - return OptionParsing::GetOptionValueAsString(compiler_args, - option, value); - } - } - } - } - } + for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx) + if (DWARFUnit *dwarf_cu = debug_info.GetUnitAtIndex(cu_idx)) + return FindOptionInDWARFCU(option, dwarf_cu, value); } return false; diff --git a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.cpp b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.cpp index 916b75bd8ca44..b33c8f8e7b9e4 100644 --- a/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.cpp +++ b/lldb/source/Plugins/TypeSystem/Swift/TypeSystemSwift.cpp @@ -17,6 +17,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Symbol/CompileUnit.h" #include "llvm/Support/Error.h" +#include "lldb/Utility/LLDBLog.h" #include #include @@ -75,7 +76,7 @@ void TypeSystemSwift::Terminate() { bool TypeSystemSwift::CheckFlagInCU(CompileUnit *cu, const char *flag) { AutoBool interop_enabled = - ModuleList::GetGlobalModuleListProperties().GetSwiftEnableCxxInterop(); + ModuleList::GetGlobalModuleListProperties().GetSwiftEnableCxxInterop(); switch (interop_enabled) { case AutoBool::True: return true; @@ -90,18 +91,18 @@ bool TypeSystemSwift::CheckFlagInCU(CompileUnit *cu, const char *flag) { auto *sym_file = module->GetSymbolFile(); if (!sym_file) return false; - auto options = sym_file->GetCompileOptions(); - for (auto &[unit, args] : options) { - if (unit.get() == cu) { - if (cu->GetLanguage() == eLanguageTypeSwift) - for (const char *arg : args.GetArgumentArrayRef()) - if (strcmp(arg, flag) == 0) - return true; - return false; - } + std::string value; + if (sym_file->GetCompileOption(flag, value, cu)) { + LLDB_LOGV(GetLog(LLDBLog::Types), + "[CheckFlagInCU] Found flag {0} in CU: {1}", flag, + cu->GetPrimaryFile().GetFilename().AsCString()); + return true; } } } + LLDB_LOGV(GetLog(LLDBLog::Types), + "[CheckFlagInCU] Did not find flag {0} in CU: {1}", flag, + cu->GetPrimaryFile().GetFilename().AsCString()); return false; } diff --git a/lldb/test/API/lang/swift/cxx_interop/forward/expressions/TestSwiftForwardInteropExpressions.py b/lldb/test/API/lang/swift/cxx_interop/forward/expressions/TestSwiftForwardInteropExpressions.py index c76b52a59ecd3..f278858085d74 100644 --- a/lldb/test/API/lang/swift/cxx_interop/forward/expressions/TestSwiftForwardInteropExpressions.py +++ b/lldb/test/API/lang/swift/cxx_interop/forward/expressions/TestSwiftForwardInteropExpressions.py @@ -15,13 +15,14 @@ def setup(self, bkpt_str): self, bkpt_str, lldb.SBFileSpec('main.swift')) return thread - @skipIf(bugnumber='rdar://152745034') @skipIfLinux # rdar://106871422" @skipIf(setting=('symbols.use-swift-clangimporter', 'false')) # rdar://106871275 @swiftTest def test(self): self.setup('Break here') + types_log = self.getBuildArtifact('types.log') + self.expect("log enable lldb types -v -f "+ types_log) # Check that we can call free functions. self.expect('expr returnsInt()', substrs=['Int32', '42']) @@ -54,6 +55,9 @@ def test(self): # Check that po prints the fields of a base class self.expect('po cxxClass', substrs=['CxxClass', 'a : 100', 'b : 101']) + self.filecheck('platform shell cat "%s"' % types_log, __file__) + # CHECK: [CheckFlagInCU] Found flag -enable-experimental-cxx-interop in CU: + @expectedFailureAll(bugnumber="rdar://106216567") @swiftTest def test_po_subclass(self): diff --git a/lldb/test/API/lang/swift/embedded/expr/TestSwiftEmbeddedExpression.py b/lldb/test/API/lang/swift/embedded/expr/TestSwiftEmbeddedExpression.py index a1d04ba6ee86f..a129d3c3d9e1f 100644 --- a/lldb/test/API/lang/swift/embedded/expr/TestSwiftEmbeddedExpression.py +++ b/lldb/test/API/lang/swift/embedded/expr/TestSwiftEmbeddedExpression.py @@ -14,4 +14,10 @@ def test(self): self, "break here", lldb.SBFileSpec("main.swift") ) + types_log = self.getBuildArtifact('types.log') + self.expect("log enable lldb types -v -f "+ types_log) + self.expect("expr a.foo()", substrs=["(Int)", " = 16"]) + + self.filecheck('platform shell cat "%s"' % types_log, __file__) + # CHECK: [CheckFlagInCU] Found flag -enable-embedded-swift in CU: