mirror of
https://github.com/JakeHillion/object-introspection.git
synced 2024-11-12 21:56:54 +00:00
TypeGraph: Add option to record enumerator names
This commit is contained in:
parent
a2f7462a5d
commit
373dbe8f6c
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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 "";
|
||||
|
@ -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_;
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
)");
|
||||
}
|
||||
|
||||
|
@ -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_;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user