#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Support/Debug.h" #include "revng/Support/MetaAddress.h" namespace llvm { class Type; } /// Class representing either a constant value or an offset from a symbol class MaterializedValue { public: class MemoryRange { public: MetaAddress Address; unsigned Size = 0; }; private: bool IsValid = false; std::optional SymbolName; llvm::APInt Value; llvm::SmallVector AffectedBy; bool IsMutable = false; private: MaterializedValue(const llvm::APInt &Value, bool IsMutable) : IsValid(true), Value(Value), IsMutable(IsMutable) {} MaterializedValue(llvm::StringRef SymbolName, const llvm::APInt &Offset) : IsValid(true), SymbolName(SymbolName.str()), Value(Offset) {} public: MaterializedValue() = default; MaterializedValue(const MaterializedValue &) = default; MaterializedValue(MaterializedValue &&) = default; MaterializedValue &operator=(const MaterializedValue &) = default; MaterializedValue &operator=(MaterializedValue &&) = default; public: static MaterializedValue invalid() { return MaterializedValue(); } static MaterializedValue fromMutable(const llvm::APInt &API) { return MaterializedValue(API, true); } static MaterializedValue fromMutable(llvm::ConstantInt *CI); static MaterializedValue fromConstant(const llvm::APInt &API) { return MaterializedValue(API, false); } static MaterializedValue fromConstant(llvm::ConstantInt *CI); static MaterializedValue fromSymbol(llvm::StringRef SymbolName, const llvm::APInt &Offset) { return MaterializedValue(SymbolName, Offset); } static MaterializedValue apply(llvm::Instruction *Operation, llvm::ArrayRef Operands); public: template MaterializedValue load(T &MemoryOracle, unsigned Size) const { // Cannot load symbols or invalid values if (hasSymbol() or not IsValid) return MaterializedValue::invalid(); return MemoryOracle.load(Value.getLimitedValue(), Size); } MaterializedValue byteSwap() const { MaterializedValue Result = *this; Result.Value = Value.byteSwap(); return Result; } public: bool operator==(const MaterializedValue &Other) const { auto MaxBitWidth = std::max(Value.getBitWidth(), Other.Value.getBitWidth()); auto ZExtValue = Value.zext(MaxBitWidth); auto ZExtOther = Other.Value.zext(MaxBitWidth); auto This = std::tie(IsValid, SymbolName, ZExtValue, IsMutable); auto That = std::tie(Other.IsValid, Other.SymbolName, ZExtOther, Other.IsMutable); return This == That; } bool operator<(const MaterializedValue &Other) const { auto MaxBitWidth = std::max(Value.getBitWidth(), Other.Value.getBitWidth()); if (Value.zext(MaxBitWidth).ult(Other.Value.zext(MaxBitWidth))) return true; auto This = std::tie(IsValid, SymbolName, IsMutable); auto That = std::tie(Other.IsValid, Other.SymbolName, Other.IsMutable); return This < That; } const llvm::APInt &value() const { revng_assert(isValid()); return Value; } bool isMutable() const { return IsMutable; } bool isValid() const { return IsValid; } bool hasSymbol() const { return SymbolName.has_value(); } std::string symbolName() const { revng_assert(isValid()); revng_assert(hasSymbol()); revng_assert(not llvm::StringRef(*SymbolName).contains('\0')); return *SymbolName; } llvm::Constant *toConstant(llvm::LLVMContext &Context) const; llvm::Constant *toConstant(llvm::Type *DestinationType) const; void dump() const debug_function { dump(dbg); } template void dump(T &Output) const { if (not isValid()) { Output << "(invalid)"; } else { if (hasSymbol()) Output << symbolName().data() << "+"; llvm::SmallString<40> String; value().toStringUnsigned(String, 16); Output << "0x" << String.c_str(); if (Value.getBitWidth() == 128) { Output << " (" << MetaAddress::decomposeIntegerPC(Value).toString() << ")"; } } } }; using MaterializedValues = std::vector; template void dumpMaterializedValues(O &Output, llvm::StringRef Prefix, const MaterializedValues &Values) { for (const MaterializedValue &Value : Values) { Output << Prefix.str(); Value.dump(Output); } }