mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
236 lines
8.6 KiB
C++
236 lines
8.6 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "revng/ADT/Concepts.h"
|
|
#include "revng/ADT/MutableSet.h"
|
|
#include "revng/ADT/SortedVector.h"
|
|
#include "revng/ADT/UpcastablePointer.h"
|
|
#include "revng/ADT/UpcastablePointer/YAMLTraits.h"
|
|
#include "revng/Model/ABI.h"
|
|
#include "revng/Model/Architecture.h"
|
|
#include "revng/Model/Configuration.h"
|
|
#include "revng/Model/DefinedType.h"
|
|
#include "revng/Model/DynamicFunction.h"
|
|
#include "revng/Model/EnumDefinition.h"
|
|
#include "revng/Model/Function.h"
|
|
#include "revng/Model/FunctionAttribute.h"
|
|
#include "revng/Model/RawFunctionDefinition.h"
|
|
#include "revng/Model/Register.h"
|
|
#include "revng/Model/Segment.h"
|
|
#include "revng/Model/TypeDefinition.h"
|
|
#include "revng/Support/CommonOptions.h"
|
|
#include "revng/Support/MetaAddress.h"
|
|
#include "revng/Support/MetaAddress/MetaAddressRange.h"
|
|
#include "revng/Support/MetaAddress/YAMLTraits.h"
|
|
#include "revng/Support/YAMLTraits.h"
|
|
#include "revng/TupleTree/TupleTree.h"
|
|
#include "revng/TupleTree/TupleTreeDiff.h"
|
|
|
|
#include "revng/Model/Generated/Early/Binary.h"
|
|
|
|
namespace model {
|
|
class VerifyHelper;
|
|
}
|
|
|
|
// TODO: Prevent changing the keys. Currently we need them to be public and
|
|
// non-const for serialization purposes.
|
|
|
|
class model::Binary : public model::generated::Binary {
|
|
public:
|
|
using generated::Binary::Binary;
|
|
|
|
public:
|
|
/// Introduce a new type definition to the binary.
|
|
///
|
|
/// \note there are also helpers for each of the type definition kinds which
|
|
/// should be preferred when creating a definition of a known kind.
|
|
/// as in, prefer `makeStructDefinition` to `makeDefinition<StructDef>`.
|
|
///
|
|
/// \param Arguments A variadic argument list to pass to the type constructor.
|
|
///
|
|
/// \tparam NewType The type of the new definition to make.
|
|
///
|
|
/// \returns A pair of:
|
|
/// - the reference to the newly made definition which can be used
|
|
/// to modify it right away,
|
|
/// - the corresponding defined type ready to be attached to others.
|
|
template<std::derived_from<model::TypeDefinition> NewType,
|
|
typename... ArgumentTypes>
|
|
[[nodiscard]] std::pair<NewType &, model::UpcastableType>
|
|
makeTypeDefinition(ArgumentTypes &&...Arguments) {
|
|
using UTD = model::UpcastableTypeDefinition;
|
|
UTD New = UTD::make<NewType>(std::forward<ArgumentTypes>(Arguments)...);
|
|
auto &&[Reference, Result] = recordNewType(std::move(New));
|
|
return { llvm::cast<NewType>(Reference), std::move(Result) };
|
|
}
|
|
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeStructDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<StructDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeUnionDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<UnionDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeEnumDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<EnumDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeTypedefDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<TypedefDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeCABIFunctionDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<CABIFunctionDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
template<typename... Ts>
|
|
[[nodiscard]] auto makeRawFunctionDefinition(Ts &&...As) {
|
|
return makeTypeDefinition<RawFunctionDefinition>(std::forward<Ts>(As)...);
|
|
}
|
|
|
|
public:
|
|
/// Record the new type into the model and assign a new ID.
|
|
///
|
|
/// \returns A pair of:
|
|
/// - the reference to the newly inserted definition which can be
|
|
/// used to modify it right away,
|
|
/// - the corresponding defined type ready to be attached to others.
|
|
std::pair<TypeDefinition &, model::UpcastableType>
|
|
recordNewType(model::UpcastableTypeDefinition &&T);
|
|
|
|
/// Uses `SortedVector::batch_insert()` to emplace all the elements from
|
|
/// \ref NewTypes range into the `TypeDefinitions()` set.
|
|
///
|
|
/// This inserts all the elements at the end of the underlying vector, and
|
|
/// then triggers sorting, instead of conventional searching for the position
|
|
/// of each element on its insertion.
|
|
///
|
|
/// \note Unlike recordNewTypeDefinitions, this method does not assign type
|
|
/// IDs.
|
|
///
|
|
/// \note It takes advantage of `std::move_iterator` to ensure all
|
|
/// the elements are accessed strictly as r-values, so the original
|
|
/// container, \ref NewTypes range points to, is left in an unspecified
|
|
/// state after the invocation, as all of its elements are moved out of.
|
|
///
|
|
/// \note Since a strict version of `batch-insert`'er is used, if this causes
|
|
/// multiple elements to have the same \ref TypeDefinition::Key,
|
|
/// an assert will be fired.
|
|
///
|
|
/// \tparam Range constrained input range type.
|
|
/// \param NewTypes the input range.
|
|
template<RangeOf<UpcastablePointer<TypeDefinition>> Range>
|
|
void recordNewTypeDefinitions(Range &&NewTypes) {
|
|
auto Inserter = TypeDefinitions().batch_insert();
|
|
|
|
static_assert(std::is_rvalue_reference_v<decltype(NewTypes)>);
|
|
auto Movable = as_rvalue(std::move(NewTypes));
|
|
for (UpcastablePointer<TypeDefinition> &&NewType : Movable) {
|
|
static_assert(std::is_rvalue_reference_v<decltype(NewType)>);
|
|
Inserter.emplace(std::move(NewType));
|
|
}
|
|
}
|
|
|
|
public:
|
|
model::UpcastableType makeType(const model::TypeDefinition::Key &Key) {
|
|
return model::DefinedType::make(getTypeDefinitionReference(Key));
|
|
}
|
|
model::UpcastableType makeConstType(const model::TypeDefinition::Key &Key) {
|
|
return model::DefinedType::makeConst(getTypeDefinitionReference(Key));
|
|
}
|
|
model::UpcastableType makeType(const model::TypeDefinition::Key &Key) const {
|
|
return model::DefinedType::make(getTypeDefinitionReference(Key));
|
|
}
|
|
model::UpcastableType
|
|
makeConstType(const model::TypeDefinition::Key &Key) const {
|
|
return model::DefinedType::makeConst(getTypeDefinitionReference(Key));
|
|
}
|
|
|
|
/// Return the first available type ID
|
|
uint64_t getAvailableTypeID() const;
|
|
|
|
public:
|
|
/// The helper for the prototype unwrapping.
|
|
/// Use this when you need to access/modify the existing prototype,
|
|
/// and \ref DefaultPrototype() when you need to assign a new one.
|
|
model::TypeDefinition *defaultPrototype() {
|
|
// TODO: after `abi::Definition` is merged back into the model,
|
|
// the prototype will always be present, so this should return
|
|
// a reference instead.
|
|
if (DefaultPrototype().isEmpty())
|
|
return nullptr;
|
|
else
|
|
return &DefaultPrototype()->toPrototype();
|
|
}
|
|
|
|
/// The helper for the prototype unwrapping.
|
|
/// Use this when you need to access/modify the existing prototype,
|
|
/// and \ref DefaultPrototype() when you need to assign a new one.
|
|
const model::TypeDefinition *defaultPrototype() const {
|
|
// TODO: after `abi::Definition` is merged back into the model,
|
|
// the prototype will always be present, so this should return
|
|
// a reference instead.
|
|
if (DefaultPrototype().isEmpty())
|
|
return nullptr;
|
|
else
|
|
return &DefaultPrototype()->toPrototype();
|
|
}
|
|
|
|
model::TypeDefinition *prototypeOrDefault(model::TypeDefinition *Prototype) {
|
|
if (Prototype)
|
|
return Prototype;
|
|
|
|
return defaultPrototype();
|
|
}
|
|
|
|
const model::TypeDefinition *
|
|
prototypeOrDefault(const model::TypeDefinition *Prototype) const {
|
|
if (Prototype)
|
|
return Prototype;
|
|
|
|
return defaultPrototype();
|
|
}
|
|
|
|
/// Returns a valid ABI describing the target used for the emission of C.
|
|
model::ABI::Values targetABI() const;
|
|
|
|
public:
|
|
/// \note Only use this when absolutely necessary, for example, when doing
|
|
/// bulk reference replacement.
|
|
/// In the general case prefer \ref makeType instead.
|
|
model::TypeDefinitionReference
|
|
getTypeDefinitionReference(const model::TypeDefinition::Key &Key);
|
|
|
|
model::TypeDefinitionReference
|
|
getTypeDefinitionReference(const model::TypeDefinition::Key &Key) const;
|
|
|
|
model::BinaryIdentifierReference
|
|
getBinaryIdentifierReference(const model::BinaryIdentifier::Key &Key);
|
|
|
|
model::BinaryIdentifierReference
|
|
getBinaryIdentifierReference(const model::BinaryIdentifier::Key &Key) const;
|
|
|
|
public:
|
|
bool verify(VerifyHelper &VH) const;
|
|
bool verify(bool Assert) const debug_function;
|
|
bool verify() const debug_function;
|
|
|
|
bool verifyTypeDefinitions(VerifyHelper &VH) const;
|
|
bool verifyTypeDefinitions(bool Assert) const debug_function;
|
|
bool verifyTypeDefinitions() const debug_function;
|
|
|
|
public:
|
|
void dumpTypeGraph(const char *Path) const debug_function;
|
|
|
|
public:
|
|
MetaAddressRangeSet executableRanges() const;
|
|
};
|
|
|
|
#include "revng/Model/Generated/Late/Binary.h"
|