diff options
author | Giuliano Procida <gprocida@google.com> | 2024-05-14 17:00:46 +0100 |
---|---|---|
committer | Giuliano Procida <gprocida@google.com> | 2024-05-14 17:00:46 +0100 |
commit | 120708097f00900e4582becaae61bea313be1aaf (patch) | |
tree | 11fb9f7f0397a182b6218ec2ffd4d37621262996 | |
parent | 6007ac729006c2bb7b38a31a816e30572f46f07d (diff) | |
parent | f82154992367ecb47f469c071bec6b979277e3ef (diff) | |
download | stg-main.tar.gz |
* aosp/upstream-main:
DWARF processor: handle DW_TAG_GNU_formal_parameter_pack DIEs
rust: delegate DWARF processing for `variant_part` to variant DWARF processor
rust: add DWARF processor for `Variant` node
rust: add DWARF processor for `VariantMember` nodes
Signed-off-by: Giuliano Procida <gprocida@google.com>
Change-Id: I0d3cf9167a0c6edc43f4a8c60bb428d9ea602bab
-rw-r--r-- | dwarf_processor.cc | 111 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg | 75 | ||||
-rw-r--r-- | test_cases/info_tests/variant/expected/simple_rs.elf_stg | 108 |
3 files changed, 280 insertions, 14 deletions
diff --git a/dwarf_processor.cc b/dwarf_processor.cc index 9e84971..9955b82 100644 --- a/dwarf_processor.cc +++ b/dwarf_processor.cc @@ -496,6 +496,7 @@ class Processor { std::vector<Id> base_classes; std::vector<Id> members; std::vector<Id> methods; + std::optional<VariantAndMembers> variant_and_members = std::nullopt; for (auto& child : entry.GetChildren()) { auto child_tag = child.GetTag(); @@ -550,7 +551,11 @@ class Processor { // properly (resulting in no references to such DIEs). break; case DW_TAG_variant_part: - // TODO: Add a DWARF processor to process variants. + if (full_name.empty()) { + Die() << "Variant name should not be empty: " + << EntryToString(entry); + } + variant_and_members = GetVariantAndMembers(child); break; default: Die() << "Unexpected tag for child of struct/class/union: " @@ -558,6 +563,17 @@ class Processor { } } + if (variant_and_members.has_value()) { + // Add a Variant node since this entry represents a variant rather than a + // struct or union. + const Id id = + AddProcessedNode<Variant>(entry, full_name, GetByteSize(entry), + variant_and_members->discriminant_type_id, + std::move(variant_and_members->members)); + AddNamedTypeNode(id); + return; + } + if (entry.GetFlag(DW_AT_declaration) || !ShouldKeepDefinition(entry, type_name)) { // Declaration may have partial information about members or method. @@ -577,6 +593,37 @@ class Processor { } } + void ProcessVariantMember(Entry& entry) { + // TODO: Process signed discriminant values. + auto dw_discriminant_value = + entry.MaybeGetUnsignedConstant(DW_AT_discr_value); + auto discriminant_value = + dw_discriminant_value + ? std::optional(static_cast<int64_t>(*dw_discriminant_value)) + : std::nullopt; + + auto children = entry.GetChildren(); + if (children.size() != 1) { + Die() << "Unexpected number of children for variant member: " + << EntryToString(entry); + } + + auto child = children[0]; + if (child.GetTag() != DW_TAG_member) { + Die() << "Unexpected tag for variant member child: " + << Hex(child.GetTag()) << ", " << EntryToString(child); + } + if (GetDataBitOffset(child, 0, is_little_endian_binary_) != 0) { + Die() << "Unexpected data member location for variant member: " + << EntryToString(child); + } + + const std::string name = GetNameOrEmpty(child); + auto referred_type_id = GetReferredTypeId(GetReferredType(child)); + AddProcessedNode<VariantMember>(entry, name, discriminant_value, + referred_type_id); + } + void ProcessMember(Entry& entry) { const auto name = GetNameOrEmpty(entry); auto referred_type = GetReferredType(entry); @@ -726,6 +773,56 @@ class Processor { } } + struct VariantAndMembers { + Id discriminant_type_id; + std::vector<Id> members; + }; + + VariantAndMembers GetVariantAndMembers(Entry& entry) { + std::vector<Id> members; + std::optional<Id> discriminant_type_id = std::nullopt; + auto discriminant_entry = entry.MaybeGetReference(DW_AT_discr); + if (!discriminant_entry.has_value()) { + Die() << "Variant must have a discriminant: " << EntryToString(entry); + } + + for (auto& child : entry.GetChildren()) { + auto child_tag = child.GetTag(); + switch (child_tag) { + case DW_TAG_member: { + if (child.GetOffset() != discriminant_entry->GetOffset()) { + Die() << "Encountered unexpected member for variant: " + << EntryToString(entry); + } + discriminant_type_id = GetReferredTypeId(GetReferredType(child)); + if (GetDataBitOffset(child, 0, is_little_endian_binary_) != 0) { + Die() << "Unexpected member location for variant discriminant: " + << EntryToString(child); + } + if (!child.GetFlag(DW_AT_artificial)) { + Die() << "Variant discriminant must be an artificial member: " + << EntryToString(child); + } + break; + } + case DW_TAG_variant: + members.push_back(GetIdForEntry(child)); + ProcessVariantMember(child); + break; + default: + Die() << "Unexpected tag for child of variant: " << Hex(child_tag) + << ", " << EntryToString(child); + } + } + + if (!discriminant_type_id.has_value()) { + Die() << "No discriminant member found for variant: " + << EntryToString(entry); + } + return VariantAndMembers{.discriminant_type_id = *discriminant_type_id, + .members = std::move(members)}; + } + struct NameWithContext { std::optional<Dwarf_Off> specification; std::optional<std::string> unscoped_name; @@ -901,10 +998,20 @@ class Processor { case DW_TAG_template_value_parameter: case DW_TAG_GNU_template_template_param: case DW_TAG_GNU_template_parameter_pack: - case DW_TAG_GNU_formal_parameter_pack: // We just skip these as neither GCC nor Clang seem to use them // properly (resulting in no references to such DIEs). break; + case DW_TAG_GNU_formal_parameter_pack: + // https://wiki.dwarfstd.org/C++0x_Variadic_templates.md + // + // As per this (rejected) proposal, GCC includes parameters as + // children of this DIE. + for (auto& child2 : child.GetChildren()) { + if (child2.GetTag() == DW_TAG_formal_parameter) { + parameters.push_back(GetReferredTypeId(GetReferredType(child2))); + } + } + break; default: Die() << "Unexpected tag for child of function: " << Hex(child_tag) << ", " << EntryToString(child); diff --git a/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg b/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg index debfaf8..748f73e 100644 --- a/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg +++ b/test_cases/info_tests/variant/expected/negative_discriminant_rs.elf_stg @@ -6,28 +6,91 @@ primitive { encoding: BOOLEAN bytesize: 0x00000001 } +primitive { + id: 0xd4bacb77 + name: "u32" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000004 +} +primitive { + id: 0xedc43a15 + name: "i64" + encoding: SIGNED_INTEGER + bytesize: 0x00000008 +} +member { + id: 0x976dcda7 + name: "__0" + type_id: 0xd4bacb77 # u32 + offset: 64 +} +variant_member { + id: 0x72c55dce + name: "MinusTwo" + discriminant_value: 65534 + type_id: 0xc8fb9972 +} +variant_member { + id: 0x528ee922 + name: "MinusOne" + discriminant_value: 65535 + type_id: 0xdfc84a58 +} +variant_member { + id: 0x27839c0b + name: "Zero" + discriminant_value: 0 + type_id: 0x5da8c8f1 +} struct_union { - id: 0x7a8d8645 + id: 0xdfc84a58 kind: STRUCT - name: "negative_discriminant::Foo" + name: "negative_discriminant::Foo::MinusOne" definition { bytesize: 16 } } +struct_union { + id: 0xc8fb9972 + kind: STRUCT + name: "negative_discriminant::Foo::MinusTwo" + definition { + bytesize: 16 + member_id: 0x976dcda7 # u32 __0 + } +} +struct_union { + id: 0x5da8c8f1 + kind: STRUCT + name: "negative_discriminant::Foo::Zero" + definition { + bytesize: 16 + member_id: 0x976dcda7 # u32 __0 + } +} +variant { + id: 0x29673df8 + name: "negative_discriminant::Foo" + bytesize: 16 + discriminant_type_id: 0xedc43a15 + member_id: 0x72c55dce + member_id: 0x528ee922 + member_id: 0x27839c0b +} function { - id: 0xa0f30a2f + id: 0xb409a4c0 return_type_id: 0x62aebfd4 # bool - parameter_id: 0x7a8d8645 # struct negative_discriminant::Foo + parameter_id: 0x29673df8 # variant negative_discriminant::Foo } elf_symbol { id: 0x0f95dadc name: "is_minus_one" is_defined: true symbol_type: FUNCTION - type_id: 0xa0f30a2f # bool(struct negative_discriminant::Foo) + type_id: 0xb409a4c0 # bool(variant negative_discriminant::Foo) full_name: "negative_discriminant::is_minus_one" } interface { id: 0x84ea5130 - symbol_id: 0x0f95dadc # bool negative_discriminant::is_minus_one(struct negative_discriminant::Foo) + symbol_id: 0x0f95dadc # bool negative_discriminant::is_minus_one(variant negative_discriminant::Foo) } diff --git a/test_cases/info_tests/variant/expected/simple_rs.elf_stg b/test_cases/info_tests/variant/expected/simple_rs.elf_stg index 4621cf8..0d051aa 100644 --- a/test_cases/info_tests/variant/expected/simple_rs.elf_stg +++ b/test_cases/info_tests/variant/expected/simple_rs.elf_stg @@ -1,33 +1,129 @@ version: 0x00000002 root_id: 0x84ea5130 # interface primitive { + id: 0x2d2f93e0 + name: "u8" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000001 +} +primitive { + id: 0x47ea5d8b + name: "i16" + encoding: SIGNED_INTEGER + bytesize: 0x00000002 +} +primitive { id: 0x62aebfd4 name: "bool" encoding: BOOLEAN bytesize: 0x00000001 } +primitive { + id: 0xd4bacb77 + name: "u32" + encoding: UNSIGNED_INTEGER + bytesize: 0x00000004 +} +member { + id: 0x976dc47d + name: "__0" + type_id: 0xd4bacb77 # u32 + offset: 32 +} +member { + id: 0xdb2c3143 + name: "__1" + type_id: 0xd4bacb77 # u32 + offset: 64 +} +member { + id: 0xa0f58f35 + name: "x" + type_id: 0x47ea5d8b # i16 + offset: 16 +} +member { + id: 0xff34ede2 + name: "y" + type_id: 0x47ea5d8b # i16 + offset: 32 +} +member { + id: 0x2172932a + name: "z" + type_id: 0x47ea5d8b # i16 + offset: 48 +} +variant_member { + id: 0xfc632c0e + name: "Unit" + discriminant_value: 0 + type_id: 0x624786fb +} +variant_member { + id: 0xad130615 + name: "TwoU32s" + discriminant_value: 1 + type_id: 0x117f6853 +} +variant_member { + id: 0xc48d72bf + name: "ThreeI16s" + discriminant_value: 2 + type_id: 0x0e0db07a +} struct_union { - id: 0x176387ba + id: 0x0e0db07a kind: STRUCT - name: "simple::Foo" + name: "simple::Foo::ThreeI16s" + definition { + bytesize: 12 + member_id: 0xa0f58f35 # i16 x + member_id: 0xff34ede2 # i16 y + member_id: 0x2172932a # i16 z + } +} +struct_union { + id: 0x117f6853 + kind: STRUCT + name: "simple::Foo::TwoU32s" definition { bytesize: 12 + member_id: 0x976dc47d # u32 __0 + member_id: 0xdb2c3143 # u32 __1 } } +struct_union { + id: 0x624786fb + kind: STRUCT + name: "simple::Foo::Unit" + definition { + bytesize: 12 + } +} +variant { + id: 0x15514ee1 + name: "simple::Foo" + bytesize: 12 + discriminant_type_id: 0x2d2f93e0 + member_id: 0xfc632c0e + member_id: 0xad130615 + member_id: 0xc48d72bf +} function { - id: 0xbb888a50 + id: 0xbb043806 return_type_id: 0x62aebfd4 # bool - parameter_id: 0x176387ba # struct simple::Foo + parameter_id: 0x15514ee1 # variant simple::Foo } elf_symbol { id: 0x4e2f2fc8 name: "is_unit" is_defined: true symbol_type: FUNCTION - type_id: 0xbb888a50 # bool(struct simple::Foo) + type_id: 0xbb043806 # bool(variant simple::Foo) full_name: "simple::is_unit" } interface { id: 0x84ea5130 - symbol_id: 0x4e2f2fc8 # bool simple::is_unit(struct simple::Foo) + symbol_id: 0x4e2f2fc8 # bool simple::is_unit(variant simple::Foo) } |