Import sections into segment's struct

Each model::Segment is associated to a model::StructType. Now we also
create sub-`structs` for sections, if available.
This commit is contained in:
Alessandro Di Federico
2024-02-08 16:57:40 +01:00
committed by Pietro Fezzardi
parent 95aa074e4c
commit b34031f828
2 changed files with 90 additions and 41 deletions
@@ -6,6 +6,7 @@
#include "revng/Model/Binary.h"
#include "revng/Model/QualifiedType.h"
#include "revng/Model/Section.h"
#include "revng/Support/Assert.h"
#include "revng/Support/IRHelpers.h"
#include "revng/Support/MetaAddress.h"
@@ -21,55 +22,97 @@ struct DataSymbol {
bool operator==(const DataSymbol &) const = default;
};
using DataSymbolVecTy = llvm::SmallVectorImpl<DataSymbol>;
inline bool checkForOverlap(const model::StructType &Struct,
const model::StructField &Field) {
uint64_t Size = *Field.Type().size();
uint64_t Offset,
uint64_t Size) {
for (auto &Current : Struct.Fields()) {
uint64_t CurrentSize = *Current.Type().size();
if ((Current.Offset() < Field.Offset() + Size))
if (Current.Offset() + CurrentSize > Field.Offset())
if ((Current.Offset() < Offset + Size))
if (Current.Offset() + CurrentSize > Offset)
return true;
}
return false;
}
inline model::TypePath populateSegmentTypeStruct(model::Binary &Binary,
model::Segment &Segment,
DataSymbolVecTy &DataSymbols) {
model::TypePath StructPath = createEmptyStruct(Binary, Segment.VirtualSize());
auto *Struct = llvm::cast<model::StructType>(StructPath.get());
inline void importSymbolsInto(model::Binary &Binary,
llvm::SmallVector<DataSymbol, 32> &DataSymbols,
model::StructType *Struct,
MetaAddress StructStartAddress) {
MetaAddress StructEndAddress = StructStartAddress + Struct->Size();
if (not StructEndAddress.isValid())
return;
for (const auto &DataSymbol : DataSymbols) {
const auto &[Address, Size, Name] = DataSymbol;
for (auto It = DataSymbols.begin(); It != DataSymbols.end(); ++It) {
const auto &[SymbolStartAddress, SymbolSize, SymbolName] = *It;
MetaAddress SymbolEndAddress = SymbolStartAddress + SymbolSize;
if (Segment.contains(Address)) {
auto Offset = Address - Segment.StartAddress();
if (SymbolEndAddress.isValid()
and SymbolStartAddress.addressGreaterThanOrEqual(StructStartAddress)
and SymbolEndAddress.addressLowerThanOrEqual(StructEndAddress)) {
auto Offset = SymbolStartAddress - StructStartAddress;
revng_assert(Offset.has_value());
model::QualifiedType FieldType;
// Discard any symbols that would overlap an already existing one.
if (checkForOverlap(*Struct, *Offset, SymbolSize)) {
It = std::prev(DataSymbols.erase(It));
continue;
}
model::TypePath T;
if (Size == 1 || Size == 2 || Size == 4 || Size == 8) {
T = Binary.getPrimitiveType(model::PrimitiveTypeKind::Generic, Size);
FieldType = { T, {} };
if (SymbolSize == 1 || SymbolSize == 2 || SymbolSize == 4
|| SymbolSize == 8) {
T = Binary.getPrimitiveType(model::PrimitiveTypeKind::Generic,
SymbolSize);
} else {
// Replace non-standardly sized types with an array of bytes
T = Binary.getPrimitiveType(model::PrimitiveTypeKind::Generic, 1);
FieldType = { T, { { model::QualifierKind::Array, Size } } };
// If the symbol has a non-standard size, make it an empty struct with
// the same size instead.
T = createEmptyStruct(Binary, SymbolSize);
}
model::StructField Field{ *Offset, {}, Name.str(), {}, FieldType };
if (!checkForOverlap(*Struct, Field)) {
// Discard any symbols that would overlap an already existing one.
const auto &[_, Success] = Struct->Fields().insert(Field);
revng_assert(Success);
}
model::QualifiedType FieldType = { T, {} };
model::StructField Field{ *Offset, {}, SymbolName.str(), {}, FieldType };
const auto &[_, Success] = Struct->Fields().insert(Field);
revng_assert(Success);
}
}
}
revng_assert(Struct->verify());
return StructPath;
inline model::TypePath
populateSegmentTypeStruct(model::Binary &Binary,
model::Segment &Segment,
llvm::SmallVector<DataSymbol, 32> DataSymbols) {
using namespace llvm;
using namespace model;
// Create a struct for the segment
TypePath SegmentStructPath = createEmptyStruct(Binary, Segment.VirtualSize());
auto *SegmentStruct = cast<model::StructType>(SegmentStructPath.get());
for (model::Section &Section : Segment.Sections()) {
auto Offset = Section.StartAddress() - Segment.StartAddress();
revng_assert(Offset.has_value());
// Create a struct for each section
TypePath SectionStructPath = createEmptyStruct(Binary, Section.Size());
auto *SectionStruct = cast<model::StructType>(SectionStructPath.get());
// Import (and consume) symbols that fall within such section
importSymbolsInto(Binary,
DataSymbols,
SectionStruct,
Section.StartAddress());
// Insert the field the segment struct
StructField SectionField{
*Offset, {}, Section.Name(), {}, { SectionStructPath, {} }
};
SegmentStruct->Fields().insert(SectionField);
}
// Pour the remaining symbols into the segment struct
importSymbolsInto(Binary, DataSymbols, SegmentStruct, Segment.StartAddress());
revng_assert(SegmentStruct->verify());
return SegmentStructPath;
}
@@ -4,12 +4,8 @@
---
Segments:
- Type: "/Types/12084688553483582712-StructType"
- Type: "/Types/1815-StructType"
Types:
- Kind: PrimitiveType
ID: 513
PrimitiveKind: Generic
Size: 1
- Kind: PrimitiveType
ID: 516
PrimitiveKind: Generic
@@ -19,16 +15,22 @@ Types:
PrimitiveKind: Generic
Size: 8
- Kind: StructType
ID: 12084688553483582712
ID: 1815
Size: 92
Fields:
- Offset: 0
CustomName: "unreserved__custom_data"
OriginalName: .custom_data
Type:
UnqualifiedType: "/Types/1816-StructType"
- Kind: StructType
ID: 1816
Size: 92
Fields:
- Offset: 0
OriginalName: char_80_global
Type:
UnqualifiedType: "/Types/513-PrimitiveType"
Qualifiers:
- Kind: Array
Size: 80
UnqualifiedType: "/Types/1817-StructType"
- Offset: 80
OriginalName: uint64_global
Type:
@@ -37,3 +39,7 @@ Types:
OriginalName: uint32_global
Type:
UnqualifiedType: "/Types/516-PrimitiveType"
- Kind: StructType
ID: 1817
Size: 80
Fields: []