#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include "boost/icl/interval_map.hpp" #include "llvm/ADT/Optional.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFTypes.h" #include "revng/Support/revng.h" namespace llvm { namespace object { class ObjectFile; class MachOBindEntry; } // namespace object } // namespace llvm /// \brief Simple data structure to describe an ELF segment // TODO: information hiding struct SegmentInfo { llvm::GlobalVariable *Variable; ///< \brief LLVM variable containing this /// segment's data MetaAddress StartVirtualAddress; MetaAddress EndVirtualAddress; uint64_t StartFileOffset; uint64_t EndFileOffset; bool IsWriteable; bool IsExecutable; bool IsReadable; std::vector> ExecutableSections; llvm::ArrayRef Data; SegmentInfo() : Variable(nullptr), StartVirtualAddress(MetaAddress::invalid()), EndVirtualAddress(MetaAddress::invalid()), StartFileOffset(0), EndFileOffset(0), IsWriteable(false), IsExecutable(false), IsReadable(false) {} /// Produce a name for this segment suitable for human understanding std::string generateName() const; bool contains(MetaAddress Address) const { return (StartVirtualAddress.addressLowerThanOrEqual(Address) and Address.addressLowerThan(EndVirtualAddress)); } bool contains(MetaAddress Start, uint64_t Size) const { return contains(Start) and contains(Start + Size - 1); } uint64_t size() const { return EndVirtualAddress - StartVirtualAddress; } template void insertExecutableRanges(std::back_insert_iterator Inserter) const { if (!IsExecutable) return; if (ExecutableSections.size() > 0) { std::copy(ExecutableSections.begin(), ExecutableSections.end(), Inserter); } else { Inserter = std::make_pair(StartVirtualAddress, EndVirtualAddress); } } std::pair pagesRange() const { MetaAddress Start = StartVirtualAddress; Start = Start - (Start.address() % 4096); MetaAddress End = EndVirtualAddress; End = End + (((End.address() + (4096 - 1)) / 4096) * 4096 - End.address()); return { Start, End }; } bool containsInPages(MetaAddress Address) const { auto Pair = pagesRange(); return (Pair.first.addressLowerThanOrEqual(Address) and Address.addressLowerThan(Pair.second)); } }; namespace LabelType { enum Values { Invalid, AbsoluteValue, BaseRelativeValue, SymbolRelativeValue, Symbol }; inline const char *getName(Values V) { switch (V) { case Invalid: return "Invalid"; case AbsoluteValue: return "AbsoluteValue"; case BaseRelativeValue: return "BaseRelativeValue"; case SymbolRelativeValue: return "SymbolRelativeValue"; case Symbol: return "Symbol"; } revng_abort(); } } // namespace LabelType namespace SymbolType { enum Values { Unknown, Code, Data, Section, File }; inline const char *getName(Values V) { switch (V) { case Unknown: return "Unknown"; case Code: return "Code"; case Data: return "Data"; case Section: return "Section"; case File: return "File"; } revng_abort(); } inline SymbolType::Values fromELF(unsigned char ELFSymbolType) { switch (ELFSymbolType) { case llvm::ELF::STT_FUNC: return SymbolType::Code; case llvm::ELF::STT_OBJECT: return SymbolType::Data; case llvm::ELF::STT_SECTION: return SymbolType::Section; case llvm::ELF::STT_FILE: return SymbolType::File; default: return SymbolType::Unknown; } } } // namespace SymbolType namespace LabelOrigin { enum Values { Unknown, StaticSymbol, DynamicSymbol, DynamicRelocation }; inline const char *getName(Values V) { switch (V) { case Unknown: return "Unknown"; case StaticSymbol: return "StaticSymbol"; case DynamicSymbol: return "DynamicSymbol"; case DynamicRelocation: return "DynamicRelocation"; } revng_abort(); } } // namespace LabelOrigin class Label { private: LabelType::Values Type; MetaAddress Address; uint64_t Size; /// Name of the symbol, if any llvm::StringRef SymbolName; SymbolType::Values SymbolType; /// Label value. It has different meanings depending on the label type uint64_t Value; LabelOrigin::Values Origin; bool SizeIsVirtual; private: Label(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size) : Type(LabelType::Invalid), Address(Address), Size(Size), SymbolName(), SymbolType(SymbolType::Unknown), Value(0), Origin(Origin), SizeIsVirtual(false) {} public: static Label createInvalid() { return Label(LabelOrigin::Unknown, MetaAddress::invalid(), 0); } static Label createAbsoluteValue(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size, uint64_t Value) { Label Result(Origin, Address, Size); Result.Type = LabelType::AbsoluteValue; Result.Value = Value; return Result; } static Label createBaseRelativeValue(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size, uint64_t Value) { Label Result(Origin, Address, Size); Result.Type = LabelType::BaseRelativeValue; Result.Value = Value; return Result; } static Label createSymbolRelativeValue(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size, llvm::StringRef SymbolName, SymbolType::Values SymbolType, uint64_t Offset) { Label Result(Origin, Address, Size); Result.Type = LabelType::SymbolRelativeValue; Result.SymbolName = SymbolName; Result.SymbolType = SymbolType; Result.Value = Offset; return Result; } static Label createSymbol(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size, llvm::StringRef SymbolName, SymbolType::Values SymbolType) { Label Result(Origin, Address, Size); Result.Type = LabelType::Symbol; Result.SymbolName = SymbolName; Result.SymbolType = SymbolType; return Result; } public: LabelType::Values type() const { return Type; } bool isInvalid() const { return Type == LabelType::Invalid; } bool isAbsoluteValue() const { return Type == LabelType::AbsoluteValue; } bool isBaseRelativeValue() const { return Type == LabelType::BaseRelativeValue; } bool isSymbolRelativeValue() const { return Type == LabelType::SymbolRelativeValue; } bool isSymbol() const { return Type == LabelType::Symbol; } bool isCode() const { return SymbolType == SymbolType::Code; } bool hasValue() const { return isAbsoluteValue() or isBaseRelativeValue(); } LabelOrigin::Values origin() const { return Origin; } MetaAddress address() const { return Address; } uint64_t size() const { return Size; } uint64_t value() const { revng_assert(hasValue()); return Value; } llvm::StringRef symbolName() const { revng_assert(isSymbolRelativeValue() or isSymbol()); return SymbolName; } uint64_t offset() const { revng_assert(isSymbolRelativeValue()); return Value; } void setVirtualSize(uint64_t VirtualSize) { SizeIsVirtual = true; Size = VirtualSize; } bool isSizeVirtual() const { return SizeIsVirtual; } bool matches(MetaAddress OtherAddress, uint64_t OtherSize) const { return Address == OtherAddress and Size == OtherSize; } bool contains(MetaAddress OtherAddress, uint64_t OtherSize) const { auto ThisBegin = Address.toGeneric(); auto OtherBegin = OtherAddress.toGeneric(); auto ThisEnd = ThisBegin + Size; auto OtherEnd = OtherBegin + OtherSize; return (ThisBegin.addressLowerThanOrEqual(OtherBegin) and OtherEnd.addressLowerThan(ThisEnd)); } void dump() const debug_function { dump(dbg); dbg << "\n"; } template void dump(T &Output) const { Output << LabelType::getName(Type) << " @ ("; Address.dump(Output); Output << "," << Size << ") "; if (isSymbolRelativeValue() or isSymbol()) Output << SymbolName.data(); else if (isBaseRelativeValue()) Output << "IMAGE_BASE"; if (isSymbolRelativeValue() or isBaseRelativeValue()) Output << "+"; if (isSymbolRelativeValue() or isAbsoluteValue() or isBaseRelativeValue()) Output << "0x" << std::hex << Value; if (isSymbolRelativeValue() or isSymbol()) { Output << " [" << SymbolType::getName(SymbolType) << "]"; } Output << " [from " << LabelOrigin::getName(Origin) << "]"; } }; // // What follows is a set of functions we use to read an integer of a specified // (or pointer) size using the appropriate endianess associated to an ELF type. // template struct Endianess { /// \brief Reads an integer of type T, using the endianess of the ELF type EE static uint64_t read(const uint8_t *Buf); }; template struct Endianess { static uint64_t read(const uint8_t *Buf) { using namespace llvm::support; return llvm::support::endian::read(Buf); } }; template struct Endianess { static uint64_t read(const uint8_t *Buf) { using namespace llvm::support; return llvm::support::endian::read(Buf); } }; template struct Endianess { static uint64_t read(const uint8_t *Buf) { using namespace llvm::support; return llvm::support::endian::read(Buf); } }; template struct Endianess { static uint64_t read(const uint8_t *Buf) { using namespace llvm::support; return llvm::support::endian::read(Buf); } }; /// \brief Read a pointer-sized integer according to the given ELF type EE template inline uint64_t readPointer(const uint8_t *Buf); template<> inline uint64_t readPointer(const uint8_t *Buf) { return Endianess::read(Buf); } template<> inline uint64_t readPointer(const uint8_t *Buf) { return Endianess::read(Buf); } template<> inline uint64_t readPointer(const uint8_t *Buf) { return Endianess::read(Buf); } template<> inline uint64_t readPointer(const uint8_t *Buf) { return Endianess::read(Buf); } /// \brief A pair on steroids to wrap a value or a pointer to a value class Pointer { public: Pointer() : IsIndirect(false), Value(MetaAddress::invalid()) {} Pointer(bool IsIndirect, MetaAddress Value) : IsIndirect(IsIndirect), Value(Value) {} bool isIndirect() const { return IsIndirect; } MetaAddress value() const { return Value; } private: bool IsIndirect; MetaAddress Value; }; class FilePortion; using boost::icl::partial_absorber; template using interval_map = boost::icl::interval_map; /// \brief BinaryFile describes an input image file in a semi-architecture /// independent way class BinaryFile { public: using LabelList = llvm::SmallVector