Skip to content

Reland "[lldb][RPC] Upstream lldb-rpc-gen tool" (#146969)" Attempt 2 #148996

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

chelcassanova
Copy link
Contributor

Second attempt at relanding the lldb-rpc-gen tool. This should fix an assert that was hitting when building on Linux. The assert would hit in the server source emitter, specifically when attemping to determine the storage size for a return type is that is a pointer, but isn't a const char *, const char ** or void pointer.

The assert would hit when attempting to generate
SBAttachInfo::GetProcessPluginName, which returns a const char * (meaning it shouldn't have been in the code block for the assert at all). The reason that it was hitting the assert when generating this function is that lldb_rpc_gen::TypeIsConstCharPtr was returning false for this function even though it did return a const char *. This was happening because when checking the return type for a const char *, TypeIsConstCharPtr would only check that the underlying type was a signed char. This failed on Linux (but was fine on Darwin), as the underlying type also needs to be checked for being an unsigned char.

Original PR Description:
This commit upstreams the lldb-rpc-gen tool, a ClangTool that generates the LLDB RPC client and server interfaces. This tool, as well as LLDB RPC itself is built by default. If it needs to be disabled, put -DLLDB_BUILD_LLDBRPC=OFF in your CMake invocation.

https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804

Original PR Link:
github.com//pull/138031

@llvmbot
Copy link
Member

llvmbot commented Jul 15, 2025

@llvm/pr-subscribers-lldb

Author: Chelsea Cassanova (chelcassanova)

Changes

Second attempt at relanding the lldb-rpc-gen tool. This should fix an assert that was hitting when building on Linux. The assert would hit in the server source emitter, specifically when attemping to determine the storage size for a return type is that is a pointer, but isn't a const char *, const char ** or void pointer.

The assert would hit when attempting to generate
SBAttachInfo::GetProcessPluginName, which returns a const char * (meaning it shouldn't have been in the code block for the assert at all). The reason that it was hitting the assert when generating this function is that lldb_rpc_gen::TypeIsConstCharPtr was returning false for this function even though it did return a const char *. This was happening because when checking the return type for a const char *, TypeIsConstCharPtr would only check that the underlying type was a signed char. This failed on Linux (but was fine on Darwin), as the underlying type also needs to be checked for being an unsigned char.

Original PR Description:
This commit upstreams the lldb-rpc-gen tool, a ClangTool that generates the LLDB RPC client and server interfaces. This tool, as well as LLDB RPC itself is built by default. If it needs to be disabled, put -DLLDB_BUILD_LLDBRPC=OFF in your CMake invocation.

https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804

Original PR Link:
github.com//pull/138031


Patch is 40.60 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/148996.diff

15 Files Affected:

  • (modified) lldb/cmake/modules/LLDBConfig.cmake (+2)
  • (modified) lldb/test/CMakeLists.txt (+6-1)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h ()
  • (added) lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test (+9)
  • (added) lldb/test/Shell/RPC/Generator/lit.local.cfg (+3)
  • (modified) lldb/test/Shell/helper/toolchain.py (+10)
  • (modified) lldb/test/Shell/lit.site.cfg.py.in (+1)
  • (modified) lldb/tools/CMakeLists.txt (+3)
  • (added) lldb/tools/lldb-rpc/CMakeLists.txt (+22)
  • (added) lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake (+75)
  • (added) lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake (+101)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/CMakeLists.txt (+23)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp (+501)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.h (+108)
  • (modified) lldb/tools/lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp (+22-14)
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 8c30b6e09d2c7..f674c29682160 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -323,4 +323,6 @@ else()
     set(LLDB_CAN_USE_DEBUGSERVER OFF)
 endif()
 
+set(LLDB_BUILD_LLDBRPC ON CACHE BOOL "")
+
 include(LLDBGenerateConfig)
diff --git a/lldb/test/CMakeLists.txt b/lldb/test/CMakeLists.txt
index 6449ac5a9247f..7cf239c7f95ab 100644
--- a/lldb/test/CMakeLists.txt
+++ b/lldb/test/CMakeLists.txt
@@ -132,6 +132,10 @@ if(TARGET lldb-framework)
   add_lldb_test_dependency(lldb-framework)
 endif()
 
+if (LLDB_BUILD_LLDBRPC)
+  add_lldb_test_dependency(lldb-rpc-generate-sources)
+endif()
+
 # Add dependencies that are not exported targets when building standalone.
 if(NOT LLDB_BUILT_STANDALONE)
   add_lldb_test_dependency(
@@ -249,7 +253,8 @@ llvm_canonicalize_cmake_booleans(
   LLDB_TEST_SHELL_DISABLE_REMOTE
   LLDB_TOOL_LLDB_SERVER_BUILD
   LLDB_USE_SYSTEM_DEBUGSERVER
-  LLDB_IS_64_BITS)
+  LLDB_IS_64_BITS
+  LLDB_BUILD_LLDBRPC)
 
 # Configure the individual test suites.
 add_subdirectory(API)
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h b/lldb/test/Shell/RPC/Generator/Inputs/SBDummy.h
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test
new file mode 100644
index 0000000000000..15fcf8fb39c7d
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test
@@ -0,0 +1,9 @@
+RUN: %lldb-rpc-gen --output-dir=%t %S/../Inputs/SBDummy.h
+
+RUN: ls %t | FileCheck %s
+
+# We're just making sure that the tool emits the class names,
+# methods and skipped methods file in the output directory.
+CHECK: SBAPI.def
+CHECK: SBClasses.def
+CHECK: SkippedMethods.txt
diff --git a/lldb/test/Shell/RPC/Generator/lit.local.cfg b/lldb/test/Shell/RPC/Generator/lit.local.cfg
new file mode 100644
index 0000000000000..db9494781c00c
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/lit.local.cfg
@@ -0,0 +1,3 @@
+# All tests for the tool need lldb-rpc-gen to be built.
+if not config.lldb_has_lldbrpc:
+   config.unsupported = True
diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py
index 42968128f2702..728f6347242f1 100644
--- a/lldb/test/Shell/helper/toolchain.py
+++ b/lldb/test/Shell/helper/toolchain.py
@@ -156,6 +156,16 @@ def use_lldb_substitutions(config):
             extra_args=["platform"],
             unresolved="ignore",
         ),
+        ToolSubst(
+            "%lldb-rpc-gen",
+            command=FindTool("lldb-rpc-gen"),
+            # We need the LLDB build directory root to pass into the tool, not the test build root.
+            extra_args=[
+                "-p " + config.lldb_build_directory + "/..",
+                '--extra-arg="-resource-dir=' + config.clang_resource_dir + '"',
+            ],
+            unresolved="ignore",
+        ),
         "lldb-test",
         "lldb-dap",
         ToolSubst(
diff --git a/lldb/test/Shell/lit.site.cfg.py.in b/lldb/test/Shell/lit.site.cfg.py.in
index 5be5359217769..beaa41e6fd379 100644
--- a/lldb/test/Shell/lit.site.cfg.py.in
+++ b/lldb/test/Shell/lit.site.cfg.py.in
@@ -33,6 +33,7 @@ config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
 config.have_lldb_server = @LLDB_TOOL_LLDB_SERVER_BUILD@
 config.lldb_system_debugserver = @LLDB_USE_SYSTEM_DEBUGSERVER@
 config.llvm_use_sanitizer = "@LLVM_USE_SANITIZER@"
+config.lldb_has_lldbrpc = @LLDB_BUILD_LLDBRPC@
 # The shell tests use their own module caches.
 config.lldb_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_LLDB@", "lldb-shell")
 config.clang_module_cache = os.path.join("@LLDB_TEST_MODULE_CACHE_CLANG@", "lldb-shell")
diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt
index 6804dc234555b..73ffbbbee3056 100644
--- a/lldb/tools/CMakeLists.txt
+++ b/lldb/tools/CMakeLists.txt
@@ -10,6 +10,9 @@ add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL)
 
 add_lldb_tool_subdirectory(lldb-instr)
 add_lldb_tool_subdirectory(lldb-dap)
+if (LLDB_BUILD_LLDBRPC)
+  add_lldb_tool_subdirectory(lldb-rpc)
+endif()
 
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_lldb_tool_subdirectory(darwin-debug)
diff --git a/lldb/tools/lldb-rpc/CMakeLists.txt b/lldb/tools/lldb-rpc/CMakeLists.txt
new file mode 100644
index 0000000000000..fdd6cf9163e96
--- /dev/null
+++ b/lldb/tools/lldb-rpc/CMakeLists.txt
@@ -0,0 +1,22 @@
+include(CheckCXXCompilerFlag)
+# Umbrella target for the entire framework is a default target.
+add_custom_target(lldb-rpc ALL)
+
+if(LLDB_CODESIGN_IDENTITY)
+  # Use explicit LLDB identity
+  set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY})
+else()
+  # Use explicit LLVM identity or default to ad-hoc signing if empty
+  if(NOT LLVM_CODESIGNING_IDENTITY)
+    set(LLVM_CODESIGNING_IDENTITY -)
+  endif()
+endif()
+
+# LLDBRPCGeneration.cmake needs the LLDB_RPC_GEN_EXE variable
+# which gets defined in the lldb-rpc-gen folder, so we're adding
+# this folder before we add that file.
+add_lldb_tool_subdirectory(lldb-rpc-gen)
+include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCGeneration.cmake)
+include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCHeaders.cmake)
+
+add_dependencies(lldb-rpc lldb-rpc-generate-sources liblldbrpc-headers)
diff --git a/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake b/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake
new file mode 100644
index 0000000000000..ca73c546d781f
--- /dev/null
+++ b/lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake
@@ -0,0 +1,75 @@
+if (NOT DEFINED LLDB_RPC_GEN_EXE)
+  message(FATAL_ERROR
+    "Unable to generate lldb-rpc sources because LLDB_RPC_GEN_EXE is not
+    defined. If you are cross-compiling, please build lldb-rpc-gen for your host
+    platform.")
+endif()
+set(lldb_rpc_generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
+set(lldb_rpc_server_generated_source_dir "${lldb_rpc_generated_dir}/server")
+
+file(GLOB api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SB*.h)
+# We don't generate SBCommunication
+list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBCommunication.h)
+# SBDefines.h is mostly definitions and forward declarations, nothing to
+# generate.
+list(REMOVE_ITEM api_headers ${LLDB_SOURCE_DIR}/include/lldb/API/SBDefines.h)
+
+# Generate the list of byproducts. Note that we cannot just glob the files in
+# the directory with the generated sources because BYPRODUCTS needs to be known
+# at configure time but the files are generated at build time.
+set(lldb_rpc_gen_byproducts
+  ${lldb_rpc_generated_dir}/SBClasses.def
+  ${lldb_rpc_generated_dir}/SBAPI.def
+  ${lldb_rpc_generated_dir}/lldb.py
+  ${lldb_rpc_server_generated_source_dir}/SBAPI.h
+)
+
+set(lldb_rpc_gen_server_impl_files)
+foreach(path ${api_headers})
+  get_filename_component(filename_no_ext ${path} NAME_WLE)
+
+  set(server_header_file "Server_${filename_no_ext}.h")
+  list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_header_file}")
+
+  set(server_impl_file "Server_${filename_no_ext}.cpp")
+  list(APPEND lldb_rpc_gen_byproducts "${lldb_rpc_server_generated_source_dir}/${server_impl_file}")
+  list(APPEND lldb_rpc_gen_server_impl_files "${lldb_rpc_server_generated_source_dir}/${server_impl_file}")
+
+endforeach()
+
+# Make sure that the clang-resource-dir is set correctly or else the tool will
+# fail to run. This is only needed when we do a standalone build.
+set(clang_resource_dir_arg)
+if (TARGET clang-resource-headers)
+  set(clang_resource_headers_dir
+    $<TARGET_PROPERTY:clang-resource-headers,INTERFACE_INCLUDE_DIRECTORIES>)
+  set(clang_resource_dir_arg --extra-arg="-resource-dir=${clang_resource_headers_dir}/..")
+else()
+  set(clang_resource_dir_arg --extra-arg="-resource-dir=${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}")
+endif()
+
+add_custom_command(OUTPUT ${lldb_rpc_gen_byproducts}
+  COMMAND ${CMAKE_COMMAND} -E make_directory
+    ${lldb_rpc_generated_dir}
+
+  COMMAND ${CMAKE_COMMAND} -E make_directory
+    ${lldb_rpc_server_generated_source_dir}
+
+  COMMAND ${LLDB_RPC_GEN_EXE}
+    -p ${CMAKE_BINARY_DIR}
+    --output-dir=${lldb_rpc_generated_dir}
+    ${clang_resource_dir_arg}
+    --extra-arg="-USWIG"
+    ${api_headers}
+
+  DEPENDS ${LLDB_RPC_GEN_EXE} ${api_headers}
+  COMMENT "Generating sources for lldb-rpc-server..."
+  WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+)
+
+add_custom_target(lldb-rpc-generate-sources
+  DEPENDS
+    ${lldb_rpc_gen_byproducts}
+    lldb-sbapi-dwarf-enums)
+
+add_dependencies(lldb-rpc-generate-sources clang-resource-headers)
diff --git a/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake b/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake
new file mode 100644
index 0000000000000..97ad481140248
--- /dev/null
+++ b/lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake
@@ -0,0 +1,101 @@
+set(derived_headers_location "${CMAKE_CURRENT_BINARY_DIR}/DerivedHeaders")
+
+# Obtain the original headers from their staged location in the build directory.
+set(original_headers_location "${CMAKE_BINARY_DIR}/include/lldb")
+set(headers_to_process
+  SBDefines.h
+  lldb-defines.h
+  lldb-enumerations.h
+  lldb-types.h
+)
+
+file(MAKE_DIRECTORY ${derived_headers_location})
+
+# Take the original headers and convert them RPC as necessary using the conversion script.
+set(original_headers)
+set(derived_headers)
+foreach(header ${headers_to_process})
+  set(original_header "${original_headers_location}/${header}")
+
+  get_filename_component(header_filename ${header} NAME)
+  string(REPLACE "lldb-" "lldb-rpc-" rpc_header_filename "${header_filename}")
+  set(derived_header "${derived_headers_location}/${rpc_header_filename}")
+
+  list(APPEND original_headers "${original_header}")
+  list(APPEND derived_headers "${derived_header}")
+  add_custom_command(OUTPUT ${derived_header}
+    COMMAND ${Python3_EXECUTABLE} ${LLDB_SOURCE_DIR}/scripts/convert-lldb-header-to-rpc-header.py
+            ${original_header} ${derived_header}
+    DEPENDS ${original_header}
+
+    COMMENT "Creating ${derived_header}"
+  )
+endforeach()
+
+# Do the same thing for any header files that were autogenerated.
+set(generated_headers_to_process
+  API/SBLanguages.h
+)
+foreach(header ${generated_headers_to_process})
+  set(original_header "${LLDB_OBJ_DIR}/include/lldb/${header}")
+
+  get_filename_component(header_filename ${header} NAME)
+  string(REPLACE "lldb-" "lldb-rpc-" rpc_header_filename "${header_filename}")
+  set(derived_header "${derived_headers_location}/${rpc_header_filename}")
+
+  list(APPEND original_headers "${original_header}")
+  list(APPEND derived_headers "${derived_header}")
+  add_custom_command(OUTPUT ${derived_header}
+    COMMAND ${CMAKE_COMMAND} -E copy ${original_header} ${derived_header}
+    COMMAND ${Python3_EXECUTABLE} ${LLDB_SOURCE_DIR}/scripts/convert-lldb-header-to-rpc-header.py
+            ${original_header} ${derived_header}
+    DEPENDS lldb-sbapi-dwarf-enums
+
+    COMMENT "Creating ${derived_header}"
+  )
+endforeach()
+
+add_custom_target(copy-aux-rpc-headers DEPENDS ${derived_headers})
+add_dependencies(copy-aux-rpc-headers liblldb-header-staging)
+
+list(APPEND public_headers
+  ${derived_headers_location}/SBDefines.h
+  ${derived_headers_location}/SBLanguages.h
+  ${derived_headers_location}/lldb-rpc-enumerations.h
+  ${derived_headers_location}/lldb-rpc-types.h
+  ${derived_headers_location}/lldb-rpc-defines.h
+)
+
+# Collect and preprocess headers for the framework bundle
+set(version_header
+  ${derived_headers_location}/lldb-rpc-defines.h
+)
+
+function(FixIncludePaths in subfolder out)
+  get_filename_component(base_name ${in} NAME)
+  set(parked_header ${CMAKE_CURRENT_BINARY_DIR}/ParkedHeaders/${subfolder}/${base_name})
+  set(${out} ${parked_header} PARENT_SCOPE)
+  find_program(unifdef_EXECUTABLE unifdef)
+
+  add_custom_command(OUTPUT ${parked_header}
+    COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.py
+            -f lldb_rpc -i ${in} -o ${parked_header} -p ${unifdef_EXECUTABLE} USWIG
+    DEPENDS ${in}
+    COMMENT "Fixing includes in ${in}"
+  )
+endfunction()
+
+set(preprocessed_headers)
+
+# Apply include-paths fix and any version fix on all headers and park them.
+foreach(source_header ${public_headers})
+  FixIncludePaths(${source_header} Headers parked_header)
+  list(APPEND preprocessed_headers ${parked_header})
+endforeach()
+
+# Wrap header preprocessing in a target, so liblldbrpc can depend on.
+add_custom_target(liblldbrpc-headers DEPENDS ${preprocessed_headers})
+add_dependencies(liblldbrpc-headers copy-aux-rpc-headers liblldb-header-staging)
+set_target_properties(liblldbrpc-headers PROPERTIES
+  LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ParkedHeaders
+)
diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/CMakeLists.txt b/lldb/tools/lldb-rpc/lldb-rpc-gen/CMakeLists.txt
new file mode 100644
index 0000000000000..65b76431d1bea
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/CMakeLists.txt
@@ -0,0 +1,23 @@
+add_lldb_tool(lldb-rpc-gen
+    RPCCommon.cpp
+    server/RPCServerHeaderEmitter.cpp
+    server/RPCServerSourceEmitter.cpp
+    lldb-rpc-gen.cpp
+
+    CLANG_LIBS
+      clangAST
+      clangBasic
+      clangCodeGen
+      clangFrontend
+      clangLex
+      clangRewrite
+      clangSerialization
+      clangTooling
+
+    LINK_COMPONENTS
+      Support
+  )
+
+if (NOT DEFINED LLDB_RPC_GEN_EXE)
+  set(LLDB_RPC_GEN_EXE $<TARGET_FILE:lldb-rpc-gen> CACHE STRING "Executable that generates lldb-rpc-server")
+endif()
diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp b/lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp
new file mode 100644
index 0000000000000..37831a0cf195c
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp
@@ -0,0 +1,501 @@
+//===-- RPCCommon.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RPCCommon.h"
+
+#include "clang/AST/AST.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Lex/Lexer.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <cstring>
+
+using namespace clang;
+
+// We intentionally do not generate some classes because they are currently
+// inconvenient, they aren't really used by most consumers, or we're not sure
+// why they exist.
+static constexpr llvm::StringRef DisallowedClasses[] = {
+    "SBCommunication", // This class is pretty much unused by consumers, so we
+                       // skip it.
+    "SBInputReader",   // This class is pretty much unused by consumers, so we
+                       // skip it.
+    "SBCommandPluginInterface", // This class uses virtual functions, and the SB
+                                // API should not have those, so we skip this
+                                // class.
+    "SBCommand", // There's nothing too difficult about this one, but many of
+                 // its methods take a SBCommandPluginInterface pointer so
+                 // there's no reason to support this.
+};
+
+// NOTE: In lldb-rpc-gen, we use mangled names when we need to work with
+// functions. We do this because we support many functions that have overloads,
+// and mangled names have no ambiguity which makes it easier to keep track of.
+// This is also possible since the LLDB SB API is stable.
+
+// We intentionally avoid generating certain methods either because they are
+// difficult to support correctly or they aren't really used much from C++.
+// NOTE: These methods are marked as deprecated using LLDB_DEPRECATED.
+// Normally this macro defines to the deprecated annotation, but this
+// functionality is removed in SBDefines.h when generating SWIG bindings which
+// we use for testing. Because of this, there is no annotation for the tool to
+// pick up on so this list will be used while we have this restriction in
+// SBDefines.h.
+static constexpr llvm::StringRef DisallowedMethods[] = {
+    // The threading functionality in SBHostOS is deprecated and thus we do not
+    // generate them. It would be ideal to add the annotations to the methods
+    // and then support not generating deprecated methods. However, without
+    // annotations the generator generates most things correctly. This one is
+    // problematic because it returns a pointer to an "opaque" structure
+    // (thread_t) that is not `void *`, so special casing it is more effort than
+    // it's worth.
+    "_ZN4lldb8SBHostOS10ThreadJoinEP17_opaque_pthread_tPPvPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadCancelEP17_opaque_pthread_tPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadCreateEPKcPFPvS3_ES3_PNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS12ThreadDetachEP17_opaque_pthread_tPNS_7SBErrorE",
+    "_ZN4lldb8SBHostOS13ThreadCreatedEPKc",
+};
+
+static constexpr llvm::StringRef ClassesWithoutDefaultCtor[] = {
+    "SBHostOS",
+    "SBReproducer",
+};
+
+static constexpr llvm::StringRef ClassesWithoutCopyOperations[] = {
+    "SBHostOS",
+    "SBReproducer",
+    "SBStream",
+    "SBProgress",
+};
+
+static constexpr llvm::StringRef MethodsWithPointerPlusLen[] = {
+    "_ZN4lldb6SBData11ReadRawDataERNS_7SBErrorEyPvm",
+    "_ZN4lldb6SBData7SetDataERNS_7SBErrorEPKvmNS_9ByteOrderEh",
+    "_ZN4lldb6SBData20SetDataWithOwnershipERNS_7SBErrorEPKvmNS_9ByteOrderEh",
+    "_ZN4lldb6SBData25CreateDataFromUInt64ArrayENS_9ByteOrderEjPym",
+    "_ZN4lldb6SBData25CreateDataFromUInt32ArrayENS_9ByteOrderEjPjm",
+    "_ZN4lldb6SBData25CreateDataFromSInt64ArrayENS_9ByteOrderEjPxm",
+    "_ZN4lldb6SBData25CreateDataFromSInt32ArrayENS_9ByteOrderEjPim",
+    "_ZN4lldb6SBData25CreateDataFromDoubleArrayENS_9ByteOrderEjPdm",
+    "_ZN4lldb6SBData22SetDataFromUInt64ArrayEPym",
+    "_ZN4lldb6SBData22SetDataFromUInt32ArrayEPjm",
+    "_ZN4lldb6SBData22SetDataFromSInt64ArrayEPxm",
+    "_ZN4lldb6SBData22SetDataFromSInt32ArrayEPim",
+    "_ZN4lldb6SBData22SetDataFromDoubleArrayEPdm",
+    "_ZN4lldb10SBDebugger22GetDefaultArchitectureEPcm",
+    "_ZN4lldb10SBDebugger13DispatchInputEPvPKvm",
+    "_ZN4lldb10SBDebugger13DispatchInputEPKvm",
+    "_ZN4lldb6SBFile4ReadEPhmPm",
+    "_ZN4lldb6SBFile5WriteEPKhmPm",
+    "_ZNK4lldb10SBFileSpec7GetPathEPcm",
+    "_ZN4lldb10SBFileSpec11ResolvePathEPKcPcm",
+    "_ZN4lldb8SBModule10GetVersionEPjj",
+    "_ZN4lldb12SBModuleSpec12SetUUIDBytesEPKhm",
+    "_ZNK4lldb9SBProcess9GetSTDOUTEPcm",
+    "_ZNK4lldb9SBProcess9GetSTDERREPcm",
+    "_ZNK4lldb9SBProcess19GetAsyncProfileDataEPcm",
+    "_ZN4lldb9SBProcess10ReadMemoryEyPvmRNS_7SBErrorE",
+    "_ZN4lldb9SBProcess11WriteMemoryEyPKvmRNS_7SBErrorE",
+    "_ZN4lldb9SBProcess21ReadCStringFromMemoryEyPvmRNS_7SBErrorE",
+    "_ZNK4lldb16SBStructuredData14GetStringValueEPcm",
+    "_ZN4lldb8SBTarget23BreakpointCreateByNamesEPPKcjjRKNS_"
+    "14SBFileSpecListES6_",
+    "_ZN4lldb8SBTarget10ReadMemoryENS_9SBAddressEPvmRNS_7SBErrorE",
+    "_ZN4lldb8SBTarget15GetInstructionsENS_9SBAddressEPKvm",
+    "_ZN4lldb8SBTarget25GetInstructionsWithFlavorENS_9SBAddressEPKcPKvm",
+    "_ZN4lldb8SBTarget15GetInstructionsEyPKvm",
+    "_ZN4lldb8SBTarget25GetInstructionsWithFlavorEyPKcPKvm",
+    "_ZN4lldb8SBThread18GetStopDescriptionEPcm",
+    // The below mangled names are used for dummy methods in shell tests
+    // that test the emitters' output. If you're adding any new mangled names
+    // from the actual SB API to this list please add them above.
+    "_ZN4lldb33SBRPC_"
+    "CHECKCONSTCHARPTRPTRWITHLEN27CheckConstCharPtrPtrWithLenEPPKcm",
+    "_ZN4lldb19SBRPC_CHECKARRAYPTR13CheckArrayPtrEPPKcm",
+    "_ZN4lldb18SBRPC_CHECKVOIDPTR12CheckVoidPtrEPvm",
+};
+
+// These classes inherit from rpc::ObjectRef directly (as opposed to
+// rpc::LocalObjectRef). Changing them from ObjectRef to LocalObjectRef is ABI
+// breaking, so we preserve that compatibility here.
+//
+// lldb-rpc-gen emits classes as LocalObjectRefs by default.
+//
+// FIXME: Does it matter which one it emits by default?
+static constexpr llvm::StringRef ClassesThatInheritFromObjectRef[] = {
+    "SBAddress",
+    "SBBreakpointName",
+    "SBCommandInterpreter",
+    "SBCommandRe...
[truncated]

@chelcassanova
Copy link
Contributor Author

Unfortuately, I haven't been able to reproduce the Ubuntu bot failure seen here: https://lab.llvm.org/buildbot/#/builders/195/builds/11604, even while using a Linux VM. At this point I'd really appreciate some pointers/help with reproing that issue.

@chelcassanova chelcassanova force-pushed the upstream-lldb-rpc/reland-lldb-rpc-gen-tool-attempt-2 branch from 7ddb39b to 94cb15f Compare July 16, 2025 00:22
@DavidSpickett
Copy link
Collaborator

You should email the worker admin and see if they can help. "Worker:" tab then "admin".

It is doing remote testing but the failure seems to be before that step so I think it's something to do with the host.

@chelcassanova chelcassanova force-pushed the upstream-lldb-rpc/reland-lldb-rpc-gen-tool-attempt-2 branch from 94cb15f to 015acc5 Compare July 17, 2025 15:45
@chelcassanova
Copy link
Contributor Author

You should email the worker admin and see if they can help. "Worker:" tab then "admin".

Thanks! I've reached out to them and I'm waiting to hear back.

It is doing remote testing but the failure seems to be before that step so I think it's something to do with the host.

It's a build failure that looks to be related to the sysroot not being set correctly in the tool for that specific configuration (which is why we're seeing the failure to resolve includes like <cstdint>)

