[Lldb-commits] [lldb] dece902 - [lldb][MCP] Fix compiler error in Windows on Arm build

2025-08-13 Thread David Spickett via lldb-commits

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

2025-08-13 Thread Michael Buch via lldb-commits

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

2025-08-13 Thread Michael Buch via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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

2025-08-13 Thread Kazu Hirata via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread Igor Kudrin via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread Chad Smith via lldb-commits

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)

2025-08-13 Thread John Harrison via lldb-commits

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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits

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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits


@@ -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)

2025-08-13 Thread Adrian Prantl via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread Jonas Devlieghere via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread Ely Ronnen via lldb-commits

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)

2025-08-13 Thread John Harrison via lldb-commits

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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread John Harrison via lldb-commits


@@ -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)

2025-08-13 Thread LLVM Continuous Integration via lldb-commits

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)

2025-08-13 Thread LLVM Continuous Integration via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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)

2025-08-13 Thread via lldb-commits

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()
+