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
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions lldb/test/Shell/RPC/Generator/Inputs/Client/CheckArrayPointer.h
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions lldb/test/Shell/RPC/Generator/Inputs/Client/CheckConstSBRef.h
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions lldb/test/Shell/RPC/Generator/Inputs/Client/CheckSBPointer.h
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions lldb/test/Shell/RPC/Generator/Inputs/Client/CheckVoidPtr.h
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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));
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions lldb/test/Shell/RPC/Generator/Tests/Client/CheckConstSBRef.test
Original file line number Diff line number Diff line change
@@ -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)
Original file line number Diff line number Diff line change
@@ -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);
15 changes: 15 additions & 0 deletions lldb/test/Shell/RPC/Generator/Tests/Client/CheckSBPointer.test
Original file line number Diff line number Diff line change
@@ -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));
10 changes: 10 additions & 0 deletions lldb/test/Shell/RPC/Generator/Tests/Client/CheckVoidPtr.test
Original file line number Diff line number Diff line change
@@ -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);
124 changes: 124 additions & 0 deletions lldb/tools/lldb-rpc/lldb-rpc-gen/client/RPCLibraryHeaderEmitter.cpp
Original file line number Diff line number Diff line change
@@ -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());
}
Original file line number Diff line number Diff line change
@@ -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
Loading