-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[lldb][rpc] Use Clang attributes to keep track of pointer plus len #148981
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
base: main
Are you sure you want to change the base?
[lldb][rpc] Use Clang attributes to keep track of pointer plus len #148981
Conversation
In LLDB RPC, we need to keep track of methods that have a pointer parameter followed by a lengtgh parameter as these parameters need some exceptions when they're being emitted by lldb-rpc-gen. Previously, we used an exception list to keep track of every method that fell under this category using their mangled names. This method worked, but manually maintaining an exception list this way is unwieldly and can lead to hard-to-track errors for clients that use RPC and forget to add a method that they use to said list. This commit changes this by using the Clang annotation attribute to annotate every method that uses a pointer plus length directly in the SB API, and checks that a given method has this attribute when determining if a method has a pointer plus length.
@llvm/pr-subscribers-lldb Author: Chelsea Cassanova (chelcassanova) ChangesIn LLDB RPC, we need to keep track of methods that have a pointer parameter followed by a lengtgh parameter as these parameters need some exceptions when they're being emitted by lldb-rpc-gen. Previously, we used an exception list to keep track of every method that fell under this category using their mangled names. This method worked, but manually maintaining an exception list this way is unwieldly and can lead to hard-to-track errors for clients that use RPC and forget to add a method that they use to said list. This commit changes this by using the Clang annotation attribute to annotate every method that uses a pointer plus length directly in the SB API, and checks that a given method has this attribute when determining if a method has a pointer plus length. Patch is 34.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/148981.diff 12 Files Affected:
diff --git a/lldb/include/lldb/API/SBData.h b/lldb/include/lldb/API/SBData.h
index 89a699f2f713a..1242ffdfc85b5 100644
--- a/lldb/include/lldb/API/SBData.h
+++ b/lldb/include/lldb/API/SBData.h
@@ -69,6 +69,7 @@ class LLDB_API SBData {
const char *GetString(lldb::SBError &error, lldb::offset_t offset);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t ReadRawData(lldb::SBError &error, lldb::offset_t offset, void *buf,
size_t size);
@@ -80,9 +81,11 @@ class LLDB_API SBData {
// DataExtractor, but having two SetData() signatures triggers a SWIG bug
// where the typemap isn't applied before resolving the overload, and thus
// the right function never gets called
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
void SetData(lldb::SBError &error, const void *buf, size_t size,
lldb::ByteOrder endian, uint8_t addr_size);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
void SetDataWithOwnership(lldb::SBError &error, const void *buf, size_t size,
lldb::ByteOrder endian, uint8_t addr_size);
@@ -96,41 +99,46 @@ class LLDB_API SBData {
// in the following CreateData*() and SetData*() prototypes, the two
// parameters array and array_len should not be renamed or rearranged,
// because doing so will break the SWIG typemap
- static lldb::SBData CreateDataFromUInt64Array(lldb::ByteOrder endian,
- uint32_t addr_byte_size,
- uint64_t *array,
- size_t array_len);
-
- static lldb::SBData CreateDataFromUInt32Array(lldb::ByteOrder endian,
- uint32_t addr_byte_size,
- uint32_t *array,
- size_t array_len);
-
- static lldb::SBData CreateDataFromSInt64Array(lldb::ByteOrder endian,
- uint32_t addr_byte_size,
- int64_t *array,
- size_t array_len);
-
- static lldb::SBData CreateDataFromSInt32Array(lldb::ByteOrder endian,
- uint32_t addr_byte_size,
- int32_t *array,
- size_t array_len);
-
- static lldb::SBData CreateDataFromDoubleArray(lldb::ByteOrder endian,
- uint32_t addr_byte_size,
- double *array,
- size_t array_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ static lldb::SBData
+ CreateDataFromUInt64Array(lldb::ByteOrder endian, uint32_t addr_byte_size,
+ uint64_t *array, size_t array_len);
+
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ static lldb::SBData
+ CreateDataFromUInt32Array(lldb::ByteOrder endian, uint32_t addr_byte_size,
+ uint32_t *array, size_t array_len);
+
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ static lldb::SBData
+ CreateDataFromSInt64Array(lldb::ByteOrder endian, uint32_t addr_byte_size,
+ int64_t *array, size_t array_len);
+
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ static lldb::SBData
+ CreateDataFromSInt32Array(lldb::ByteOrder endian, uint32_t addr_byte_size,
+ int32_t *array, size_t array_len);
+
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ static lldb::SBData
+ CreateDataFromDoubleArray(lldb::ByteOrder endian, uint32_t addr_byte_size,
+ double *array, size_t array_len);
bool SetDataFromCString(const char *data);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
bool SetDataFromUInt64Array(uint64_t *array, size_t array_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
bool SetDataFromUInt32Array(uint32_t *array, size_t array_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
bool SetDataFromSInt64Array(int64_t *array, size_t array_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
bool SetDataFromSInt32Array(int32_t *array, size_t array_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
bool SetDataFromDoubleArray(double *array, size_t array_len);
protected:
diff --git a/lldb/include/lldb/API/SBDebugger.h b/lldb/include/lldb/API/SBDebugger.h
index 192fbee9c0c6d..716d2bebb6bd6 100644
--- a/lldb/include/lldb/API/SBDebugger.h
+++ b/lldb/include/lldb/API/SBDebugger.h
@@ -323,6 +323,7 @@ class LLDB_API SBDebugger {
bool GetUseSourceCache() const;
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
static bool GetDefaultArchitecture(char *arch_name, size_t arch_name_len);
static bool SetDefaultArchitecture(const char *arch_name);
@@ -367,6 +368,7 @@ class LLDB_API SBDebugger {
void DispatchInput(void *baton, const void *data, size_t data_len);
#endif
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
void DispatchInput(const void *data, size_t data_len);
void DispatchInputInterrupt();
diff --git a/lldb/include/lldb/API/SBFile.h b/lldb/include/lldb/API/SBFile.h
index ebdc5607b7942..842f0b86665a7 100644
--- a/lldb/include/lldb/API/SBFile.h
+++ b/lldb/include/lldb/API/SBFile.h
@@ -34,7 +34,9 @@ class LLDB_API SBFile {
SBFile &operator=(const SBFile &rhs);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
SBError Read(uint8_t *buf, size_t num_bytes, size_t *OUTPUT);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
SBError Write(const uint8_t *buf, size_t num_bytes, size_t *OUTPUT);
SBError Flush();
bool IsValid() const;
diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h
index 36641843aabeb..1a25b0005e24c 100644
--- a/lldb/include/lldb/API/SBFileSpec.h
+++ b/lldb/include/lldb/API/SBFileSpec.h
@@ -51,8 +51,10 @@ class LLDB_API SBFileSpec {
void SetDirectory(const char *directory);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
uint32_t GetPath(char *dst_path, size_t dst_len) const;
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len);
bool GetDescription(lldb::SBStream &description) const;
diff --git a/lldb/include/lldb/API/SBModule.h b/lldb/include/lldb/API/SBModule.h
index 85332066ee687..7f39f7cc90368 100644
--- a/lldb/include/lldb/API/SBModule.h
+++ b/lldb/include/lldb/API/SBModule.h
@@ -274,6 +274,7 @@ class LLDB_API SBModule {
/// This function always returns the number of version numbers
/// that this object file has regardless of the number of
/// version numbers that were copied into \a versions.
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
uint32_t GetVersion(uint32_t *versions, uint32_t num_versions);
/// Get accessor for the symbol file specification.
diff --git a/lldb/include/lldb/API/SBModuleSpec.h b/lldb/include/lldb/API/SBModuleSpec.h
index 8d1ecfe6e6f8b..fd48c585ed25f 100644
--- a/lldb/include/lldb/API/SBModuleSpec.h
+++ b/lldb/include/lldb/API/SBModuleSpec.h
@@ -71,6 +71,7 @@ class LLDB_API SBModuleSpec {
void SetTriple(const char *triple);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
const uint8_t *GetUUIDBytes();
size_t GetUUIDLength();
diff --git a/lldb/include/lldb/API/SBProcess.h b/lldb/include/lldb/API/SBProcess.h
index 882b8bd837131..a5784c893df7c 100644
--- a/lldb/include/lldb/API/SBProcess.h
+++ b/lldb/include/lldb/API/SBProcess.h
@@ -63,10 +63,13 @@ class LLDB_API SBProcess {
size_t PutSTDIN(const char *src, size_t src_len);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t GetSTDOUT(char *dst, size_t dst_len) const;
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t GetSTDERR(char *dst, size_t dst_len) const;
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t GetAsyncProfileData(char *dst, size_t dst_len) const;
#ifndef SWIG
@@ -197,11 +200,14 @@ class LLDB_API SBProcess {
///
void ForceScriptedState(StateType new_state);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t ReadMemory(addr_t addr, void *buf, size_t size, lldb::SBError &error);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t WriteMemory(addr_t addr, const void *buf, size_t size,
lldb::SBError &error);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t ReadCStringFromMemory(addr_t addr, void *char_buf, size_t size,
lldb::SBError &error);
diff --git a/lldb/include/lldb/API/SBStructuredData.h b/lldb/include/lldb/API/SBStructuredData.h
index f96e169f236ed..4c972e2544a8a 100644
--- a/lldb/include/lldb/API/SBStructuredData.h
+++ b/lldb/include/lldb/API/SBStructuredData.h
@@ -104,6 +104,7 @@ class SBStructuredData {
/// \return
/// Returns the byte size needed to completely write the string value at
/// \a dst in all cases.
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t GetStringValue(char *dst, size_t dst_len) const;
/// Return the generic pointer if this data structure is a generic type.
diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h
index 2776a8f9010fe..7721db805d240 100644
--- a/lldb/include/lldb/API/SBTarget.h
+++ b/lldb/include/lldb/API/SBTarget.h
@@ -607,6 +607,7 @@ class LLDB_API SBTarget {
///
/// \return
/// The amount of data read in host bytes.
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t ReadMemory(const SBAddress addr, void *buf, size_t size,
lldb::SBError &error);
@@ -688,12 +689,13 @@ class LLDB_API SBTarget {
const SBFileSpecList &module_list,
const SBFileSpecList &comp_unit_list);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
lldb::SBBreakpoint BreakpointCreateByNames(
const char *symbol_name[], uint32_t num_names,
uint32_t
name_type_mask, // Logical OR one or more FunctionNameType enum bits
- lldb::LanguageType symbol_language,
- const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);
+ lldb::LanguageType symbol_language, const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list);
lldb::SBBreakpoint BreakpointCreateByNames(
const char *symbol_name[], uint32_t num_names,
@@ -900,24 +902,27 @@ class LLDB_API SBTarget {
lldb::SBAddress end_addr,
const char *flavor_string);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
lldb::SBInstructionList GetInstructions(lldb::SBAddress base_addr,
const void *buf, size_t size);
// The "WithFlavor" is necessary to keep SWIG from getting confused about
// overloaded arguments when using the buf + size -> Python Object magic.
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
lldb::SBInstructionList GetInstructionsWithFlavor(lldb::SBAddress base_addr,
const char *flavor_string,
const void *buf,
size_t size);
#ifndef SWIG
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
lldb::SBInstructionList GetInstructions(lldb::addr_t base_addr,
const void *buf, size_t size);
- lldb::SBInstructionList GetInstructionsWithFlavor(lldb::addr_t base_addr,
- const char *flavor_string,
- const void *buf,
- size_t size);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
+ lldb::SBInstructionList
+ GetInstructionsWithFlavor(lldb::addr_t base_addr, const char *flavor_string,
+ const void *buf, size_t size);
#endif
lldb::SBSymbolContextList FindSymbols(const char *name,
diff --git a/lldb/include/lldb/API/SBThread.h b/lldb/include/lldb/API/SBThread.h
index f8ae627da5ace..317741ab38ff8 100644
--- a/lldb/include/lldb/API/SBThread.h
+++ b/lldb/include/lldb/API/SBThread.h
@@ -81,6 +81,7 @@ class LLDB_API SBThread {
SBThreadCollection
GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type);
+ [[clang::annotate("lldb-rpc-gen pointer plus len")]]
size_t GetStopDescription(char *dst_or_null, size_t dst_len);
SBValue GetStopReturnValue();
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..c396e10ed3e11
--- /dev/null
+++ b/lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp
@@ -0,0 +1,469 @@
+//===-- 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/Attrs.inc"
+#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>
+#include <iostream>
+
+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",
+};
+
+// 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",
+ "SBCommandReturnObject",
+ "SBError",
+ "SBExecutionContext",
+ "SBExpressionOptions",
+ "SBFileSpec",
+ "SBFileSpecList",
+ "SBFormat",
+ "SBFunction",
+ "SBHistoricalFrame",
+ "SBHistoricalLineEntry",
+ "SBHistoricalLineEntryList",
+ "SBLineEntry",
+ "SBStream",
+ "SBStringList",
+ "SBStructuredData",
+ "SBSymbolContext",
+ "SBSymbolContextList",
+ "SBTypeMember",
+ "SBTypeSummaryOptions",
+ "SBValueList",
+};
+
+QualType lldb_rpc_gen::GetUnderlyingType(QualType T) {
+ QualType UnderlyingType;
+ if (T->isPointerType())
+ UnderlyingType = T->getPointeeType();
+ else if (T->isReferenceType())
+ UnderlyingType = T.getNonReferenceType();
+ else
+ UnderlyingType = T;
+
+ return UnderlyingType;
+}
+
+QualType lldb_rpc_gen::GetUnqualifiedUnderlyingType(QualType T) {
+ return GetUnderlyingType(T).getUnqualifiedType();
+}
+
+std::string lldb_rpc_gen::GetMangledName(ASTContext &Context,
+ CXXMethodDecl *MDecl) {
+ std::string Mangled;
+ llvm::raw_string_ostream MangledStream(Mangled);
+
+ GlobalDecl GDecl;
+ if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(MDecl))
+ GDecl = GlobalDecl(CtorDecl, Ctor_Complete);
+ else if (const auto *DtorDecl = dyn_cast<CXXDestructorDecl>(MDecl))
+ GDecl = GlobalDecl(DtorDecl, Dtor_Deleting);
+ else
+ GDecl = GlobalDecl(MDecl);
+
+ MangleContext *MC = Context.createMangleContext();
+ MC->mangleName(GDecl, MangledStream);
+ return Mangled;
+}
+
+static auto CheckTypeForLLDBPrivate = [](const Type *Ty) {};
+bool lldb_rpc_gen::TypeIsFromLLDBPrivate(QualType T) {
+ auto CheckTypeForLLDBPrivate = [](const Type *Ty) {
+ if (!Ty)
+ return false;
+ const auto *CXXRDecl = Ty->getAsCXXRecordDecl();
+ if (!CXXRDecl)
+ return false;
+ const auto *NSDecl =
+ llvm::dyn_cast<NamespaceDecl>(CXXRDecl->getDeclContext());
+ if (!NSDecl)
+ return false;
+ return NSDecl->getName() == "lldb_private";
+ };
+
+ // First, get the underlying type (remove qualifications and strip off any
+ // pointers/references). Then we'll need to desugar this type. This will
+ // remove things like typedefs, so instead of seeing "lldb::DebuggerSP" we'll
+ // actually see something like "std::shared_ptr<lldb_private::Debugger>".
+ QualType UnqualifiedUnderlyingType = GetUnqualifiedUnderlyingType(T);
+ const Type *DesugaredType =
+ UnqualifiedUnderlyingType->getUnqualifiedDesugaredType();
+ assert(DesugaredType && "DesugaredType from a valid Type is nullptr!");
+
+ // Check the type itself.
+ if (CheckTypeForLLDBPrivate(DesugaredType))
+ return true;
+
+ // If that didn't work, it's possible that the type has a template argument
+ // that is an lldb_private type.
+ if (const auto *TemplateSDecl =
+ llvm::dyn_cast_or_null<ClassTemplateSpecializationDecl>(
+ DesugaredType->getAsCXXRecordDecl())) {
+ for (const TemplateArgument &TA :
+ TemplateSDecl->getTemplateArgs().asArray()) {
+ if (TA.getKind() != TemplateArgument::Type)
+ continue;
+ if (CheckTypeForLLDBPrivate(TA.g...
[truncated]
|
In LLDB RPC, we need to keep track of methods that have a pointer parameter followed by a lengtgh parameter as these parameters need some exceptions when they're being emitted by lldb-rpc-gen. Previously, we used an exception list to keep track of every method that fell under this category using their mangled names. This method worked, but manually maintaining an exception list this way is unwieldly and can lead to hard-to-track errors for clients that use RPC and forget to add a method that they use to said list.
This commit changes this by using the Clang annotation attribute to annotate every method that uses a pointer plus length directly in the SB API, and checks that a given method has this attribute when determining if a method has a pointer plus length.