Skip to content

[DRAFT][lldb][rpc] Upstream RPC Client Library Emitters #147655

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

This commit upstreams the client side emitters for the lldb-rpc-gen tool alongside tests for its functionality and heuristics.

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

@llvmbot
Copy link
Member

llvmbot commented Jul 9, 2025

@llvm/pr-subscribers-lldb

Author: Chelsea Cassanova (chelcassanova)

Changes

This commit upstreams the client side emitters for the lldb-rpc-gen tool alongside tests for its functionality and heuristics.

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


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

17 Files Affected:

  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckArrayPointer.h (+20)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstCharPtrPtrWithLen.h (+19)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstSBRef.h (+19)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckNonConstSBRef.h (+20)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckSBPointer.h (+21)
  • (added) lldb/test/Shell/RPC/Generator/Inputs/Client/CheckVoidPtr.h (+19)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckArrayPointer.test (+11)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstCharPtrPtrWithLen.test (+10)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstSBRef.test (+14)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckNonConstSBRef.test (+13)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckSBPointer.test (+15)
  • (added) lldb/test/Shell/RPC/Generator/Tests/Client/CheckVoidPtr.test (+10)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.cpp (+124)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.h (+44)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibrarySourceEmitter.cpp (+542)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibrarySourceEmitter.h (+92)
  • (added) lldb/tools/lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp (+414)
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckArrayPointer.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckArrayPointer.h
new file mode 100644
index 0000000000000..18ec92a976b8a
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckArrayPointer.h
@@ -0,0 +1,20 @@
+#ifndef LLDB_API_SBRPC_CHECKARRAYPTR_H
+#define LLDB_API_SBRPC_CHECKARRAYPTR_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKARRAYPTR {
+public:
+  // Pointers to arrays followed by length must use a
+  // Bytes object constructed using that pointer and the sizeof()
+  // the array object.
+  int CheckArrayPtr(uint64_t *array, size_t array_len);
+
+}; // class SBRPC_CHECKARRAYPTR
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKARRAYPTR_H
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstCharPtrPtrWithLen.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstCharPtrPtrWithLen.h
new file mode 100644
index 0000000000000..fa64492cf5aa7
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstCharPtrPtrWithLen.h
@@ -0,0 +1,19 @@
+#ifndef LLDB_API_SBRPC_CHECKCONSTCHARPTRPTRWITHLEN_H
+#define LLDB_API_SBRPC_CHECKCONSTCHARPTRPTRWITHLEN_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKCONSTCHARPTRPTRWITHLEN {
+public:
+  // const char ** followed by len must use a StringList
+  // when being encoded.
+  int CheckConstCharPtrPtrWithLen(const char **arg1, size_t len);
+
+}; // class SBRPC_CHECKCONSTCHARPTRPTRWITHLEN
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKCONSTCHARPTRPTRWITHLEN_H
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstSBRef.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstSBRef.h
new file mode 100644
index 0000000000000..153fdad60a494
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstSBRef.h
@@ -0,0 +1,19 @@
+#ifndef LLDB_API_SBRPC_CHECKCONSTSBREF_H
+#define LLDB_API_SBRPC_CHECKCONSTSBREF_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKCONSTSBREF {
+public:
+  // Const references to SB classes should be encoded as usual without
+  // needing to create a new object with its own connection.
+  int CheckConstSBRef(const SBDebugger &debugger_ref);
+
+}; // class SBRPC_CHECKCONSTSBREF
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKCONSTSBREF_H
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckNonConstSBRef.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckNonConstSBRef.h
new file mode 100644
index 0000000000000..90ee3d3a7fbd6
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckNonConstSBRef.h
@@ -0,0 +1,20 @@
+#ifndef LLDB_API_SBRPC_CHECKNONCONSTSBREF_H
+#define LLDB_API_SBRPC_CHECKNONCONSTSBREF_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKNONCONSTSBREF {
+public:
+  // Non-const references to SB classes will have new objects
+  // of that class constructed with the connection as the first parameter
+  // before being encoded if their existing connection is invalid.
+  int CheckNonConstSBRef(SBDebugger &debugger_ref);
+
+}; // class SBRPC_CHECKNONCONSTSBREF
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKNONCONSTSBREF_H
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckSBPointer.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckSBPointer.h
new file mode 100644
index 0000000000000..d9b7efa820f53
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckSBPointer.h
@@ -0,0 +1,21 @@
+#ifndef LLDB_API_SBRPC_CHECKSBPTR_H
+#define LLDB_API_SBRPC_CHECKSBPTR_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKSBPTR {
+public:
+  // Pointers to SB objects must be checked to
+  // see if they're null. If so, then a new object of the given
+  // class must be created and encoded. Otherwise, the original
+  // parameter will be encoded.
+  int CheckSBPtr(SBDebugger *debugger_ptr);
+
+}; // class SBRPC_CHECKSBPTR
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKSBPTR_H
diff --git a/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckVoidPtr.h b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckVoidPtr.h
new file mode 100644
index 0000000000000..fa6484fc8d7cd
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Inputs/Client/CheckVoidPtr.h
@@ -0,0 +1,19 @@
+#ifndef LLDB_API_SBRPC_CHECKVOIDPTR_H
+#define LLDB_API_SBRPC_CHECKVOIDPTR_H
+
+#include <cstddef>
+#include <cstdio>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+class LLDB_API SBRPC_CHECKVOIDPTR {
+public:
+  // void * followed by length must use a Bytes object
+  // when being encoded.
+  int CheckVoidPtr(void *buf, size_t len);
+
+}; // class SBRPC_CHECKVOIDPTR
+} // namespace lldb
+
+#endif // LLDB_API_SBRPC_CHECKVOIDPTR_H
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckArrayPointer.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckArrayPointer.test
new file mode 100644
index 0000000000000..1b58b389d612e
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckArrayPointer.test
@@ -0,0 +1,11 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckArrayPointer.h
+
+RUN: cat %t/lib/CheckArrayPointer.cpp | FileCheck %s
+
+# Pointers to arrays followed by length must use a
+# Bytes object constructed using that pointer and the sizeof()
+# the array object.
+CHECK: lldb_rpc::SBRPC_CHECKARRAYPTR::CheckArrayPtr
+CHECK: Bytes array_buffer(array, sizeof(uint64_t));
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstCharPtrPtrWithLen.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstCharPtrPtrWithLen.test
new file mode 100644
index 0000000000000..84d18c95fa7d2
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstCharPtrPtrWithLen.test
@@ -0,0 +1,10 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckConstCharPtrPtrWithLen.h
+
+RUN: cat %t/lib/CheckConstCharPtrPtrWithLen.cpp | FileCheck %s
+
+# const char ** followed by len must use a StringList
+# when being encoded.
+CHECK: lldb_rpc::SBRPC_CHECKCONSTCHARPTRPTRWITHLEN::CheckConstCharPtrPtrWithLen
+CHECK: StringList arg1_list
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstSBRef.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstSBRef.test
new file mode 100644
index 0000000000000..9b10d1711a9bc
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstSBRef.test
@@ -0,0 +1,14 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckConstSBRef.h
+
+RUN: cat %t/lib/CheckConstSBRef.cpp | FileCheck %s
+
+# Const references to SB classes should be encoded as usual without
+# needing to create a new object with its own connection. Here
+# we're checking to make sure that the given SB object ref will get
+# encoded immediately after the previous argument gets encoded without
+# anything happening in between.
+CHECK: lldb_rpc::SBRPC_CHECKCONSTSBREF::CheckConstSBRef
+CHECK: RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, *this);
+CHECK: RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, debugger_ref)
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckNonConstSBRef.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckNonConstSBRef.test
new file mode 100644
index 0000000000000..d396e927b46d2
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckNonConstSBRef.test
@@ -0,0 +1,13 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckNonConstSBRef.h
+
+RUN: cat %t/lib/CheckNonConstSBRef.cpp | FileCheck %s
+
+# Non-const references to SB classes will have new objects
+# of that class constructed with the connection as the first parameter
+# before being encoded if their existing connection is invalid.
+CHECK: lldb_rpc::SBRPC_CHECKNONCONSTSBREF::CheckNonConstSBRef
+CHECK: if (connection_sp && !debugger_ref.ObjectRefIsValid())
+CHECK:     debugger_ref = lldb_rpc::SBDebugger(connection_sp);
+CHECK:   RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, debugger_ref);
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckSBPointer.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckSBPointer.test
new file mode 100644
index 0000000000000..5f355138182a8
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckSBPointer.test
@@ -0,0 +1,15 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckSBPointer.h
+
+RUN: cat %t/lib/CheckSBPointer.cpp | FileCheck %s
+
+# Pointers to SB objects must be checked to
+# see if they're null. If so, then a new object of the given
+# class must be created and encoded. Otherwise, the original
+# parameter will be encoded.
+CHECK: lldb_rpc::SBRPC_CHECKSBPTR::CheckSBPtr
+CHECK: if (debugger_ptr)
+CHECK:   RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, *debugger_ptr);
+CHECK: else
+CHECK:    RPCValueEncoder(send, rpc_common::RPCPacket::ValueType::Argument, rpc::ObjectRef(ObjectRefGetConnectionID(), eClass_lldb_SBDebugger, LLDB_RPC_INVALID_OBJECT_ID));
diff --git a/lldb/test/Shell/RPC/Generator/Tests/Client/CheckVoidPtr.test b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckVoidPtr.test
new file mode 100644
index 0000000000000..9907126a28fa6
--- /dev/null
+++ b/lldb/test/Shell/RPC/Generator/Tests/Client/CheckVoidPtr.test
@@ -0,0 +1,10 @@
+RUN: mkdir -p %t/server
+RUN: mkdir -p %t/lib
+RUN: %lldb-rpc-gen --output-dir=%t %S/../../Inputs/CheckVoidPtr.h
+
+RUN: cat %t/lib/CheckVoidPtr.cpp | FileCheck %s
+
+# void * followed by length must use a Bytes object
+# when being encoded.
+CHECK: lldb_rpc::SBRPC_CHECKVOIDPTR::CheckVoidPtr
+CHECK: Bytes buf_buffer(buf, len);
diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.cpp b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.cpp
new file mode 100644
index 0000000000000..9537b490856f1
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.cpp
@@ -0,0 +1,124 @@
+#include "RPCLibraryHeaderEmitter.h"
+#include "RPCCommon.h"
+
+#include "clang/AST/AST.h"
+#include "clang/AST/Mangle.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace lldb_rpc_gen;
+
+void RPCLibraryHeaderEmitter::StartClass(std::string ClassName) {
+  CurrentClass = std::move(ClassName);
+  std::string BaseClass =
+      lldb_rpc_gen::SBClassInheritsFromObjectRef(CurrentClass)
+          ? "ObjectRef"
+          : "LocalObjectRef";
+  EmitLine("class " + CurrentClass + " : public rpc::" + BaseClass + " {");
+  EmitLine("public:");
+  IndentLevel++;
+  if (lldb_rpc_gen::SBClassRequiresDefaultCtor(CurrentClass))
+    EmitLine(CurrentClass + "();");
+
+  // NOTE: There's currently only one RPC-specific extension that is actually
+  // used AFAICT. We can generalize this if we need more.
+  if (CurrentClass == "SBDebugger")
+    EmitLine("int SetIOFile(const char *path);");
+}
+
+void RPCLibraryHeaderEmitter::EndClass() {
+  if (lldb_rpc_gen::SBClassRequiresCopyCtorAssign(CurrentClass)) {
+    if (!CopyCtorEmitted)
+      EmitLine(CurrentClass + "(const lldb_rpc::" + CurrentClass + " &rhs);");
+    if (!CopyAssignEmitted)
+      EmitLine(CurrentClass + " &operator=(const lldb_rpc::" + CurrentClass +
+               " &rhs);");
+  }
+  if (!MoveCtorEmitted)
+    EmitLine(CurrentClass + "(lldb_rpc::" + CurrentClass + " &&rhs);");
+  if (!MoveAssignEmitted)
+    EmitLine(CurrentClass + " &operator=(" + CurrentClass + " &&rhs);");
+
+  IndentLevel--;
+  EmitLine("}; // class " + CurrentClass);
+  CurrentClass.clear();
+}
+
+void RPCLibraryHeaderEmitter::EmitMethod(const Method &method) {
+  std::string DeclarationLine;
+  llvm::raw_string_ostream DeclarationLineStream(DeclarationLine);
+
+  if (method.IsCopyCtor)
+    CopyCtorEmitted = true;
+  else if (method.IsCopyAssign)
+    CopyAssignEmitted = true;
+  else if (method.IsMoveCtor)
+    MoveCtorEmitted = true;
+  else if (method.IsMoveAssign)
+    MoveAssignEmitted = true;
+
+  if (method.IsExplicitCtorOrConversionMethod)
+    DeclarationLineStream << "explicit ";
+  else if (!method.IsInstance)
+    DeclarationLineStream << "static ";
+
+  if (!method.IsDtor && !method.IsConversionMethod && !method.IsCtor)
+    DeclarationLineStream << lldb_rpc_gen::ReplaceLLDBNamespaceWithRPCNamespace(
+                                 method.ReturnType.getAsString(method.Policy))
+                          << " ";
+  DeclarationLineStream << method.BaseName << "("
+                        << method.CreateParamListAsString(
+                               eLibrary, /*IncludeDefaultValue = */ true)
+                        << ")";
+  if (method.IsConst)
+    DeclarationLineStream << " const";
+  DeclarationLineStream << ";";
+
+  EmitLine(DeclarationLine);
+}
+
+void RPCLibraryHeaderEmitter::EmitEnum(EnumDecl *E) {
+  // NOTE: All of the enumerations embedded in SB classes are currently
+  // anonymous and backed by an unsigned int.
+  EmitLine("enum : unsigned {");
+  IndentLevel++;
+  for (const EnumConstantDecl *EC : E->enumerators()) {
+    std::string EnumValue = EC->getNameAsString();
+    SmallString<16> ValueStr;
+    EC->getInitVal().toString(ValueStr);
+    EnumValue += " = " + ValueStr.str().str() + ", ";
+    EmitLine(EnumValue);
+  }
+
+  IndentLevel--;
+  EmitLine("};");
+}
+
+std::string RPCLibraryHeaderEmitter::GetHeaderGuard() {
+  const std::string UpperFilenameNoExt =
+      llvm::sys::path::stem(
+          llvm::sys::path::filename(OutputFile->getFilename()))
+          .upper();
+  return "GENERATED_LLDB_RPC_LIBRARY_" + UpperFilenameNoExt + "_H";
+}
+
+void RPCLibraryHeaderEmitter::Begin() {
+  const std::string HeaderGuard = GetHeaderGuard();
+  EmitLine("#ifndef " + HeaderGuard);
+  EmitLine("#define " + HeaderGuard);
+  EmitLine("");
+  EmitLine("#include <lldb-rpc/common/RPCPublic.h>");
+  EmitLine("#include \"SBDefines.h\"");
+  EmitLine("#include \"LLDBRPC.h\"");
+  EmitLine("");
+  EmitLine("namespace lldb_rpc {");
+}
+
+void RPCLibraryHeaderEmitter::End() {
+  EmitLine("} // namespace lldb_rpc");
+  EmitLine("#endif // " + GetHeaderGuard());
+}
diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.h b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.h
new file mode 100644
index 0000000000000..b9f22585c7955
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.h
@@ -0,0 +1,44 @@
+#ifndef LLDB_RPC_GEN_RPCLIBRARYHEADEREMITTER_H
+#define LLDB_RPC_GEN_RPCLIBRARYHEADEREMITTER_H
+
+#include "RPCCommon.h"
+
+#include "clang/AST/AST.h"
+#include "llvm/Support/ToolOutputFile.h"
+
+using namespace clang;
+
+namespace lldb_rpc_gen {
+
+class RPCLibraryHeaderEmitter : public FileEmitter {
+public:
+  RPCLibraryHeaderEmitter(std::unique_ptr<llvm::ToolOutputFile> &&OutputFile)
+      : FileEmitter(std::move(OutputFile)), CurrentClass() {
+    Begin();
+  }
+
+  ~RPCLibraryHeaderEmitter() { End(); }
+
+  void StartClass(std::string ClassName);
+
+  void EndClass();
+
+  void EmitMethod(const Method &method);
+
+  void EmitEnum(EnumDecl *E);
+
+private:
+  std::string GetHeaderGuard();
+
+  void Begin();
+
+  void End();
+
+  std::string CurrentClass;
+  bool CopyCtorEmitted = false;
+  bool CopyAssignEmitted = false;
+  bool MoveCtorEmitted = false;
+  bool MoveAssignEmitted = false;
+};
+} // namespace lldb_rpc_gen
+#endif // LLDB_RPC_GEN_RPCLIBRARYHEADEREMITTER_H
diff --git a/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibrarySourceEmitter.cpp b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibrarySourceEmitter.cpp
new file mode 100644
index 0000000000000..571fedc6edcce
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibrarySourceEmitter.cpp
@@ -0,0 +1,542 @@
+#include "RPCLibrarySourceEmitter.h"
+#include "RPCCommon.h"
+
+#include "clang/AST/AST.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang;
+using namespace lldb_rpc_gen;
+
+static constexpr llvm::StringRef ReturnVariableName("__result");
+
+// This map stores any method that needs custom logic with a struct that
+// tells us where the logic needs to be inserted and what code needs to be
+// inserted. The code here is stored as a raw string literal.
+const llvm::StringMap<RPCLibrarySourceEmitter::CustomLogic>
+    CustomLogicForMethods = {
+        {"_ZN4lldb10SBDebugger6CreateEbPFvPKcPvES3_",
+         {RPCLibrarySourceEmitter::CustomLogicLocation::eAfterDecode, R"code(
+    // Now source the .lldbinit files manually since we can't rely on the
+    // LLDB.framework on the other side to have special support for sourcing the right file
+    // since it would try to source "~/.lldbinit-lldb-rpc-server" followed by
+    // "~/.lldbinit". We want it to try "~.lldbinit-%s" where %s is the
+    // current program basename followed by "~/.lldbinit".
+
+    if (source_init_files && __result.ObjectRefIsValid()) {
+      const char *program_basename = rpc::GetProgramBasename();
+      if (program_basename) {
+        char init_path[PATH_MAX];
+        snprintf(init_path, sizeof(init_path), "~/.lldbinit-%s",
+                 program_basename);
+        lldb_rpc::SBFileSpec program_init_file(connection, init_path, true);
+        if (program_init_file.Exists()) {
+          char command_str[PATH_MAX];
+          snprintf(command_str, sizeof(command_str),
+                   "command source -s 1 -c 1 -e 0 '%s'", init_path);
+          __result.HandleCommand(command_str);
+        } else {
+          __result.HandleCommand("command source -s 1 -c 1 -e 0 '~/.lldbinit'");
+        }
+      }
+    })code"}},
+};
+
+static std::string GetLocalObjectRefCtor(const std::string &ClassName) {
+  return "rpc::LocalObjectRef(LLDB_RPC_INVALID_CONNECTION_ID, eClass_lldb_" +
+         ClassName + ", LLDB_RPC_INVALID_OBJECT_ID)";
+}
+
+static std::string GetObjectRefCtor(const std::string &ClassName) {
+  return "rpc::ObjectRef(LLDB_RPC_INVALID_CONNECTION_ID, eClass_lldb_" +
+         ClassName + ", LLDB_RPC_INVALID_OBJECT_ID)";
+}
+
+void RPCLibrarySourceEmitter::EmitCopyCtor() {
+  EmitLine("lldb_rpc::" + CurrentClass + "::" + CurrentClass +
+           "(const lldb_rpc::" + CurrentClass + " &rhs) = default;");
+}
+
+void RPCLibrarySourceEmitter::EmitCopyAssign() {
+  EmitLine("lldb_rpc::" + CurrentClass + " &lldb_rpc::" + CurrentClass +
+           "::operator=(const lldb_rpc::" + CurrentClass + " &rhs) = default;");
+}
+
+void RPCLibrarySourceEmitter::EmitMoveCtor() {
+  EmitLine("lldb_rpc::" + CurrentClass + "::" + CurrentClass +
+           "(lldb_rpc::" + CurrentClass + " &&rhs) = default;");
+}
+
+void RPCLibrarySourceEmitter::EmitMoveAssign() {
+  EmitLine("lldb_rpc::" + CurrentClass + " &lldb_rpc::" + CurrentClass +
+           "::operator=(lldb_rpc::" + CurrentClass + " &&rhs) = default;");
+}
+
+void RPCLibrarySourceEmitter::EmitMethod(const Method &method) {
+  if (method.IsCopyCtor) {
+    CopyCtorEmitted = true;
+    EmitCopyCtor();
+    return;
+  } else if (method.IsCopyAssign) {
+    CopyAssignEmitted = true;
+    EmitCopyAssign();
+    return;
+  } else if (method.IsMoveCtor) {
+    MoveCtorEmitted = true;
+    EmitMoveCtor();
+    return;
+  } else if (method.IsMoveAssign) {
+    MoveAssignEmitted = true;
+    EmitMoveAssign();
+    return;
+  }
+
+  EmitCommentHeader(method);
+  EmitFunctionHeader(method);
+  EmitFunctionBody(method);
+  EmitFunctionFooter();
+}
+
+void RPCLibrarySourceEmitter::StartClass(std::string ClassName) {
+  CurrentClass = std::move(ClassName);
+  if (lldb_rpc_gen::SBClassRequiresDefaultCtor(CurrentClass)) {
+    std::string BaseClassCtor =
+        lldb_rpc_gen::SBClassInheritsFromObjectRef(CurrentClass)
+            ? GetObjectRefCtor(CurrentClass)
+            : GetLocalObjectRefCtor(CurrentClass);
+    EmitLine("lldb_rpc...
[truncated]

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.

2 participants