@chelcassanova
Copy link
Contributor Author

To sum up the conversation I've been having with Vladimir Vereschaka (@vvereschaka) thus far, for the cross-compile build on the lldb-remote-linux-ubuntu bot, the step that generates and compiles the sources from lldb-rpc-gen is taking place too early on the target. It's taking place before the target Clang toolchain is fully built, which is why it's unable to resolve the includes for things like <ctstdint>. He proposes splitting up the build for RPC into two stages (similar to what we do with lldb-server). As I understand it, the lldb-rpc-gen tool would get built on the host, while the sources are generated and compiled on the target using the just-built tool.

…pt 2

Second attempt at relanding the lldb-rpc-gen tool. This should fix an
assert that was hitting when building on Linux. The assert would hit in
the server source emitter, specifically when attemping to determine the
storage size for a return type is that is a pointer, but isn't a const
char *, const char ** or void pointer.

The assert would hit when attempting to generate
SBAttachInfo::GetProcessPluginName, which returns a const char *
(meaning it shouldn't have been in the code block for the assert at
all). The reason that it was hitting the assert when generating this
function is that lldb_rpc_gen::TypeIsConstCharPtr was returning false
for this function even though it did return a const char *. This was
happening because when checking the return type for a const char *,
TypeIsConstCharPtr would only check that the underlying type was a
signed char. This failed on Linux (but was fine on Darwin), as the
underlying type also needs to be checked for being an unsigned char.

