mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Have driver_ast_parser report the size of structs and types.
PiperOrigin-RevId: 660453033
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "clang/include/clang/AST/ASTContext.h"
|
||||
#include "clang/include/clang/AST/Decl.h"
|
||||
#include "clang/include/clang/AST/Type.h"
|
||||
#include "clang/include/clang/ASTMatchers/ASTMatchFinder.h"
|
||||
@@ -89,7 +90,7 @@ struct DriverStructReporter : public MatchFinder::MatchCallback {
|
||||
}
|
||||
|
||||
void run(const MatchFinder::MatchResult &result) override {
|
||||
const auto &sm = result.Context->getSourceManager();
|
||||
const auto *ctx = result.Context;
|
||||
|
||||
const auto *typedef_decl =
|
||||
result.Nodes.getNodeAs<clang::TypedefDecl>("typedef_decl");
|
||||
@@ -104,22 +105,28 @@ struct DriverStructReporter : public MatchFinder::MatchCallback {
|
||||
const auto *struct_decl =
|
||||
result.Nodes.getNodeAs<clang::RecordDecl>("struct_decl");
|
||||
if (struct_decl == nullptr) {
|
||||
// Add the typedef to TypeAliases, and recurse on the underlying type.
|
||||
// Generate the definition for the underlying type, then copy it for
|
||||
// this struct.
|
||||
const auto type = typedef_decl->getUnderlyingType();
|
||||
const auto type_name = type.getAsString();
|
||||
TypeAliases[name] = type_name;
|
||||
add_type_definition(type, type_name, sm);
|
||||
add_type_definition(type, type_name, ctx);
|
||||
|
||||
if (type->isRecordType()) {
|
||||
RecordDefinitions[name] = RecordDefinitions[type_name];
|
||||
} else {
|
||||
TypeAliases[name] = TypeAliases[type_name];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
add_type_definition(result.Context->getTypeDeclType(struct_decl), name, sm);
|
||||
add_type_definition(ctx->getTypeDeclType(struct_decl), name, ctx);
|
||||
}
|
||||
|
||||
// Adds the type definition of `type` to either `RecordDefinitions` or
|
||||
// `TypeAliases`, mapped to `name`. Recursively adds the type definitions
|
||||
// of any nested types.
|
||||
void add_type_definition(const clang::QualType &type, const std::string &name,
|
||||
const clang::SourceManager &sm) {
|
||||
const clang::ASTContext *ctx) {
|
||||
// We've already handled this type.
|
||||
if (ParsedTypes.contains(name)) {
|
||||
return;
|
||||
@@ -132,9 +139,12 @@ struct DriverStructReporter : public MatchFinder::MatchCallback {
|
||||
if (canonical_type->isRecordType()) {
|
||||
const auto record_decl = canonical_type->getAsRecordDecl();
|
||||
|
||||
add_record_definition(record_decl, name, sm);
|
||||
add_record_definition(record_decl, name, ctx);
|
||||
} else {
|
||||
TypeAliases[name] = canonical_type.getAsString();
|
||||
// getTypeSize returns the size in bits, so we divide by 8 to get bytes.
|
||||
uint64_t size = ctx->getTypeSize(canonical_type) / 8;
|
||||
TypeAliases[name] = json::object(
|
||||
{{"size", size}, {"type", canonical_type.getAsString()}});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +152,7 @@ struct DriverStructReporter : public MatchFinder::MatchCallback {
|
||||
// to `name`. Recursively adds the type definitions of any nested types.
|
||||
void add_record_definition(const clang::RecordDecl *record_decl,
|
||||
const std::string &name,
|
||||
const clang::SourceManager &sm) {
|
||||
const clang::ASTContext *ctx) {
|
||||
json fields;
|
||||
for (const auto *field : record_decl->fields()) {
|
||||
auto field_type = field->getType();
|
||||
@@ -182,13 +192,15 @@ struct DriverStructReporter : public MatchFinder::MatchCallback {
|
||||
{{"name", field->getNameAsString()}, {"type", field_type_name}}));
|
||||
|
||||
// Recurse on the field type.
|
||||
add_type_definition(field_type, base_type_name, sm);
|
||||
add_type_definition(field_type, base_type_name, ctx);
|
||||
}
|
||||
|
||||
std::string source = record_decl->getLocation().printToString(sm);
|
||||
|
||||
std::string source =
|
||||
record_decl->getLocation().printToString(ctx->getSourceManager());
|
||||
// getTypeSize returns the size in bits, so we divide by 8 to get bytes.
|
||||
uint64_t size = ctx->getTypeSize(record_decl->getTypeForDecl()) / 8;
|
||||
RecordDefinitions[name] =
|
||||
json::object({{"source", source}, {"fields", fields}});
|
||||
json::object({{"source", source}, {"fields", fields}, {"size", size}});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestParser(t *testing.T) {
|
||||
}()
|
||||
|
||||
input := parser.InputJSON{
|
||||
Structs: []string{"TestStruct"},
|
||||
Structs: []string{"TestStruct", "TestStruct2"},
|
||||
}
|
||||
if err := json.NewEncoder(structsFile).Encode(&input); err != nil {
|
||||
t.Fatalf("failed to write input structs file: %v", err)
|
||||
@@ -84,6 +84,17 @@ func TestParser(t *testing.T) {
|
||||
parser.RecordField{Name: "e", Type: "TestStruct::e_t[4]"},
|
||||
parser.RecordField{Name: "f", Type: "TestUnion"},
|
||||
},
|
||||
Size: 44,
|
||||
Source: "test_struct.cc:25:16",
|
||||
},
|
||||
"TestStruct2": parser.RecordDef{
|
||||
Fields: []parser.RecordField{
|
||||
parser.RecordField{Name: "a", Type: "int"},
|
||||
parser.RecordField{Name: "b", Type: "int"},
|
||||
parser.RecordField{Name: "e", Type: "TestStruct::e_t[4]"},
|
||||
parser.RecordField{Name: "f", Type: "TestUnion"},
|
||||
},
|
||||
Size: 44,
|
||||
Source: "test_struct.cc:25:16",
|
||||
},
|
||||
"TestStruct::e_t": parser.RecordDef{
|
||||
@@ -91,6 +102,7 @@ func TestParser(t *testing.T) {
|
||||
parser.RecordField{Name: "c", Type: "OtherInt"},
|
||||
parser.RecordField{Name: "d", Type: "OtherInt"},
|
||||
},
|
||||
Size: 8,
|
||||
Source: "test_struct.cc:28:3",
|
||||
},
|
||||
"TestUnion": parser.RecordDef{
|
||||
@@ -98,12 +110,13 @@ func TestParser(t *testing.T) {
|
||||
parser.RecordField{Name: "u_a", Type: "int"},
|
||||
parser.RecordField{Name: "u_b", Type: "int"},
|
||||
},
|
||||
Size: 4,
|
||||
Source: "test_struct.cc:20:9",
|
||||
},
|
||||
},
|
||||
Aliases: parser.TypeAliases{
|
||||
"OtherInt": "int",
|
||||
"int": "int",
|
||||
"OtherInt": parser.TypeDef{Type: "int", Size: 4},
|
||||
"int": parser.TypeDef{Type: "int", Size: 4},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -61,29 +61,38 @@ func (s RecordField) String() string {
|
||||
// RecordDef represents the definition of a record (struct or union).
|
||||
type RecordDef struct {
|
||||
Fields []RecordField
|
||||
Size uint64
|
||||
Source string
|
||||
}
|
||||
|
||||
// Equals returns true if the two record definitions are equal. We only
|
||||
// compare the fields, not the source.
|
||||
// Equals returns true if the two record definitions are equal. We ignore the source of the records.
|
||||
func (s RecordDef) Equals(other RecordDef) bool {
|
||||
return slices.Equal(s.Fields, other.Fields)
|
||||
return s.Size == other.Size && slices.Equal(s.Fields, other.Fields)
|
||||
}
|
||||
|
||||
// TypeDef represents the definition of a type.
|
||||
type TypeDef struct {
|
||||
Type string
|
||||
Size uint64
|
||||
}
|
||||
|
||||
// RecordDefs is a map of type names to definitions.
|
||||
type RecordDefs map[string]RecordDef
|
||||
|
||||
// TypeAliases is a map of type aliases to their underlying type.
|
||||
type TypeAliases map[string]string
|
||||
type TypeAliases map[string]TypeDef
|
||||
|
||||
// GetRecordDiff prints a diff between two records.
|
||||
func GetRecordDiff(name nvproxy.DriverStructName, s1, s2 RecordDef) string {
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "--- A: %s\n", s1.Source)
|
||||
fmt.Fprintf(&b, "+++ B: %s\n", s2.Source)
|
||||
func GetRecordDiff(name nvproxy.DriverStructName, a, b RecordDef) string {
|
||||
var sb strings.Builder
|
||||
fmt.Fprintf(&sb, "--- A: %s\n", a.Source)
|
||||
fmt.Fprintf(&sb, "+++ B: %s\n", b.Source)
|
||||
|
||||
fmt.Fprintf(&b, "struct %s\n", name)
|
||||
fmt.Fprint(&b, cmp.Diff(s1.Fields, s2.Fields))
|
||||
fmt.Fprintf(&sb, "struct %s\n", name)
|
||||
if a.Size != b.Size {
|
||||
fmt.Fprintf(&sb, " size: %d -> %d (bytes)\n", a.Size, b.Size)
|
||||
}
|
||||
fmt.Fprint(&sb, cmp.Diff(a.Fields, b.Fields))
|
||||
|
||||
return b.String()
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
@@ -170,8 +170,8 @@ func Main() error {
|
||||
continue
|
||||
}
|
||||
|
||||
if baseAlias != nextAlias {
|
||||
log.Infof("alias %s changed from %s to %s", name, baseAlias, nextAlias)
|
||||
if baseAlias.Type != nextAlias.Type {
|
||||
log.Infof("alias %s changed from %s to %s", name, baseAlias.Type, nextAlias.Type)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,3 +31,5 @@ typedef struct TestStruct {
|
||||
} e[4];
|
||||
TestUnion f;
|
||||
} TestStruct;
|
||||
|
||||
typedef TestStruct TestStruct2;
|
||||
|
||||
Reference in New Issue
Block a user