[Lldb-commits] [lldb] dece902 - [lldb][MCP] Fix compiler error in Windows on Arm build
Author: David Spickett Date: 2025-08-13T12:55:40Z New Revision: dece902a52c01ed386f63ce0ead6b781a630e580 URL: https://github.com/llvm/llvm-project/commit/dece902a52c01ed386f63ce0ead6b781a630e580 DIFF: https://github.com/llvm/llvm-project/commit/dece902a52c01ed386f63ce0ead6b781a630e580.diff LOG: [lldb][MCP] Fix compiler error in Windows on Arm build Caused by https://github.com/llvm/llvm-project/pull/153297. This is likely not Windows on Arm specific but the other Windows bots don't have this problem. json::parse tries to construct llvm::Expected by moving another instance of Message into it. This would normally use this constructor: ``` /// Create an Expected success value from the given OtherT value, which /// must be convertible to T. template Expected(OtherT &&Val, std::enable_if_t> * = nullptr) <...> ``` Note that llvm::Expected does not have a T&& constructor. Presumably the authors thought the converting one would be used. Except that in our build, using clang-cl 19.1.7, Visual Studio 2022, MSVC STL 202208, somehow is_convertible_v is false for Message. If you add a static_assert to check that this is the case, it suddenly becomes convertible. As best I can understand, this is because evaluation of the properties of Message are delayed. Delayed so much that by the time the constructor is called, it's still false. So we can "fix" this by asserting that it is convertible some time before it is checked by the constructor. I'm not sure if that's a compiler problem or the way MSVC STL's variant is written. I couldn't reproduce this behaviour in smaller examples or on Linux systems. This is the least invasive fix and only touches the new lldb code, so I'm going with it. Including the whole error here because it's a strange one and maybe later someone who has a clue about this can fix it in a better way. ``` C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build>ninja [5/15] Building CXX object tools\lldb\source\Pro...CP\CMakeFiles\lldbProtocolMCP.dir\Server.cpp.obj FAILED: tools/lldb/source/Protocol/MCP/CMakeFiles/lldbProtocolMCP.dir/Server.cpp.obj C:\Users\tcwg\scoop\shims\ccache.exe C:\Users\tcwg\scoop\apps\llvm-arm64\current\bin\clang-cl.exe /nologo -TP -DGTEST_HAS_RTTI=0 -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\source\Protocol\MCP -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\source\Protocol\MCP -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\llvm\include -IC:\Users\tcwg\scoop\apps\python\current\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\llvm\..\clang\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\..\clang\include -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\source -IC:\Users\tcwg\llvm-worker\lldb-aarch64-windows\build\tools\lldb\source /DWIN32 /D_WINDOWS /Zc:inline /Zc:__cplusplus /Oi /Brepro /bigobj /permissive- -Werror=unguarded-availability-new /W4 -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported /Gw -Wno-vla-extension /O2 /Ob2 /DNDEBUG -std:c++17 -MD -wd4018 -wd4068 -wd4150 -wd4201 -wd4251 -wd4521 -wd4530 -wd4589 /EHs-c- /GR- /showIncludes /Fotools\lldb\source\Protocol\MCP\CMakeFiles\lldbProtocolMCP.dir\Server.cpp.obj /Fdtools\lldb\source\Protocol\MCP\CMakeFiles\lldbProtocolMCP.dir\lldbProtocolMCP.pdb -c -- C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\source\Protocol\MCP\Server.cpp In file included from C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\source\Protocol\MCP\Server.cpp:9: In file included from C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\include\lldb/Protocol/MCP/Server.h:12: In file included from C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\include\lldb/Protocol/MCP/Protocol.h:17: C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\llvm\include\llvm/Support/JSON.h(938,12): error: no viable conversion from returned value of type 'remove_reference_t &>' (aka 'std::variant') to function return type 'Expected>' 938 | return std::move(Result); |^ C:\Users\tcwg\llvm-worker\lldb-aarch64-windows\llvm-project\lldb\s
[Lldb-commits] [lldb] 8968183 - [lldb][ClangASTImporter][NFC] Factor out completion logic out of ClangASTImporterDelegate
Author: Michael Buch Date: 2025-08-13T10:22:23+01:00 New Revision: 89681839e367476e0ff66bec3a3931e1c41c7cb4 URL: https://github.com/llvm/llvm-project/commit/89681839e367476e0ff66bec3a3931e1c41c7cb4 DIFF: https://github.com/llvm/llvm-project/commit/89681839e367476e0ff66bec3a3931e1c41c7cb4.diff LOG: [lldb][ClangASTImporter][NFC] Factor out completion logic out of ClangASTImporterDelegate Upstreams two helpers that make this more readable. Added: Modified: lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h Removed: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 624eea91b48f2..8a39fae9498c0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -235,6 +235,35 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { clang::ASTContext *m_src_ctx; ClangASTImporter &importer; + void CompleteDecl( + Decl *decl, + lldb_private::ClangASTImporter::ASTContextMetadata const &to_context_md) { +// The decl that should be completed has to be imported into the target +// context from some other context. +assert(to_context_md.hasOrigin(decl)); +// We should only complete decls coming from the source context. +assert(to_context_md.getOrigin(decl).ctx == m_src_ctx); + +Decl *original_decl = to_context_md.getOrigin(decl).decl; + +// Complete the decl now. +TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); +if (auto *tag_decl = dyn_cast(decl)) { + if (auto *original_tag_decl = dyn_cast(original_decl)) { +if (original_tag_decl->isCompleteDefinition()) { + m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); + tag_decl->setCompleteDefinition(true); +} + } + + tag_decl->setHasExternalLexicalStorage(false); + tag_decl->setHasExternalVisibleStorage(false); +} else if (auto *container_decl = dyn_cast(decl)) { + container_decl->setHasExternalLexicalStorage(false); + container_decl->setHasExternalVisibleStorage(false); +} + } + public: /// Constructs a CompleteTagDeclsScope. /// \param importer The ClangASTImporter that we should observe. @@ -257,30 +286,7 @@ class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { NamedDecl *decl = m_decls_to_complete.pop_back_val(); m_decls_already_completed.insert(decl); - // The decl that should be completed has to be imported into the target - // context from some other context. - assert(to_context_md->hasOrigin(decl)); - // We should only complete decls coming from the source context. - assert(to_context_md->getOrigin(decl).ctx == m_src_ctx); - - Decl *original_decl = to_context_md->getOrigin(decl).decl; - - // Complete the decl now. - TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); - if (auto *tag_decl = dyn_cast(decl)) { -if (auto *original_tag_decl = dyn_cast(original_decl)) { - if (original_tag_decl->isCompleteDefinition()) { -m_delegate->ImportDefinitionTo(tag_decl, original_tag_decl); -tag_decl->setCompleteDefinition(true); - } -} - -tag_decl->setHasExternalLexicalStorage(false); -tag_decl->setHasExternalVisibleStorage(false); - } else if (auto *container_decl = dyn_cast(decl)) { -container_decl->setHasExternalLexicalStorage(false); -container_decl->setHasExternalVisibleStorage(false); - } + CompleteDecl(decl, *to_context_md); to_context_md->removeOrigin(decl); } @@ -1370,6 +1376,18 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, from, m_source_ctx, &to->getASTContext()); } + if (auto *to_namespace_decl = dyn_cast(to)) { +m_main.BuildNamespaceMap(to_namespace_decl); +to_namespace_decl->setHasExternalVisibleStorage(); + } + + MarkDeclImported(from, to); +} + +void ClangASTImporter::ASTImporterDelegate::MarkDeclImported(Decl *from, + Decl *to) { + Log *log = GetLog(LLDBLog::Expressions); + if (auto *to_tag_decl = dyn_cast(to)) { to_tag_decl->setHasExternalLexicalStorage(); to_tag_decl->getPrimaryContext()->setMustBuildLookupTable(); @@ -1384,11 +1402,6 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete")); } - if (auto *to_namespace_decl = dyn_cast(to)) { -m_main.BuildNamespaceMap(to_namespace_decl); -to_namespace_decl->setHasExternalVisibleStorage(); - } - if (auto *to_container_decl = dyn_cas
[Lldb-commits] [lldb] c68b4d6 - [lldb][ClangASTImporter][NFC] Create helper for CanImport
Author: Michael Buch Date: 2025-08-13T10:22:23+01:00 New Revision: c68b4d64dd89993468a23dcc1c5deb858d7e3b2f URL: https://github.com/llvm/llvm-project/commit/c68b4d64dd89993468a23dcc1c5deb858d7e3b2f DIFF: https://github.com/llvm/llvm-project/commit/c68b4d64dd89993468a23dcc1c5deb858d7e3b2f.diff LOG: [lldb][ClangASTImporter][NFC] Create helper for CanImport Upstreams a `CanImport` helper for `clang::Decl`s. Added: Modified: lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h Removed: diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index 8a39fae9498c0..08e2d0f1b4011 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -371,6 +371,16 @@ clang::Decl *ClangASTImporter::DeportDecl(clang::ASTContext *dst_ctx, return result; } +bool ClangASTImporter::CanImport(const Decl *d) { + if (!d) +return false; + if (isa(d)) +return GetDeclOrigin(d).Valid(); + if (isa(d)) +return GetDeclOrigin(d).Valid(); + return false; +} + bool ClangASTImporter::CanImport(const CompilerType &type) { if (!ClangUtil::IsClangType(type)) return false; @@ -380,23 +390,10 @@ bool ClangASTImporter::CanImport(const CompilerType &type) { const clang::Type::TypeClass type_class = qual_type->getTypeClass(); switch (type_class) { - case clang::Type::Record: { -const clang::CXXRecordDecl *cxx_record_decl = -qual_type->getAsCXXRecordDecl(); -if (cxx_record_decl) { - if (GetDeclOrigin(cxx_record_decl).Valid()) -return true; -} - } break; - - case clang::Type::Enum: { -auto *enum_decl = llvm::cast(qual_type)->getOriginalDecl(); -if (enum_decl) { - if (GetDeclOrigin(enum_decl).Valid()) -return true; -} - } break; - + case clang::Type::Record: +return CanImport(qual_type->getAsCXXRecordDecl()); + case clang::Type::Enum: +return CanImport(llvm::cast(qual_type)->getOriginalDecl()); case clang::Type::ObjCObject: case clang::Type::ObjCInterface: { const clang::ObjCObjectType *objc_class_type = @@ -406,10 +403,7 @@ bool ClangASTImporter::CanImport(const CompilerType &type) { objc_class_type->getInterface(); // We currently can't complete objective C types through the newly added // ASTContext because it only supports TagDecl objects right now... - if (class_interface_decl) { -if (GetDeclOrigin(class_interface_decl).Valid()) - return true; - } + return CanImport(class_interface_decl); } } break; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 1c77c5bb4a47b..03d2556ca6f23 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -157,6 +157,8 @@ class ClangASTImporter { /// \see ClangASTImporter::Import bool CanImport(const CompilerType &type); + bool CanImport(const clang::Decl *d); + /// If the given type was copied from another TypeSystemClang then copy over /// all missing information (e.g., the definition of a 'class' type). /// ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 3f61e4e - [LLDB][NativePDB] Resolve declaration for tag types (#152579)
Author: nerix Date: 2025-08-13T14:47:21+01:00 New Revision: 3f61e4eae65fcca0aaef4c726dd8f2ed6b473e7f URL: https://github.com/llvm/llvm-project/commit/3f61e4eae65fcca0aaef4c726dd8f2ed6b473e7f DIFF: https://github.com/llvm/llvm-project/commit/3f61e4eae65fcca0aaef4c726dd8f2ed6b473e7f.diff LOG: [LLDB][NativePDB] Resolve declaration for tag types (#152579) Tag types like stucts or enums didn't have a declaration attached to them. The source locations are present in the IPI stream in `LF_UDT_MOD_SRC_LINE` records: ``` 0x101F | LF_UDT_MOD_SRC_LINE [size = 18, hash = 0x1C63] udt = 0x1058, mod = 3, file = 1, line = 0 0x2789 | LF_UDT_MOD_SRC_LINE [size = 18, hash = 0x1E5A] udt = 0x1253, mod = 35, file = 93, line = 17069 ``` The file is an ID in the string table `/names`: ``` ID | String 1 | '\' 12 | 'D:\a\_work\1\s\src\ExternalAPIs\WindowsSDKInc\c\Include\10.0.22621.0\um\wingdi.h' 93 | 'D:\a\_work\1\s\src\ExternalAPIs\WindowsSDKInc\c\Include\10.0.22621.0\um\winnt.h' ``` Here, we're not interested in `mod`. This would indicate which module contributed the UDT. I was looking at Rustc's PDB and found that it uses `` for some types, so I added a check for that. This makes two DIA PDB shell tests to work with the native PDB plugin. - Co-authored-by: Michael Buch Added: lldb/test/Shell/SymbolFile/NativePDB/unknown-udt-decl.ll Modified: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h lldb/test/Shell/SymbolFile/PDB/class-layout.test lldb/test/Shell/SymbolFile/PDB/enums-layout.test Removed: diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 986d647b4de2d..337052fc6dbd0 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -644,8 +644,14 @@ SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id, std::string uname = GetUnqualifiedTypeName(record); - // FIXME: Search IPI stream for LF_UDT_MOD_SRC_LINE. + llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); Declaration decl; + if (maybeDecl) +decl = std::move(*maybeDecl); + else +LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(), + "Failed to resolve declaration for '{1}': {0}", uname); + return MakeType(toOpaqueUid(type_id), ConstString(uname), size, nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::ResolveState::Forward); @@ -668,7 +674,14 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, CompilerType ct) { std::string uname = GetUnqualifiedTypeName(er); + llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); Declaration decl; + if (maybeDecl) +decl = std::move(*maybeDecl); + else +LLDB_LOG_ERROR(GetLog(LLDBLog::Symbols), maybeDecl.takeError(), + "Failed to resolve declaration for '{1}': {0}", uname); + TypeSP underlying_type = GetOrCreateType(er.UnderlyingType); return MakeType( @@ -2556,3 +2569,70 @@ SymbolFileNativePDB::GetContextForType(TypeIndex ti) { } return ctx; } + +void SymbolFileNativePDB::CacheUdtDeclarations() { + for (CVType cvt : m_index->ipi().typeArray()) { +switch (cvt.kind()) { +case LF_UDT_SRC_LINE: { + UdtSourceLineRecord udt_src; + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_src)); + m_udt_declarations.try_emplace( + udt_src.UDT, UdtDeclaration{/*FileNameIndex=*/udt_src.SourceFile, + /*IsIpiIndex=*/true, + /*Line=*/udt_src.LineNumber}); +} break; +case LF_UDT_MOD_SRC_LINE: { + UdtModSourceLineRecord udt_mod_src; + llvm::cantFail(TypeDeserializer::deserializeAs(cvt, udt_mod_src)); + // Some types might be contributed by multiple modules. We assume that + // they all point to the same file and line because we can only provide + // one location. + m_udt_declarations.try_emplace( + udt_mod_src.UDT, + UdtDeclaration{/*FileNameIndex=*/udt_mod_src.SourceFile, + /*IsIpiIndex=*/false, + /*Line=*/udt_mod_src.LineNumber}); +} break; +default: + break; +} + } +} + +llvm::Expected +SymbolFileNativePDB::ResolveUdtDeclaration(PdbTypeSymId type_id) { + std::call_once(m_cached_udt_declarations, [this] { CacheUdtDeclarations(); }); + + auto it = m_udt_declarations.find(type_id.index); + if (it == m_udt_declarations.end()) +return llvm::createStringError("No UDT declaration found"); + + llvm::StringRef file_name; +
[Lldb-commits] [lldb] b3396c5 - [lldb] Account for registers being host endian when casting values (#150011)
Author: David Spickett Date: 2025-08-13T14:58:29+01:00 New Revision: b3396c5e96f366ba85daf5f6404f18eb8a467aea URL: https://github.com/llvm/llvm-project/commit/b3396c5e96f366ba85daf5f6404f18eb8a467aea DIFF: https://github.com/llvm/llvm-project/commit/b3396c5e96f366ba85daf5f6404f18eb8a467aea.diff LOG: [lldb] Account for registers being host endian when casting values (#150011) Fixes https://github.com/llvm/llvm-project/issues/135707 Follow up to https://github.com/llvm/llvm-project/pull/148836 which fixed some of this issue but not all of it. Our Value/ValueObject system does not store the endian directly in the values. Instead it assumes that the endian of the result of a cast can be assumed to be the target's endian, or the host but only as a fallback. It assumes the place it is copying from is also that endian. This breaks down when you have register values. These are always host endian and continue to be when cast. Casting them to big endian when on a little endian host breaks certain calls like GetValueAsUnsigned. To fix this, check the context of the value. If it has a register context, always treat it as host endian and make the result host endian. I had an alternative where I passed an "is_register" flag into all calls to this, but it felt like a layering violation and changed many more lines. This solution isn't much more robust, but it works for all the test cases I know of. Perhaps you can create a register value without a RegisterInfo backing it, but I don't know of a way myself. For testing, I had to add a minimal program file for each arch so that there is a type system to support the casting. This is generated from YAML since we only need the machine and endian to be set. Added: Modified: lldb/source/Core/Value.cpp lldb/test/API/commands/expression/TestRegisterExpressionEndian.py Removed: diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp index 028f0587c5790..86327e3a57334 100644 --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -488,9 +488,11 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { - Target *target = exe_ctx->GetTargetPtr(); - if (target) { -data.SetByteOrder(target->GetArchitecture().GetByteOrder()); + if (Target *target = exe_ctx->GetTargetPtr()) { +// Registers are always stored in host endian. +data.SetByteOrder(m_context_type == ContextType::RegisterInfo + ? endian::InlHostByteOrder() + : target->GetArchitecture().GetByteOrder()); data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); break; } diff --git a/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py index 66e38df3a9696..d6de8731385b6 100644 --- a/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py +++ b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py @@ -40,9 +40,15 @@ def readRegisters(self): class TestXMLRegisterFlags(GDBRemoteTestBase): def do_endian_test(self, endian): -architecture, pc_reg_name = { -Endian.BIG: ("s390x", "pswa"), -Endian.LITTLE: ("aarch64", "pc"), +architecture, pc_reg_name, yaml_file, data, machine = { +Endian.BIG: ("s390x", "pswa", "s390x.yaml", "ELFDATA2MSB", "EM_S390"), +Endian.LITTLE: ( +"aarch64", +"pc", +"aarch64.yaml", +"ELFDATA2LSB", +"EM_AARCH64", +), }[endian] self.server.responder = Responder( @@ -58,14 +64,35 @@ def do_endian_test(self, endian): ), endian, ) -target = self.dbg.CreateTarget("") + +# We need to have a program file, so that we have a full type system, +# so that we can do the casts later. +obj_path = self.getBuildArtifact("main.o") +yaml_path = self.getBuildArtifact(yaml_file) +with open(yaml_path, "w") as f: +f.write( +dedent( +f"""\ +--- !ELF +FileHeader: + Class:ELFCLASS64 + Data: {data} + Type: ET_REL + Machine: {machine} +... +""" +) +) +self.yaml2obj(yaml_path, obj_path) +target = self.dbg.CreateTarget(obj_path) + process = self.connect(target) lldbutil.expect_state_changes( self, self.dbg.GetListener(), process, [lldb.eStateStopped] ) # If expressions convert registe
[Lldb-commits] [lldb] bfc331e - [lldb] Fix warnings
Author: Kazu Hirata Date: 2025-08-13T09:22:25-07:00 New Revision: bfc331e54407085395b45d1bfb9b04833342acdf URL: https://github.com/llvm/llvm-project/commit/bfc331e54407085395b45d1bfb9b04833342acdf DIFF: https://github.com/llvm/llvm-project/commit/bfc331e54407085395b45d1bfb9b04833342acdf.diff LOG: [lldb] Fix warnings This patch fixes: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp:647:3: error: 'llvm::Expected' may not intend to support class template argument deduction [-Werror,-Wctad-maybe-unsupported] lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp:677:3: error: 'llvm::Expected' may not intend to support class template argument deduction [-Werror,-Wctad-maybe-unsupported] Added: Modified: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp Removed: diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index 337052fc6dbd0..108e439317b76 100644 --- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -644,7 +644,7 @@ SymbolFileNativePDB::CreateClassStructUnion(PdbTypeSymId type_id, std::string uname = GetUnqualifiedTypeName(record); - llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); + llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); Declaration decl; if (maybeDecl) decl = std::move(*maybeDecl); @@ -674,7 +674,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, CompilerType ct) { std::string uname = GetUnqualifiedTypeName(er); - llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); + llvm::Expected maybeDecl = ResolveUdtDeclaration(type_id); Declaration decl; if (maybeDecl) decl = std::move(*maybeDecl); ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 3a36070 - [lldb] Disable JSONTransportTests on Windows. (#153453)
Author: John Harrison Date: 2025-08-13T11:07:03-07:00 New Revision: 3a3607080eade5f8f4a734b9532e99294322783a URL: https://github.com/llvm/llvm-project/commit/3a3607080eade5f8f4a734b9532e99294322783a DIFF: https://github.com/llvm/llvm-project/commit/3a3607080eade5f8f4a734b9532e99294322783a.diff LOG: [lldb] Disable JSONTransportTests on Windows. (#153453) This is to unblock CI. Disabling the tests while I investigate the timeouts. Added: Modified: lldb/unittests/Host/JSONTransportTest.cpp Removed: diff --git a/lldb/unittests/Host/JSONTransportTest.cpp b/lldb/unittests/Host/JSONTransportTest.cpp index cb6da6b1bc677..4e94582d3bc6a 100644 --- a/lldb/unittests/Host/JSONTransportTest.cpp +++ b/lldb/unittests/Host/JSONTransportTest.cpp @@ -132,6 +132,9 @@ class JSONRPCTransportTest : public JSONTransportTest { } // namespace +// Failing on Windows, see https://github.com/llvm/llvm-project/issues/153446. +#ifndef _WIN32 + TEST_F(HTTPDelimitedJSONTransportTest, MalformedRequests) { std::string malformed_header = "COnTent-LenGth: -1\r\nContent-Type: text/json\r\n\r\nnotjosn"; @@ -336,3 +339,5 @@ TEST_F(JSONRPCTransportTest, NoDataTimeout) { RunOnce(/*timeout=*/std::chrono::milliseconds(10)), FailedWithMessage("timeout")); } + +#endif ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/153494 This PR adds support for parsing data symbols from the WebAssembly name section. >From e68b6d31ab7ba418b23c7289e12d0befeb07f6d6 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 13 Aug 2025 13:44:35 -0700 Subject: [PATCH] [lldb] Support parsing data symbols from the Wasm name section This PR adds support for parsing data symbols from the WebAssembly name section. --- .../ObjectFile/wasm/ObjectFileWasm.cpp| 114 ++ 1 file changed, 92 insertions(+), 22 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 919cc21c32ffd..b3144f28f4913 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -251,11 +251,11 @@ bool ObjectFileWasm::ParseHeader() { static llvm::Expected> ParseFunctions(SectionSP code_section_sp) { - DataExtractor code_section_data; - code_section_sp->GetSectionData(code_section_data); + DataExtractor data; + code_section_sp->GetSectionData(data); lldb::offset_t offset = 0; - const uint64_t function_count = code_section_data.GetULEB128(&offset); + const uint64_t function_count = data.GetULEB128(&offset); if (function_count > std::numeric_limits::max()) return llvm::createStringError("function count overflows uint32_t"); @@ -263,7 +263,7 @@ ParseFunctions(SectionSP code_section_sp) { functions.reserve(function_count); for (uint32_t i = 0; i < function_count; ++i) { -const uint64_t function_size = code_section_data.GetULEB128(&offset); +const uint64_t function_size = data.GetULEB128(&offset); if (function_size > std::numeric_limits::max()) return llvm::createStringError("function size overflows uint32_t"); // llvm-objdump considers the ULEB with the function size to be part of the @@ -281,9 +281,45 @@ ParseFunctions(SectionSP code_section_sp) { return functions; } +static llvm::Expected> +ParseData(SectionSP data_section_sp) { + DataExtractor data; + data_section_sp->GetSectionData(data); + + lldb::offset_t offset = 0; + + const uint64_t segment_count = data.GetULEB128(&offset); + if (segment_count > std::numeric_limits::max()) +return llvm::createStringError("segment count overflows uint32_t"); + + std::vector segments; + segments.reserve(segment_count); + + for (uint32_t i = 0; i < segment_count; ++i) { +const uint64_t flags = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment flags overflows uint32_t"); + +const uint64_t segment_size = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment size overflows uint32_t"); + +segments.emplace_back(data_section_sp, offset, segment_size); + +std::optional next_offset = +llvm::checkedAddUnsigned(offset, segment_size); +if (!next_offset) + return llvm::createStringError("segment offset overflows uint64_t"); +offset = *next_offset; + } + + return segments; +} + static llvm::Expected> ParseNames(SectionSP name_section_sp, - const std::vector &functions) { + const std::vector &function_ranges, + const std::vector &segment_ranges) { DataExtractor name_section_data; name_section_sp->GetSectionData(name_section_data); @@ -305,17 +341,34 @@ ParseNames(SectionSP name_section_sp, for (uint64_t i = 0; c && i < count; ++i) { const uint64_t idx = data.getULEB128(c); const std::optional name = GetWasmString(data, c); -if (!name || idx >= functions.size()) +if (!name || idx >= function_ranges.size()) continue; symbols.emplace_back( symbols.size(), Mangled(*name), lldb::eSymbolTypeCode, /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, -/*is_artificial=*/false, functions[idx], +/*is_artificial=*/false, function_ranges[idx], /*size_is_valid=*/true, /*contains_linker_annotations=*/false, /*flags=*/0); } } break; -case llvm::wasm::WASM_NAMES_DATA_SEGMENT: +case llvm::wasm::WASM_NAMES_DATA_SEGMENT: { + const uint64_t count = data.getULEB128(c); + if (count > std::numeric_limits::max()) +return llvm::createStringError("data count overflows uint32_t"); + for (uint64_t i = 0; c && i < count; ++i) { +const uint64_t idx = data.getULEB128(c); +const std::optional name = GetWasmString(data, c); +if (!name || idx >= segment_ranges.size()) + continue; +symbols.emplace_back( +symbols.size(), Mangled(*name), lldb::eSymbolTypeData, +/*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, +/*is_artificial=*/false, segment_ranges[idx], +
[Lldb-commits] [lldb] 36c2a66 - [lldb][test] Make TestFindRangesInMemory.py more robust (#152817)
Author: Igor Kudrin Date: 2025-08-13T14:15:45-07:00 New Revision: 36c2a6696853020ffc0072566b1f5e77efe96d0c URL: https://github.com/llvm/llvm-project/commit/36c2a6696853020ffc0072566b1f5e77efe96d0c DIFF: https://github.com/llvm/llvm-project/commit/36c2a6696853020ffc0072566b1f5e77efe96d0c.diff LOG: [lldb][test] Make TestFindRangesInMemory.py more robust (#152817) `GetHeapRanges()` could return two overlapping ranges because it did not check whether `heap_pointer1` lies within the range returned for `heap_pointer2`. This could result in a test failure in `test_find_ranges_in_memory_two_matches` when `process.FindRangesInMemory()` returned 3 instead of 2. The patch ensures that `GetHeapRanges()` returns either two non-overlapping ranges or one range covering both heap pointers. The issue was probably introduced in #111951 Added: Modified: lldb/test/API/python_api/find_in_memory/address_ranges_helper.py Removed: diff --git a/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py index dcceca6d8a5c5..102f2b0edd4c6 100644 --- a/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py +++ b/lldb/test/API/python_api/find_in_memory/address_ranges_helper.py @@ -55,27 +55,34 @@ def GetRangeFromAddrValue(test_base, addr, shrink=False): return lldb.SBAddressRange(start, size) -def IsWithinRange(addr, size, range, target): -start_addr = range.GetBaseAddress().GetLoadAddress(target) -end_addr = start_addr + range.GetByteSize() -addr = addr.GetValueAsUnsigned() -return addr >= start_addr and addr + size <= end_addr - - def GetHeapRanges(test_base, shrink=False): frame = test_base.thread.GetSelectedFrame() ex = frame.EvaluateExpression("heap_pointer1") test_base.assertTrue(ex.IsValid()) -range = GetRangeFromAddrValue(test_base, ex, shrink) -addr_ranges = lldb.SBAddressRangeList() -addr_ranges.Append(range) +range1 = GetRangeFromAddrValue(test_base, ex, shrink) +range1_start = range1.GetBaseAddress().GetLoadAddress(test_base.target) +range1_end = range1_start + range1.GetByteSize() ex = frame.EvaluateExpression("heap_pointer2") test_base.assertTrue(ex.IsValid()) -size = len(DOUBLE_INSTANCE_PATTERN_HEAP) -if not IsWithinRange(ex, size, addr_ranges[0], test_base.target): -addr_ranges.Append(GetRangeFromAddrValue(test_base, ex, shrink)) +range2 = GetRangeFromAddrValue(test_base, ex, shrink) +range2_start = range2.GetBaseAddress().GetLoadAddress(test_base.target) +range2_end = range2_start + range2.GetByteSize() + +addr_ranges = lldb.SBAddressRangeList() + +if range1_end < range2_start or range2_end < range1_start: +# The ranges do not overlap; add them both. +addr_ranges.Append(range1) +addr_ranges.Append(range2) +else: +# Merge overlapping ranges. +base = min(range1_start, range2_start) +end = max(range1_end, range2_end) +start = lldb.SBAddress(base, test_base.target) +size = end - base +addr_ranges.Append(lldb.SBAddressRange(start, size)) return addr_ranges ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][test] Make TestFindRangesInMemory.py more robust (PR #152817)
https://github.com/igorkudrin closed https://github.com/llvm/llvm-project/pull/152817 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/153494 >From b12ff1822eaafa93cc818ccaca22d3b59106dbb8 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 13 Aug 2025 13:44:35 -0700 Subject: [PATCH] [lldb] Support parsing data symbols from the Wasm name section This PR adds support for parsing data symbols from the WebAssembly name section. --- .../ObjectFile/wasm/ObjectFileWasm.cpp| 114 ++ .../test/Shell/Symtab/Inputs/simple.wasm.yaml | 97 --- lldb/test/Shell/Symtab/symtab-wasm.test | 10 +- 3 files changed, 176 insertions(+), 45 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 919cc21c32ffd..b3144f28f4913 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -251,11 +251,11 @@ bool ObjectFileWasm::ParseHeader() { static llvm::Expected> ParseFunctions(SectionSP code_section_sp) { - DataExtractor code_section_data; - code_section_sp->GetSectionData(code_section_data); + DataExtractor data; + code_section_sp->GetSectionData(data); lldb::offset_t offset = 0; - const uint64_t function_count = code_section_data.GetULEB128(&offset); + const uint64_t function_count = data.GetULEB128(&offset); if (function_count > std::numeric_limits::max()) return llvm::createStringError("function count overflows uint32_t"); @@ -263,7 +263,7 @@ ParseFunctions(SectionSP code_section_sp) { functions.reserve(function_count); for (uint32_t i = 0; i < function_count; ++i) { -const uint64_t function_size = code_section_data.GetULEB128(&offset); +const uint64_t function_size = data.GetULEB128(&offset); if (function_size > std::numeric_limits::max()) return llvm::createStringError("function size overflows uint32_t"); // llvm-objdump considers the ULEB with the function size to be part of the @@ -281,9 +281,45 @@ ParseFunctions(SectionSP code_section_sp) { return functions; } +static llvm::Expected> +ParseData(SectionSP data_section_sp) { + DataExtractor data; + data_section_sp->GetSectionData(data); + + lldb::offset_t offset = 0; + + const uint64_t segment_count = data.GetULEB128(&offset); + if (segment_count > std::numeric_limits::max()) +return llvm::createStringError("segment count overflows uint32_t"); + + std::vector segments; + segments.reserve(segment_count); + + for (uint32_t i = 0; i < segment_count; ++i) { +const uint64_t flags = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment flags overflows uint32_t"); + +const uint64_t segment_size = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment size overflows uint32_t"); + +segments.emplace_back(data_section_sp, offset, segment_size); + +std::optional next_offset = +llvm::checkedAddUnsigned(offset, segment_size); +if (!next_offset) + return llvm::createStringError("segment offset overflows uint64_t"); +offset = *next_offset; + } + + return segments; +} + static llvm::Expected> ParseNames(SectionSP name_section_sp, - const std::vector &functions) { + const std::vector &function_ranges, + const std::vector &segment_ranges) { DataExtractor name_section_data; name_section_sp->GetSectionData(name_section_data); @@ -305,17 +341,34 @@ ParseNames(SectionSP name_section_sp, for (uint64_t i = 0; c && i < count; ++i) { const uint64_t idx = data.getULEB128(c); const std::optional name = GetWasmString(data, c); -if (!name || idx >= functions.size()) +if (!name || idx >= function_ranges.size()) continue; symbols.emplace_back( symbols.size(), Mangled(*name), lldb::eSymbolTypeCode, /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, -/*is_artificial=*/false, functions[idx], +/*is_artificial=*/false, function_ranges[idx], /*size_is_valid=*/true, /*contains_linker_annotations=*/false, /*flags=*/0); } } break; -case llvm::wasm::WASM_NAMES_DATA_SEGMENT: +case llvm::wasm::WASM_NAMES_DATA_SEGMENT: { + const uint64_t count = data.getULEB128(c); + if (count > std::numeric_limits::max()) +return llvm::createStringError("data count overflows uint32_t"); + for (uint64_t i = 0; c && i < count; ++i) { +const uint64_t idx = data.getULEB128(c); +const std::optional name = GetWasmString(data, c); +if (!name || idx >= segment_ranges.size()) + continue; +symbols.emplace_back( +symbols.size(), Mangled(*name), lldb::eSymbolTypeData, +/*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, +/*is_a
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) Changes This PR adds support for parsing data symbols from the WebAssembly name section. --- Full diff: https://github.com/llvm/llvm-project/pull/153494.diff 3 Files Affected: - (modified) lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp (+92-22) - (modified) lldb/test/Shell/Symtab/Inputs/simple.wasm.yaml (+78-19) - (modified) lldb/test/Shell/Symtab/symtab-wasm.test (+6-4) ``diff diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 919cc21c32ffd..b3144f28f4913 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -251,11 +251,11 @@ bool ObjectFileWasm::ParseHeader() { static llvm::Expected> ParseFunctions(SectionSP code_section_sp) { - DataExtractor code_section_data; - code_section_sp->GetSectionData(code_section_data); + DataExtractor data; + code_section_sp->GetSectionData(data); lldb::offset_t offset = 0; - const uint64_t function_count = code_section_data.GetULEB128(&offset); + const uint64_t function_count = data.GetULEB128(&offset); if (function_count > std::numeric_limits::max()) return llvm::createStringError("function count overflows uint32_t"); @@ -263,7 +263,7 @@ ParseFunctions(SectionSP code_section_sp) { functions.reserve(function_count); for (uint32_t i = 0; i < function_count; ++i) { -const uint64_t function_size = code_section_data.GetULEB128(&offset); +const uint64_t function_size = data.GetULEB128(&offset); if (function_size > std::numeric_limits::max()) return llvm::createStringError("function size overflows uint32_t"); // llvm-objdump considers the ULEB with the function size to be part of the @@ -281,9 +281,45 @@ ParseFunctions(SectionSP code_section_sp) { return functions; } +static llvm::Expected> +ParseData(SectionSP data_section_sp) { + DataExtractor data; + data_section_sp->GetSectionData(data); + + lldb::offset_t offset = 0; + + const uint64_t segment_count = data.GetULEB128(&offset); + if (segment_count > std::numeric_limits::max()) +return llvm::createStringError("segment count overflows uint32_t"); + + std::vector segments; + segments.reserve(segment_count); + + for (uint32_t i = 0; i < segment_count; ++i) { +const uint64_t flags = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment flags overflows uint32_t"); + +const uint64_t segment_size = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment size overflows uint32_t"); + +segments.emplace_back(data_section_sp, offset, segment_size); + +std::optional next_offset = +llvm::checkedAddUnsigned(offset, segment_size); +if (!next_offset) + return llvm::createStringError("segment offset overflows uint64_t"); +offset = *next_offset; + } + + return segments; +} + static llvm::Expected> ParseNames(SectionSP name_section_sp, - const std::vector &functions) { + const std::vector &function_ranges, + const std::vector &segment_ranges) { DataExtractor name_section_data; name_section_sp->GetSectionData(name_section_data); @@ -305,17 +341,34 @@ ParseNames(SectionSP name_section_sp, for (uint64_t i = 0; c && i < count; ++i) { const uint64_t idx = data.getULEB128(c); const std::optional name = GetWasmString(data, c); -if (!name || idx >= functions.size()) +if (!name || idx >= function_ranges.size()) continue; symbols.emplace_back( symbols.size(), Mangled(*name), lldb::eSymbolTypeCode, /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, -/*is_artificial=*/false, functions[idx], +/*is_artificial=*/false, function_ranges[idx], /*size_is_valid=*/true, /*contains_linker_annotations=*/false, /*flags=*/0); } } break; -case llvm::wasm::WASM_NAMES_DATA_SEGMENT: +case llvm::wasm::WASM_NAMES_DATA_SEGMENT: { + const uint64_t count = data.getULEB128(c); + if (count > std::numeric_limits::max()) +return llvm::createStringError("data count overflows uint32_t"); + for (uint64_t i = 0; c && i < count; ++i) { +const uint64_t idx = data.getULEB128(c); +const std::optional name = GetWasmString(data, c); +if (!name || idx >= segment_ranges.size()) + continue; +symbols.emplace_back( +symbols.size(), Mangled(*name), lldb::eSymbolTypeData, +/*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, +/*is_artificial=*/false, segment_ranges[idx], +/*size_is_valid=*/true, /*contains_linker_annotations=*/false, +/*flags=*/0); +
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/153494 >From 2d0a3dad2321cdd34dca93919fab0dd9f0e9ed4f Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Wed, 13 Aug 2025 13:44:35 -0700 Subject: [PATCH] [lldb] Support parsing data symbols from the Wasm name section This PR adds support for parsing data symbols from the WebAssembly name section. --- .../ObjectFile/wasm/ObjectFileWasm.cpp| 114 ++ .../test/Shell/Symtab/Inputs/simple.wasm.yaml | 82 ++--- lldb/test/Shell/Symtab/symtab-wasm.test | 10 +- 3 files changed, 161 insertions(+), 45 deletions(-) diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 919cc21c32ffd..b3144f28f4913 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -251,11 +251,11 @@ bool ObjectFileWasm::ParseHeader() { static llvm::Expected> ParseFunctions(SectionSP code_section_sp) { - DataExtractor code_section_data; - code_section_sp->GetSectionData(code_section_data); + DataExtractor data; + code_section_sp->GetSectionData(data); lldb::offset_t offset = 0; - const uint64_t function_count = code_section_data.GetULEB128(&offset); + const uint64_t function_count = data.GetULEB128(&offset); if (function_count > std::numeric_limits::max()) return llvm::createStringError("function count overflows uint32_t"); @@ -263,7 +263,7 @@ ParseFunctions(SectionSP code_section_sp) { functions.reserve(function_count); for (uint32_t i = 0; i < function_count; ++i) { -const uint64_t function_size = code_section_data.GetULEB128(&offset); +const uint64_t function_size = data.GetULEB128(&offset); if (function_size > std::numeric_limits::max()) return llvm::createStringError("function size overflows uint32_t"); // llvm-objdump considers the ULEB with the function size to be part of the @@ -281,9 +281,45 @@ ParseFunctions(SectionSP code_section_sp) { return functions; } +static llvm::Expected> +ParseData(SectionSP data_section_sp) { + DataExtractor data; + data_section_sp->GetSectionData(data); + + lldb::offset_t offset = 0; + + const uint64_t segment_count = data.GetULEB128(&offset); + if (segment_count > std::numeric_limits::max()) +return llvm::createStringError("segment count overflows uint32_t"); + + std::vector segments; + segments.reserve(segment_count); + + for (uint32_t i = 0; i < segment_count; ++i) { +const uint64_t flags = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment flags overflows uint32_t"); + +const uint64_t segment_size = data.GetULEB128(&offset); +if (flags > std::numeric_limits::max()) + return llvm::createStringError("segment size overflows uint32_t"); + +segments.emplace_back(data_section_sp, offset, segment_size); + +std::optional next_offset = +llvm::checkedAddUnsigned(offset, segment_size); +if (!next_offset) + return llvm::createStringError("segment offset overflows uint64_t"); +offset = *next_offset; + } + + return segments; +} + static llvm::Expected> ParseNames(SectionSP name_section_sp, - const std::vector &functions) { + const std::vector &function_ranges, + const std::vector &segment_ranges) { DataExtractor name_section_data; name_section_sp->GetSectionData(name_section_data); @@ -305,17 +341,34 @@ ParseNames(SectionSP name_section_sp, for (uint64_t i = 0; c && i < count; ++i) { const uint64_t idx = data.getULEB128(c); const std::optional name = GetWasmString(data, c); -if (!name || idx >= functions.size()) +if (!name || idx >= function_ranges.size()) continue; symbols.emplace_back( symbols.size(), Mangled(*name), lldb::eSymbolTypeCode, /*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, -/*is_artificial=*/false, functions[idx], +/*is_artificial=*/false, function_ranges[idx], /*size_is_valid=*/true, /*contains_linker_annotations=*/false, /*flags=*/0); } } break; -case llvm::wasm::WASM_NAMES_DATA_SEGMENT: +case llvm::wasm::WASM_NAMES_DATA_SEGMENT: { + const uint64_t count = data.getULEB128(c); + if (count > std::numeric_limits::max()) +return llvm::createStringError("data count overflows uint32_t"); + for (uint64_t i = 0; c && i < count; ++i) { +const uint64_t idx = data.getULEB128(c); +const std::optional name = GetWasmString(data, c); +if (!name || idx >= segment_ranges.size()) + continue; +symbols.emplace_back( +symbols.size(), Mangled(*name), lldb::eSymbolTypeData, +/*external=*/false, /*is_debug=*/false, /*is_trampoline=*/false, +/*is_art
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
https://github.com/JDevlieghere ready_for_review https://github.com/llvm/llvm-project/pull/153494 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
cs01 wrote: @labath Is there anything else needed of me? Looks like there are workflows awaiting approval still. https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/153121 >From 572e2caaff35bb0bed0dc56487cca7ffeeab2b5f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 7 Aug 2025 08:56:11 -0700 Subject: [PATCH] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. This abstracts the base Transport handler to have a MessageHandler component and allows us to generalize both JSON-RPC 2.0 for MCP (or an LSP) and DAP format. This should allow us to create clearly defined clients and servers for protocols, both for testing and for RPC between the lldb instances and an lldb-mcp multiplexer. This basic model is inspiried by the clangd/Transport.h file and the mlir/lsp-server-support/Transport.h that are both used for LSP servers within the llvm project. --- lldb/include/lldb/Host/JSONTransport.h| 324 ++- lldb/source/Host/common/JSONTransport.cpp | 116 +- lldb/source/Protocol/MCP/Protocol.cpp | 1 + lldb/tools/lldb-dap/DAP.cpp | 177 lldb/tools/lldb-dap/DAP.h | 25 +- lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 4 + lldb/tools/lldb-dap/Transport.cpp | 5 +- lldb/tools/lldb-dap/Transport.h | 5 +- lldb/tools/lldb-dap/tool/lldb-dap.cpp | 20 +- lldb/unittests/DAP/DAPTest.cpp| 16 +- lldb/unittests/DAP/Handler/DisconnectTest.cpp | 20 +- lldb/unittests/DAP/TestBase.cpp | 48 +-- lldb/unittests/DAP/TestBase.h | 91 +++-- lldb/unittests/Host/JSONTransportTest.cpp | 382 +++--- .../ProtocolServer/ProtocolMCPServerTest.cpp | 174 15 files changed, 765 insertions(+), 643 deletions(-) diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h index 72f4404c92887..18126f599c380 100644 --- a/lldb/include/lldb/Host/JSONTransport.h +++ b/lldb/include/lldb/Host/JSONTransport.h @@ -13,29 +13,25 @@ #ifndef LLDB_HOST_JSONTRANSPORT_H #define LLDB_HOST_JSONTRANSPORT_H +#include "lldb/Host/MainLoop.h" #include "lldb/Host/MainLoopBase.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" #include #include +#include #include namespace lldb_private { -class TransportEOFError : public llvm::ErrorInfo { -public: - static char ID; - - TransportEOFError() = default; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; -}; - class TransportUnhandledContentsError : public llvm::ErrorInfo { public: @@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTranspo
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,219 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - messages will not be sent concurrently +/// - messages MAY be sent while Run() is reading, or its callback is active ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/153121 >From d5f998c50d3188fc9eeb94ce80e4d4dfd15d6790 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 7 Aug 2025 08:56:11 -0700 Subject: [PATCH] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. This abstracts the base Transport handler to have a MessageHandler component and allows us to generalize both JSON-RPC 2.0 for MCP (or an LSP) and DAP format. This should allow us to create clearly defined clients and servers for protocols, both for testing and for RPC between the lldb instances and an lldb-mcp multiplexer. This basic model is inspiried by the clangd/Transport.h file and the mlir/lsp-server-support/Transport.h that are both used for LSP servers within the llvm project. --- lldb/include/lldb/Host/JSONTransport.h| 324 ++- lldb/source/Host/common/JSONTransport.cpp | 116 +- lldb/source/Protocol/MCP/Protocol.cpp | 1 + lldb/tools/lldb-dap/DAP.cpp | 177 lldb/tools/lldb-dap/DAP.h | 25 +- lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 4 + lldb/tools/lldb-dap/Transport.cpp | 5 +- lldb/tools/lldb-dap/Transport.h | 5 +- lldb/tools/lldb-dap/tool/lldb-dap.cpp | 21 +- lldb/unittests/DAP/DAPTest.cpp| 16 +- lldb/unittests/DAP/Handler/DisconnectTest.cpp | 20 +- lldb/unittests/DAP/TestBase.cpp | 48 +-- lldb/unittests/DAP/TestBase.h | 91 +++-- lldb/unittests/Host/JSONTransportTest.cpp | 382 +++--- .../ProtocolServer/ProtocolMCPServerTest.cpp | 174 15 files changed, 765 insertions(+), 644 deletions(-) diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h index 72f4404c92887..18126f599c380 100644 --- a/lldb/include/lldb/Host/JSONTransport.h +++ b/lldb/include/lldb/Host/JSONTransport.h @@ -13,29 +13,25 @@ #ifndef LLDB_HOST_JSONTRANSPORT_H #define LLDB_HOST_JSONTRANSPORT_H +#include "lldb/Host/MainLoop.h" #include "lldb/Host/MainLoopBase.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" #include #include +#include #include namespace lldb_private { -class TransportEOFError : public llvm::ErrorInfo { -public: - static char ID; - - TransportEOFError() = default; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; -}; - class TransportUnhandledContentsError : public llvm::ErrorInfo { public: @@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTranspo
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,219 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - messages will not be sent concurrently +/// - messages MAY be sent while Run() is reading, or its callback is active +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remaining messages w
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -23,41 +24,59 @@ namespace lldb_protocol::mcp { static llvm::StringLiteral kProtocolVersion = "2024-11-05"; +/// A Request or Response 'id'. +using Id = std::variant; + /// A request that expects a response. struct Request { - uint64_t id = 0; + Id id; // Per the spec, this must be a string or number. ashgti wrote: Done, also moved these changes into #153297 https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -62,6 +62,7 @@ class TestFile { template static llvm::Expected roundtripJSON(const T &input) { llvm::json::Value value = toJSON(input); + llvm::errs() << "JSON: " << value << "\n"; ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
ashgti wrote: Rebased on main with #153297 included and reverted the comment changes. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
https://github.com/JDevlieghere auto_merge_enabled https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
JDevlieghere wrote: > @labath Is there anything else needed of me? Looks like there are workflows > awaiting approval still. I ran them and enabled auto-merge so this PR will get merged automatically if everything passes. https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
https://github.com/JDevlieghere approved this pull request. Left some comments with nits but besides that LGTM. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -258,36 +259,33 @@ void DAP::SendJSON(const llvm::json::Value &json) { llvm::json::Path::Root root; if (!fromJSON(json, message, root)) { DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}", - transport.GetClientName()); + m_client_name); return; } Send(message); } void DAP::Send(const Message &message) { - // FIXME: After all the requests have migrated from LegacyRequestHandler > - // RequestHandler<> this should be handled in RequestHandler<>::operator(). - if (auto *resp = std::get_if(&message); - resp && debugger.InterruptRequested()) { -// Clear the interrupt request. -debugger.CancelInterruptRequest(); - -// If the debugger was interrupted, convert this response into a 'cancelled' -// response because we might have a partial result. -Response cancelled{/*request_seq=*/resp->request_seq, - /*command=*/resp->command, - /*success=*/false, - /*message=*/eResponseMessageCancelled, - /*body=*/std::nullopt}; -if (llvm::Error err = transport.Write(cancelled)) - DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}", -transport.GetClientName()); -return; + if (const protocol::Event *event = std::get_if(&message)) { +transport.Event(*event); + } else if (const Request *req = std::get_if(&message)) { +transport.Request(*req); + } else if (const Response *resp = std::get_if(&message)) { +// FIXME: After all the requests have migrated from LegacyRequestHandler > +// RequestHandler<> this should be handled in RequestHandler<>::operator(). +if (debugger.InterruptRequested()) + // If the debugger was interrupted, convert this response into a + // 'cancelled' response because we might have a partial result. + transport.Response(Response{/*request_seq=*/resp->request_seq, + /*command=*/resp->command, + /*success=*/false, + /*message=*/eResponseMessageCancelled, + /*body=*/std::nullopt}); +else + transport.Response(*resp); JDevlieghere wrote: According to the style guide, this does require braces: ```suggestion if (debugger.InterruptRequested()) { // If the debugger was interrupted, convert this response into a // 'cancelled' response because we might have a partial result. transport.Response(Response{/*request_seq=*/resp->request_seq, /*command=*/resp->command, /*success=*/false, /*message=*/eResponseMessageCancelled, /*body=*/std::nullopt}); } else { transport.Response(*resp); } ``` https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -344,13 +346,14 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, bool client_failed = false; { std::scoped_lock lock(dap_sessions_mutex); -for (auto [sock, dap] : dap_sessions) { +for (auto [loop, dap] : dap_sessions) { if (llvm::Error error = dap->Disconnect()) { client_failed = true; -llvm::errs() << "DAP client " << dap->transport.GetClientName() - << " disconnected failed: " +llvm::errs() << "DAP client disconnected failed: " JDevlieghere wrote: Since you're here: ```suggestion WithColor::error() << "DAP client disconnected failed: " ``` https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -938,88 +933,74 @@ void DAP::ClearCancelRequest(const CancelArguments &args) { } template -static std::optional getArgumentsIfRequest(const Message &pm, +static std::optional getArgumentsIfRequest(const Request &req, llvm::StringLiteral command) { - auto *const req = std::get_if(&pm); - if (!req || req->command != command) + if (req.command != command) return std::nullopt; T args; llvm::json::Path::Root root; - if (!fromJSON(req->arguments, args, root)) + if (!fromJSON(req.arguments, args, root)) return std::nullopt; return args; } -Status DAP::TransportHandler() { - llvm::set_thread_name(transport.GetClientName() + ".transport_handler"); +void DAP::OnEvent(const protocol::Event &event) { + // no-op, no supported events from the client to the server as of DAP v1.68. +} - auto cleanup = llvm::make_scope_exit([&]() { -// Ensure we're marked as disconnecting when the reader exits. +void DAP::OnRequest(const protocol::Request &request) { + if (request.command == "disconnect") disconnecting = true; -m_queue_cv.notify_all(); - }); - Status status; - auto handle = transport.RegisterReadObject( - m_loop, - [&](MainLoopBase &loop, llvm::Expected message) { -if (message.errorIsA()) { - llvm::consumeError(message.takeError()); - loop.RequestTermination(); - return; -} + const std::optional cancel_args = + getArgumentsIfRequest(request, "cancel"); + if (cancel_args) { +{ + std::lock_guard guard(m_cancelled_requests_mutex); + if (cancel_args->requestId) +m_cancelled_requests.insert(*cancel_args->requestId); +} -if (llvm::Error err = message.takeError()) { - status = Status::FromError(std::move(err)); - loop.RequestTermination(); - return; -} +// If a cancel is requested for the active request, make a best +// effort attempt to interrupt. +std::lock_guard guard(m_active_request_mutex); +if (m_active_request && cancel_args->requestId == m_active_request->seq) { + DAP_LOG(log, "({0}) interrupting inflight request (command={1} seq={2})", + m_client_name, m_active_request->command, m_active_request->seq); + debugger.RequestInterrupt(); +} + } -if (const protocol::Request *req = -std::get_if(&*message); -req && req->arguments == "disconnect") - disconnecting = true; - -const std::optional cancel_args = -getArgumentsIfRequest(*message, "cancel"); -if (cancel_args) { - { -std::lock_guard guard(m_cancelled_requests_mutex); -if (cancel_args->requestId) - m_cancelled_requests.insert(*cancel_args->requestId); - } + std::lock_guard guard(m_queue_mutex); + DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, + request.command, request.seq); + m_queue.push_back(request); + m_queue_cv.notify_one(); +} - // If a cancel is requested for the active request, make a best - // effort attempt to interrupt. - std::lock_guard guard(m_active_request_mutex); - if (m_active_request && - cancel_args->requestId == m_active_request->seq) { -DAP_LOG(log, -"({0}) interrupting inflight request (command={1} seq={2})", -transport.GetClientName(), m_active_request->command, -m_active_request->seq); -debugger.RequestInterrupt(); - } -} +void DAP::OnResponse(const protocol::Response &response) { + std::lock_guard guard(m_queue_mutex); + DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, + response.command, response.request_seq); + m_queue.push_back(response); + m_queue_cv.notify_one(); +} -std::lock_guard guard(m_queue_mutex); -m_queue.push_back(std::move(*message)); -m_queue_cv.notify_one(); - }); - if (auto err = handle.takeError()) -return Status::FromError(std::move(err)); - if (llvm::Error err = m_loop.Run().takeError()) -return Status::FromError(std::move(err)); - return status; +void DAP::TransportHandler(llvm::Error *error) { + llvm::ErrorAsOutParameter ErrAsOutParam(*error); + auto cleanup = llvm::make_scope_exit([&]() { +// Ensure we're marked as disconnecting when the reader exits. +disconnecting = true; JDevlieghere wrote: I know this was already there, but technically we're racing on `disconnecting` here. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Support parsing data symbols from the Wasm name section (PR #153494)
https://github.com/adrian-prantl approved this pull request. https://github.com/llvm/llvm-project/pull/153494 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] bcb48aa - [lldb] refactor PlatformAndroid and make threadsafe (#145382)
Author: Chad Smith Date: 2025-08-13T22:43:45Z New Revision: bcb48aa5b2cfc75967c734a97201e0c91273169d URL: https://github.com/llvm/llvm-project/commit/bcb48aa5b2cfc75967c734a97201e0c91273169d DIFF: https://github.com/llvm/llvm-project/commit/bcb48aa5b2cfc75967c734a97201e0c91273169d.diff LOG: [lldb] refactor PlatformAndroid and make threadsafe (#145382) ## Problem When the new setting ``` set target.parallel-module-load true ``` was added, lldb began fetching modules from the devices from multiple threads simultaneously. This caused crashes of lldb when debugging on android devices. The top of the stack in the crash look something like this: ``` #0 0x555aaf2b27fe llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/opt/llvm/bin/lldb-dap+0xb87fe) #1 0x555aaf2b0a99 llvm::sys::RunSignalHandlers() (/opt/llvm/bin/lldb-dap+0xb6a99) #2 0x555aaf2b2fda SignalHandler(int, siginfo_t*, void*) (/opt/llvm/bin/lldb-dap+0xb8fda) #3 0x7f9c02444560 __restore_rt /home/engshare/third-party2/glibc/2.34/src/glibc-2.34/signal/../sysdeps/unix/sysv/linux/libc_sigaction.c:13:0 #4 0x7f9c04ea7707 lldb_private::ConnectionFileDescriptor::Disconnect(lldb_private::Status*) (usr/bin/../lib/liblldb.so.15+0x22a7707) #5 0x7f9c04ea5b41 lldb_private::ConnectionFileDescriptor::~ConnectionFileDescriptor() (usr/bin/../lib/liblldb.so.15+0x22a5b41) #6 0x7f9c04ea5c1e lldb_private::ConnectionFileDescriptor::~ConnectionFileDescriptor() (usr/bin/../lib/liblldb.so.15+0x22a5c1e) #7 0x7f9c052916ff lldb_private::platform_android::AdbClient::SyncService::Stat(lldb_private::FileSpec const&, unsigned int&, unsigned int&, unsigned int&) (usr/bin/../lib/liblldb.so.15+0x26916ff) #8 0x7f9c0528b9dc lldb_private::platform_android::PlatformAndroid::GetFile(lldb_private::FileSpec const&, lldb_private::FileSpec const&) (usr/bin/../lib/liblldb.so.15+0x268b9dc) ``` Our workaround was to set `set target.parallel-module-load ` to `false` to avoid the crash. ## Background PlatformAndroid creates two different classes with one stateful adb connection shared between the two -- one through AdbClient and another through AdbClient::SyncService. The connection management and state is complex, and seems to be responsible for the segfault we are seeing. The AdbClient code resets these connections at times, and re-establishes connections if they are not active. Similarly, PlatformAndroid caches its SyncService, which uses an AdbClient class, but the SyncService puts its connection into a different 'sync' state that is incompatible with a standard connection. ## Changes in this diff * This diff refactors the code to (hopefully) have clearer ownership of the connection, clearer separation of AdbClient and SyncService by making a new class for clearer separations of concerns, called AdbSyncService. * New unit tests are added * Additional logs were added (see https://github.com/llvm/llvm-project/pull/145382#issuecomment-3055535017 for details) Added: Modified: lldb/source/Plugins/Platform/Android/AdbClient.cpp lldb/source/Plugins/Platform/Android/AdbClient.h lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp lldb/source/Plugins/Platform/Android/PlatformAndroid.h lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp lldb/unittests/Platform/Android/AdbClientTest.cpp lldb/unittests/Platform/Android/PlatformAndroidTest.cpp Removed: diff --git a/lldb/source/Plugins/Platform/Android/AdbClient.cpp b/lldb/source/Plugins/Platform/Android/AdbClient.cpp index a179260ca15f6..0fbb48a2e16a0 100644 --- a/lldb/source/Plugins/Platform/Android/AdbClient.cpp +++ b/lldb/source/Plugins/Platform/Android/AdbClient.cpp @@ -8,61 +8,48 @@ #include "AdbClient.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/FileUtilities.h" - #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" -#include "lldb/Host/PosixApi.h" -#include "lldb/Utility/DataBuffer.h" -#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Connection.h" #include "lldb/Utility/DataEncoder.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timeout.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/FileUtilities.h" +#include #include - -#include #include #include #include -// On Windows, transitive dependencies pull in , which defines a -// macro that clashes with a method name. -#ifdef SendMessage -#undef SendMessage -#endif - using namespace lldb; using namespace lldb_private; using namespace lldb_private::platform_android; using namespace std::chrono; +usi
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
https://github.com/JDevlieghere closed https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
github-actions[bot] wrote: @cs01 Congratulations on having your first Pull Request (PR) merged into the LLVM Project! Your changes will be combined with recent changes from other authors, then tested by our [build bots](https://lab.llvm.org/buildbot/). If there is a problem with a build, you may receive a report in an email or a comment on this PR. Please check whether problems have been caused by your change specifically, as the builds can include changes from many authors. It is not uncommon for your change to be included in a build that fails due to someone else's changes, or infrastructure issues. How to do this, and the rest of the post-merge process, is covered in detail [here](https://llvm.org/docs/MyFirstTypoFix.html#myfirsttypofix-issues-after-landing-your-pr). If your change does cause a problem, it may be reverted, or you can revert it yourself. This is a normal part of [LLVM development](https://llvm.org/docs/DeveloperPolicy.html#patch-reversion-policy). You can fix your changes and open a new PR to merge them again. If you don't get any reports, no action is required from you. Your changes are working as expected, well done! https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb-dap] Migrating 'completions' to structured types. (PR #153317)
https://github.com/eronnen approved this pull request. https://github.com/llvm/llvm-project/pull/153317 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/153121 >From d5f998c50d3188fc9eeb94ce80e4d4dfd15d6790 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 7 Aug 2025 08:56:11 -0700 Subject: [PATCH 1/2] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. This abstracts the base Transport handler to have a MessageHandler component and allows us to generalize both JSON-RPC 2.0 for MCP (or an LSP) and DAP format. This should allow us to create clearly defined clients and servers for protocols, both for testing and for RPC between the lldb instances and an lldb-mcp multiplexer. This basic model is inspiried by the clangd/Transport.h file and the mlir/lsp-server-support/Transport.h that are both used for LSP servers within the llvm project. --- lldb/include/lldb/Host/JSONTransport.h| 324 ++- lldb/source/Host/common/JSONTransport.cpp | 116 +- lldb/source/Protocol/MCP/Protocol.cpp | 1 + lldb/tools/lldb-dap/DAP.cpp | 177 lldb/tools/lldb-dap/DAP.h | 25 +- lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 4 + lldb/tools/lldb-dap/Transport.cpp | 5 +- lldb/tools/lldb-dap/Transport.h | 5 +- lldb/tools/lldb-dap/tool/lldb-dap.cpp | 21 +- lldb/unittests/DAP/DAPTest.cpp| 16 +- lldb/unittests/DAP/Handler/DisconnectTest.cpp | 20 +- lldb/unittests/DAP/TestBase.cpp | 48 +-- lldb/unittests/DAP/TestBase.h | 91 +++-- lldb/unittests/Host/JSONTransportTest.cpp | 382 +++--- .../ProtocolServer/ProtocolMCPServerTest.cpp | 174 15 files changed, 765 insertions(+), 644 deletions(-) diff --git a/lldb/include/lldb/Host/JSONTransport.h b/lldb/include/lldb/Host/JSONTransport.h index 72f4404c92887..18126f599c380 100644 --- a/lldb/include/lldb/Host/JSONTransport.h +++ b/lldb/include/lldb/Host/JSONTransport.h @@ -13,29 +13,25 @@ #ifndef LLDB_HOST_JSONTRANSPORT_H #define LLDB_HOST_JSONTRANSPORT_H +#include "lldb/Host/MainLoop.h" #include "lldb/Host/MainLoopBase.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-forward.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" #include #include +#include #include namespace lldb_private { -class TransportEOFError : public llvm::ErrorInfo { -public: - static char ID; - - TransportEOFError() = default; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; -}; - class TransportUnhandledContentsError : public llvm::ErrorInfo { public: @@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTra
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -54,112 +50,220 @@ class TransportUnhandledContentsError std::string m_unhandled_contents; }; -class TransportInvalidError : public llvm::ErrorInfo { +/// A transport is responsible for maintaining the connection to a client +/// application, and reading/writing structured messages to it. +/// +/// Transports have limited thread safety requirements: +/// - Messages will not be sent concurrently. +/// - Messages MAY be sent while Run() is reading, or its callback is active. +template class Transport { public: - static char ID; - - TransportInvalidError() = default; + using Message = std::variant; + + virtual ~Transport() = default; + + // Called by transport to send outgoing messages. + virtual void Event(const Evt &) = 0; + virtual void Request(const Req &) = 0; + virtual void Response(const Resp &) = 0; + + /// Implemented to handle incoming messages. (See Run() below). + class MessageHandler { + public: +virtual ~MessageHandler() = default; +virtual void OnEvent(const Evt &) = 0; +virtual void OnRequest(const Req &) = 0; +virtual void OnResponse(const Resp &) = 0; + }; + + /// Called by server or client to receive messages from the connection. + /// The transport should in turn invoke the handler to process messages. + /// The MainLoop is used to handle reading from the incoming connection and + /// will run until the loop is terminated. + virtual llvm::Error Run(MainLoop &, MessageHandler &) = 0; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; +protected: + template inline auto Logv(const char *Fmt, Ts &&...Vals) { +Log(llvm::formatv(Fmt, std::forward(Vals)...).str()); + } + virtual void Log(llvm::StringRef message) = 0; }; -/// A transport class that uses JSON for communication. -class JSONTransport { +/// A JSONTransport will encode and decode messages using JSON. +template +class JSONTransport : public Transport { public: - using ReadHandleUP = MainLoopBase::ReadHandleUP; - template - using Callback = std::function)>; - - JSONTransport(lldb::IOObjectSP input, lldb::IOObjectSP output); - virtual ~JSONTransport() = default; - - /// Transport is not copyable. - /// @{ - JSONTransport(const JSONTransport &rhs) = delete; - void operator=(const JSONTransport &rhs) = delete; - /// @} - - /// Writes a message to the output stream. - template llvm::Error Write(const T &t) { -const std::string message = llvm::formatv("{0}", toJSON(t)).str(); -return WriteImpl(message); + using Transport::Transport; + + JSONTransport(lldb::IOObjectSP in, lldb::IOObjectSP out) + : m_in(in), m_out(out) {} + + void Event(const Evt &evt) override { Write(evt); } + void Request(const Req &req) override { Write(req); } + void Response(const Resp &resp) override { Write(resp); } + + /// Run registers the transport with the given MainLoop and handles any + /// incoming messages using the given MessageHandler. + llvm::Error + Run(MainLoop &loop, + typename Transport::MessageHandler &handler) override { +llvm::Error error = llvm::Error::success(); +Status status; +auto read_handle = loop.RegisterReadObject( +m_in, +std::bind(&JSONTransport::OnRead, this, &error, std::placeholders::_1, + std::ref(handler)), +status); +if (status.Fail()) { + // This error is only set if the read object handler is invoked, mark it + // as consumed if registration of the handler failed. + llvm::consumeError(std::move(error)); + return status.takeError(); +} + +status = loop.Run(); +if (status.Fail()) + return status.takeError(); +return error; } - /// Registers the transport with the MainLoop. - template - llvm::Expected RegisterReadObject(MainLoopBase &loop, - Callback read_cb) { -Status error; -ReadHandleUP handle = loop.RegisterReadObject( -m_input, -[read_cb, this](MainLoopBase &loop) { - char buf[kReadBufferSize]; - size_t num_bytes = sizeof(buf); - if (llvm::Error error = m_input->Read(buf, num_bytes).takeError()) { -read_cb(loop, std::move(error)); -return; - } - if (num_bytes) -m_buffer.append(std::string(buf, num_bytes)); - - // If the buffer has contents, try parsing any pending messages. - if (!m_buffer.empty()) { -llvm::Expected> messages = Parse(); -if (llvm::Error error = messages.takeError()) { - read_cb(loop, std::move(error)); - return; -} - -for (const auto &message : *messages) - if constexpr (std::is_same::value) -read_cb(loop, message); - else -read_cb(loop, llvm::json::parse(message)); - } - - // On EOF, notify the callback after the remain
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -344,13 +346,14 @@ serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, bool client_failed = false; { std::scoped_lock lock(dap_sessions_mutex); -for (auto [sock, dap] : dap_sessions) { +for (auto [loop, dap] : dap_sessions) { if (llvm::Error error = dap->Disconnect()) { client_failed = true; -llvm::errs() << "DAP client " << dap->transport.GetClientName() - << " disconnected failed: " +llvm::errs() << "DAP client disconnected failed: " ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -258,36 +259,33 @@ void DAP::SendJSON(const llvm::json::Value &json) { llvm::json::Path::Root root; if (!fromJSON(json, message, root)) { DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}", - transport.GetClientName()); + m_client_name); return; } Send(message); } void DAP::Send(const Message &message) { - // FIXME: After all the requests have migrated from LegacyRequestHandler > - // RequestHandler<> this should be handled in RequestHandler<>::operator(). - if (auto *resp = std::get_if(&message); - resp && debugger.InterruptRequested()) { -// Clear the interrupt request. -debugger.CancelInterruptRequest(); - -// If the debugger was interrupted, convert this response into a 'cancelled' -// response because we might have a partial result. -Response cancelled{/*request_seq=*/resp->request_seq, - /*command=*/resp->command, - /*success=*/false, - /*message=*/eResponseMessageCancelled, - /*body=*/std::nullopt}; -if (llvm::Error err = transport.Write(cancelled)) - DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}", -transport.GetClientName()); -return; + if (const protocol::Event *event = std::get_if(&message)) { +transport.Event(*event); + } else if (const Request *req = std::get_if(&message)) { +transport.Request(*req); + } else if (const Response *resp = std::get_if(&message)) { +// FIXME: After all the requests have migrated from LegacyRequestHandler > +// RequestHandler<> this should be handled in RequestHandler<>::operator(). +if (debugger.InterruptRequested()) + // If the debugger was interrupted, convert this response into a + // 'cancelled' response because we might have a partial result. + transport.Response(Response{/*request_seq=*/resp->request_seq, + /*command=*/resp->command, + /*success=*/false, + /*message=*/eResponseMessageCancelled, + /*body=*/std::nullopt}); +else + transport.Response(*resp); ashgti wrote: Done. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Refactoring JSONTransport into an abstract RPC Message Handler and transport layer. (PR #153121)
@@ -938,88 +933,74 @@ void DAP::ClearCancelRequest(const CancelArguments &args) { } template -static std::optional getArgumentsIfRequest(const Message &pm, +static std::optional getArgumentsIfRequest(const Request &req, llvm::StringLiteral command) { - auto *const req = std::get_if(&pm); - if (!req || req->command != command) + if (req.command != command) return std::nullopt; T args; llvm::json::Path::Root root; - if (!fromJSON(req->arguments, args, root)) + if (!fromJSON(req.arguments, args, root)) return std::nullopt; return args; } -Status DAP::TransportHandler() { - llvm::set_thread_name(transport.GetClientName() + ".transport_handler"); +void DAP::OnEvent(const protocol::Event &event) { + // no-op, no supported events from the client to the server as of DAP v1.68. +} - auto cleanup = llvm::make_scope_exit([&]() { -// Ensure we're marked as disconnecting when the reader exits. +void DAP::OnRequest(const protocol::Request &request) { + if (request.command == "disconnect") disconnecting = true; -m_queue_cv.notify_all(); - }); - Status status; - auto handle = transport.RegisterReadObject( - m_loop, - [&](MainLoopBase &loop, llvm::Expected message) { -if (message.errorIsA()) { - llvm::consumeError(message.takeError()); - loop.RequestTermination(); - return; -} + const std::optional cancel_args = + getArgumentsIfRequest(request, "cancel"); + if (cancel_args) { +{ + std::lock_guard guard(m_cancelled_requests_mutex); + if (cancel_args->requestId) +m_cancelled_requests.insert(*cancel_args->requestId); +} -if (llvm::Error err = message.takeError()) { - status = Status::FromError(std::move(err)); - loop.RequestTermination(); - return; -} +// If a cancel is requested for the active request, make a best +// effort attempt to interrupt. +std::lock_guard guard(m_active_request_mutex); +if (m_active_request && cancel_args->requestId == m_active_request->seq) { + DAP_LOG(log, "({0}) interrupting inflight request (command={1} seq={2})", + m_client_name, m_active_request->command, m_active_request->seq); + debugger.RequestInterrupt(); +} + } -if (const protocol::Request *req = -std::get_if(&*message); -req && req->arguments == "disconnect") - disconnecting = true; - -const std::optional cancel_args = -getArgumentsIfRequest(*message, "cancel"); -if (cancel_args) { - { -std::lock_guard guard(m_cancelled_requests_mutex); -if (cancel_args->requestId) - m_cancelled_requests.insert(*cancel_args->requestId); - } + std::lock_guard guard(m_queue_mutex); + DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, + request.command, request.seq); + m_queue.push_back(request); + m_queue_cv.notify_one(); +} - // If a cancel is requested for the active request, make a best - // effort attempt to interrupt. - std::lock_guard guard(m_active_request_mutex); - if (m_active_request && - cancel_args->requestId == m_active_request->seq) { -DAP_LOG(log, -"({0}) interrupting inflight request (command={1} seq={2})", -transport.GetClientName(), m_active_request->command, -m_active_request->seq); -debugger.RequestInterrupt(); - } -} +void DAP::OnResponse(const protocol::Response &response) { + std::lock_guard guard(m_queue_mutex); + DAP_LOG(log, "({0}) queued (command={1} seq={2})", m_client_name, + response.command, response.request_seq); + m_queue.push_back(response); + m_queue_cv.notify_one(); +} -std::lock_guard guard(m_queue_mutex); -m_queue.push_back(std::move(*message)); -m_queue_cv.notify_one(); - }); - if (auto err = handle.takeError()) -return Status::FromError(std::move(err)); - if (llvm::Error err = m_loop.Run().takeError()) -return Status::FromError(std::move(err)); - return status; +void DAP::TransportHandler(llvm::Error *error) { + llvm::ErrorAsOutParameter ErrAsOutParam(*error); + auto cleanup = llvm::make_scope_exit([&]() { +// Ensure we're marked as disconnecting when the reader exits. +disconnecting = true; ashgti wrote: Added a lock guard around `disconnecting` and made it private. https://github.com/llvm/llvm-project/pull/153121 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `lldb-aarch64-ubuntu` running on `linaro-lldb-aarch64-ubuntu` while building `lldb` at step 6 "test". Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/22573 Here is the relevant piece of the build log for the reference ``` Step 6 (test) failure: build (failure) ... PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/8/12 (2299 of 2308) PASS: lldb-unit :: ValueObject/./LLDBValueObjectTests/9/12 (2300 of 2308) PASS: lldb-unit :: Utility/./UtilityTests/4/9 (2301 of 2308) PASS: lldb-unit :: tools/lldb-server/tests/./LLDBServerTests/0/2 (2302 of 2308) PASS: lldb-unit :: tools/lldb-server/tests/./LLDBServerTests/1/2 (2303 of 2308) PASS: lldb-unit :: Host/./HostTests/4/9 (2304 of 2308) PASS: lldb-unit :: Target/./TargetTests/11/14 (2305 of 2308) PASS: lldb-unit :: Host/./HostTests/5/9 (2306 of 2308) PASS: lldb-unit :: Process/gdb-remote/./ProcessGdbRemoteTests/8/9 (2307 of 2308) UNRESOLVED: lldb-api :: tools/lldb-server/TestLldbGdbServer.py (2308 of 2308) TEST 'lldb-api :: tools/lldb-server/TestLldbGdbServer.py' FAILED Script: -- /usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --cmake-build-type Release /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-server -p TestLldbGdbServer.py -- Exit Code: 1 Command Output (stdout): -- lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision bcb48aa5b2cfc75967c734a97201e0c91273169d) clang revision bcb48aa5b2cfc75967c734a97201e0c91273169d llvm revision bcb48aa5b2cfc75967c734a97201e0c91273169d Skipping the following test categories: ['libc++', 'msvcstl', 'dsym', 'gmodules', 'debugserver', 'objc'] -- Command Output (stderr): -- UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hc_then_Csignal_signals_correct_thread_launch_debugserver (TestLldbGdbServer.LldbGdbServerTestCase) (test case does not fall in any category of interest for this run) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hc_then_Csignal_signals_correct_thread_launch_llgs (TestLldbGdbServer.LldbGdbServerTestCase) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hg_fails_on_another_pid_llgs (TestLldbGdbServer.LldbGdbServerTestCase) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hg_fails_on_minus_one_pid_llgs (TestLldbGdbServer.LldbGdbServerTestCase) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hg_fails_on_zero_pid_llgs (TestLldbGdbServer.LldbGdbServerTestCase) UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hg_switches_to_3_threads_launch_debugserver (TestLldbGdbServer.LldbGdbServerTestCase) (test case does not fall in any category of interest for this run) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_Hg_switches_to_3_threads_launch_llgs (TestLldbGdbServer.LldbGdbServerTestCase) UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_P_and_p_thread_suffix_work_debugserver (TestLldbGdbServer.LldbGdbServerTestCase) (test case does not fall in any category of interest for this run) PASS: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_P_and_p_thread_suffix_work_llgs (TestLldbGdbServer.LldbGdbServerTestCase) UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_P_writes_all_gpr_registers_debugserver (TestLldbGdbServer.LldbGdbServerTestCase) (test case does not fall
[Lldb-commits] [lldb] [lldb] refactor PlatformAndroid and make threadsafe (PR #145382)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `lldb-remote-linux-win` running on `as-builder-10` while building `lldb` at step 16 "test-check-lldb-unit". Full details are available at: https://lab.llvm.org/buildbot/#/builders/197/builds/7996 Here is the relevant piece of the build log for the reference ``` Step 16 (test-check-lldb-unit) failure: Test just built components: check-lldb-unit completed (failure) ... -- Builtin supported architectures: aarch64 -- Configuring done -- Generating done -- Build files have been written to: C:/buildbot/as-builder-10/lldb-x-aarch64/build/runtimes/runtimes-aarch64-unknown-linux-gnu-bins 0.517 [0/1/1]Generating C:/buildbot/as-builder-10/lldb-x-aarch64/build/compile_commands.json 45/16/246]Completed 'builtins-aarch64-unknown-linux-gnu' 0.960 [44/16/246]Performing configure step for 'runtimes-aarch64-unknown-linux-gnu' 3.433 [41/12/254]Linking CXX executable tools\lldb\unittests\ABI\AArch64\ABIAArch64Tests.exe 3.678 [39/12/255]Performing build step for 'runtimes-aarch64-unknown-linux-gnu' 3.895 [39/12/256]Building CXX object tools\lldb\unittests\Platform\Android\CMakeFiles\AdbClientTests.dir\AdbClientTest.cpp.obj FAILED: tools/lldb/unittests/Platform/Android/CMakeFiles/AdbClientTests.dir/AdbClientTest.cpp.obj ccache C:\PROGRA~1\MICROS~1\2022\COMMUN~1\VC\Tools\MSVC\1444~1.352\bin\Hostx64\x64\cl.exe /nologo /TP -DGTEST_HAS_RTTI=0 -DLLVM_BUILD_STATIC -DUNICODE -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_ENABLE_EXTENDED_ALIGNED_STORAGE -D_GLIBCXX_ASSERTIONS -D_HAS_EXCEPTIONS=0 -D_SCL_SECURE_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS -D_UNICODE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -IC:\buildbot\as-builder-10\lldb-x-aarch64\build\tools\lldb\unittests\Platform\Android -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\unittests\Platform\Android -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\build\tools\lldb\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\build\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\llvm\include -IC:\Python312\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\llvm\..\clang\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\build\tools\lldb\..\clang\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\source -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\unittests -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\source\Plugins\Platform\Android -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\third-party\unittest\googletest\include -IC:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\third-party\unittest\googlemock\include -D__OPTIMIZE__ /Zc:inline /Zc:preprocessor /Zc:__cplusplus /Oi /bigobj /permissive- /W4 -wd4141 -wd4146 -wd4244 -wd4267 -wd4291 -wd4351 -wd4456 -wd4457 -wd4458 -wd4459 -wd4503 -wd4624 -wd4722 -wd4100 -wd4127 -wd4512 -wd4505 -wd4610 -wd4510 -wd4702 -wd4245 -wd4706 -wd4310 -wd4701 -wd4703 -wd4389 -wd4611 -wd4805 -wd4204 -wd4577 -wd4091 -wd4592 -wd4319 -wd4709 -wd5105 -wd4324 -wd4251 -wd4275 -w14062 -we4238 /Gw /O2 /Ob2 -MD -wd4018 -wd4068 -wd4150 -wd4201 -wd4251 -wd4521 -wd4530 -wd4589 /EHs-c- /GR- -UNDEBUG -std:c++17 /showIncludes /Fotools\lldb\unittests\Platform\Android\CMakeFiles\AdbClientTests.dir\AdbClientTest.cpp.obj /Fdtools\lldb\unittests\Platform\Android\CMakeFiles\AdbClientTests.dir\ /FS -c C:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\unittests\Platform\Android\AdbClientTest.cpp C:\buildbot\as-builder-10\lldb-x-aarch64\llvm-project\lldb\unittests\Platform\Android\AdbClientTest.cpp(116): error C3861: 'setenv': identifier not found 4.252 [39/11/257]Linking CXX executable tools\lldb\unittests\UnwindAssembly\x86-but-no-x86-target\UnwindAssemblyX86ButNoX86TargetTests.exe 5.133 [39/9/259]Linking CXX executable tools\lldb\unittests\DataFormatter\LLDBFormatterTests.exe 6.126 [39/8/260]Linking CXX executable tools\lldb\unittests\UnwindAssembly\ARM64\Arm64InstEmulationTests.exe 6.542 [39/7/261]Linking CXX executable tools\lldb\unittests\Thread\ThreadTests.exe 6.553 [39/6/262]Linking CXX executable tools\lldb\unittests\Core\LLDBCoreTests.exe 7.492 [39/5/263]Linking CXX executable tools\lldb\unittests\Callback\LLDBCallbackTests.exe 9.313 [39/4/264]Linking CXX executable bin\lldb-test.exe 9.912 [39/3/265]Linking CXX executable tools\lldb\unittests\Expression\ExpressionTests.exe 11.328 [39/2/266]Building CXX object tools\lldb\unittests\Target\CMakeFiles\TargetTests.dir\LocateModuleCallbackTest.cpp.obj 13.004 [39/1/267]Building CXX object tools\lldb\unittests\Platform\Android\CMakeFiles\AdbClientTests.dir\PlatformAndroidTest.cpp.obj ninja: build stopped: subcommand failed. ``` https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mail
[Lldb-commits] [lldb] [lldb][Expression] Avoid creating ValueObjectSyntheticFilter for incomplete C++ types in ObjC++ targets (PR #153454)
https://github.com/jimingham requested changes to this pull request. At the site where you are fixing this, this is a workaround of a workaround, so I don't so much mind that. But you shouldn't be mentioning a specific language in a TypeSystem method, so I don't like the IsCXXClassType. IsClassTypeForLanguage would be okay, but not IsCXXClassType. https://github.com/llvm/llvm-project/pull/153454 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [vscode-lldb] Support lldb-dap environment in debug configuration (PR #153536)
https://github.com/royitaqi created https://github.com/llvm/llvm-project/pull/153536 # Changes 1. Add a new debug configuration field called `debugAdapterEnv`, which accepts a string-valued dictionary. 3. In the adapter descriptor factory, honor the said field before looking at the VS Code settings `Lldb-dap: Environment `. 1. This order is consistent with how things are done for other debug configuration fields, e.g. lldb-dap path and args. 4. In the lldb-dap server, note down the environment entries as a part of the dap spawn info (now it becomes "path + args + env"), and prompt the user to restart server if such info has changed. # Motivation 1. lldb-dap environment can be set in `launch.json`. 2. Other debugger extensions can invoke lldb-dap extension with lldb-dap environment (via debug configuration). # Tests Manually verified the following. - [ v ] Test 1: Environment entries in settings are effective (no regress) - [ v ] Test 2: Bad formatted environment entries in launch.json are rejected: non-dict. E.g. array, string, true, 1 - [ v ] Test 3: Bad formatted environment entries in launch.json are rejected: non-string values in dict. E.g. true, 1, dict, array - [ v ] Test 4: Environment entries in launch.json are effective - [ v ] Test 5: When debug configuration has environment entries (from launch.json), the ones in the settings are ignored - [ v ] Test 6: In server mode, changing environment entries will prompt the user to restart server - [ v ] Test 7: If the user choose to keep the existing server, environment entries shouldn't change - [ v ] Test 8: If the user choose to restart server, environment entries should reflect new value I have a video as proof, but not sure if it's needed or where to upload. >From a8b0d3ebb8e3b5519ecda14699346123781abc2b Mon Sep 17 00:00:00 2001 From: Roy Shi Date: Wed, 13 Aug 2025 22:47:58 -0700 Subject: [PATCH] [vscode-lldb] Support lldb-dap environment in debug configuration --- lldb/tools/lldb-dap/package.json | 9 .../lldb-dap/src-ts/debug-adapter-factory.ts | 42 ++- lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 26 ++-- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d677a81cc7974..3e6928cf4327f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -370,6 +370,15 @@ }, "markdownDescription": "The list of additional arguments used to launch the debug adapter executable. Overrides any user or workspace settings." }, + "debugAdapterEnv": { +"type": "object", +"patternProperties": { + ".*": { +"type": "string" + } +}, +"markdownDescription": "Additional environment variables to set when launching the debug adapter executable. E.g. `{ \"FOO\": \"1\" }`" + }, "program": { "type": "string", "description": "Path to the program to debug." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 157aa2ac76a1f..e7bdd835894c0 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -157,6 +157,42 @@ async function getDAPArguments( .get("arguments", []); } +/** + * Retrieves the environment that will be provided to lldb-dap either from settings or the provided + * {@link vscode.DebugConfiguration}. + * + * @param workspaceFolder The {@link vscode.WorkspaceFolder} that the debug session will be launched within + * @param configuration The {@link vscode.DebugConfiguration} that will be launched + * @throws An {@link ErrorWithNotification} if something went wrong + * @returns The environment that will be provided to lldb-dap + */ +async function getDAPEnvironment( + workspaceFolder: vscode.WorkspaceFolder | undefined, + configuration: vscode.DebugConfiguration, +): Promise { + const debugConfigEnv = configuration.debugAdapterEnv; + if (debugConfigEnv) { +if ( + Array.isArray(debugConfigEnv) || + typeof debugConfigEnv !== "object" || + Object.values(debugConfigEnv).findIndex( +(entry) => typeof entry !== "string", + ) !== -1 +) { + throw new ErrorWithNotification( +"The debugAdapterEnv property must be a dictionary with string values. Please update your launch configuration", +new ConfigureButton(), + ); +} +return debugConfigEnv; + } + + const config = vscode.workspace.workspaceFile +? vscode.workspace.getConfiguration("lldb-dap") +: vscode.workspace.getConfiguration("lldb-dap", workspaceFolder); + return config.get<{ [key: string]: string }>("environment") || {}; +} + /** * Creates a new {@link vscode.Debug
[Lldb-commits] [lldb] [vscode-lldb] Support lldb-dap environment in debug configuration (PR #153536)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (royitaqi) Changes # Changes 1. Add a new debug configuration field called `debugAdapterEnv`, which accepts a string-valued dictionary. 3. In the adapter descriptor factory, honor the said field before looking at the VS Code settings `Lldb-dap: Environment `. 1. This order is consistent with how things are done for other debug configuration fields, e.g. lldb-dap path and args. 4. In the lldb-dap server, note down the environment entries as a part of the dap spawn info (now it becomes "path + args + env"), and prompt the user to restart server if such info has changed. # Motivation 1. lldb-dap environment can be set in `launch.json`. 2. Other debugger extensions can invoke lldb-dap extension with lldb-dap environment (via debug configuration). # Tests Manually verified the following. - [ v ] Test 1: Environment entries in settings are effective (no regress) - [ v ] Test 2: Bad formatted environment entries in launch.json are rejected: non-dict. E.g. array, string, true, 1 - [ v ] Test 3: Bad formatted environment entries in launch.json are rejected: non-string values in dict. E.g. true, 1, dict, array - [ v ] Test 4: Environment entries in launch.json are effective - [ v ] Test 5: When debug configuration has environment entries (from launch.json), the ones in the settings are ignored - [ v ] Test 6: In server mode, changing environment entries will prompt the user to restart server - [ v ] Test 7: If the user choose to keep the existing server, environment entries shouldn't change - [ v ] Test 8: If the user choose to restart server, environment entries should reflect new value I have a video as proof, but not sure if it's needed or where to upload. --- Full diff: https://github.com/llvm/llvm-project/pull/153536.diff 3 Files Affected: - (modified) lldb/tools/lldb-dap/package.json (+9) - (modified) lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts (+40-2) - (modified) lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts (+22-4) ``diff diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json index d677a81cc7974..3e6928cf4327f 100644 --- a/lldb/tools/lldb-dap/package.json +++ b/lldb/tools/lldb-dap/package.json @@ -370,6 +370,15 @@ }, "markdownDescription": "The list of additional arguments used to launch the debug adapter executable. Overrides any user or workspace settings." }, + "debugAdapterEnv": { +"type": "object", +"patternProperties": { + ".*": { +"type": "string" + } +}, +"markdownDescription": "Additional environment variables to set when launching the debug adapter executable. E.g. `{ \"FOO\": \"1\" }`" + }, "program": { "type": "string", "description": "Path to the program to debug." diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts index 157aa2ac76a1f..e7bdd835894c0 100644 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts @@ -157,6 +157,42 @@ async function getDAPArguments( .get("arguments", []); } +/** + * Retrieves the environment that will be provided to lldb-dap either from settings or the provided + * {@link vscode.DebugConfiguration}. + * + * @param workspaceFolder The {@link vscode.WorkspaceFolder} that the debug session will be launched within + * @param configuration The {@link vscode.DebugConfiguration} that will be launched + * @throws An {@link ErrorWithNotification} if something went wrong + * @returns The environment that will be provided to lldb-dap + */ +async function getDAPEnvironment( + workspaceFolder: vscode.WorkspaceFolder | undefined, + configuration: vscode.DebugConfiguration, +): Promise { + const debugConfigEnv = configuration.debugAdapterEnv; + if (debugConfigEnv) { +if ( + Array.isArray(debugConfigEnv) || + typeof debugConfigEnv !== "object" || + Object.values(debugConfigEnv).findIndex( +(entry) => typeof entry !== "string", + ) !== -1 +) { + throw new ErrorWithNotification( +"The debugAdapterEnv property must be a dictionary with string values. Please update your launch configuration", +new ConfigureButton(), + ); +} +return debugConfigEnv; + } + + const config = vscode.workspace.workspaceFile +? vscode.workspace.getConfiguration("lldb-dap") +: vscode.workspace.getConfiguration("lldb-dap", workspaceFolder); + return config.get<{ [key: string]: string }>("environment") || {}; +} + /** * Creates a new {@link vscode.DebugAdapterExecutable} based on the provided workspace folder and * debug configuration. Assumes that the given debug configuration is for a local launch of lldb-dap
[Lldb-commits] [lldb] b563b27 - [lldb] Convert registers values into target endian for expressions (#148836)
Author: David Spickett Date: 2025-08-13T09:48:29+01:00 New Revision: b563b274b8a8b00dadb63e67d648421c110449ff URL: https://github.com/llvm/llvm-project/commit/b563b274b8a8b00dadb63e67d648421c110449ff DIFF: https://github.com/llvm/llvm-project/commit/b563b274b8a8b00dadb63e67d648421c110449ff.diff LOG: [lldb] Convert registers values into target endian for expressions (#148836) Relates to https://github.com/llvm/llvm-project/issues/135707 Where it was reported that reading the PC using "register read" had different results to an expression "$pc". This was happening because registers are treated in lldb as pure "values" that don't really have an endian. We have to store them somewhere on the host of course, so the endian becomes host endian. When you want to use a register as a value in an expression you're pretending that it's a variable in memory. In target memory. Therefore we must convert the register value to that endian before use. The test I have added is based on the one used for XML register flags. Where I fake an AArch64 little endian and an s390x big endian target. I set up the data in such a way the pc value should print the same for both, either with register read or an expression. I considered just adding a live process test that checks the two are the same but with on one doing cross endian testing, I doubt it would have ever caught this bug. Simulating this means most of the time, little endian hosts will test little to little and little to big. In the minority of cases with a big endian host, they'll check the reverse. Covering all the combinations. Added: lldb/test/API/commands/expression/TestRegisterExpressionEndian.py Modified: lldb/source/Expression/Materializer.cpp Removed: diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 329768dd7915a..771a9ab84a20c 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -1377,29 +1377,26 @@ class EntityRegister : public Materializer::Entity { return; } -DataExtractor register_data; - -if (!reg_value.GetData(register_data)) { - err = Status::FromErrorStringWithFormat( - "couldn't get the data for register %s", m_register_info.name); - return; -} - -if (register_data.GetByteSize() != m_register_info.byte_size) { +if (reg_value.GetByteSize() != m_register_info.byte_size) { err = Status::FromErrorStringWithFormat( "data for register %s had size %llu but we expected %llu", - m_register_info.name, (unsigned long long)register_data.GetByteSize(), + m_register_info.name, (unsigned long long)reg_value.GetByteSize(), (unsigned long long)m_register_info.byte_size); return; } -m_register_contents = std::make_shared( -register_data.GetDataStart(), register_data.GetByteSize()); +lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0); +reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(), + buf.GetByteSize(), map.GetByteOrder(), err); +if (!err.Success()) + return; + +m_register_contents = std::make_shared(buf); Status write_error; -map.WriteMemory(load_addr, register_data.GetDataStart(), -register_data.GetByteSize(), write_error); +map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(), +write_error); if (!write_error.Success()) { err = Status::FromErrorStringWithFormat( diff --git a/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py new file mode 100644 index 0..66e38df3a9696 --- /dev/null +++ b/lldb/test/API/commands/expression/TestRegisterExpressionEndian.py @@ -0,0 +1,86 @@ +""" Check that registers written to memory for expression evaluation are +written using the target's endian not the host's. +""" + +from enum import Enum +from textwrap import dedent +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test.gdbclientutils import * +from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase + + +class Endian(Enum): +BIG = 0 +LITTLE = 1 + + +class Responder(MockGDBServerResponder): +def __init__(self, doc, endian): +super().__init__() +self.target_xml = doc +self.endian = endian + +def qXferRead(self, obj, annex, offset, length): +if annex == "target.xml": +return self.target_xml, False +return (None,) + +def readRegister(self, regnum): +return "E01" + +def readRegisters(self): +# 64 bit pc value. +data = ["00", "00", "00", "00", "00", "00", "12", "34"] +if self.endian == Endian.LITTLE: +data.reverse() +