Original PR Description:
This commit upstreams the lldb-rpc-gen tool, a ClangTool that generates
the LLDB RPC client and server interfaces. This tool, as well as LLDB
RPC itself is built by default. If it needs to be disabled, put
-DLLDB_BUILD_LLDBRPC=OFF in your CMake invocation.

https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804

Original PR Link:
github.com/llvm/pull/138031
@chelcassanova chelcassanova force-pushed the upstream-lldb-rpc/reland-lldb-rpc-gen-tool-attempt-2 branch from 9391375 to 3e4e125 Compare July 18, 2025 23:26
@vvereschaka vvereschaka self-requested a review July 19, 2025 00:41
@vvereschaka
Copy link
Contributor

Thank you @chelcassanova,

I'll take a look and test the changes with the cross builder.

As I understand it, the lldb-rpc-gen tool would get built on the host, while the sources are generated and compiled on the target using the just-built tool.

To be more precisely, the generated sources also will get built on the host for the cross-platform builds, but during the second stage when the clang toolchain for the target platform is already fully in place.

As example, here is how Aarch64 lldb-server gets built on x86_64 builder host using just-built clang cross toolchain:
https://lab.llvm.org/buildbot/#/builders/195/builds/12045/steps/11/logs/stdio
https://lab.llvm.org/buildbot/#/builders/195/builds/12045/steps/12/logs/stdio

