From 3065dd14e997b80227e59a9483e18599fc32f9e3 Mon Sep 17 00:00:00 2001 From: Thierry Treyer Date: Thu, 28 Sep 2023 10:59:54 -0700 Subject: [PATCH] Maintain type/name of Incomplete type --- oi/type_graph/DrgnParser.cpp | 72 +++++++++++++++----------- oi/type_graph/EnforceCompatibility.cpp | 6 +++ oi/type_graph/Printer.cpp | 6 +++ oi/type_graph/Printer.h | 1 + oi/type_graph/Types.cpp | 2 + oi/type_graph/Types.h | 44 ++++++++++++++++ oi/type_graph/Visitor.h | 2 + test/TypeGraphParser.cpp | 3 ++ test/test_drgn_parser.cpp | 3 +- 9 files changed, 108 insertions(+), 31 deletions(-) diff --git a/oi/type_graph/DrgnParser.cpp b/oi/type_graph/DrgnParser.cpp index 850fe5e..1333869 100644 --- a/oi/type_graph/DrgnParser.cpp +++ b/oi/type_graph/DrgnParser.cpp @@ -87,43 +87,55 @@ Type& DrgnParser::enumerateType(struct drgn_type* type) { if (auto it = drgn_types_.find(type); it != drgn_types_.end()) return it->second; - if (!drgn_utils::isSizeComplete(type) && - drgn_type_kind(type) != DRGN_TYPE_VOID) { - return makeType(nullptr, Primitive::Kind::Incomplete); - } + bool isTypeIncomplete = !drgn_utils::isSizeComplete(type) && + drgn_type_kind(type) != DRGN_TYPE_VOID; enum drgn_type_kind kind = drgn_type_kind(type); Type* t = nullptr; depth_++; - switch (kind) { - case DRGN_TYPE_CLASS: - case DRGN_TYPE_STRUCT: - case DRGN_TYPE_UNION: - t = &enumerateClass(type); - break; - case DRGN_TYPE_ENUM: - t = &enumerateEnum(type); - break; - case DRGN_TYPE_TYPEDEF: - t = &enumerateTypedef(type); - break; - case DRGN_TYPE_POINTER: - t = &enumeratePointer(type); - break; - case DRGN_TYPE_ARRAY: - t = &enumerateArray(type); - break; - case DRGN_TYPE_INT: - case DRGN_TYPE_BOOL: - case DRGN_TYPE_FLOAT: - case DRGN_TYPE_VOID: - t = &enumeratePrimitive(type); - break; - default: - throw DrgnParserError{"Unknown drgn type kind: " + std::to_string(kind)}; + try { + switch (kind) { + case DRGN_TYPE_CLASS: + case DRGN_TYPE_STRUCT: + case DRGN_TYPE_UNION: + t = &enumerateClass(type); + break; + case DRGN_TYPE_ENUM: + t = &enumerateEnum(type); + break; + case DRGN_TYPE_TYPEDEF: + t = &enumerateTypedef(type); + break; + case DRGN_TYPE_POINTER: + t = &enumeratePointer(type); + break; + case DRGN_TYPE_ARRAY: + t = &enumerateArray(type); + break; + case DRGN_TYPE_INT: + case DRGN_TYPE_BOOL: + case DRGN_TYPE_FLOAT: + case DRGN_TYPE_VOID: + t = &enumeratePrimitive(type); + break; + default: + throw DrgnParserError{"Unknown drgn type kind: " + + std::to_string(kind)}; + } + } catch (const DrgnParserError& e) { + if (isTypeIncomplete) { + t = &makeType(type, Primitive::Kind::Incomplete); + } else { + depth_--; + throw e; + } } depth_--; + if (isTypeIncomplete) { + return makeType(nullptr, *t); + } + return *t; } diff --git a/oi/type_graph/EnforceCompatibility.cpp b/oi/type_graph/EnforceCompatibility.cpp index 00919b3..e97b5d4 100644 --- a/oi/type_graph/EnforceCompatibility.cpp +++ b/oi/type_graph/EnforceCompatibility.cpp @@ -78,6 +78,12 @@ void EnforceCompatibility::visit(Class& c) { return true; if (auto* ptr = dynamic_cast(&member.type())) { + if (auto* incomplete = dynamic_cast(&ptr->pointeeType())) { + // This is a pointer to an incomplete type. CodeGen v1 does not record + // the pointer's address in this case. + return true; + } + if (auto* primitive = dynamic_cast(&ptr->pointeeType())) { if (primitive->kind() == Primitive::Kind::Incomplete) { // This is a pointer to an incomplete type. CodeGen v1 does not record diff --git a/oi/type_graph/Printer.cpp b/oi/type_graph/Printer.cpp index 27f0c88..9e9d173 100644 --- a/oi/type_graph/Printer.cpp +++ b/oi/type_graph/Printer.cpp @@ -36,6 +36,12 @@ void Printer::print(const Type& type) { depth_--; } +void Printer::visit(const Incomplete& i) { + prefix(); + out_ << "Incomplete:" << std::endl; + print(i.underlyingType()); +} + void Printer::visit(const Class& c) { if (prefix(c)) return; diff --git a/oi/type_graph/Printer.h b/oi/type_graph/Printer.h index dc8f18c..a66581e 100644 --- a/oi/type_graph/Printer.h +++ b/oi/type_graph/Printer.h @@ -32,6 +32,7 @@ class Printer : public ConstVisitor { void print(const Type& type); + void visit(const Incomplete& i) override; void visit(const Class& c) override; void visit(const Container& c) override; void visit(const Primitive& p) override; diff --git a/oi/type_graph/Types.cpp b/oi/type_graph/Types.cpp index 1232c50..f67c914 100644 --- a/oi/type_graph/Types.cpp +++ b/oi/type_graph/Types.cpp @@ -29,6 +29,8 @@ namespace oi::detail::type_graph { OI_TYPE_LIST #undef X +const std::string Incomplete::kName = "void"; + std::string Primitive::getName(Kind kind) { switch (kind) { case Kind::Int8: diff --git a/oi/type_graph/Types.h b/oi/type_graph/Types.h index 9587327..9659366 100644 --- a/oi/type_graph/Types.h +++ b/oi/type_graph/Types.h @@ -40,6 +40,7 @@ #include "oi/EnumBitset.h" #define OI_TYPE_LIST \ + X(Incomplete) \ X(Class) \ X(Container) \ X(Primitive) \ @@ -184,6 +185,49 @@ struct TemplateParam { std::optional value; }; +/* + * Incomplete + * + * A wrapper around a type we couldn't determine the size of. + */ +class Incomplete : public Type { + public: + Incomplete(Type& underlyingType) : underlyingType_(underlyingType) { + } + + static inline constexpr bool has_node_id = false; + + DECLARE_ACCEPT + + const std::string& name() const override { + return kName; + } + + std::string_view inputName() const override { + return underlyingType_.inputName(); + } + + size_t size() const override { + return 0; + } + + uint64_t align() const override { + return 0; + } + + NodeId id() const override { + return -1; + } + + Type& underlyingType() const { + return underlyingType_; + } + + private: + Type& underlyingType_; + static const std::string kName; +}; + /* * Class * diff --git a/oi/type_graph/Visitor.h b/oi/type_graph/Visitor.h index 94eb0d0..9d932c5 100644 --- a/oi/type_graph/Visitor.h +++ b/oi/type_graph/Visitor.h @@ -71,6 +71,8 @@ class RecursiveVisitor : public Visitor { if (type) accept(*type); } + virtual void visit(Incomplete&) { + } virtual void visit(Class& c) { for (const auto& param : c.templateParams) { accept(param.type()); diff --git a/test/TypeGraphParser.cpp b/test/TypeGraphParser.cpp index 57d2e67..bc1eade 100644 --- a/test/TypeGraphParser.cpp +++ b/test/TypeGraphParser.cpp @@ -211,6 +211,9 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) { std::to_string(refId)}; type = &it->second.get(); + } else if (nodeTypeName == "Incomplete") { + auto& underlyingType = parseType(input, indent + 2); + type = &typeGraph_.makeType(underlyingType); } else if (nodeTypeName == "Class" || nodeTypeName == "Struct" || nodeTypeName == "Union") { // Format: "Class: MyClass (size: 12)" diff --git a/test/test_drgn_parser.cpp b/test/test_drgn_parser.cpp index 1371ab7..72b345b 100644 --- a/test/test_drgn_parser.cpp +++ b/test/test_drgn_parser.cpp @@ -367,7 +367,8 @@ TEST_F(DrgnParserTest, PointerNoFollow) { TEST_F(DrgnParserTest, PointerIncomplete) { test("oid_test_case_pointers_incomplete_raw", R"( [0] Pointer - Primitive: void (incomplete) + Incomplete: + Primitive: void (incomplete) )"); }