mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Drop type inlining
Type inlining was a feature that allowed type definitions of structs/unions/enums to be printed in C directly inside the definition of another parent struct/union, if the inner type was only used once in the parent type. This kind of reasoning is inherently global: a type definition of the subtype can be inlined in the parent type one only if *globally* the subtype it isn't referred anywhere else. This caused issues with type inlining inside definitions of stack types in the body of functions. Indeed, for a given function, due to type inlining, it was necessary to do global reasoning about what other types could be inlined in the definition of the function's stack frame type. This, in turn, had heavy consequences on invalidation, because any change to any type (even if it wasn't referred in a given function's body) was causing invalidation of all functions' bodies. For this reason it was decided to drop the type inlining feature.
This commit is contained in:
@@ -8,10 +8,7 @@
|
||||
|
||||
namespace revng::options {
|
||||
|
||||
// Disabled by default.
|
||||
extern llvm::cl::opt<bool> EnableTypeInlining;
|
||||
|
||||
// Enabled by default.
|
||||
extern llvm::cl::opt<bool> DisableStackFrameInlining;
|
||||
extern llvm::cl::opt<bool> EnableStackFrameInlining;
|
||||
|
||||
} // namespace revng::options
|
||||
|
||||
@@ -26,14 +26,15 @@ protected:
|
||||
|
||||
public:
|
||||
struct ConfigurationOptions {
|
||||
/// When set to true, the types that are only ever depended on by a single
|
||||
/// other type (for example, a nested struct), are printed inside the parent
|
||||
/// type definition instead of separately.
|
||||
bool EnableTypeInlining = true;
|
||||
|
||||
/// When set to true, function stack frame types are printed inside the
|
||||
/// struct body as opposed to the type header.
|
||||
bool EnableStackFrameInlining = true;
|
||||
/// When set to true, function stack frame types are printed also inside the
|
||||
/// struct body, and not just in the header.
|
||||
/// This may break the property that we emit syntactically valid C code,
|
||||
/// because including the header will cause the definition of the stack
|
||||
/// frame type to be duplicated in the header and inside the function body.
|
||||
/// For this reason it's disabled by default. And it should only be turned
|
||||
/// on when printing artifacts that only show the body of the function, for
|
||||
/// which emitting recompilable C code is not a strict requirement.
|
||||
bool EnableStackFrameInlining = false;
|
||||
|
||||
/// Because we are emitting C11, we cannot specify underlying enum type
|
||||
/// (the feature was only backported from C++ in C23), which means that
|
||||
@@ -61,54 +62,10 @@ public:
|
||||
const ConfigurationOptions Configuration;
|
||||
|
||||
private:
|
||||
/// This is the cache containing the names of artificial types (like array
|
||||
/// wrappers).
|
||||
std::map<model::UpcastableType, std::string> ArtificialNameCache = {};
|
||||
|
||||
/// This is the cache containing the dependency data for the types.
|
||||
/// It is here so that we don't have to recompute it with multiple invocations
|
||||
std::optional<DependencyGraph> DependencyCache = std::nullopt;
|
||||
|
||||
/// This is the cache containing the keys of the types that should be inlined
|
||||
/// into their only user.
|
||||
std::set<model::TypeDefinition::Key> TypesToInlineCache = {};
|
||||
|
||||
/// This is the cache containing the keys of the stack frame types that
|
||||
/// should be inlined into the functions they belong to.
|
||||
std::set<model::TypeDefinition::Key> StackFrameTypeCache = {};
|
||||
|
||||
/// Is only set to true if \ref collectInlinableTypes was invoked.
|
||||
bool InlinableCacheIsReady = false;
|
||||
|
||||
public:
|
||||
/// Gather (and store internally) the list of types that can (and should)
|
||||
/// be inlined. This list is then later used by the invocations of
|
||||
/// \ref printDefinition.
|
||||
void collectInlinableTypes();
|
||||
|
||||
bool shouldInline(model::TypeDefinition::Key Key) const {
|
||||
revng_assert(InlinableCacheIsReady,
|
||||
"`shouldInline` must not be called before "
|
||||
"`collectInlinableTypes`.");
|
||||
|
||||
if (not TypesToInlineCache.contains(Key)) {
|
||||
// This type is not allowed be inlined.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StackFrameTypeCache.contains(Key)) {
|
||||
// This is a stack frame.
|
||||
return Configuration.EnableStackFrameInlining;
|
||||
|
||||
} else {
|
||||
return Configuration.EnableTypeInlining;
|
||||
}
|
||||
}
|
||||
|
||||
bool shouldInline(const model::TypeDefinition &Type) const {
|
||||
return shouldInline(Type.key());
|
||||
}
|
||||
|
||||
public:
|
||||
CTypeBuilder(llvm::raw_ostream &OutputStream,
|
||||
const model::Binary &Binary,
|
||||
|
||||
@@ -1928,14 +1928,19 @@ void CCodeGenerator::emitFunction(bool NeedsLocalStateVar) {
|
||||
|
||||
revng_assert(not IsStackDefined, "Multiple stack variables?");
|
||||
const model::StructDefinition &Struct = *ModelFunction.stackFrameType();
|
||||
if (B.shouldInline(Struct.key())) {
|
||||
// In the artifacts generated by this LLVM-based backend we've given up
|
||||
// the requirement of emitting syntactically valid C code. Hence, we can
|
||||
// always emit the stack frame type definition inside the body of the
|
||||
// function itself, because we don't care anymore if it clashes with a
|
||||
// global definition that we have emitted in a header outside the
|
||||
// function's body.
|
||||
if (B.Configuration.EnableStackFrameInlining) {
|
||||
B.printDefinition(Struct, " " + std::move(VarName));
|
||||
} else {
|
||||
auto Named = B.getNamedCInstance(*ModelFunction.StackFrameType(),
|
||||
std::move(VarName));
|
||||
B.append(Named + ";\n");
|
||||
}
|
||||
|
||||
IsStackDefined = true;
|
||||
|
||||
} else {
|
||||
|
||||
@@ -136,9 +136,7 @@ void Decompile::run(pipeline::ExecutionContext &EC,
|
||||
B(llvm::nulls(),
|
||||
Model,
|
||||
/* EnableTaglessMode = */ false,
|
||||
{ .EnableTypeInlining = options::EnableTypeInlining,
|
||||
.EnableStackFrameInlining = !options::DisableStackFrameInlining });
|
||||
B.collectInlinableTypes();
|
||||
{ .EnableStackFrameInlining = options::EnableStackFrameInlining });
|
||||
|
||||
for (const model::Function &Function :
|
||||
getFunctionsAndCommit(EC, DecompiledFunctions.name())) {
|
||||
|
||||
@@ -38,13 +38,17 @@ void DecompileToDirectory::run(pipeline::ExecutionContext &EC,
|
||||
const model::Binary &Model = *getModelFromContext(EC);
|
||||
|
||||
namespace options = revng::options;
|
||||
ptml::CTypeBuilder
|
||||
B(llvm::nulls(),
|
||||
Model,
|
||||
/* EnableTaglessMode = */ true,
|
||||
{ .EnableTypeInlining = options::EnableTypeInlining,
|
||||
.EnableStackFrameInlining = !options::DisableStackFrameInlining });
|
||||
B.collectInlinableTypes();
|
||||
ptml::CTypeBuilder B(llvm::nulls(),
|
||||
Model,
|
||||
/* EnableTaglessMode = */ true,
|
||||
// Disable stack frame inlining because enabling it could
|
||||
// break the property that we emit syntactically valid C
|
||||
// code, due to the stack frame type definition being
|
||||
// duplicated in the global header and in the function's
|
||||
// body. In this artifact, where all the decompiled
|
||||
// functions are put in a single .c file, recompilability
|
||||
// is still important.
|
||||
{ .EnableStackFrameInlining = false });
|
||||
|
||||
{
|
||||
ControlFlowGraphCache Cache{ CFGMap };
|
||||
|
||||
@@ -26,13 +26,16 @@ void DecompileToSingleFile::run(pipeline::ExecutionContext &EC,
|
||||
llvm::raw_string_ostream Out = OutCFile.asStream();
|
||||
|
||||
namespace options = revng::options;
|
||||
ptml::CTypeBuilder
|
||||
B(Out,
|
||||
*getModelFromContext(EC),
|
||||
/* EnableTaglessMode = */ false,
|
||||
{ .EnableTypeInlining = options::EnableTypeInlining,
|
||||
.EnableStackFrameInlining = !options::DisableStackFrameInlining });
|
||||
B.collectInlinableTypes();
|
||||
ptml::CTypeBuilder B(Out,
|
||||
*getModelFromContext(EC),
|
||||
/* EnableTaglessMode = */ false,
|
||||
// Disable stack frame inlining because enabling it could
|
||||
// break the property that we emit syntactically valid C
|
||||
// code, due to the stack frame type definition being
|
||||
// duplicated in the global header and in the function's
|
||||
// body. In the single file artifact recompilability is
|
||||
// still important.
|
||||
{ .EnableStackFrameInlining = false });
|
||||
|
||||
// Make a single C file with an empty set of targets, which means all the
|
||||
// functions in DecompiledFunctions
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
static Logger<> Log{ "model-to-header" };
|
||||
|
||||
bool ptml::HeaderBuilder::printModelHeader() {
|
||||
B.collectInlinableTypes();
|
||||
|
||||
auto Scope = B.getScopeTag(ptml::tags::Div);
|
||||
|
||||
|
||||
@@ -10,17 +10,6 @@
|
||||
#include "revng/Pipes/Kinds.h"
|
||||
#include "revng/Pipes/ModelGlobal.h"
|
||||
|
||||
static llvm::cl::opt<bool> InlineTypes("inline-types",
|
||||
llvm::cl::desc("Enable printing struct, "
|
||||
"union and enum types "
|
||||
"inline in their parent "
|
||||
"types. This also "
|
||||
"enables printing stack "
|
||||
"types definitions "
|
||||
"inline in the function "
|
||||
"body."),
|
||||
llvm::cl::init(false));
|
||||
|
||||
namespace revng::pipes {
|
||||
|
||||
inline constexpr char ModelHeaderFileContainerMIMEType[] = "text/x.c+ptml";
|
||||
@@ -64,8 +53,7 @@ public:
|
||||
B(Header,
|
||||
*getModelFromContext(EC),
|
||||
/* EnableTaglessMode = */ false,
|
||||
{ .EnableTypeInlining = options::EnableTypeInlining,
|
||||
.EnableStackFrameInlining = !options::DisableStackFrameInlining,
|
||||
{ .EnableStackFrameInlining = options::EnableStackFrameInlining,
|
||||
.EnablePrintingOfTheMaximumEnumValue = true });
|
||||
ptml::HeaderBuilder(B).printModelHeader();
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ public:
|
||||
{ .EnablePrintingOfTheMaximumEnumValue = true,
|
||||
.EnableExplicitPaddingMode = false,
|
||||
.EnableStructSizeAnnotation = true });
|
||||
B.collectInlinableTypes();
|
||||
|
||||
B.printDefinition(Type);
|
||||
}
|
||||
|
||||
@@ -8,23 +8,10 @@ using namespace llvm::cl;
|
||||
|
||||
namespace revng::options {
|
||||
|
||||
/// TODO: type inlining is currently broken in rare cases involving recursive
|
||||
/// array struct fields. That's why it's disabled by default.
|
||||
/// When the bugs a fixed, turn this option into `disable-type-inlining`
|
||||
/// and reverse it's using.
|
||||
opt<bool> EnableTypeInlining("enable-type-inlining",
|
||||
desc("Enable printing struct, union and enum "
|
||||
"types inline in their parent types if "
|
||||
"they're only used once. This also enables "
|
||||
"printing stack types definitions inline "
|
||||
"in "
|
||||
"the function body."),
|
||||
init(false));
|
||||
|
||||
opt<bool> DisableStackFrameInlining("disable-stack-frame-inlining",
|
||||
desc("Disable printing the definition "
|
||||
"of the function stack type inside "
|
||||
"its body."),
|
||||
init(false));
|
||||
opt<bool> EnableStackFrameInlining("enable-stack-frame-inlining",
|
||||
desc("Enable printing the definition "
|
||||
"of a function's stack type inside "
|
||||
"the function's body."),
|
||||
init(false));
|
||||
|
||||
} // namespace revng::options
|
||||
|
||||
@@ -143,7 +143,7 @@ struct ImportFromCAnalysis {
|
||||
}
|
||||
|
||||
ptml::CTypeBuilder::ConfigurationOptions Configuration = {
|
||||
.EnableTypeInlining = false, .EnableStackFrameInlining = false
|
||||
.EnableStackFrameInlining = false
|
||||
};
|
||||
ptml::HeaderBuilder::ConfigurationOptions HeaderConfiguration = {};
|
||||
if (TheOption == ImportFromCOption::EditType) {
|
||||
|
||||
@@ -106,16 +106,10 @@ void ptml::CTypeBuilder::printDefinition(const model::StructDefinition &S,
|
||||
for (const auto &Field : S.Fields()) {
|
||||
printPadding(PreviousOffset, Field.Offset());
|
||||
|
||||
auto *Definition = Field.Type()->skipToDefinition();
|
||||
if (not Definition or not shouldInline(*Definition)) {
|
||||
auto F = getDefinitionTag(S, Field);
|
||||
std::string Result = getModelComment(Field)
|
||||
+ getNamedCInstance(*Field.Type(), F) + ';';
|
||||
*Out << getCommentableTag(std::move(Result), S, Field) << '\n';
|
||||
|
||||
} else {
|
||||
printInlineDefinition(NameBuilder.name(S, Field), *Field.Type());
|
||||
}
|
||||
auto F = getDefinitionTag(S, Field);
|
||||
std::string Result = getModelComment(Field)
|
||||
+ getNamedCInstance(*Field.Type(), F) + ';';
|
||||
*Out << getCommentableTag(std::move(Result), S, Field) << '\n';
|
||||
|
||||
PreviousOffset = Field.Offset() + Field.Type()->size().value();
|
||||
}
|
||||
@@ -137,16 +131,10 @@ void ptml::CTypeBuilder::printDefinition(const model::UnionDefinition &U,
|
||||
{
|
||||
Scope Scope(*Out, ptml::c::scopes::UnionBody);
|
||||
for (const auto &Field : U.Fields()) {
|
||||
auto *Definition = Field.Type()->skipToDefinition();
|
||||
if (not Definition or not shouldInline(*Definition)) {
|
||||
auto F = getDefinitionTag(U, Field);
|
||||
std::string Result = getModelComment(Field)
|
||||
+ getNamedCInstance(*Field.Type(), F) + ';';
|
||||
*Out << getCommentableTag(std::move(Result), U, Field) << '\n';
|
||||
|
||||
} else {
|
||||
printInlineDefinition(NameBuilder.name(U, Field), *Field.Type());
|
||||
}
|
||||
auto F = getDefinitionTag(U, Field);
|
||||
std::string Result = getModelComment(Field)
|
||||
+ getNamedCInstance(*Field.Type(), F) + ';';
|
||||
*Out << getCommentableTag(std::move(Result), U, Field) << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,88 +284,6 @@ void ptml::CTypeBuilder::printInlineDefinition(llvm::StringRef Name,
|
||||
}
|
||||
}
|
||||
|
||||
static Logger<> InlineTypeLog{ "inline-type-selection" };
|
||||
|
||||
void ptml::CTypeBuilder::collectInlinableTypes() {
|
||||
if (not DependencyCache.has_value())
|
||||
DependencyCache = DependencyGraph::make(Binary.TypeDefinitions());
|
||||
|
||||
StackFrameTypeCache = {};
|
||||
for (const model::Function &Function : Binary.Functions())
|
||||
if (auto *StackFrame = Function.stackFrameType())
|
||||
StackFrameTypeCache.insert(StackFrame->key());
|
||||
|
||||
if (Configuration.EnableTypeInlining
|
||||
|| Configuration.EnableStackFrameInlining) {
|
||||
std::map<model::TypeDefinition::Key, uint64_t> DependentTypeCount;
|
||||
for (const auto *Node : DependencyCache->nodes()) {
|
||||
if (isDeclarationTheSameAsDefinition(*Node->T)) {
|
||||
// Skip types that never produce a definition since there's no point
|
||||
// inlining them.
|
||||
continue;
|
||||
}
|
||||
|
||||
auto &&[Iterator, _] = DependentTypeCount.try_emplace(Node->T->key(), 0);
|
||||
Iterator->second += Node->predecessorCount();
|
||||
if (Node->K == TypeNode::Kind::Declaration) {
|
||||
// Ignore a reference from a type definition to its own declaration.
|
||||
// But only do so if there is exactly one. If there are more, keep it in
|
||||
// order to ensure it is never marked for inlining.
|
||||
auto SelfEdgeCounter = [Key = Node->T->key()](auto *N) {
|
||||
return N->T->key() == Key;
|
||||
};
|
||||
if (llvm::count_if(Node->predecessors(), SelfEdgeCounter) == 1)
|
||||
--Iterator->second;
|
||||
|
||||
// Since dependency graph does not take functions into account,
|
||||
// explicitly add one "use" to each struct that appears as a function
|
||||
// stack frame.
|
||||
if (StackFrameTypeCache.contains(Node->T->key()))
|
||||
++Iterator->second;
|
||||
}
|
||||
|
||||
if (InlineTypeLog.isEnabled()) {
|
||||
InlineTypeLog << getNodeLabel(Node) << "' is depended on by: {\n";
|
||||
|
||||
for (auto *Predecessor : Node->predecessors())
|
||||
InlineTypeLog << "- " << getNodeLabel(Predecessor) << '\n';
|
||||
|
||||
InlineTypeLog << "}\n" << DoLog;
|
||||
}
|
||||
}
|
||||
|
||||
auto SingleDependencyFilter = std::views::filter([](const auto &Pair) {
|
||||
return Pair.second == 1;
|
||||
});
|
||||
TypesToInlineCache = DependentTypeCount | SingleDependencyFilter
|
||||
| std::views::keys
|
||||
| revng::to<std::set<model::TypeDefinition::Key>>();
|
||||
|
||||
if (InlineTypeLog.isEnabled()) {
|
||||
revng_log(InlineTypeLog, "Final list of types that can be inlined: {");
|
||||
{
|
||||
LoggerIndent Indent{ InlineTypeLog };
|
||||
for (const model::TypeDefinition::Key &T : TypesToInlineCache)
|
||||
revng_log(InlineTypeLog, ::toString(T));
|
||||
}
|
||||
revng_log(InlineTypeLog, "}");
|
||||
}
|
||||
}
|
||||
|
||||
if (Configuration.EnableStackFrameInlining && InlineTypeLog.isEnabled()) {
|
||||
revng_log(InlineTypeLog, "Which also includes stack frames: {");
|
||||
{
|
||||
LoggerIndent Indent{ InlineTypeLog };
|
||||
for (const model::TypeDefinition::Key &T : StackFrameTypeCache)
|
||||
if (TypesToInlineCache.contains(T))
|
||||
revng_log(InlineTypeLog, ::toString(T));
|
||||
}
|
||||
revng_log(InlineTypeLog, "}");
|
||||
}
|
||||
|
||||
InlinableCacheIsReady = true;
|
||||
}
|
||||
|
||||
static Logger<> TypePrinterLog{ "type-definition-printer" };
|
||||
|
||||
void ptml::CTypeBuilder::printTypeDefinitions() {
|
||||
@@ -415,7 +321,7 @@ void ptml::CTypeBuilder::printTypeDefinitions() {
|
||||
revng_log(TypePrinterLog, "Definition");
|
||||
|
||||
revng_assert(Defined.contains(DependencyCache->getDeclaration(NodeT)));
|
||||
if (isDeclarationTheSameAsDefinition(*NodeT) or shouldInline(*NodeT)) {
|
||||
if (isDeclarationTheSameAsDefinition(*NodeT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,8 +90,11 @@ struct EmitCPass : clift::impl::CliftEmitCBase<EmitCPass> {
|
||||
return;
|
||||
|
||||
llvm::raw_null_ostream NullStream;
|
||||
ptml::CTypeBuilder B(NullStream, *Model, /* EnableTaglessMode = */ Tagless);
|
||||
B.collectInlinableTypes();
|
||||
ptml::CTypeBuilder B(NullStream,
|
||||
*Model,
|
||||
Tagless,
|
||||
ptml::CTypeBuilder::ConfigurationOptions{
|
||||
.EnableStackFrameInlining = true });
|
||||
|
||||
getOperation()->walk([&](clift::FunctionOp Function) {
|
||||
if (not Function.isExternal())
|
||||
|
||||
@@ -1308,7 +1308,7 @@ public:
|
||||
if (const model::Type *T = ModelFunction.StackFrameType().get()) {
|
||||
const auto *D = llvm::cast<model::DefinedType>(T)->Definition().get();
|
||||
|
||||
if (C.shouldInline(D->key()))
|
||||
if (C.Configuration.EnableStackFrameInlining)
|
||||
C.printDefinition(*D);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,12 +12,6 @@ sources:
|
||||
- primitive-types.h.model.yml
|
||||
- union.h.model.yml
|
||||
- pointer-to-struct.h.model.yml
|
||||
- inline-struct.h.model.yml
|
||||
- do-not-inline-types-pointing-to-itself.h.model.yml
|
||||
- do-not-generate-struct-for-stack-type.h.model.yml
|
||||
- do-not-inline-used-stack-type.h.model.yml
|
||||
- inline-enum.h.model.yml
|
||||
- inline-union.h.model.yml
|
||||
- annotate-attibutes.model.yml
|
||||
commands:
|
||||
- type: revng.model-to-header-unit-test
|
||||
@@ -26,7 +20,7 @@ commands:
|
||||
filter: model-to-header
|
||||
suffix: .h
|
||||
command: |-
|
||||
revng artifact --enable-type-inlining emit-model-header /dev/null --model "$INPUT"
|
||||
revng artifact emit-model-header /dev/null --model "$INPUT"
|
||||
| revng ptml > "$OUTPUT";
|
||||
revng check-decompiled-c "$OUTPUT";
|
||||
FileCheck --input-file="$OUTPUT" "${SOURCE}.filecheck";
|
||||
|
||||
-45
@@ -1,45 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
Functions:
|
||||
- Entry: "0x401129:Code_x86_64"
|
||||
Name: fn
|
||||
StackFrameType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3001-StructDefinition"
|
||||
Prototype:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-CABIFunctionDefinition"
|
||||
ExportedNames:
|
||||
- fn
|
||||
TypeDefinitions:
|
||||
- Kind: CABIFunctionDefinition
|
||||
ID: 3002
|
||||
ABI: SystemV_x86_64
|
||||
ReturnType:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 8
|
||||
Arguments: []
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 8
|
||||
Size: 16
|
||||
|
||||
Segments:
|
||||
- StartAddress: "0x400000:Generic64"
|
||||
VirtualSize: 40960
|
||||
StartOffset: 0
|
||||
FileSize: 40960
|
||||
IsReadable: true
|
||||
IsWriteable: false
|
||||
IsExecutable: true
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
# The definition will be generated inline in the decompiled functions.
|
||||
CHECK: typedef struct _PACKED struct_3001 struct_3001;
|
||||
CHECK-NOT: struct_3001
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Name: B
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: next
|
||||
Type:
|
||||
Kind: PointerType
|
||||
PointerSize: 8
|
||||
PointeeType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3001-StructDefinition"
|
||||
Size: 8
|
||||
---
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef struct _PACKED B B;
|
||||
CHECK: struct _PACKED B {
|
||||
CHECK: B *next;
|
||||
CHECK: };
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
Functions:
|
||||
- Entry: "0x401129:Code_x86_64"
|
||||
Name: fn
|
||||
StackFrameType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3001-StructDefinition"
|
||||
Prototype:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-CABIFunctionDefinition"
|
||||
ExportedNames:
|
||||
- fn
|
||||
TypeDefinitions:
|
||||
- Kind: CABIFunctionDefinition
|
||||
ID: 3002
|
||||
ABI: SystemV_x86_64
|
||||
ReturnType:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 8
|
||||
Arguments: []
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Generic
|
||||
Size: 8
|
||||
Size: 16
|
||||
- Kind: StructDefinition
|
||||
ID: 3003
|
||||
Name: S
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: s1
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3001-StructDefinition"
|
||||
Size: 16
|
||||
|
||||
Segments:
|
||||
- StartAddress: "0x400000:Generic64"
|
||||
VirtualSize: 40960
|
||||
StartOffset: 0
|
||||
FileSize: 40960
|
||||
IsReadable: true
|
||||
IsWriteable: false
|
||||
IsExecutable: true
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef struct _PACKED struct_3001 struct_3001;
|
||||
CHECK: struct _PACKED struct_3001 {
|
||||
CHECK: generic64_t offset_0;
|
||||
CHECK: uint8_t padding_at_8[8];
|
||||
CHECK: };
|
||||
CHECK: typedef struct _PACKED S S;
|
||||
CHECK: struct _PACKED S {
|
||||
CHECK: struct_3001 s1;
|
||||
CHECK: };
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Name: X
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: the_struct_y
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-StructDefinition"
|
||||
Size: 56
|
||||
- Kind: StructDefinition
|
||||
ID: 3002
|
||||
Name: Y
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: the_union_w
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3003-UnionDefinition"
|
||||
- Offset: 4
|
||||
Name: the_union_z
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3004-UnionDefinition"
|
||||
- Offset: 48
|
||||
Name: ptr_to_E
|
||||
Type:
|
||||
Kind: PointerType
|
||||
PointerSize: 8
|
||||
PointeeType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3007-EnumDefinition"
|
||||
Size: 56
|
||||
- Kind: UnionDefinition
|
||||
ID: 3003
|
||||
Name: W
|
||||
Fields:
|
||||
- Index: 0
|
||||
Name: field
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Signed
|
||||
Size: 4
|
||||
- Kind: UnionDefinition
|
||||
ID: 3004
|
||||
Name: Z
|
||||
Fields:
|
||||
- Index: 0
|
||||
Name: the_enum_e
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3005-EnumDefinition"
|
||||
- Index: 1
|
||||
Name: array_of_a
|
||||
Type:
|
||||
Kind: PointerType
|
||||
PointerSize: 8
|
||||
PointeeType:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3006-StructDefinition"
|
||||
- Kind: EnumDefinition
|
||||
ID: 3005
|
||||
Name: E
|
||||
UnderlyingType:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Unsigned
|
||||
Size: 4
|
||||
Entries:
|
||||
- Value: 2
|
||||
Name: VALUE
|
||||
- Value: 7
|
||||
Name: OTHER
|
||||
- Kind: StructDefinition
|
||||
ID: 3006
|
||||
Name: A
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: field
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Signed
|
||||
Size: 4
|
||||
Size: 4
|
||||
- Kind: EnumDefinition
|
||||
ID: 3007
|
||||
Name: E2
|
||||
UnderlyingType:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Unsigned
|
||||
Size: 4
|
||||
Entries:
|
||||
- Value: 1
|
||||
Name: FIRST
|
||||
- Value: 2
|
||||
Name: SECOND
|
||||
---
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef enum _PACKED E2 E2;
|
||||
CHECK: enum _PACKED E2 {
|
||||
CHECK: FIRST = 0x1U,
|
||||
CHECK: SECOND = 0x2U,
|
||||
CHECK: enum_max_value_E2 = 0xffffffffU,
|
||||
CHECK: };
|
||||
CHECK: typedef struct _PACKED X X;
|
||||
CHECK: typedef struct _PACKED Y Y;
|
||||
CHECK: typedef union _PACKED W W;
|
||||
CHECK: typedef union _PACKED Z Z;
|
||||
CHECK: typedef enum _PACKED E E;
|
||||
CHECK: typedef struct _PACKED A A;
|
||||
CHECK: struct _PACKED X {
|
||||
CHECK: struct _PACKED Y {
|
||||
CHECK: union _PACKED W {
|
||||
CHECK: int32_t field;
|
||||
CHECK: } the_union_w;
|
||||
CHECK: union _PACKED Z {
|
||||
CHECK: enum _PACKED E {
|
||||
CHECK: VALUE = 0x2U,
|
||||
CHECK: OTHER = 0x7U,
|
||||
CHECK: enum_max_value_E = 0xffffffffU,
|
||||
CHECK: } the_enum_e;
|
||||
CHECK: struct _PACKED A {
|
||||
CHECK: int32_t field;
|
||||
CHECK: } array_of_a[10];
|
||||
CHECK: } the_union_z;
|
||||
CHECK: uint8_t padding_at_44[4];
|
||||
CHECK: E2 *ptr_to_E;
|
||||
CHECK: } the_struct_y;
|
||||
CHECK: };
|
||||
@@ -1,32 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
- Kind: StructDefinition
|
||||
ID: 1
|
||||
Name: B
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: the_a
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-EnumDefinition"
|
||||
Size: 4
|
||||
- Kind: EnumDefinition
|
||||
ID: 3002
|
||||
Name: A
|
||||
UnderlyingType:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Unsigned
|
||||
Size: 4
|
||||
Entries:
|
||||
- Value: 0
|
||||
Name: FIRST
|
||||
- Value: 1
|
||||
Name: SECOND
|
||||
---
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef struct _PACKED B B;
|
||||
CHECK: typedef enum _PACKED A A;
|
||||
CHECK: struct _PACKED B {
|
||||
CHECK: enum _ENUM_UNDERLYING(uint32_t) _PACKED A {
|
||||
CHECK: FIRST = 0x0U,
|
||||
CHECK: SECOND = 0x1U,
|
||||
CHECK: enum_max_value_A = 0xffffffffU,
|
||||
CHECK: } the_a;
|
||||
CHECK: };
|
||||
@@ -1,31 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Name: B
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: a1
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-StructDefinition"
|
||||
Size: 4
|
||||
- Kind: StructDefinition
|
||||
ID: 3002
|
||||
Name: A
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: x
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Signed
|
||||
Size: 4
|
||||
Size: 4
|
||||
---
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef struct _PACKED B B;
|
||||
CHECK: typedef struct _PACKED A A;
|
||||
CHECK: struct _PACKED B {
|
||||
CHECK: struct _PACKED A {
|
||||
CHECK: int32_t x;
|
||||
CHECK: } a1;
|
||||
CHECK: };
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
Architecture: x86_64
|
||||
|
||||
TypeDefinitions:
|
||||
- Kind: StructDefinition
|
||||
ID: 3001
|
||||
Name: B
|
||||
Fields:
|
||||
- Offset: 0
|
||||
Name: a1
|
||||
Type:
|
||||
Kind: DefinedType
|
||||
Definition: "/TypeDefinitions/3002-UnionDefinition"
|
||||
Size: 4
|
||||
- Kind: UnionDefinition
|
||||
ID: 3002
|
||||
Name: A
|
||||
Fields:
|
||||
- Index: 0
|
||||
Name: x
|
||||
Type:
|
||||
Kind: PrimitiveType
|
||||
PrimitiveKind: Signed
|
||||
Size: 4
|
||||
---
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
#
|
||||
# This file is distributed under the MIT License. See LICENSE.md for details.
|
||||
#
|
||||
|
||||
CHECK: typedef struct _PACKED B B;
|
||||
CHECK: typedef union _PACKED A A;
|
||||
CHECK: struct _PACKED B {
|
||||
CHECK: union _PACKED A {
|
||||
CHECK: int32_t x;
|
||||
CHECK: } a1;
|
||||
CHECK: };
|
||||
Reference in New Issue
Block a user