TypeGraph: Add option to record enumerator names

This commit is contained in:
Alastair Robertson 2023-08-16 11:15:09 -07:00 committed by Alastair Robertson
parent a2f7462a5d
commit 373dbe8f6c
10 changed files with 116 additions and 44 deletions

View File

@ -48,6 +48,7 @@ using type_graph::AlignmentCalc;
using type_graph::Class;
using type_graph::Container;
using type_graph::DrgnParser;
using type_graph::DrgnParserOptions;
using type_graph::EnforceCompatibility;
using type_graph::Enum;
using type_graph::Flattener;
@ -823,8 +824,10 @@ void CodeGen::registerContainer(const fs::path& path) {
}
void CodeGen::addDrgnRoot(struct drgn_type* drgnType, TypeGraph& typeGraph) {
DrgnParser drgnParser{typeGraph, containerInfos_,
config_.features[Feature::ChaseRawPointers]};
DrgnParserOptions options{
.chaseRawPointers = config_.features[Feature::ChaseRawPointers],
};
DrgnParser drgnParser{typeGraph, containerInfos_, options};
Type& parsedRoot = drgnParser.parse(drgnType);
typeGraph.addRoot(parsedRoot);
}
@ -841,8 +844,10 @@ void CodeGen::transform(TypeGraph& typeGraph) {
if (config_.features[Feature::PolymorphicInheritance]) {
// Parse new children nodes
DrgnParser drgnParser{typeGraph, containerInfos_,
config_.features[Feature::ChaseRawPointers]};
DrgnParserOptions options{
.chaseRawPointers = config_.features[Feature::ChaseRawPointers],
};
DrgnParser drgnParser{typeGraph, containerInfos_, options};
pm.addPass(AddChildren::createPass(drgnParser, symbols_));
// Re-run passes over newly added children

View File

@ -427,7 +427,20 @@ Enum& DrgnParser::enumerateEnum(struct drgn_type* type) {
const char* typeTag = drgn_type_tag(type);
std::string name = typeTag ? typeTag : "";
uint64_t size = get_drgn_type_size(type);
return makeType<Enum>(type, name, size);
std::map<int64_t, std::string> enumeratorMap;
if (options_.readEnumValues) {
drgn_type_enumerator* enumerators = drgn_type_enumerators(type);
size_t numEnumerators = drgn_type_num_enumerators(type);
for (size_t i = 0; i < numEnumerators; i++) {
// Treat all enum values as signed, under the assumption that -1 is more
// likely to appear in practice than UINT_MAX
int64_t val = enumerators[i].svalue;
enumeratorMap[val] = enumerators[i].name;
}
}
return makeType<Enum>(type, name, size, std::move(enumeratorMap));
}
Typedef& DrgnParser::enumerateTypedef(struct drgn_type* type) {
@ -497,7 +510,7 @@ bool DrgnParser::chasePointer() const {
// Always chase top-level pointers
if (depth_ == 1)
return true;
return chaseRawPointers_;
return options_.chaseRawPointers;
}
DrgnParserError::DrgnParserError(const std::string& msg, struct drgn_error* err)

View File

@ -29,6 +29,11 @@ struct ContainerInfo;
namespace oi::detail::type_graph {
struct DrgnParserOptions {
bool chaseRawPointers = true;
bool readEnumValues = true;
};
/*
* DrgnParser
*
@ -49,10 +54,8 @@ class DrgnParser {
public:
DrgnParser(TypeGraph& typeGraph,
const std::vector<ContainerInfo>& containers,
bool chaseRawPointers)
: typeGraph_(typeGraph),
containers_(containers),
chaseRawPointers_(chaseRawPointers) {
DrgnParserOptions options)
: typeGraph_(typeGraph), containers_(containers), options_(options) {
}
Type& parse(struct drgn_type* root);
@ -96,7 +99,7 @@ class DrgnParser {
TypeGraph& typeGraph_;
const std::vector<ContainerInfo>& containers_;
int depth_;
bool chaseRawPointers_;
DrgnParserOptions options_;
};
class DrgnParserError : public std::runtime_error {

View File

@ -97,6 +97,9 @@ void Printer::visit(const Primitive& p) {
void Printer::visit(const Enum& e) {
prefix();
out_ << "Enum: " << e.name() << " (size: " << e.size() << ")" << std::endl;
for (const auto& [val, name] : e.enumerators()) {
print_enumerator(val, name);
}
}
void Printer::visit(const Array& a) {
@ -230,6 +233,13 @@ void Printer::print_qualifiers(const QualifierSet& qualifiers) {
depth_--;
}
void Printer::print_enumerator(int64_t val, const std::string& name) {
depth_++;
prefix();
out_ << "Enumerator: " << val << ":" << name << std::endl;
depth_--;
}
std::string Printer::align_str(uint64_t align) {
if (align == 0)
return "";

View File

@ -51,6 +51,7 @@ class Printer : public ConstVisitor {
void print_child(const Type& child);
void print_value(const std::string& value);
void print_qualifiers(const QualifierSet& qualifiers);
void print_enumerator(int64_t val, const std::string& name);
static std::string align_str(uint64_t align);
NodeTracker& tracker_;

View File

@ -30,6 +30,7 @@
*/
#include <cstddef>
#include <map>
#include <optional>
#include <string>
#include <vector>
@ -330,8 +331,12 @@ class Container : public Type {
class Enum : public Type {
public:
explicit Enum(std::string name, size_t size)
: name_(std::move(name)), size_(size) {
explicit Enum(std::string name,
size_t size,
std::map<int64_t, std::string> enumerators = {})
: name_(std::move(name)),
size_(size),
enumerators_(std::move(enumerators)) {
}
static inline constexpr bool has_node_id = false;
@ -358,9 +363,14 @@ class Enum : public Type {
return -1;
}
std::map<int64_t, std::string> enumerators() const {
return enumerators_;
}
private:
std::string name_;
size_t size_;
std::map<int64_t, std::string> enumerators_;
};
class Array : public Type {

View File

@ -6,16 +6,16 @@ definitions = '''
};
enum class ScopedEnumInt8 : int8_t {
CaseA,
CaseB,
CaseC,
CaseA = 2,
CaseB = 3,
CaseC = 4,
};
enum UNSCOPED_ENUM {
CASE_A,
CASE_B,
CASE_C,
CASE_A = 5,
CASE_B = -2,
CASE_C = 20,
};
struct Holder {

View File

@ -10,13 +10,14 @@ using namespace type_graph;
class AddChildrenTest : public DrgnParserTest {
protected:
std::string run(std::string_view function, bool chaseRawPointers) override;
std::string run(std::string_view function,
DrgnParserOptions options) override;
};
std::string AddChildrenTest::run(std::string_view function,
bool chaseRawPointers) {
DrgnParserOptions options) {
TypeGraph typeGraph;
auto drgnParser = getDrgnParser(typeGraph, chaseRawPointers);
auto drgnParser = getDrgnParser(typeGraph, options);
auto* drgnRoot = getDrgnRoot(function);
Type& type = drgnParser.parse(drgnRoot);

View File

@ -35,8 +35,8 @@ const std::vector<ContainerInfo>& getContainerInfos() {
} // namespace
DrgnParser DrgnParserTest::getDrgnParser(TypeGraph& typeGraph,
bool chaseRawPointers) {
DrgnParser drgnParser{typeGraph, getContainerInfos(), chaseRawPointers};
DrgnParserOptions options) {
DrgnParser drgnParser{typeGraph, getContainerInfos(), options};
return drgnParser;
}
@ -47,9 +47,9 @@ drgn_type* DrgnParserTest::getDrgnRoot(std::string_view function) {
}
std::string DrgnParserTest::run(std::string_view function,
bool chaseRawPointers) {
DrgnParserOptions options) {
TypeGraph typeGraph;
auto drgnParser = getDrgnParser(typeGraph, chaseRawPointers);
auto drgnParser = getDrgnParser(typeGraph, options);
auto* drgnRoot = getDrgnRoot(function);
Type& type = drgnParser.parse(drgnRoot);
@ -63,8 +63,8 @@ std::string DrgnParserTest::run(std::string_view function,
void DrgnParserTest::test(std::string_view function,
std::string_view expected,
bool chaseRawPointers) {
auto actual = run(function, chaseRawPointers);
DrgnParserOptions options) {
auto actual = run(function, options);
expected.remove_prefix(1); // Remove initial '\n'
EXPECT_EQ(expected, actual);
@ -72,8 +72,8 @@ void DrgnParserTest::test(std::string_view function,
void DrgnParserTest::testContains(std::string_view function,
std::string_view expected,
bool chaseRawPointers) {
auto actual = run(function, chaseRawPointers);
DrgnParserOptions options) {
auto actual = run(function, options);
expected.remove_prefix(1); // Remove initial '\n'
EXPECT_THAT(actual, HasSubstr(expected));
@ -83,11 +83,11 @@ void DrgnParserTest::testMultiCompiler(
std::string_view function,
[[maybe_unused]] std::string_view expectedClang,
[[maybe_unused]] std::string_view expectedGcc,
bool chaseRawPointers) {
DrgnParserOptions options) {
#if defined(__clang__)
test(function, expectedClang, chaseRawPointers);
test(function, expectedClang, options);
#else
test(function, expectedGcc, chaseRawPointers);
test(function, expectedGcc, options);
#endif
}
@ -95,11 +95,11 @@ void DrgnParserTest::testMultiCompilerContains(
std::string_view function,
[[maybe_unused]] std::string_view expectedClang,
[[maybe_unused]] std::string_view expectedGcc,
bool chaseRawPointers) {
DrgnParserOptions options) {
#if defined(__clang__)
testContains(function, expectedClang, chaseRawPointers);
testContains(function, expectedClang, options);
#else
testContains(function, expectedGcc, chaseRawPointers);
testContains(function, expectedGcc, options);
#endif
}
@ -240,21 +240,40 @@ TEST_F(DrgnParserTest, Container) {
TEST_F(DrgnParserTest, Enum) {
test("oid_test_case_enums_scoped", R"(
Enum: ScopedEnum (size: 4)
Enumerator: 0:CaseA
Enumerator: 1:CaseB
Enumerator: 2:CaseC
)");
}
TEST_F(DrgnParserTest, EnumInt8) {
test("oid_test_case_enums_scoped_int8", R"(
Enum: ScopedEnumInt8 (size: 1)
Enumerator: 2:CaseA
Enumerator: 3:CaseB
Enumerator: 4:CaseC
)");
}
TEST_F(DrgnParserTest, UnscopedEnum) {
test("oid_test_case_enums_unscoped", R"(
Enum: UNSCOPED_ENUM (size: 4)
Enumerator: -2:CASE_B
Enumerator: 5:CASE_A
Enumerator: 20:CASE_C
)");
}
TEST_F(DrgnParserTest, EnumNoValues) {
DrgnParserOptions options{
.readEnumValues = false,
};
test("oid_test_case_enums_scoped", R"(
Enum: ScopedEnum (size: 4)
)",
options);
}
TEST_F(DrgnParserTest, Typedef) {
test("oid_test_case_typedefs_c_style", R"(
[2] Typedef: TdUInt64
@ -314,6 +333,9 @@ TEST_F(DrgnParserTest, Pointer) {
}
TEST_F(DrgnParserTest, PointerNoFollow) {
DrgnParserOptions options{
.chaseRawPointers = false,
};
test("oid_test_case_pointers_struct_primitive_ptrs", R"(
[1] Pointer
[0] Struct: PrimitivePtrs (size: 24)
@ -324,7 +346,7 @@ TEST_F(DrgnParserTest, PointerNoFollow) {
Member: c (offset: 16)
Primitive: uintptr_t
)",
false);
options);
}
TEST_F(DrgnParserTest, PointerIncomplete) {
@ -652,8 +674,14 @@ TEST_F(DrgnParserTest, BitfieldsEnum) {
[0] Struct: Enum (size: 4)
Member: e (offset: 0, bitsize: 2)
Enum: MyEnum (size: 4)
Enumerator: 0:One
Enumerator: 1:Two
Enumerator: 2:Three
Member: f (offset: 0.25, bitsize: 4)
Enum: MyEnum (size: 4)
Enumerator: 0:One
Enumerator: 1:Two
Enumerator: 2:Three
)");
}

View File

@ -24,25 +24,26 @@ class DrgnParserTest : public ::testing::Test {
delete symbols_;
}
static type_graph::DrgnParser getDrgnParser(type_graph::TypeGraph& typeGraph,
bool chaseRawPointers);
static type_graph::DrgnParser getDrgnParser(
type_graph::TypeGraph& typeGraph, type_graph::DrgnParserOptions options);
drgn_type* getDrgnRoot(std::string_view function);
virtual std::string run(std::string_view function, bool chaseRawPointers);
virtual std::string run(std::string_view function,
type_graph::DrgnParserOptions options);
void test(std::string_view function,
std::string_view expected,
bool chaseRawPointers = true);
type_graph::DrgnParserOptions options = {});
void testContains(std::string_view function,
std::string_view expected,
bool chaseRawPointers = true);
type_graph::DrgnParserOptions options = {});
void testMultiCompiler(std::string_view function,
std::string_view expectedClang,
std::string_view expectedGcc,
bool chaseRawPointers = true);
type_graph::DrgnParserOptions options = {});
void testMultiCompilerContains(std::string_view function,
std::string_view expectedClang,
std::string_view expectedGcc,
bool chaseRawPointers = true);
type_graph::DrgnParserOptions options = {});
static SymbolService* symbols_;
};