@chelcassanova
Copy link
Contributor Author

To be more precisely, the generated sources also will get built on the host for the cross-platform builds, but during the second stage when the clang toolchain for the target platform is already fully in place.

Ah ok, this is why for lldb-server it has a CMake variable to skip building it in phase 1. I added a variable to CMake (LLDB_CAN_USE_LLDB_RPC_SERVER) that when enabled, should allow the lldb-rpc-server to get built separate from the lldb-rpc-gen tool.

Copy link
Contributor

@vvereschaka vvereschaka left a comment

Choose a reason for hiding this comment

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

Hi @chelcassanova ,

I have two questions in addition:

  • I see the following warnings during the build
[671/5326] Fixing includes in /home/buildbot/worker/temp/build-stage2/tools/lldb/tools/lldb-rpc/DerivedHeaders/SBLanguages.h
Unable to find unifdef executable. Guards will not be removed from input files. Exiting...
[672/5326] Fixing includes in /home/buildbot/worker/temp/build-stage2/tools/lldb/tools/lldb-rpc/DerivedHeaders/SBDefines.h
Unable to find unifdef executable. Guards will not be removed from input files. Exiting...
...

Is it expectable?

  • I didn't find any result binaries, such as lldb-rpc-server or similar. Is it also expectable?

@@ -323,4 +323,14 @@ else()
set(LLDB_CAN_USE_DEBUGSERVER OFF)
endif()

