mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Add model drop-types tool
This commit is contained in:
@@ -411,7 +411,12 @@ set(FILECHECK_TESTS
|
||||
llvm-passes/select-scope.ll
|
||||
llvm-passes/switch-to-statements.ll
|
||||
llvm-passes/ternary-reduction.ll
|
||||
llvm-passes/twoscomplement-normalization.ll)
|
||||
llvm-passes/twoscomplement-normalization.ll
|
||||
model/drop-types/ArrayPropagation.yml
|
||||
model/drop-types/DropStructField.yml
|
||||
model/drop-types/DropViaPointer.yml
|
||||
model/drop-types/UnionCascade.yml
|
||||
model/drop-types/UnionPartialDrop.yml)
|
||||
|
||||
foreach(F IN LISTS FILECHECK_TESTS)
|
||||
add_filecheck_test(${F})
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
# Arrays do not break the dependency chain: a field of type `Array<victim>`
|
||||
# is treated as a direct reference to `victim`, so dropping `victim` removes
|
||||
# the field from the containing struct.
|
||||
#
|
||||
# RUN: %root/bin/revng model drop-types %s 1001-StructDefinition | FileCheck %s
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
# This type is dropped.
|
||||
# CHECK-NOT: 1001-StructDefinition
|
||||
- ID: 1001
|
||||
Kind: StructDefinition
|
||||
Name: "victim"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# Container survives; the array field (offset 0) is removed, only the
|
||||
# primitive field at offset 16 stays.
|
||||
# CHECK: ID: 1002
|
||||
# CHECK: Name: container_with_array
|
||||
# CHECK: Fields:
|
||||
# CHECK-NEXT: - Offset: 16
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Kind: PrimitiveType
|
||||
# CHECK-NOT: - Offset: 0
|
||||
- ID: 1002
|
||||
Kind: StructDefinition
|
||||
Name: "container_with_array"
|
||||
Size: 20
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: ArrayType
|
||||
ElementCount: 4
|
||||
ElementType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1001-StructDefinition"
|
||||
- Offset: 16
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
# Dropping a struct that is used as a direct (non-pointer) field type should
|
||||
# remove that field from the containing struct, but the containing struct
|
||||
# itself must survive (its other fields are unaffected).
|
||||
#
|
||||
# RUN: %root/bin/revng model drop-types %s 1001-StructDefinition | FileCheck %s
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
# This type is dropped — it must not appear in the output.
|
||||
# CHECK-NOT: 1001-StructDefinition
|
||||
# CHECK-NOT: Name: victim
|
||||
- ID: 1001
|
||||
Kind: StructDefinition
|
||||
Name: "victim"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# The container survives; only the primitive field at offset 4 remains.
|
||||
# CHECK: ID: 1002
|
||||
# CHECK: Name: container
|
||||
# CHECK: Fields:
|
||||
# CHECK-NEXT: Offset: 4
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Kind: PrimitiveType
|
||||
- ID: 1002
|
||||
Kind: StructDefinition
|
||||
Name: "container"
|
||||
Size: 8
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1001-StructDefinition"
|
||||
- Offset: 4
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
@@ -0,0 +1,47 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
# Dropping a struct that is only reached via a pointer should NOT remove the
|
||||
# containing struct's field. Instead, the pointer's pointee is replaced with
|
||||
# void.
|
||||
#
|
||||
# RUN: %root/bin/revng model drop-types %s 1001-StructDefinition | FileCheck %s
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
# This type is dropped — it must not appear in the output.
|
||||
# CHECK-NOT: 1001-StructDefinition
|
||||
- ID: 1001
|
||||
Kind: StructDefinition
|
||||
Name: "victim"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# The container survives with its pointer field; the pointee is now void.
|
||||
# CHECK: ID: 1002
|
||||
# CHECK: Name: container_with_ptr
|
||||
# CHECK: Fields:
|
||||
# CHECK-NEXT: Offset: 0
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Kind: PointerType
|
||||
# CHECK: PointeeType:
|
||||
# CHECK-NEXT: Kind: PrimitiveType
|
||||
# CHECK-NEXT: PrimitiveKind: Void
|
||||
- ID: 1002
|
||||
Kind: StructDefinition
|
||||
Name: "container_with_ptr"
|
||||
Size: 8
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PointerType
|
||||
PointerSize: 8
|
||||
PointeeType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1001-StructDefinition"
|
||||
@@ -0,0 +1,67 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
# When ALL fields of a union reference deleted types, the union itself must
|
||||
# also be dropped and deletion cascades to its dependents (here, the field
|
||||
# in `uses_u` referencing the union).
|
||||
#
|
||||
# RUN: %root/bin/revng model drop-types %s 1001-StructDefinition 1002-StructDefinition | FileCheck %s
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
# Dropped directly.
|
||||
# CHECK-NOT: 1001-StructDefinition
|
||||
- ID: 1001
|
||||
Kind: StructDefinition
|
||||
Name: "v1"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# Dropped directly.
|
||||
# CHECK-NOT: 1002-StructDefinition
|
||||
- ID: 1002
|
||||
Kind: StructDefinition
|
||||
Name: "v2"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# Both entries reference deleted types, so the union itself is cascaded.
|
||||
# CHECK-NOT: 1003-UnionDefinition
|
||||
# CHECK-NOT: UnionDefinition
|
||||
- ID: 1003
|
||||
Kind: UnionDefinition
|
||||
Name: "u"
|
||||
Fields:
|
||||
- Index: 0
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1001-StructDefinition"
|
||||
- Index: 1
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1002-StructDefinition"
|
||||
|
||||
# Survives but loses its only field (which referenced the cascaded union).
|
||||
# CHECK: ID: 1004
|
||||
# CHECK: Name: uses_u
|
||||
# CHECK-NOT: Fields:
|
||||
- ID: 1004
|
||||
Kind: StructDefinition
|
||||
Name: "uses_u"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1003-UnionDefinition"
|
||||
@@ -0,0 +1,46 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
# When only SOME of a union's fields reference deleted types, the union
|
||||
# itself survives. The deleted entries are removed and the remaining ones
|
||||
# are reindexed starting from zero.
|
||||
#
|
||||
# RUN: %root/bin/revng model drop-types %s 1001-StructDefinition | FileCheck %s
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
# This type is dropped.
|
||||
# CHECK-NOT: 1001-StructDefinition
|
||||
- ID: 1001
|
||||
Kind: StructDefinition
|
||||
Name: "victim"
|
||||
Size: 4
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
|
||||
# The union survives with only the primitive entry, reindexed to 0.
|
||||
# CHECK: ID: 1002
|
||||
# CHECK: Kind: UnionDefinition
|
||||
# CHECK: Fields:
|
||||
# CHECK-NEXT: - Index: 0
|
||||
# CHECK-NEXT: Type:
|
||||
# CHECK-NEXT: Kind: PrimitiveType
|
||||
# CHECK-NOT: - Index: 1
|
||||
- ID: 1002
|
||||
Kind: UnionDefinition
|
||||
Name: "u"
|
||||
Fields:
|
||||
- Index: 0
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/1001-StructDefinition"
|
||||
- Index: 1
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 4
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
add_subdirectory(apply)
|
||||
add_subdirectory(diff)
|
||||
add_subdirectory(drop-types)
|
||||
add_subdirectory(export)
|
||||
add_subdirectory(import)
|
||||
add_subdirectory(merge)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
revng_add_executable(model-drop-types Main.cpp)
|
||||
|
||||
target_link_libraries(model-drop-types revngModel)
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
#include "revng/Model/Binary.h"
|
||||
#include "revng/Model/Processing.h"
|
||||
#include "revng/Support/Debug.h"
|
||||
#include "revng/Support/InitRevng.h"
|
||||
#include "revng/Support/YAMLTraits.h"
|
||||
|
||||
namespace cl = llvm::cl;
|
||||
|
||||
static cl::OptionCategory ThisToolCategory("model-drop-types options", "");
|
||||
|
||||
static cl::opt<std::string> InputFilename(cl::Positional,
|
||||
cl::cat(ThisToolCategory),
|
||||
cl::desc("<input model>"),
|
||||
cl::init("-"),
|
||||
cl::value_desc("model"));
|
||||
|
||||
static cl::opt<std::string> OutputFilename("o",
|
||||
cl::cat(ThisToolCategory),
|
||||
cl::init("-"),
|
||||
cl::desc("Override output "
|
||||
"filename"),
|
||||
cl::value_desc("filename"));
|
||||
|
||||
static cl::list<std::string> TypeKeys(cl::Positional,
|
||||
cl::cat(ThisToolCategory),
|
||||
cl::desc("<type keys to drop...>"),
|
||||
cl::OneOrMore);
|
||||
|
||||
int main(int Argc, char *Argv[]) {
|
||||
revng::InitRevng X(Argc, Argv, "", { &ThisToolCategory });
|
||||
|
||||
llvm::ExitOnError ExitOnError;
|
||||
|
||||
auto MaybeModel = TupleTree<model::Binary>::fromFileOrSTDIN(InputFilename);
|
||||
if (not MaybeModel)
|
||||
ExitOnError(MaybeModel.takeError());
|
||||
|
||||
auto &Model = *MaybeModel;
|
||||
|
||||
// Resolve the type keys into TypeDefinition pointers
|
||||
std::set<const model::TypeDefinition *> TypesToDrop;
|
||||
for (const std::string &KeyString : TypeKeys) {
|
||||
// Keys have the form "ID-Kind", e.g. "42-StructDefinition"
|
||||
auto SplitPoint = KeyString.find('-');
|
||||
if (SplitPoint == std::string::npos) {
|
||||
dbg << "Invalid type key (expected ID-Kind): " << KeyString << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
uint64_t ID = 0;
|
||||
if (llvm::StringRef(KeyString).substr(0, SplitPoint).getAsInteger(10, ID)) {
|
||||
dbg << "Invalid ID in type key: " << KeyString << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
llvm::StringRef KindName = llvm::StringRef(KeyString).substr(SplitPoint
|
||||
+ 1);
|
||||
auto Kind = model::TypeDefinitionKind::fromName(KindName);
|
||||
if (Kind == model::TypeDefinitionKind::Invalid) {
|
||||
dbg << "Unknown type kind: " << KindName.str() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Look up the type in the model
|
||||
bool Found = false;
|
||||
for (const model::UpcastableTypeDefinition &Type :
|
||||
Model->TypeDefinitions()) {
|
||||
if (Type->ID() == ID && Type->Kind() == Kind) {
|
||||
TypesToDrop.insert(Type.get());
|
||||
Found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (not Found) {
|
||||
dbg << "Type not found in model: " << KeyString << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned Dropped = model::dropTypesDependingOnDefinitions(Model, TypesToDrop);
|
||||
|
||||
dbg << "Dropped " << Dropped << " type(s)\n";
|
||||
|
||||
ExitOnError(Model.toFile(OutputFilename));
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user