EnforceCompatibility: Stub out void pointers

CodeGen v1 does not record anything for pointers to incomplete types.
Not even the address, as is done for other pointers.

Introduce a new Primitive type "Incomplete". This behaves identically to
"Void", but allows us to tell whether a type was defined as void or if
it ended up like that because of incomplete DWARF information.
This commit is contained in:
Alastair Robertson 2023-07-31 14:28:05 +01:00 committed by GitHub
parent 7bb6791af9
commit 6fbb60826f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 49 additions and 8 deletions

View File

@ -20,7 +20,7 @@ workflows:
- build-gcc
oid_test_args: "-ftype-graph"
tests_regex: "OidIntegration\\..*"
exclude_regex: ".*inheritance_polymorphic.*|.*pointers_incomplete_containing_struct|.*arrays_member_int0"
exclude_regex: ".*inheritance_polymorphic.*|.*arrays_member_int0"
- test:
name: test-typed-data-segment-gcc
requires:
@ -68,7 +68,7 @@ workflows:
oid_test_args: "-ftype-graph"
tests_regex: "OidIntegration\\..*"
# Tests disabled due to bad DWARF generated by the old clang compiler in CI
exclude_regex: ".*inheritance_polymorphic.*|.*pointers_incomplete_containing_struct|.*arrays_member_int0|.*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"
exclude_regex: ".*inheritance_polymorphic.*|.*arrays_member_int0|.*fbstring.*|.*std_string_*|.*multi_arg_tb_.*|.*ignored_a"
executors:
ubuntu-docker:

View File

@ -83,8 +83,9 @@ 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)) {
return makeType<Primitive>(nullptr, Primitive::Kind::Void);
if (!drgn_utils::isSizeComplete(type) &&
drgn_type_kind(type) != DRGN_TYPE_VOID) {
return makeType<Primitive>(nullptr, Primitive::Kind::Incomplete);
}
enum drgn_type_kind kind = drgn_type_kind(type);

View File

@ -72,9 +72,22 @@ void EnforceCompatibility::visit(Class& c) {
accept(child);
}
// CodeGen v1 replaces parent containers with padding
std::erase_if(c.members, [](Member member) {
return member.name.starts_with(Flattener::ParentPrefix);
// CodeGen v1 replaces parent containers with padding
if (member.name.starts_with(Flattener::ParentPrefix))
return true;
if (auto* ptr = dynamic_cast<Pointer*>(&member.type())) {
if (auto* primitive = dynamic_cast<Primitive*>(&ptr->pointeeType())) {
if (primitive->kind() == Primitive::Kind::Incomplete) {
// This is a pointer to an incomplete type. CodeGen v1 does not record
// the pointer's address in this case.
return true;
}
}
}
return false;
});
}

View File

@ -87,7 +87,10 @@ void Printer::visit(const Container& c) {
void Printer::visit(const Primitive& p) {
prefix();
out_ << "Primitive: " << p.name() << std::endl;
out_ << "Primitive: " << p.name();
if (p.kind() == Primitive::Kind::Incomplete)
out_ << " (incomplete)";
out_ << std::endl;
}
void Printer::visit(const Enum& e) {

View File

@ -71,6 +71,9 @@ Primitive& TypeGraph::makeType<Primitive>(Primitive::Kind kind) {
case Primitive::Kind::Void:
static Primitive pVoid{kind};
return pVoid;
case Primitive::Kind::Incomplete:
static Primitive pIncomplete{kind};
return pIncomplete;
}
}

View File

@ -60,6 +60,7 @@ std::string Primitive::name() const {
case Kind::UIntPtr:
return "uintptr_t";
case Kind::Void:
case Kind::Incomplete:
return "void";
}
}
@ -95,6 +96,7 @@ std::size_t Primitive::size() const {
case Kind::UIntPtr:
return sizeof(uintptr_t);
case Kind::Void:
case Kind::Incomplete:
return 0;
}
}

View File

@ -411,6 +411,8 @@ class Primitive : public Type {
UIntPtr, // Really an alias, but useful to have as its own primitive
Void,
Incomplete, // Behaves the same as Void, but alerts us that the type was
// stubbed out due to incomplete DWARF
};
explicit Primitive(Kind kind) : kind_(kind) {
@ -428,6 +430,9 @@ class Primitive : public Type {
virtual NodeId id() const override {
return -1;
}
Kind kind() const {
return kind_;
}
private:
Kind kind_;

View File

@ -49,6 +49,8 @@ Primitive::Kind getKind(std::string_view kindStr) {
return Primitive::Kind::UIntPtr;
if (kindStr == "void")
return Primitive::Kind::Void;
if (kindStr == "void (incomplete)")
return Primitive::Kind::Incomplete;
throw TypeGraphParserError{"Invalid Primitive::Kind: " +
std::string{kindStr}};
}

View File

@ -330,7 +330,7 @@ TEST_F(DrgnParserTest, PointerNoFollow) {
TEST_F(DrgnParserTest, PointerIncomplete) {
test("oid_test_case_pointers_incomplete_raw", R"(
[0] Pointer
Primitive: void
Primitive: void (incomplete)
)");
}

View File

@ -30,3 +30,15 @@ TEST(EnforceCompatibilityTest, TypesToStub) {
[0] Class: EnumMap (size: 8)
)");
}
TEST(EnforceCompatibilityTest, VoidPointer) {
test(EnforceCompatibility::createPass(), R"(
[0] Class: MyClass (size: 8)
Member: p (offset: 0)
[1] Pointer
Primitive: void (incomplete)
)",
R"(
[0] Class: MyClass (size: 8)
)");
}