mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
4c8215fc47
* Changes to the `LayoutTypeSystem` graph
Pointers are identified in the TypeSystem graph as leaf nodes which
have a new type of edge (PointerEdge) that connects them to another
node of the graph. The destination of the edge represents the layout of
the pointed type.
* Changes to the Front-end
Pointer edges, and their destination nodes, are created by the DLA
front-end (`DLACreateIntraProceduralTypes`) whenever an access node has
a size that is compatible with the size of a pointer in the current
Architecture.
Successors might then be added to the newly generated node, if any,
by looking up the llvm::Value it is attached to.
* Changes to the Middle-end
Most of the DLA passes should ignore Pointer Edges, so they are modified
accordingly. Most notably, nodes that represent pointed layouts should
never be merged/pruned-off.
* Changes to the Back-end
The `TypeDeclCreationAction` of the decompiler and the `DLAMakeLayouts`
step of the DLA back-end are modified to take into account the new
information about pointers.
⚠️ There is a known issue with this version of the decompiler,
namely the fact that type loops are not detected and can cause the
emitter to enter an infinite loop.
278 lines
8.2 KiB
C++
278 lines
8.2 KiB
C++
//
|
|
// Copyright (c) rev.ng Srls. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <bit>
|
|
|
|
#include "revng-c/DataLayoutAnalysis/DLALayouts.h"
|
|
|
|
namespace dla {
|
|
|
|
void Layout::deleteLayout(Layout *L) {
|
|
switch (getKind(L)) {
|
|
case LayoutKind::Struct:
|
|
delete static_cast<StructLayout *>(L);
|
|
break;
|
|
case LayoutKind::Union:
|
|
delete static_cast<UnionLayout *>(L);
|
|
break;
|
|
case LayoutKind::Array:
|
|
delete static_cast<ArrayLayout *>(L);
|
|
break;
|
|
case LayoutKind::Base:
|
|
delete static_cast<BaseLayout *>(L);
|
|
break;
|
|
case LayoutKind::Padding:
|
|
delete static_cast<PaddingLayout *>(L);
|
|
break;
|
|
default:
|
|
revng_unreachable("Unexpected LayoutKind");
|
|
}
|
|
}
|
|
|
|
std::strong_ordering Layout::structuralOrder(const Layout *A, const Layout *B) {
|
|
revng_assert(nullptr != A and nullptr != B);
|
|
|
|
if (auto Cmp = A->Kind <=> B->Kind; Cmp != 0)
|
|
return Cmp;
|
|
|
|
auto Kind = A->Kind;
|
|
|
|
switch (Kind) {
|
|
|
|
case LayoutKind::Struct: {
|
|
|
|
auto *StructA = llvm::cast<StructLayout>(A);
|
|
auto *StructB = llvm::cast<StructLayout>(B);
|
|
|
|
if (std::lexicographical_compare(StructA->fields().begin(),
|
|
StructA->fields().end(),
|
|
StructB->fields().begin(),
|
|
StructB->fields().end(),
|
|
Layout::structuralLess))
|
|
return std::strong_ordering::less;
|
|
|
|
if (std::lexicographical_compare(StructB->fields().begin(),
|
|
StructB->fields().end(),
|
|
StructA->fields().begin(),
|
|
StructA->fields().end(),
|
|
Layout::structuralLess))
|
|
return std::strong_ordering::greater;
|
|
|
|
return std::strong_ordering::equal;
|
|
|
|
} break;
|
|
|
|
case LayoutKind::Union: {
|
|
|
|
auto *UnionA = llvm::cast<UnionLayout>(A);
|
|
auto *UnionB = llvm::cast<UnionLayout>(B);
|
|
|
|
if (std::lexicographical_compare(UnionA->elements().begin(),
|
|
UnionA->elements().end(),
|
|
UnionB->elements().begin(),
|
|
UnionB->elements().end(),
|
|
Layout::structuralLess))
|
|
return std::strong_ordering::less;
|
|
|
|
if (std::lexicographical_compare(UnionB->elements().begin(),
|
|
UnionB->elements().end(),
|
|
UnionA->elements().begin(),
|
|
UnionA->elements().end(),
|
|
Layout::structuralLess))
|
|
return std::strong_ordering::greater;
|
|
|
|
return std::strong_ordering::equal;
|
|
|
|
} break;
|
|
|
|
case LayoutKind::Array: {
|
|
auto *ArrayA = llvm::cast<ArrayLayout>(A);
|
|
auto *ArrayB = llvm::cast<ArrayLayout>(B);
|
|
bool hasKnownLength = ArrayA->hasKnownLength();
|
|
auto Cmp = hasKnownLength <=> ArrayB->hasKnownLength();
|
|
if (Cmp != 0)
|
|
return Cmp;
|
|
|
|
if (hasKnownLength) {
|
|
Cmp = ArrayA->length() <=> ArrayB->length();
|
|
if (Cmp != 0)
|
|
return Cmp;
|
|
}
|
|
|
|
return structuralOrder(ArrayA->getElem(), ArrayB->getElem());
|
|
} break;
|
|
|
|
case LayoutKind::Padding: {
|
|
return A->size() <=> B->size();
|
|
} break;
|
|
|
|
case LayoutKind::Base: {
|
|
auto *BaseA = llvm::cast<BaseLayout>(A);
|
|
auto *BaseB = llvm::cast<BaseLayout>(B);
|
|
|
|
// Discriminate between pointer and non-pointer layouts
|
|
if (BaseA->PointeeLayout and not BaseB->PointeeLayout)
|
|
return std::strong_ordering::greater;
|
|
if (BaseB->PointeeLayout and not BaseA->PointeeLayout)
|
|
return std::strong_ordering::less;
|
|
if (BaseA->PointeeLayout and BaseB->PointeeLayout)
|
|
return BaseA->PointeeLayout <=> BaseB->PointeeLayout;
|
|
|
|
// Both are scalars
|
|
return A->size() <=> B->size();
|
|
} break;
|
|
|
|
default:
|
|
revng_unreachable("Unexpected LayoutKind");
|
|
}
|
|
|
|
return std::strong_ordering::equal;
|
|
}
|
|
|
|
void Layout::printText(llvm::raw_ostream &O, const Layout *L, unsigned Indent) {
|
|
llvm::SmallString<8> IndentStr;
|
|
IndentStr.assign(Indent, ' ');
|
|
revng_assert(L->size());
|
|
switch (getKind(L)) {
|
|
case LayoutKind::Padding: {
|
|
auto *Padding = llvm::cast<PaddingLayout>(L);
|
|
if (Padding->size() > 1) {
|
|
O << IndentStr << "uint8_t padding [" << Padding->size() << ']';
|
|
} else {
|
|
O << "uint8_t padding";
|
|
}
|
|
} break;
|
|
case LayoutKind::Struct: {
|
|
auto *Struct = llvm::cast<StructLayout>(L);
|
|
O << IndentStr << "struct {\n";
|
|
for (const Layout *F : Struct->fields()) {
|
|
printText(O, F, Indent + 2);
|
|
O << ";\n";
|
|
}
|
|
O << IndentStr << "}";
|
|
} break;
|
|
case LayoutKind::Union: {
|
|
auto *Union = llvm::cast<UnionLayout>(L);
|
|
revng_assert(Union->numElements() > 1);
|
|
O << IndentStr << "union {\n";
|
|
for (const Layout *E : Union->elements()) {
|
|
printText(O, E, Indent + 2);
|
|
O << ";\n";
|
|
}
|
|
O << IndentStr << "}";
|
|
} break;
|
|
case LayoutKind::Array: {
|
|
auto *Array = llvm::cast<ArrayLayout>(L);
|
|
printText(O, Array->getElem(), Indent);
|
|
O << '[';
|
|
if (Array->hasKnownLength())
|
|
O << Array->length();
|
|
else
|
|
O << ' ';
|
|
O << ']';
|
|
} break;
|
|
case LayoutKind::Base: {
|
|
auto *Base = llvm::cast<BaseLayout>(L);
|
|
|
|
if (Base->PointeeLayout == nullptr) {
|
|
auto Size = Base->size();
|
|
revng_assert(Size);
|
|
revng_assert(std::has_single_bit(Size));
|
|
revng_assert(Size <= 16);
|
|
O << IndentStr << "uint" << (8 * Size) << "_t";
|
|
} else {
|
|
O << IndentStr << "ptr_t";
|
|
}
|
|
|
|
} break;
|
|
default:
|
|
revng_unreachable("Unexpected LayoutKind");
|
|
}
|
|
}
|
|
|
|
void Layout::printGraphic(llvm::raw_ostream &O,
|
|
const Layout *L,
|
|
unsigned Indent) {
|
|
auto PendingUnionsWithOffsets = printGraphicElem(O, L, Indent);
|
|
if (not PendingUnionsWithOffsets.empty()) {
|
|
for (const auto &[L, Off] : PendingUnionsWithOffsets) {
|
|
auto *U = llvm::cast<UnionLayout>(L);
|
|
for (const Layout *Elem : U->elements()) {
|
|
O << '\n';
|
|
printGraphic(O, Elem, Indent + Off);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
llvm::SmallVector<std::pair<const Layout *, unsigned>, 8>
|
|
Layout::printGraphicElem(llvm::raw_ostream &O,
|
|
const Layout *L,
|
|
unsigned Indent,
|
|
unsigned Offset) {
|
|
O << std::string(Indent, ' ');
|
|
auto Size = L->size();
|
|
revng_assert(Size);
|
|
|
|
llvm::SmallVector<std::pair<const Layout *, unsigned>, 8> Res;
|
|
switch (getKind(L)) {
|
|
case LayoutKind::Padding: {
|
|
O << std::string(Size, '-');
|
|
} break;
|
|
case LayoutKind::Base: {
|
|
auto *Base = llvm::cast<BaseLayout>(L);
|
|
if (Base->PointeeLayout == nullptr) {
|
|
std::string N = std::to_string(Size);
|
|
revng_assert(N.size() == 1);
|
|
O << std::string(Size, N[0]);
|
|
} else {
|
|
O << std::string(Size, 'P');
|
|
}
|
|
} break;
|
|
case LayoutKind::Struct: {
|
|
auto *Struct = llvm::cast<StructLayout>(L);
|
|
Layout::layout_size_t TotSize = 0ULL;
|
|
for (const Layout *F : Struct->fields()) {
|
|
auto Tmp = printGraphicElem(O, F, 0, Offset + TotSize);
|
|
Res.reserve(Res.size() + Tmp.size());
|
|
Res.insert(Res.end(), Tmp.begin(), Tmp.end());
|
|
TotSize += F->size();
|
|
}
|
|
} break;
|
|
case LayoutKind::Union: {
|
|
auto *Union = llvm::cast<UnionLayout>(L);
|
|
revng_assert(Union->numElements() > 1);
|
|
O << std::string(Size, 'U');
|
|
Res.push_back(std::make_pair(L, Indent + Offset));
|
|
} break;
|
|
case LayoutKind::Array: {
|
|
auto *Array = llvm::cast<ArrayLayout>(L);
|
|
auto ElemSize = Array->getElem()->size();
|
|
revng_assert(ElemSize);
|
|
revng_assert(ElemSize <= Size);
|
|
if (Array->hasKnownLength()) {
|
|
auto Len = Array->length();
|
|
for (decltype(Len) I = 0; I < Len; ++I) {
|
|
auto Tmp = printGraphicElem(O,
|
|
Array->getElem(),
|
|
0,
|
|
Offset + (ElemSize * I));
|
|
Res.reserve(Res.size() + Tmp.size());
|
|
Res.insert(Res.end(), Tmp.begin(), Tmp.end());
|
|
}
|
|
} else {
|
|
auto Tmp = printGraphicElem(O, Array->getElem(), 0, Offset);
|
|
Res.reserve(Res.size() + Tmp.size());
|
|
Res.insert(Res.end(), Tmp.begin(), Tmp.end());
|
|
O << std::string(Size - ElemSize, '|');
|
|
}
|
|
} break;
|
|
default:
|
|
revng_unreachable("Unexpected LayoutKind");
|
|
}
|
|
return Res;
|
|
}
|
|
|
|
} // end namespace dla
|