mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Print opaque types in model header
Emit forward declarations and definitions of the opaque-array artificial structs from the C model header (and from the helpers header). Definitions are gated on a new DefineOpaqueTypes flag threaded through PTMLHeaderBuilder::printModelHeader so that the helpers header keeps emitting only the declarations.
This commit is contained in:
@@ -33,7 +33,7 @@ public:
|
||||
/// Generate a C header containing a serialization of the type system,
|
||||
/// i.e. function prototypes, structs, unions, typedefs, and anything that
|
||||
/// resides in the model.
|
||||
bool printModelHeader();
|
||||
bool printModelHeader(bool DefineOpaqueTypes = false);
|
||||
|
||||
/// Generate a C header containing the declaration of each non-isolated
|
||||
/// function in a given LLVM IR module, i.e. QEMU helpers and revng helpers,
|
||||
|
||||
@@ -873,6 +873,20 @@ public:
|
||||
/// on every type, as types can depend on each other.
|
||||
/// This method ensures they are printed in a valid order.
|
||||
void printTypeDefinitions();
|
||||
|
||||
/// Print all opaque type definitions required by the types in the model.
|
||||
void printModelOpaqueTypeDefinitions();
|
||||
|
||||
/// Print all opaque type definitions required by the types in the headers,
|
||||
/// that are not otherwise printed by printModelOpaqueTypeDefinitions.
|
||||
void
|
||||
printHelperOpaqueTypeDefinitions(const std::set<uint64_t> &HelperByteSizes);
|
||||
|
||||
private:
|
||||
std::set<uint64_t> getModelOpaqueByteSizes();
|
||||
|
||||
/// Print a single opaque type definitions with given ByteSize
|
||||
void printOpaqueTypeDefinition(uint64_t ByteSize);
|
||||
};
|
||||
|
||||
} // namespace ptml
|
||||
|
||||
@@ -80,7 +80,7 @@ void DecompileToDirectory::run(pipeline::ExecutionContext &EC,
|
||||
B.setOutputStream(Out);
|
||||
|
||||
ptml::HeaderBuilder HB = B;
|
||||
HB.printModelHeader();
|
||||
HB.printModelHeader(/*DefineOpaqueTypes*/ true);
|
||||
|
||||
Out.flush();
|
||||
|
||||
|
||||
@@ -95,6 +95,8 @@ bool ptml::HeaderBuilder::printHelpersHeader(const llvm::Module &M) {
|
||||
+ B.getIncludeQuote("primitive-types.h") + "\n";
|
||||
B.append(std::move(Includes));
|
||||
|
||||
std::set<uint64_t> OpaqueByteSizes;
|
||||
|
||||
for (const llvm::Function &F : M.functions()) {
|
||||
|
||||
// Skip non-helpers
|
||||
@@ -140,6 +142,10 @@ bool ptml::HeaderBuilder::printHelpersHeader(const llvm::Module &M) {
|
||||
const auto *RetTy = F.getReturnType();
|
||||
if (auto *RetStructTy = dyn_cast<llvm::StructType>(RetTy)) {
|
||||
printLLVMTypeDeclaration(RetStructTy, F, B);
|
||||
const auto &DataLayout = F.getParent()->getDataLayout();
|
||||
|
||||
OpaqueByteSizes
|
||||
.insert(DataLayout.getStructLayout(RetStructTy)->getSizeInBytes());
|
||||
B.append("\n");
|
||||
}
|
||||
|
||||
@@ -148,8 +154,22 @@ bool ptml::HeaderBuilder::printHelpersHeader(const llvm::Module &M) {
|
||||
}
|
||||
|
||||
printHelperPrototype(&F, B);
|
||||
|
||||
B.append("\n");
|
||||
}
|
||||
|
||||
// Always print the opaque type definitions here.
|
||||
// The helper header is only used if we have the function body, which will
|
||||
// need these definitions.
|
||||
B.appendLineComment("\\defgroup Opaque Types");
|
||||
B.appendLineComment("\\{");
|
||||
|
||||
auto OpaqueTypeScope = B.getScopeTag(ptml::tags::Div);
|
||||
|
||||
B.printHelperOpaqueTypeDefinitions(OpaqueByteSizes);
|
||||
|
||||
B.appendLineComment("\\}");
|
||||
B.append("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
static Logger Log{ "model-to-header" };
|
||||
|
||||
bool ptml::HeaderBuilder::printModelHeader() {
|
||||
bool ptml::HeaderBuilder::printModelHeader(bool DefineOpaqueTypes) {
|
||||
|
||||
auto Scope = B.getScopeTag(ptml::tags::Div);
|
||||
|
||||
@@ -128,13 +128,32 @@ bool ptml::HeaderBuilder::printModelHeader() {
|
||||
B.appendLineComment("\\defgroup Segments");
|
||||
B.appendLineComment("\\{");
|
||||
|
||||
for (const model::Segment &Segment : B.Binary.Segments())
|
||||
for (const model::Segment &Segment : B.Binary.Segments()) {
|
||||
if (Segment.Type().isEmpty())
|
||||
continue;
|
||||
auto &SegmentType = Segment.Type()->toStruct();
|
||||
if (B.Configuration.TypesToOmit.contains(SegmentType.key()))
|
||||
continue;
|
||||
|
||||
B.printSegmentType(Segment);
|
||||
}
|
||||
|
||||
B.append("\n");
|
||||
B.appendLineComment("\\}");
|
||||
B.append("\n");
|
||||
}
|
||||
|
||||
if (DefineOpaqueTypes) {
|
||||
B.appendLineComment("\\defgroup Opaque Types");
|
||||
B.appendLineComment("\\{");
|
||||
|
||||
auto Scope = B.getScopeTag(ptml::tags::Div);
|
||||
|
||||
B.printModelOpaqueTypeDefinitions();
|
||||
|
||||
B.appendLineComment("\\}");
|
||||
B.append("\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,7 @@ public:
|
||||
{ .EnableStackFrameInlining = options::EnableStackFrameInlining,
|
||||
.EnablePrintingOfTheMaximumEnumValue = true,
|
||||
.ExplicitTargetPointerSize = getExplicitPointerSize(Model) });
|
||||
ptml::HeaderBuilder(B).printModelHeader();
|
||||
|
||||
ptml::HeaderBuilder(B).printModelHeader(/*DefineOpaqueTypes*/ true);
|
||||
Header.flush();
|
||||
ErrorCode = Header.error();
|
||||
if (ErrorCode)
|
||||
@@ -95,7 +94,7 @@ void ModelToHeader::run() {
|
||||
{ .EnableStackFrameInlining = revng::options::EnableStackFrameInlining,
|
||||
.EnablePrintingOfTheMaximumEnumValue = true,
|
||||
.ExplicitTargetPointerSize = getExplicitPointerSize(Binary) });
|
||||
ptml::HeaderBuilder(B).printModelHeader();
|
||||
ptml::HeaderBuilder(B).printModelHeader(/*DefineOpaqueTypes*/ true);
|
||||
Out->flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -321,3 +321,100 @@ void ptml::ModelCBuilder::printTypeDefinitions() {
|
||||
revng_log(TypePrinterLog, "PostOrder DONE");
|
||||
}
|
||||
}
|
||||
|
||||
void ptml::ModelCBuilder::printOpaqueTypeDefinition(uint64_t ByteSize) {
|
||||
|
||||
// Print the typedef inline with the struct definition.
|
||||
std::string
|
||||
StructLine = getKeyword(ptml::CBuilder::Keyword::Typedef) + " "
|
||||
+ getKeyword(ptml::CBuilder::Keyword::Struct) + " "
|
||||
+ ptml::Attributes.getAttributeString<"_PACKED">() + " "
|
||||
+ getOpaqueTypeDeclarationTag</*IsDefinition*/ false>(ByteSize)
|
||||
+ " ";
|
||||
*Out << std::move(StructLine);
|
||||
{
|
||||
Scope Scope(*Out, ptml::c::scopes::StructBody);
|
||||
|
||||
std::string UInt8T = getPrimitiveTag(model::PrimitiveKind::Unsigned, 1);
|
||||
std::string
|
||||
ArrayName = getOpaqueTypeFieldTag</*IsDefinition*/ true>(ByteSize);
|
||||
*Out << UInt8T << " " << ArrayName << "[" << getNumber(ByteSize) << "];\n";
|
||||
}
|
||||
|
||||
*Out << " " << getOpaqueTypeDeclarationTag</*IsDefinition*/ true>(ByteSize)
|
||||
<< ";\n";
|
||||
}
|
||||
|
||||
std::set<uint64_t> ptml::ModelCBuilder::getModelOpaqueByteSizes() {
|
||||
|
||||
std::set<uint64_t> ByteSizes = { 1, 2, 4, 8, 10, 12, 16 };
|
||||
|
||||
for (const model::UpcastableTypeDefinition &Type : Binary.TypeDefinitions()) {
|
||||
uint64_t ByteSize = Type->size().value_or(0);
|
||||
if (ByteSize)
|
||||
ByteSizes.insert(ByteSize);
|
||||
|
||||
llvm::SmallVector<model::UpcastableType> Dependencies;
|
||||
|
||||
const model::TypeDefinition *Definition = Type->tryGetAsDefinition();
|
||||
if (not Definition)
|
||||
continue;
|
||||
|
||||
if (const auto *TD = llvm::dyn_cast<model::TypedefDefinition>(Definition))
|
||||
Dependencies.push_back(TD->UnderlyingType());
|
||||
|
||||
if (const auto *S = Definition->getStruct())
|
||||
for (const auto &Field : S->Fields())
|
||||
Dependencies.push_back(Field.Type());
|
||||
|
||||
if (const auto *U = Definition->getUnion())
|
||||
for (const auto &Field : U->Fields())
|
||||
Dependencies.push_back(Field.Type());
|
||||
|
||||
if (const auto *R = Definition->getRawFunction()) {
|
||||
for (const auto &A : R->Arguments())
|
||||
Dependencies.push_back(A.Type());
|
||||
|
||||
uint64_t ReturnTypeSize = 0;
|
||||
for (const auto &RV : R->ReturnValues()) {
|
||||
Dependencies.push_back(RV.Type());
|
||||
ReturnTypeSize += RV.Type()->size().value_or(0);
|
||||
}
|
||||
if (ReturnTypeSize)
|
||||
ByteSizes.insert(ReturnTypeSize);
|
||||
}
|
||||
|
||||
if (const auto *C = Definition->getCABIFunction()) {
|
||||
for (const auto &A : C->Arguments())
|
||||
Dependencies.push_back(A.Type());
|
||||
if (not C->ReturnType().isEmpty())
|
||||
Dependencies.push_back(C->ReturnType());
|
||||
}
|
||||
|
||||
for (const model::UpcastableType &D : Dependencies)
|
||||
if (uint64_t ByeSize = D->trySize().value_or(0))
|
||||
ByteSizes.insert(ByteSize);
|
||||
}
|
||||
|
||||
return ByteSizes;
|
||||
}
|
||||
|
||||
void ptml::ModelCBuilder::printModelOpaqueTypeDefinitions() {
|
||||
std::set<uint64_t> ByteSizes = getModelOpaqueByteSizes();
|
||||
for (uint64_t ByteSize : ByteSizes) {
|
||||
*Out << "\n";
|
||||
printOpaqueTypeDefinition(ByteSize);
|
||||
}
|
||||
}
|
||||
|
||||
using MCB = ptml::ModelCBuilder;
|
||||
using SizeSet = std::set<uint64_t>;
|
||||
void MCB::printHelperOpaqueTypeDefinitions(const SizeSet &HelperByteSizes) {
|
||||
std::set<uint64_t> ModelByteSizes = getModelOpaqueByteSizes();
|
||||
for (uint64_t ByteSize : HelperByteSizes) {
|
||||
if (not ModelByteSizes.contains(ByteSize)) {
|
||||
*Out << "\n";
|
||||
printOpaqueTypeDefinition(ByteSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user