# In a cross-compile build, we need to skip building the generated
# lldb-rpc sources in the host build.
if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
Copy link
Contributor

Choose a reason for hiding this comment

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

It needs to be wrapped with the if (NOT DEFINED LLDB_CAN_USE_LLDB_RPC_SERVER) condition.
Also, I think, the full check would be optimal to look like this:

if (NOT DEFINED LLDB_CAN_USE_LLDB_RPC_SERVER)
  if ((CMAKE_CROSSCOMPILING OR LLVM_HOST_TRIPLE MATCHES "${LLVM_DEFAULT_TARGET_TRIPLE}") AND
      CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
       ... ON ...
  else()
       ... OFF ...
  endif()
endif()
  • CMAKE_CROSSCOMPILING - when the cross platform build
  • LLVM_HOST_TRIPLE MATCHES "${LLVM_DEFAULT_TARGET_TRIPLE}" - "regular" build
  • otherwise this is the cross toolchain build

set(LLDB_CAN_USE_LLDB_RPC_SERVER OFF)
endif()

set(LLDB_BUILD_LLDBRPC ON CACHE BOOL "")
Copy link
Contributor

Choose a reason for hiding this comment

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

it should be replaced with something like this:

+if (CMAKE_CROSSCOMPILING)
+  set(LLDB_BUILD_LLDBRPC OFF CACHE BOOL "")
+  get_host_tool_path(lldb-rpc-gen LLDB_RPC_GEN_EXE lldb_rpc_gen_exe lldb_rpc_gen_target)
+else()
   set(LLDB_BUILD_LLDBRPC ON CACHE BOOL "")
+endif()

We need to use the cross-platform tool during the cross compiling, which is specified by LLVM_NATIVE_TOOL_DIR. Otherwise the build will use the target exec binaries and fail because of the following error instead

/bin/sh: 1: /home/buildbot/worker/temp/build-stage2/bin/lldb-rpc-gen: Exec format error

@@ -132,6 +132,10 @@ if(TARGET lldb-framework)
add_lldb_test_dependency(lldb-framework)
endif()

if (LLDB_BUILD_LLDBRPC)
Copy link
Contributor

Choose a reason for hiding this comment

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

LLDB_BUILD_LLDBRPC -> LLDB_CAN_USE_LLDB_RPC_SERVER

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants