diff --git a/include/revng/BasicAnalyses/GeneratedCodeBasicInfo.h b/include/revng/BasicAnalyses/GeneratedCodeBasicInfo.h index 001ede5b4..1df2d002b 100644 --- a/include/revng/BasicAnalyses/GeneratedCodeBasicInfo.h +++ b/include/revng/BasicAnalyses/GeneratedCodeBasicInfo.h @@ -153,7 +153,8 @@ public: AnyPC(nullptr), UnexpectedPC(nullptr), PCRegSize(0), - RootFunction(nullptr) {} + RootFunction(nullptr), + MetaAddressStruct(nullptr) {} void getAnalysisUsage(llvm::AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -283,7 +284,7 @@ public: /// \brief Return the basic block associated to \p PC /// /// Returns nullptr if the PC doesn't have a basic block (yet) - llvm::BasicBlock *getBlockAt(uint64_t PC) const { + llvm::BasicBlock *getBlockAt(MetaAddress PC) const { auto It = JumpTargets.find(PC); if (It == JumpTargets.end()) return nullptr; @@ -329,7 +330,7 @@ public: /// \brief Return the program counter of the next (i.e., fallthrough) /// instruction of \p TheInstruction - uint64_t getNextPC(llvm::Instruction *TheInstruction) const { + MetaAddress getNextPC(llvm::Instruction *TheInstruction) const { auto Pair = getPC(TheInstruction); return Pair.first + Pair.second; } @@ -393,6 +394,15 @@ public: return ABIRegisters; } + llvm::Constant *toConstant(const MetaAddress &Address) { + revng_assert(MetaAddressStruct != nullptr); + return Address.toConstant(MetaAddressStruct); + } + + MetaAddress fromPC(uint64_t PC) const { + return MetaAddress::fromPC(ArchType, PC); + } + private: static std::vector extractCSVs(llvm::Instruction *Call, const char *MetadataKind) { @@ -424,11 +434,13 @@ private: llvm::BasicBlock *DispatcherFail; llvm::BasicBlock *AnyPC; llvm::BasicBlock *UnexpectedPC; - std::map JumpTargets; + std::map JumpTargets; unsigned PCRegSize; llvm::Function *RootFunction; std::vector CSVs; std::vector ABIRegisters; + llvm::StructType *MetaAddressStruct; + llvm::Function *NewPC; }; template<> diff --git a/include/revng/FunctionCallIdentification/FunctionCallIdentification.h b/include/revng/FunctionCallIdentification/FunctionCallIdentification.h index d8725e344..b40fa88b2 100644 --- a/include/revng/FunctionCallIdentification/FunctionCallIdentification.h +++ b/include/revng/FunctionCallIdentification/FunctionCallIdentification.h @@ -105,7 +105,7 @@ public: revng_abort(); } - bool isFallthrough(uint64_t Address) const { + bool isFallthrough(MetaAddress Address) const { return FallthroughAddresses.count(Address) != 0; } @@ -125,7 +125,7 @@ private: private: llvm::Function *FunctionCall; - std::set FallthroughAddresses; + std::set FallthroughAddresses; CustomCFG FilteredCFG; }; diff --git a/include/revng/Support/IRHelpers.h b/include/revng/Support/IRHelpers.h index 519218fd7..c8d5b2293 100644 --- a/include/revng/Support/IRHelpers.h +++ b/include/revng/Support/IRHelpers.h @@ -26,6 +26,7 @@ // Local libraries includes #include "revng/Support/Debug.h" +#include "revng/Support/MetaAddress.h" template inline bool contains(T Range, typename T::value_type V) { @@ -715,16 +716,15 @@ inline llvm::CallInst *getCallTo(llvm::Instruction *I, llvm::StringRef Name) { return nullptr; } -// TODO: this function assumes 0 is not a valid PC -inline uint64_t getBasicBlockPC(llvm::BasicBlock *BB) { +inline MetaAddress getBasicBlockPC(llvm::BasicBlock *BB) { using namespace llvm; auto It = BB->begin(); revng_assert(It != BB->end()); if (llvm::CallInst *Call = getCallTo(&*It, "newpc")) - return getLimitedValue(Call->getOperand(0)); + return MetaAddress::fromConstant(Call->getOperand(0)); - return 0; + return MetaAddress::invalid(); } template @@ -843,6 +843,6 @@ inline llvm::User *getUniqueUser(llvm::Value *V) { /// /// \return a pair of integers: the first element represents the PC and the /// second the size of the instruction. -std::pair getPC(llvm::Instruction *TheInstruction); +std::pair getPC(llvm::Instruction *TheInstruction); #endif // IRHELPERS_H diff --git a/include/revng/Support/MetaAddress.h b/include/revng/Support/MetaAddress.h new file mode 100644 index 000000000..194c6cf92 --- /dev/null +++ b/include/revng/Support/MetaAddress.h @@ -0,0 +1,358 @@ +#ifndef METAADDRESS_H +#define METAADDRESS_H + +// +// This file is distributed under the MIT License. See LICENSE.md for details. +// + +// LLVM includes +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/Casting.h" + +// Local libraries includes +#include "revng/Support/Debug.h" + +namespace MetaAddressType { + +enum Values : uint16_t { Invalid, Regular, ARMThumb }; + +inline const char *toString(Values V) { + switch (V) { + case Invalid: + return "Invalid"; + case Regular: + return "Regular"; + case ARMThumb: + return "ARMThumb"; + } + + revng_abort(); +} + +} // namespace MetaAddressType + +class MetaAddress { +private: + uint64_t Address; + uint32_t Epoch; + uint16_t AddressSpace; + MetaAddressType::Values Type; + +public: + explicit MetaAddress() { setInvalid(); } + +private: + explicit MetaAddress(uint64_t Address, + MetaAddressType::Values Type, + uint32_t Epoch, + uint16_t AddressSpace) : + Address(Address), Epoch(Epoch), AddressSpace(AddressSpace), Type(Type) { + revng_assert(verify()); + } + +public: + static MetaAddress invalid() { return MetaAddress(); } + +public: + static MetaAddress fromPC(llvm::Triple::ArchType Arch, + uint64_t PC, + uint32_t Epoch = 0, + uint16_t AddressSpace = 0) { + MetaAddress Result(0, MetaAddressType::Regular, Epoch, AddressSpace); + + unsigned Alignment = 1; + + switch (Arch) { + case llvm::Triple::arm: + if ((PC & 1) == 1) { + Result.Type = MetaAddressType::ARMThumb; + // No need to check alignment, since we already know it's an odd number + // and that's enough + } else { + Alignment = 4; + } + break; + + case llvm::Triple::aarch64: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + Alignment = 4; + break; + + case llvm::Triple::systemz: + Alignment = 2; + break; + + default: + break; + } + + if (PC % Alignment != 0) { + return MetaAddress::invalid(); + } else { + return Result.replacePC(PC); + } + } + + static MetaAddress fromAbsolute(uint64_t Address, + uint32_t Epoch = 0, + uint16_t AddressSpace = 0) { + return MetaAddress(Address, MetaAddressType::Regular, Epoch, AddressSpace); + } + + static MetaAddress fromConstant(llvm::Value *V) { + using namespace llvm; + using namespace MetaAddressType; + + auto *Struct = cast(V); + revng_assert(Struct->getNumOperands() == 4); + + auto CI = [](Value *V) { return cast(V)->getLimitedValue(); }; + + MetaAddress Result; + Result.Address = CI(Struct->getOperand(0)); + Result.Epoch = CI(Struct->getOperand(1)); + Result.AddressSpace = CI(Struct->getOperand(2)); + Result.Type = static_cast(CI(Struct->getOperand(3))); + + return Result; + } + +public: + static llvm::StructType *getStruct(llvm::Module *M) { + using namespace llvm; + auto *InvalidAddress = M->getGlobalVariable("invalid_address", true); + return cast(InvalidAddress->getType()->getPointerElementType()); + } + + static llvm::GlobalVariable *createStructVariable(llvm::Module *M) { + using namespace llvm; + auto *MetaAddressStruct = createStruct(M->getContext()); + return new GlobalVariable(*M, + MetaAddressStruct, + false, + GlobalValue::InternalLinkage, + invalid().toConstant(MetaAddressStruct), + StringRef("invalid_address")); + } + + llvm::Constant *toConstant(llvm::Type *Type) const { + using namespace llvm; + + auto *Struct = cast(Type); + + auto GetInt = [Struct](unsigned Index, uint64_t Value) { + return ConstantInt::get(cast(Struct->getElementType(Index)), + Value); + }; + + return ConstantStruct::get(Struct, + GetInt(0, this->Address), + GetInt(1, this->Epoch), + GetInt(2, this->AddressSpace), + GetInt(3, this->Type)); + } + +public: + bool operator==(const MetaAddress &Other) const { + return tie() == Other.tie(); + } + + bool operator!=(const MetaAddress &Other) const { + return not(*this == Other); + } + + bool operator<(const MetaAddress &Other) const { return tie() < Other.tie(); } + + bool operator>(const MetaAddress &Other) const { return tie() > Other.tie(); } + + bool operator<=(const MetaAddress &Other) const { + return tie() <= Other.tie(); + } + + bool operator>=(const MetaAddress &Other) const { + return tie() >= Other.tie(); + } + + template + MetaAddress &operator+=(T Offset) { + T NewAddress = Address + Offset; + + if ((Offset >= 0 and NewAddress < T(Address)) + or (Offset < 0 and NewAddress > T(Address))) { + setInvalid(); + } else { + Address = NewAddress; + revng_assert(verify()); + } + + return *this; + } + template + MetaAddress &operator-=(T Offset) { + T NewAddress = Address - Offset; + + if ((Offset < 0 and NewAddress < T(Address)) + or (Offset >= 0 and NewAddress > T(Address))) { + setInvalid(); + } else { + Address = NewAddress; + revng_assert(verify()); + } + + return *this; + } + + template + MetaAddress operator+(T Offset) const { + MetaAddress Result = *this; + Result += Offset; + return Result; + } + + template + MetaAddress operator-(T Offset) const { + MetaAddress Result = *this; + Result -= Offset; + return Result; + } + + uint64_t operator-(const MetaAddress &Other) const { + revng_assert(this->AddressSpace == Other.AddressSpace); + return Address - Other.Address; + } + +public: + MetaAddress relocate(const MetaAddress &Other) const { + revng_assert(Epoch == Other.Epoch and AddressSpace == Other.AddressSpace + and Type == Other.Type); + MetaAddress Result = *this; + Result.Address += Other.Address; + return Result; + } + + MetaAddress replacePC(uint64_t PC) const { + MetaAddress Result = *this; + Result.normalize(PC); + revng_assert(Result.verify()); + return Result; + } + + MetaAddress replaceAddress(uint64_t Address) const { + MetaAddress Result = *this; + Result.Address = Address; + if (not Result.verify()) + return MetaAddress::invalid(); + else + return Result; + } + +public: + bool isInvalid() const { return Type == MetaAddressType::Invalid; } + bool isValid() const { return not isInvalid(); } + + uint64_t address() const { return Address; } + + uint64_t asPC() const { + revng_assert(Type != MetaAddressType::Invalid); + return asPCOrZero(); + } + + uint64_t asPCOrZero() const { + switch (Type) { + case MetaAddressType::Invalid: + return 0; + case MetaAddressType::Regular: + return Address; + case MetaAddressType::ARMThumb: + return Address | 1; + } + + revng_abort(); + } + + bool isDefaultAddressSpace() const { return AddressSpace == 0; } + uint16_t addressSpace() const { return AddressSpace; } + + bool isDefaultEpoch() const { return Epoch == 0; } + uint32_t epoch() const { return Epoch; } + + MetaAddressType::Values type() const { return Type; } + +public: + bool verify() const debug_function { + switch (Type) { + case MetaAddressType::Invalid: + return *this == invalid(); + case MetaAddressType::Regular: + return true; + case MetaAddressType::ARMThumb: + return (Address & 1) == 0; + } + + revng_abort(); + } + + void dump() const debug_function { dump(dbg); } + + template + void dump(T &Output) const { + Output << std::hex << "0x" << asPC() << " (" + << MetaAddressType::toString(Type) << " at 0x" << address() << ")"; + + if (not isDefaultAddressSpace()) { + Output << " in address space " << AddressSpace; + } + + if (not isDefaultEpoch()) { + Output << " at epoch " << Epoch; + } + + revng_assert(verify()); + } + +private: + void normalize(uint64_t PC) { + switch (Type) { + case MetaAddressType::Invalid: + revng_abort(); + + case MetaAddressType::Regular: + Address = PC; + break; + + case MetaAddressType::ARMThumb: + if ((PC & 1) == 0) + setInvalid(); + else + Address = PC & ~1; + break; + } + } + + void setInvalid() { + Type = MetaAddressType::Invalid; + Address = 0; + Epoch = 0; + AddressSpace = 0; + } + + static llvm::StructType *createStruct(llvm::LLVMContext &Context) { + auto *Uint64Ty = llvm::Type::getInt64Ty(Context); + auto *Uint32Ty = llvm::Type::getInt32Ty(Context); + auto *Uint16Ty = llvm::Type::getInt16Ty(Context); + return llvm::StructType::create({ Uint64Ty, Uint32Ty, Uint16Ty, Uint16Ty }, + "MetaAddress"); + } + +private: + using Tied = std::tuple; + Tied tie() const { return std::tie(Epoch, AddressSpace, Address, Type); } +}; + +static_assert(sizeof(MetaAddress) <= 128 / 8, + "MetaAddress is larger than 128 bits"); + +#endif // METAADDRESS_H diff --git a/include/revng/Support/revng.h b/include/revng/Support/revng.h index b32bf290d..06cff45aa 100644 --- a/include/revng/Support/revng.h +++ b/include/revng/Support/revng.h @@ -19,6 +19,7 @@ // Local libraries includes #include "revng/Support/IRHelpers.h" +#include "revng/Support/MetaAddress.h" namespace llvm { class GlobalVariable; diff --git a/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp b/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp index f53e1bc3a..6d78cf439 100644 --- a/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp +++ b/lib/BasicAnalyses/GeneratedCodeBasicInfo.cpp @@ -26,6 +26,10 @@ static RegisterGCBI X("gcbi", "Generated Code Basic Info", true, true); bool GeneratedCodeBasicInfo::runOnModule(llvm::Module &M) { Function &F = *M.getFunction("root"); + NewPC = M.getFunction("newpc"); + if (NewPC != nullptr) { + MetaAddressStruct = cast(NewPC->arg_begin()->getType()); + } revng_log(PassesLog, "Starting GeneratedCodeBasicInfo"); @@ -83,7 +87,7 @@ bool GeneratedCodeBasicInfo::runOnModule(llvm::Module &M) { case BlockType::JumpTargetBlock: { auto *Call = cast(&*BB.begin()); revng_assert(Call->getCalledFunction()->getName() == "newpc"); - JumpTargets[getLimitedValue(Call->getArgOperand(0))] = &BB; + JumpTargets[MetaAddress::fromConstant(Call->getArgOperand(0))] = &BB; break; } case BlockType::EntryPoint: diff --git a/lib/FunctionCallIdentification/FunctionCallIdentification.cpp b/lib/FunctionCallIdentification/FunctionCallIdentification.cpp index 5562379d0..52bb31d23 100644 --- a/lib/FunctionCallIdentification/FunctionCallIdentification.cpp +++ b/lib/FunctionCallIdentification/FunctionCallIdentification.cpp @@ -34,10 +34,9 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { LLVMContext &C = M.getContext(); PointerType *Int8PtrTy = Type::getInt8PtrTy(C); auto *Int8NullPtr = ConstantPointerNull::get(Int8PtrTy); - auto *PCTy = IntegerType::get(C, GCBI.pcRegSize() * 8); auto *PCPtrTy = cast(GCBI.pcReg()->getType()); std::initializer_list FunctionArgsTy = { - Int8PtrTy, Int8PtrTy, PCTy, PCPtrTy, Int8PtrTy + Int8PtrTy, Int8PtrTy, MetaAddress::getStruct(&M), PCPtrTy, Int8PtrTy }; using FT = FunctionType; auto *Ty = FT::get(Type::getVoidTy(C), FunctionArgsTy, false); @@ -64,7 +63,8 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { if (Terminator != nullptr) { if (CallInst *Call = getCall(Terminator)) { - FallthroughAddresses.insert(getLimitedValue(Call->getOperand(2))); + auto Address = MetaAddress::fromConstant(Call->getOperand(2)); + FallthroughAddresses.insert(Address); continue; } } @@ -88,8 +88,8 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { bool SaveRAFound; bool StorePCFound; Constant *LinkRegister; - const uint64_t ReturnPC; - uint64_t LastPC; + const MetaAddress ReturnPC; + MetaAddress LastPC; // We can meet calls up to newpc up to (1 + "size of the delay slot") // times @@ -99,7 +99,7 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { public: Visitor(BasicBlock *BB, const GeneratedCodeBasicInfo &GCBI, - uint64_t ReturnPC, + MetaAddress ReturnPC, PointerType *PCPtrTy) : BB(BB), GCBI(GCBI), @@ -122,8 +122,10 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { if (TargetCSV != nullptr) StorePCFound = true; } else if (auto *Constant = dyn_cast(V)) { + revng_assert(LastPC.isValid()); + // Note that we willingly ignore stores to the PC here - if (Constant->getLimitedValue() == ReturnPC) { + if (LastPC.replacePC(Constant->getLimitedValue()) == ReturnPC) { if (SaveRAFound) { SaveRAFound = false; return StopNow; @@ -177,7 +179,8 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { if (Callee != nullptr && Callee->getName() == "newpc") { revng_assert(NewPCLeft > 0); - uint64_t ProgramCounter = getLimitedValue(Call->getOperand(0)); + Value *PCOperand = Call->getOperand(0); + auto ProgramCounter = MetaAddress::fromConstant(PCOperand); uint64_t InstructionSize = getLimitedValue(Call->getOperand(1)); // Check that, w.r.t. to the last newpc, we're looking at the @@ -207,7 +210,7 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { } }; - uint64_t ReturnPC = GCBI.getNextPC(Terminator); + MetaAddress ReturnPC = GCBI.getNextPC(Terminator); Visitor V(&BB, GCBI, ReturnPC, PCPtrTy); V.run(Terminator); @@ -252,8 +255,7 @@ bool FunctionCallIdentification::runOnModule(llvm::Module &M) { const std::initializer_list Args{ Callee, BlockAddress::get(ReturnBB), - ConstantInt::get(PCTy, - ReturnPC), + GCBI.toConstant(ReturnPC), V.LinkRegister, Int8NullPtr }; @@ -312,9 +314,9 @@ void FunctionCallIdentification::buildFilteredCFG(llvm::Function &F) { if (Successor->empty() or not GCBI.isTranslated(Successor)) continue; - uint64_t Address = getBasicBlockPC(Successor); - AllZero = AllZero and (Address == 0); - IsReturn = IsReturn and (Address == 0 or isFallthrough(Address)); + MetaAddress Address = getBasicBlockPC(Successor); + AllZero = AllZero and (not Address.isInvalid()); + IsReturn = IsReturn and (Address.isInvalid() or isFallthrough(Address)); } IsReturn = IsReturn and not AllZero; diff --git a/lib/FunctionIsolation/EnforceABI.cpp b/lib/FunctionIsolation/EnforceABI.cpp index bd86ca55c..65e408dc1 100644 --- a/lib/FunctionIsolation/EnforceABI.cpp +++ b/lib/FunctionIsolation/EnforceABI.cpp @@ -694,14 +694,14 @@ void EnforceABIImpl::handleRegularFunctionCall(Instruction *I) { auto *Tuple = cast(F->getMetadata("revng.func.entry")); revng_assert(Tuple != nullptr); - uint64_t PC = QMD.extract(Tuple, 1); + auto PC = MetaAddress::fromConstant(QMD.extract(Tuple, 1)); auto *Case = BasicBlock::Create(Context, "", BeforeSplit->getParent(), AfterSplit); auto *Ty = cast(PCCSV->getType()->getPointerElementType()); - Switch->addCase(ConstantInt::get(Ty, PC), Case); + Switch->addCase(ConstantInt::get(Ty, PC.asPC()), Case); Builder.SetInsertPoint(Case); generateCall(Builder, F, CallSite); diff --git a/lib/FunctionIsolation/IsolateFunctions.cpp b/lib/FunctionIsolation/IsolateFunctions.cpp index 0fbe929b6..24b6dc3a1 100644 --- a/lib/FunctionIsolation/IsolateFunctions.cpp +++ b/lib/FunctionIsolation/IsolateFunctions.cpp @@ -40,7 +40,7 @@ static RegisterPass X("isolate", "Isolate Functions Pass", true, true); class IsolateFunctionsImpl { private: struct IsolatedFunctionDescriptor { - uint64_t PC; + MetaAddress PC; Function *IsolatedFunction; ValueToValueMap ValueMap; std::map Trampolines; @@ -62,7 +62,7 @@ public: private: /// \brief Creates the call that simulates the throw of an exception - void throwException(Reason Code, BasicBlock *BB, uint64_t AdditionalPC); + void throwException(Reason Code, BasicBlock *BB, MetaAddress AdditionalPC); /// \brief Instantiate a basic block that consists only of an exception throw BasicBlock *createUnreachableBlock(StringRef Name, Function *CurrentFunction); @@ -117,7 +117,9 @@ private: const unsigned PCBitSize; }; -void IFI::throwException(Reason Code, BasicBlock *BB, uint64_t AdditionalPC) { +void IFI::throwException(Reason Code, + BasicBlock *BB, + MetaAddress AdditionalPC) { revng_assert(PC != nullptr); revng_assert(RaiseException != nullptr); @@ -132,26 +134,27 @@ void IFI::throwException(Reason Code, BasicBlock *BB, uint64_t AdditionalPC) { // Call the _debug_exception function to print usefull stuff LoadInst *ProgramCounter = Builder.CreateLoad(PC, ""); - uint64_t LastPC; + MetaAddress LastPC; if (Code == StandardTranslatedBlock) { // Retrieve the value of the PC in the basic block where the exception has // been raised, this is possible since BB should be a translated block LastPC = getPC(&*BB->rbegin()).first; - revng_assert(LastPC != 0); + revng_assert(LastPC.isValid()); } else { // The current basic block has not been translated from the original binary // (e.g. unexpectedpc or anypc), therefore we can't retrieve the // corresponding PC. - LastPC = 0; + LastPC = MetaAddress::invalid(); } // Get the PC register dimension and use it to instantiate the arguments of // the call to exception_warning - ConstantInt *ReasonValue = Builder.getInt32(Code); - ConstantInt *ConstantLastPC = Builder.getIntN(PCBitSize, LastPC); - ConstantInt *ConstantAdditionalPC = Builder.getIntN(PCBitSize, AdditionalPC); + auto *ReasonValue = Builder.getInt32(Code); + auto *ConstantLastPC = Builder.getIntN(PCBitSize, LastPC.asPCOrZero()); + auto *ConstantAdditionalPC = Builder.getIntN(PCBitSize, + AdditionalPC.asPCOrZero()); // Emit the call to the exception helper in support.c, which in turn calls the // exception_warning function and then the _Unwind_RaiseException @@ -172,7 +175,7 @@ IFI::createUnreachableBlock(StringRef Name, Function *CurrentFunction) { CurrentFunction, nullptr); - throwException(StandardNonTranslatedBlock, NewBB, 0); + throwException(StandardNonTranslatedBlock, NewBB, MetaAddress::invalid()); return NewBB; } @@ -187,7 +190,9 @@ void IFI::populateFunctionDispatcher() { "unexpectedpc", FunctionDispatcher, nullptr); - throwException(FunctionDispatcherFallBack, UnexpectedPC, 0); + throwException(FunctionDispatcherFallBack, + UnexpectedPC, + MetaAddress::invalid()); setBlockType(UnexpectedPC->getTerminator(), BlockType::UnexpectedPCBlock); // Create a builder object for the DispatcherBB basic block @@ -213,7 +218,7 @@ void IFI::populateFunctionDispatcher() { CallInst::Create(Function, "", TrampolineBB); ReturnInst::Create(Context, TrampolineBB); - auto *Label = Builder.getIntN(PCBitSize, Descriptor.PC); + auto *Label = Builder.getIntN(PCBitSize, Descriptor.PC.asPC()); Switch->addCase(Label, TrampolineBB); } } @@ -307,7 +312,9 @@ bool IFI::replaceFunctionCall(BasicBlock *NewBB, BlockAddress *Callee = dyn_cast(Call->getOperand(0)); BlockAddress *FallThroughAddress = cast(Call->getOperand(1)); BasicBlock *FallthroughOld = FallThroughAddress->getBasicBlock(); - ConstantInt *ReturnPC = cast(Call->getOperand(2)); + auto ReturnPC = MetaAddress::fromConstant(Call->getOperand(2)); + Type *PCType = PC->getType()->getPointerElementType(); + Constant *ReturnPCCI = ConstantInt::get(PCType, ReturnPC.asPC()); Value *ExternalFunctionName = Call->getOperand(4); bool IsIndirect = (Callee == nullptr); @@ -355,14 +362,14 @@ bool IFI::replaceFunctionCall(BasicBlock *NewBB, // Additional check for the return address PC LoadInst *ProgramCounter = Builder.CreateLoad(PC, ""); - Value *Result = Builder.CreateICmpEQ(ProgramCounter, ReturnPC); + Value *Result = Builder.CreateICmpEQ(ProgramCounter, ReturnPCCI); // Create a basic block that we hit if the current PC is not the one // expected after the function call auto *PCMismatch = BasicBlock::Create(Context, NewBB->getName() + "_bad_return_pc", NewBB->getParent()); - throwException(BadReturnAddress, PCMismatch, ReturnPC->getZExtValue()); + throwException(BadReturnAddress, PCMismatch, ReturnPC); // Conditional branch to jump to the right block Builder.CreateCondBr(Result, FallthroughNew, PCMismatch); @@ -370,7 +377,7 @@ bool IFI::replaceFunctionCall(BasicBlock *NewBB, // If the fallthrough basic block is not in the current function raise an // exception - throwException(StandardTranslatedBlock, NewBB, 0); + throwException(StandardTranslatedBlock, NewBB, MetaAddress::invalid()); } return true; @@ -396,6 +403,7 @@ bool IFI::cloneInstruction(BasicBlock *NewBB, Value *PCReg = getModule(NewBB)->getGlobalVariable(GCBI.pcReg()->getName(), true); revng_assert(PCReg != nullptr); + ValueToValueMap &RootToIsolated = Descriptor.ValueMap; // Create a builder object @@ -470,7 +478,7 @@ bool IFI::cloneInstruction(BasicBlock *NewBB, Descriptor.IsolatedFunction); BlockType::Values Type = GCBI.getType(BB); - uint64_t PC = getBasicBlockPC(BB); + MetaAddress PC = getBasicBlockPC(BB); if (Type == BlockType::AnyPCBlock or Type == BlockType::UnexpectedPCBlock or Type == BlockType::DispatcherBlock) { @@ -486,7 +494,7 @@ bool IFI::cloneInstruction(BasicBlock *NewBB, "", Trampoline); ReturnInst::Create(Context, Trampoline); - } else if (PC == 0) { + } else if (PC.isInvalid()) { // We're trying to jump to a basic block not starting with newpc, emit // an unreachable // TODO: emit a warning @@ -494,8 +502,10 @@ bool IFI::cloneInstruction(BasicBlock *NewBB, new UnreachableInst(M->getContext(), Trampoline); } else { auto *PCType = PCReg->getType()->getPointerElementType(); - new StoreInst(ConstantInt::get(PCType, PC), PCReg, Trampoline); - throwException(StandardNonTranslatedBlock, Trampoline, 0); + new StoreInst(ConstantInt::get(PCType, PC.asPC()), PCReg, Trampoline); + throwException(StandardNonTranslatedBlock, + Trampoline, + MetaAddress::invalid()); } Descriptor.Trampolines[BB] = Trampoline; diff --git a/lib/StackAnalysis/FunctionsSummary.cpp b/lib/StackAnalysis/FunctionsSummary.cpp index ad4012fe8..0ef30ee57 100644 --- a/lib/StackAnalysis/FunctionsSummary.cpp +++ b/lib/StackAnalysis/FunctionsSummary.cpp @@ -213,8 +213,8 @@ void FunctionsSummary::dumpInternal(const Module *M, std::stringstream Output; // Register the range of addresses covered by each basic block - using interval_set = boost::icl::interval_set; - using interval = boost::icl::interval; + using interval_set = boost::icl::interval_set; + using interval = boost::icl::interval; std::map Coverage; for (User *U : M->getFunction("newpc")->users()) { auto *Call = dyn_cast(U); @@ -222,9 +222,9 @@ void FunctionsSummary::dumpInternal(const Module *M, continue; BasicBlock *BB = Call->getParent(); - uint64_t Address = getLimitedValue(Call->getOperand(0)); + auto Address = MetaAddress::fromConstant(Call->getOperand(0)); uint64_t Size = getLimitedValue(Call->getOperand(1)); - revng_assert(Address > 0 && Size > 0); + revng_assert(Address.isValid() && Size > 0); Coverage[BB] += interval::right_open(Address, Address + Size); } @@ -252,7 +252,7 @@ void FunctionsSummary::dumpInternal(const Module *M, Output << "\",\n"; Output << " \"entry_point_address\": \""; if (Entry != nullptr) - Output << "0x" << std::hex << getBasicBlockPC(Entry); + Output << std::hex << "0x" << getBasicBlockPC(Entry).address(); Output << "\",\n"; Output << " \"jt-reasons\": ["; @@ -309,8 +309,11 @@ void FunctionsSummary::dumpInternal(const Module *M, FunctionCoverage += IntervalSet; revng_assert(IntervalSet.iterative_size() == 1); const auto &Range = *(IntervalSet.begin()); - Output << "\"start\": \"0x" << std::hex << Range.lower() << "\", "; - Output << "\"end\": \"0x" << std::hex << Range.upper() << "\""; + Output << "\"start\": \""; + Output << std::hex << "0x" << Range.lower().address(); + Output << "\", \"end\": \""; + Output << std::hex << "0x" << Range.upper().address(); + Output << "\""; } else { Output << "\"start\": \"\", \"end\": \"\""; } @@ -349,9 +352,10 @@ void FunctionsSummary::dumpInternal(const Module *M, for (const auto &Range : FunctionCoverage) { Output << CoverageDelimiter; Output << "{"; - Output << "\"start\": \"0x" << std::hex << Range.lower() << "\", "; - Output << "\"end\": \"0x" << std::hex << Range.upper() << "\""; - Output << "}"; + Output << "\"start\": \"" << std::hex << "0x" << Range.lower().address(); + Output << "\", "; + Output << "\"end\": \"" << std::hex << "0x" << Range.upper().address(); + Output << "\"}"; CoverageDelimiter = ", "; } Output << "],\n"; diff --git a/lib/StackAnalysis/Intraprocedural.cpp b/lib/StackAnalysis/Intraprocedural.cpp index 0f041b601..8c30701bf 100644 --- a/lib/StackAnalysis/Intraprocedural.cpp +++ b/lib/StackAnalysis/Intraprocedural.cpp @@ -596,7 +596,7 @@ Interrupt Analysis::handleTerminator(Instruction *T, bool IsFunctionCall = false; BasicBlock *Callee = nullptr; BasicBlock *ReturnFromCall = nullptr; - uint64_t ReturnAddress = 0; + MetaAddress ReturnAddress = MetaAddress::invalid(); if (CallInst *Call = GCBI->getFunctionCall(T->getParent())) { IsFunctionCall = true; @@ -610,7 +610,7 @@ Interrupt Analysis::handleTerminator(Instruction *T, auto *ReturnBlockAddress = cast(Arg1); ReturnFromCall = ReturnBlockAddress->getBasicBlock(); - ReturnAddress = getLimitedValue(Arg2); + ReturnAddress = MetaAddress::fromConstant(Arg2); SaTerminator << " IsFunctionCall (callee " << Callee << ", return " << ReturnFromCall << ")"; @@ -701,7 +701,8 @@ Interrupt Analysis::handleTerminator(Instruction *T, // function call? if (IsReturnFromFake) { // Continue from there - BasicBlock *ReturnBB = GCBI->getBlockAt(FakeFunctionReturnAddress); + MetaAddress MA = GCBI->fromPC(FakeFunctionReturnAddress); + BasicBlock *ReturnBB = GCBI->getBlockAt(MA); return AI::createWithSuccessor(std::move(Result), BT::FakeFunctionReturn, ReturnBB); @@ -712,7 +713,12 @@ Interrupt Analysis::handleTerminator(Instruction *T, if (IsReadyToReturn) { // If the stack is not in a valid position, we consider it an indirect // tail call - return handleCall(T, nullptr, 0, nullptr, Result, ABIBB); + return handleCall(T, + nullptr, + MetaAddress::invalid(), + nullptr, + Result, + ABIBB); } else { // We have an indirect jump with a stack not ready to return: it's a // longjmp @@ -738,7 +744,7 @@ Interrupt Analysis::handleTerminator(Instruction *T, } std::pair Analysis::finalize() { - uint64_t EntryPC = getPC(Entry->getTerminator()).first; + MetaAddress EntryPC = getPC(Entry->getTerminator()).first; #ifndef NDEBUG // Compute the set of reachable basic blocks @@ -756,13 +762,14 @@ std::pair Analysis::finalize() { // they agree. Meanwhile find the return that is closest (but after) the // entry point and that has a valid stack size Value BestSP; - uint64_t ClosestPC = EntryPC - 1; + uint64_t ClosestPC = EntryPC.address() - 1; bool First = true; Value Combined; for (auto &P : ReturnCandidates) { BasicBlock *BB = P.first; const Element &Result = P.second; - uint64_t PC = getPC(BB->getTerminator()).first; + MetaAddress PC = getPC(BB->getTerminator()).first; + uint64_t PCAddress = PC.address(); #ifndef NDEBUG revng_assert(Reachable.count(BB) != 0); @@ -779,10 +786,10 @@ std::pair Analysis::finalize() { } if (const ASSlot *Slot = StackPointerValue.directContent()) { - if (PC >= EntryPC and PC < ClosestPC + if (PC >= EntryPC and PCAddress < ClosestPC and Slot->addressSpace() == ASID::stackID() and Slot->offset() >= 0) { - ClosestPC = PC; + ClosestPC = PCAddress; BestSP = StackPointerValue; } } @@ -841,7 +848,7 @@ std::pair Analysis::finalize() { Interrupt Analysis::handleCall(Instruction *Caller, BasicBlock *Callee, - uint64_t ReturnAddress, + MetaAddress ReturnAddress, BasicBlock *ReturnFromCall, Element &Result, ABIIRBasicBlock &ABIBB) { @@ -873,7 +880,7 @@ Interrupt Analysis::handleCall(Instruction *Caller, SaTerminator << " IsFakeFunctionCall"; // Assume normal control flow (i.e., inline) - FakeReturnAddresses.insert(ReturnAddress); + FakeReturnAddresses.insert(ReturnAddress.asPC()); return AI::createWithSuccessor(std::move(Result), BT::FakeFunctionCall, Callee); @@ -987,7 +994,8 @@ Interrupt Analysis::handleCall(Instruction *Caller, // Restore the PC // TODO: handle return address from indirect tail calls - ASSlot ReturnAddressSlot = ASSlot::create(ASID::globalID(), ReturnAddress); + ASSlot ReturnAddressSlot = ASSlot::create(ASID::globalID(), + ReturnAddress.asPCOrZero()); Result.store(PC, Value::fromSlot(ReturnAddressSlot)); revng_assert(not(IsIndirectTailCall and IsKiller)); diff --git a/lib/StackAnalysis/Intraprocedural.h b/lib/StackAnalysis/Intraprocedural.h index f156b0c12..4e112850c 100644 --- a/lib/StackAnalysis/Intraprocedural.h +++ b/lib/StackAnalysis/Intraprocedural.h @@ -514,7 +514,7 @@ private: /// \brief Part of the transfer function handling function calls Interrupt handleCall(llvm::Instruction *Caller, llvm::BasicBlock *Callee, - uint64_t ReturnAddress, + MetaAddress ReturnAddress, llvm::BasicBlock *ReturnFromCall, Element &Result, ABIIRBasicBlock &ABIBB); diff --git a/lib/StackAnalysis/StackAnalysis.cpp b/lib/StackAnalysis/StackAnalysis.cpp index 5c4954c17..17a366f8e 100644 --- a/lib/StackAnalysis/StackAnalysis.cpp +++ b/lib/StackAnalysis/StackAnalysis.cpp @@ -227,7 +227,7 @@ void StackAnalysis::serializeMetadata(Function &F) { if (Entry == nullptr or Function.BasicBlocks.size() == 0) continue; - uint64_t EntryPC = getBasicBlockPC(Entry); + MetaAddress EntryPC = getBasicBlockPC(Entry); // // Add `revng.func.entry`: @@ -264,7 +264,7 @@ void StackAnalysis::serializeMetadata(Function &F) { // Create revng.func.entry metadata MDTuple *FunctionMD = QMD.tuple({ QMD.get(getName(Entry)), - QMD.get(EntryPC), + QMD.get(GCBI.toConstant(EntryPC)), TypeMD, QMD.tuple(ClobberedMDs), QMD.tuple(SlotMDs) }); diff --git a/lib/Support/IRHelpers.cpp b/lib/Support/IRHelpers.cpp index 23f47da04..84f58f244 100644 --- a/lib/Support/IRHelpers.cpp +++ b/lib/Support/IRHelpers.cpp @@ -72,7 +72,7 @@ Constant *getUniqueString(Module *M, return ConstantExpr::getBitCast(NewVariable, Int8PtrTy); } -std::pair getPC(Instruction *TheInstruction) { +std::pair getPC(Instruction *TheInstruction) { BasicBlock *Dispatcher = nullptr; CallInst *NewPCCall = nullptr; std::set Visited; @@ -97,7 +97,7 @@ std::pair getPC(Instruction *TheInstruction) { // We found two distinct newpc leading to the requested instruction if (NewPCCall != nullptr) - return { 0, 0 }; + return { MetaAddress::invalid(), 0 }; NewPCCall = Marker; break; @@ -136,9 +136,9 @@ std::pair getPC(Instruction *TheInstruction) { // Couldn't find the current PC if (NewPCCall == nullptr) - return { 0, 0 }; + return { MetaAddress::invalid(), 0 }; - auto PC = getLimitedValue(NewPCCall->getArgOperand(0)); + auto PC = MetaAddress::fromConstant(NewPCCall->getArgOperand(0)); uint64_t Size = getLimitedValue(NewPCCall->getArgOperand(1)); revng_assert(Size != 0); return { PC, Size }; diff --git a/tools/revng-lift/AdvancedValueInfoPass.h b/tools/revng-lift/AdvancedValueInfoPass.h index 85958fb80..988afc000 100644 --- a/tools/revng-lift/AdvancedValueInfoPass.h +++ b/tools/revng-lift/AdvancedValueInfoPass.h @@ -137,7 +137,8 @@ AdvancedValueInfoPass::run(llvm::Function &F, // relative) possible values have to be valid program counters if (TIT == TrackedInstructionType::PCStore) { for (const MaterializedValue &V : Values) { - if (not V.hasSymbol() and not JTM->isPC(V.value())) { + MetaAddress MA = JTM->fromPC(V.value()); + if (not V.hasSymbol() and not JTM->isPC(MA)) { Values.clear(); break; } diff --git a/tools/revng-lift/BinaryFile.cpp b/tools/revng-lift/BinaryFile.cpp index 06b378b17..85fd39677 100644 --- a/tools/revng-lift/BinaryFile.cpp +++ b/tools/revng-lift/BinaryFile.cpp @@ -60,6 +60,15 @@ auto add(T LHS, U RHS) -> Optional { } // namespace nooverflow +template +static void logAddress(T &Logger, const char *Name, MetaAddress Address) { + if (Logger.isEnabled()) { + Logger << Name; + Address.dump(Logger); + Logger << DoLog; + } +} + template bool contains(const ArrayRef &Container, const ArrayRef &Contained) { return (Container.begin() <= Contained.begin() @@ -106,13 +115,14 @@ public: } }; -static uint64_t +static MetaAddress getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { using namespace llvm::MachO; ArrayRefReader Reader(Command, Swap); uint32_t Flavor = Reader.read(); uint32_t Count = Reader.read(); + Optional PC; switch (Arch) { case Triple::x86: { @@ -120,11 +130,13 @@ getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { switch (Flavor) { case MachO::x86_THREAD_STATE32: revng_check(Count == MachO::x86_THREAD_STATE32_COUNT); - return Reader.read().eip; + PC = Reader.read().eip; + break; case MachO::x86_THREAD_STATE: revng_check(Count == MachO::x86_THREAD_STATE_COUNT); - return Reader.read().uts.ts32.eip; + PC = Reader.read().uts.ts32.eip; + break; default: revng_abort(); @@ -139,11 +151,13 @@ getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { switch (Flavor) { case MachO::x86_THREAD_STATE64: revng_check(Count == MachO::x86_THREAD_STATE64_COUNT); - return Reader.read().rip; + PC = Reader.read().rip; + break; case MachO::x86_THREAD_STATE: revng_check(Count == MachO::x86_THREAD_STATE_COUNT); - return Reader.read().uts.ts64.rip; + PC = Reader.read().uts.ts64.rip; + break; default: revng_abort(); @@ -156,7 +170,8 @@ getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { switch (Flavor) { case MachO::ARM_THREAD_STATE: revng_check(Count == MachO::ARM_THREAD_STATE_COUNT); - return Reader.read().uts.ts32.pc; + PC = Reader.read().uts.ts32.pc; + break; default: revng_abort(); @@ -169,7 +184,8 @@ getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { switch (Flavor) { case MachO::ARM_THREAD_STATE64: revng_check(Count == MachO::ARM_THREAD_STATE64_COUNT); - return Reader.read().pc; + PC = Reader.read().pc; + break; default: revng_abort(); @@ -184,11 +200,14 @@ getInitialPC(Triple::ArchType Arch, bool Swap, ArrayRef Command) { revng_check(Reader.eof()); - return 0; + if (PC) + return MetaAddress::fromPC(Arch, *PC); + else + return MetaAddress::invalid(); } -BinaryFile::BinaryFile(std::string FilePath, uint64_t BaseAddress) : - BaseAddress(0) { +BinaryFile::BinaryFile(std::string FilePath, MetaAddress BaseAddress) : + EntryPoint(MetaAddress::invalid()), BaseAddress(BaseAddress) { auto BinaryOrErr = object::createBinary(FilePath); revng_check(BinaryOrErr, "Couldn't open the input file"); @@ -567,20 +586,24 @@ void BinaryFile::registerBindEntry(const object::MachOBindEntry *Entry, using namespace llvm::object; const auto Origin = LabelOrigin::DynamicRelocation; - uint64_t Target = Entry->address(); + MetaAddress Target = MetaAddress::invalid(); uint64_t Addend = static_cast(Entry->addend()); uint64_t Size = 0; switch (Entry->type()) { + case BIND_TYPE_INVALID: case BIND_TYPE_POINTER: + Target = MetaAddress::fromAbsolute(Entry->address()); Size = PointerSize; break; case BIND_TYPE_TEXT_ABSOLUTE32: + Target = fromPC(Entry->address()); Size = 32 / 8; break; case BIND_TYPE_TEXT_PCREL32: + Target = fromPC(Entry->address()); Size = 32 / 8; - Addend -= Target; + Addend -= Target.address(); break; default: revng_abort(); @@ -599,13 +622,17 @@ private: bool HasAddress; bool HasSize; uint64_t Size; - uint64_t Address; + MetaAddress Address; public: - FilePortion() : HasAddress(false), HasSize(false), Size(0), Address(0) {} + FilePortion() : + HasAddress(false), + HasSize(false), + Size(0), + Address(MetaAddress::invalid()) {} public: - void setAddress(uint64_t Address) { + void setAddress(MetaAddress Address) { HasAddress = true; this->Address = Address; } @@ -615,14 +642,14 @@ public: this->Size = Size; } - uint64_t addressAtOffset(uint64_t Offset) { + MetaAddress addressAtOffset(uint64_t Offset) { revng_assert(HasAddress and HasSize); revng_assert(Offset <= Size); return Address + Offset; } template - uint64_t addressAtIndex(uint64_t Index) { + MetaAddress addressAtIndex(uint64_t Index) { revng_assert(HasAddress and HasSize); uint64_t Offset = Index * sizeof(T); revng_assert(Offset <= Size); @@ -695,20 +722,23 @@ static bool shouldIgnoreSymbol(StringRef Name) { return Name == "$a" or Name == "$d"; } -void BinaryFile::parseCOFF(object::ObjectFile *TheBinary, - uint64_t BaseAddress) { +static uint64_t u64(uint64_t Value) { + return Value; +} + +void BinaryFile::parseCOFF(object::ObjectFile *TheBinary, MetaAddress) { std::error_code EC; object::COFFObjectFile TheCOFF(TheBinary->getMemoryBufferRef(), EC); const object::pe32_header *PE32Header = nullptr; TheCOFF.getPE32Header(PE32Header); - uint64_t ImageBase = 0; + MetaAddress ImageBase = MetaAddress::invalid(); if (PE32Header) { // TODO: ImageBase should aligned to 4kb pages, should we check that? - ImageBase = PE32Header->ImageBase; + ImageBase = fromAbsolute(PE32Header->ImageBase); - EntryPoint = ImageBase + PE32Header->AddressOfEntryPoint; + EntryPoint = ImageBase + u64(PE32Header->AddressOfEntryPoint); ProgramHeaders.Count = PE32Header->NumberOfRvaAndSize; ProgramHeaders.Size = PE32Header->SizeOfHeaders; } else { @@ -720,8 +750,8 @@ void BinaryFile::parseCOFF(object::ObjectFile *TheBinary, } // PE32+ Header - ImageBase = PE32PlusHeader->ImageBase; - EntryPoint = ImageBase + PE32PlusHeader->AddressOfEntryPoint; + ImageBase = fromAbsolute(PE32PlusHeader->ImageBase); + EntryPoint = ImageBase + u64(PE32PlusHeader->AddressOfEntryPoint); ProgramHeaders.Count = PE32PlusHeader->NumberOfRvaAndSize; ProgramHeaders.Size = PE32PlusHeader->SizeOfHeaders; } @@ -743,11 +773,11 @@ void BinaryFile::parseCOFF(object::ObjectFile *TheBinary, using namespace nooverflow; SegmentInfo Segment; - Segment.StartVirtualAddress = *add(ImageBase, CoffRef->VirtualAddress); - Segment.EndVirtualAddress = *add(Segment.StartVirtualAddress, - CoffRef->VirtualSize); + Segment.StartVirtualAddress = ImageBase + u64(CoffRef->VirtualAddress); + Segment.EndVirtualAddress = Segment.StartVirtualAddress + + u64(CoffRef->VirtualSize); Segment.StartFileOffset = CoffRef->PointerToRawData; - Segment.EndFileOffset = *add(CoffRef->PointerToRawData, SegmentSize); + Segment.EndFileOffset = Segment.StartFileOffset + SegmentSize; Segment.IsExecutable = CoffRef->Characteristics & COFF::IMAGE_SCN_MEM_EXECUTE; Segment.IsReadable = CoffRef->Characteristics & COFF::IMAGE_SCN_MEM_READ; @@ -775,9 +805,9 @@ void BinaryFile::parseMachOSegment(ArrayRef RawDataRef, using namespace nooverflow; SegmentInfo Segment; - Segment.StartVirtualAddress = SegmentCommand.vmaddr; - Segment.EndVirtualAddress = *add(SegmentCommand.vmaddr, - SegmentCommand.vmsize); + Segment.StartVirtualAddress = fromAbsolute(SegmentCommand.vmaddr); + Segment.EndVirtualAddress = fromAbsolute(SegmentCommand.vmaddr) + + SegmentCommand.vmsize; Segment.StartFileOffset = SegmentCommand.fileoff; Segment.EndFileOffset = *add(SegmentCommand.fileoff, SegmentCommand.filesize); Segment.IsExecutable = SegmentCommand.initprot & VM_PROT_EXECUTE; @@ -792,7 +822,8 @@ void BinaryFile::parseMachOSegment(ArrayRef RawDataRef, } template -void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { +void BinaryFile::parseELF(object::ObjectFile *TheBinary, + MetaAddress BaseAddress) { // Parse the ELF file auto TheELFOrErr = object::ELFFile::create(TheBinary->getData()); if (not TheELFOrErr) { @@ -810,10 +841,10 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { using Elf_PhdrPtr = const typename object::ELFFile::Elf_Phdr *; ConstElf_ShdrPtr SymtabShdr = nullptr; Elf_PhdrPtr DynamicPhdr = nullptr; - Optional DynamicAddress; - Optional EHFrameAddress; + Optional DynamicAddress; + Optional EHFrameAddress; Optional EHFrameSize; - Optional EHFrameHdrAddress; + Optional EHFrameHdrAddress; auto Sections = TheELF.sections(); if (not Sections) { @@ -829,11 +860,11 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { SymtabShdr = &Section; } else if (Name == ".eh_frame") { revng_assert(not EHFrameAddress, "Duplicate .eh_frame"); - EHFrameAddress = relocate(static_cast(Section.sh_addr)); + EHFrameAddress = relocate(fromAbsolute(Section.sh_addr)); EHFrameSize = static_cast(Section.sh_size); } else if (Name == ".dynamic") { revng_assert(not DynamicAddress, "Duplicate .dynamic"); - DynamicAddress = relocate(static_cast(Section.sh_addr)); + DynamicAddress = relocate(fromAbsolute(Section.sh_addr)); } } } @@ -871,16 +902,24 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { if (shouldIgnoreSymbol(*Name)) continue; + auto SymbolType = SymbolType::fromELF(Symbol.getType()); + MetaAddress Address = MetaAddress::invalid(); + + if (SymbolType == SymbolType::Code) + Address = fromPC(Symbol.st_value); + else + Address = MetaAddress::fromAbsolute(Symbol.st_value); + registerLabel(Label::createSymbol(LabelOrigin::StaticSymbol, - Symbol.st_value, + Address, Symbol.st_size, *Name, - SymbolType::fromELF(Symbol.getType()))); + SymbolType)); } } const auto *ElfHeader = TheELF.getHeader(); - EntryPoint = relocate(static_cast(ElfHeader->e_entry)); + EntryPoint = relocate(fromPC(ElfHeader->e_entry)); ProgramHeaders.Count = ElfHeader->e_phnum; ProgramHeaders.Size = ElfHeader->e_phentsize; @@ -905,9 +944,9 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { case ELF::PT_LOAD: { using namespace nooverflow; SegmentInfo Segment; - auto Start = relocate(ProgramHeader.p_vaddr); + auto Start = relocate(fromAbsolute(ProgramHeader.p_vaddr)); Segment.StartVirtualAddress = Start; - Segment.EndVirtualAddress = *add(Start, ProgramHeader.p_memsz); + Segment.EndVirtualAddress = Start + u64(ProgramHeader.p_memsz); Segment.StartFileOffset = ProgramHeader.p_offset; Segment.EndFileOffset = *add(ProgramHeader.p_offset, ProgramHeader.p_filesz); @@ -927,8 +966,8 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { auto Inserter = std::back_inserter(Segment.ExecutableSections); for (Elf_Shdr &SectionHeader : *Sections) { if (SectionHeader.sh_flags & ELF::SHF_EXECINSTR) { - auto SectionStart = relocate(SectionHeader.sh_addr); - auto SectionEnd = SectionStart + SectionHeader.sh_size; + auto SectionStart = relocate(fromAbsolute(SectionHeader.sh_addr)); + auto SectionEnd = SectionStart + u64(SectionHeader.sh_size); Inserter = make_pair(SectionStart, SectionEnd); } } @@ -938,27 +977,29 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { // Check if it's the segment containing the program headers auto ProgramHeaderStart = ProgramHeader.p_offset; - auto ProgramHeaderEnd = ProgramHeader.p_offset + ProgramHeader.p_filesz; + auto ProgramHeaderEnd = ProgramHeader.p_offset + + u64(ProgramHeader.p_filesz); if (ProgramHeaderStart <= ElfHeader->e_phoff && ElfHeader->e_phoff < ProgramHeaderEnd) { - uint64_t PhdrAddress = (relocate(ProgramHeader.p_vaddr) - + ElfHeader->e_phoff - ProgramHeader.p_offset); + MetaAddress PhdrAddress = (relocate(fromAbsolute(ProgramHeader.p_vaddr)) + + u64(ElfHeader->e_phoff) + - u64(ProgramHeader.p_offset)); ProgramHeaders.Address = PhdrAddress; } } break; case ELF::PT_GNU_EH_FRAME: revng_assert(!EHFrameHdrAddress); - EHFrameHdrAddress = relocate(ProgramHeader.p_vaddr); + EHFrameHdrAddress = relocate(fromAbsolute(ProgramHeader.p_vaddr)); break; case ELF::PT_DYNAMIC: revng_assert(DynamicPhdr == nullptr, "Duplicate .dynamic program header"); DynamicPhdr = &ProgramHeader; - revng_assert(((not DynamicAddress) - or (relocate(DynamicPhdr->p_vaddr) == *DynamicAddress)), + MetaAddress DynamicPhdrMA = relocate(fromAbsolute(DynamicPhdr->p_vaddr)); + revng_assert(not DynamicAddress or DynamicPhdrMA == *DynamicAddress, ".dynamic and PT_DYNAMIC have different addresses"); - DynamicAddress = relocate(DynamicPhdr->p_vaddr); + DynamicAddress = relocate(DynamicPhdrMA); break; } } @@ -967,7 +1008,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { Optional FDEsCount; if (EHFrameHdrAddress) { - uint64_t Address; + MetaAddress Address = MetaAddress::invalid(); std::tie(Address, FDEsCount) = ehFrameFromEhFrameHdr(*EHFrameHdrAddress); if (EHFrameAddress) { @@ -1003,13 +1044,14 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { for (Elf_Dyn &DynamicTag : *DynamicEntries) { auto TheTag = DynamicTag.getTag(); + MetaAddress Relocated = relocate(fromAbsolute(DynamicTag.getPtr())); switch (TheTag) { case ELF::DT_NEEDED: NeededLibraryNameOffsets.push_back(DynamicTag.getVal()); break; case ELF::DT_STRTAB: - DynstrPortion.setAddress(relocate(DynamicTag.getPtr())); + DynstrPortion.setAddress(Relocated); break; case ELF::DT_STRSZ: @@ -1017,11 +1059,11 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { break; case ELF::DT_SYMTAB: - DynsymPortion.setAddress(relocate(DynamicTag.getPtr())); + DynsymPortion.setAddress(Relocated); break; case ELF::DT_JMPREL: - RelpltPortion.setAddress(relocate(DynamicTag.getPtr())); + RelpltPortion.setAddress(Relocated); break; case ELF::DT_PLTRELSZ: @@ -1031,7 +1073,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { case ELF::DT_REL: case ELF::DT_RELA: revng_assert(TheTag == (HasAddend ? ELF::DT_RELA : ELF::DT_REL)); - ReldynPortion.setAddress(relocate(DynamicTag.getPtr())); + ReldynPortion.setAddress(Relocated); break; case ELF::DT_RELSZ: @@ -1041,11 +1083,11 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { break; case ELF::DT_PLTGOT: - GotPortion.setAddress(relocate(DynamicTag.getPtr())); + GotPortion.setAddress(Relocated); // Obtaint the canonical value of the global pointer in MIPS if (IsMIPS) - CanonicalValues["gp"] = relocate(DynamicTag.getPtr() + 0x7ff0); + CanonicalValues["gp"] = (Relocated + 0x7ff0).address(); break; case ELF::DT_MIPS_SYMTABNO: @@ -1110,8 +1152,15 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { continue; auto SymbolType = SymbolType::fromELF(Symbol.getType()); + MetaAddress Address = MetaAddress::invalid(); + + if (SymbolType == SymbolType::Code) + Address = fromPC(Symbol.st_value); + else + Address = MetaAddress::fromAbsolute(Symbol.st_value); + registerLabel(Label::createSymbol(LabelOrigin::DynamicSymbol, - Symbol.st_value, + Address, Symbol.st_size, *Name, SymbolType)); @@ -1141,7 +1190,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { for (; GotIndex < *MIPSLocalGotEntries; GotIndex++) { auto Address = GotPortion.addressAtIndex(GotIndex); Elf_Rel NewRelocation; - NewRelocation.r_offset = Address; + NewRelocation.r_offset = Address.address(); NewRelocation.setSymbolAndType(0, R_MIPS_IMPLICIT_RELATIVE, false); MIPSImplicitRelocations.push_back(NewRelocation); } @@ -1156,7 +1205,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { auto Address = GotPortion.addressAtIndex(GotIndex); Elf_Rel NewRelocation; - NewRelocation.r_offset = Address; + NewRelocation.r_offset = Address.address(); NewRelocation.setSymbolAndType(SymbolIndex, llvm::ELF::R_MIPS_JUMP_SLOT, false); @@ -1176,7 +1225,7 @@ void BinaryFile::parseELF(object::ObjectFile *TheBinary, uint64_t BaseAddress) { if (L.isSymbol() and L.isCode()) CodePointers.insert(relocate(L.address())); else if (L.isBaseRelativeValue()) - CodePointers.insert(relocate(L.value())); + CodePointers.insert(relocate(fromPC(L.value()))); } } @@ -1195,8 +1244,9 @@ uint64_t BinaryFile::symbolsCount(const FilePortion &Relocations) { return SymbolsCount; } -Optional -BinaryFile::readRawValue(uint64_t Address, unsigned Size, Endianess E) const { +Optional BinaryFile::readRawValue(MetaAddress Address, + unsigned Size, + Endianess E) const { bool IsLittleEndian = ((E == OriginalEndianess) ? architecture().isLittleEndian() : E == LittleEndian); @@ -1242,7 +1292,7 @@ BinaryFile::readRawValue(uint64_t Address, unsigned Size, Endianess E) const { } Label BinaryFile::parseRelocation(unsigned char RelocationType, - uint64_t Target, + MetaAddress Target, uint64_t Addend, StringRef SymbolName, uint64_t SymbolSize, @@ -1325,7 +1375,7 @@ void BinaryFile::registerRelocations(Elf_Rel_Array Relocations, for (Elf_Rel Relocation : Relocations) { auto Type = static_cast(Relocation.getType(false)); uint64_t Addend = RelocationHelper::getAddend(Relocation); - uint64_t Address = relocate(Relocation.r_offset); + MetaAddress Address = relocate(fromAbsolute(Relocation.r_offset)); StringRef SymbolName; uint64_t SymbolSize = 0; @@ -1356,7 +1406,7 @@ static LabelList &operator+=(LabelList &This, const LabelList &Other) { } void BinaryFile::rebuildLabelsMap() { - using Interval = boost::icl::interval; + using Interval = boost::icl::interval; // Clear the map LabelsMap.clear(); @@ -1374,7 +1424,7 @@ void BinaryFile::rebuildLabelsMap() { std::sort(ZeroSizedLabels.begin(), ZeroSizedLabels.end(), Compare); // Create virtual terminator label - uint64_t HighestAddress = 0; + MetaAddress HighestAddress = MetaAddress::invalid(); for (const SegmentInfo &Segment : Segments) HighestAddress = std::max(HighestAddress, Segment.EndVirtualAddress); Label EndLabel = Label::createSymbol(LabelOrigin::Unknown, @@ -1386,15 +1436,15 @@ void BinaryFile::rebuildLabelsMap() { // Insert the 0-sized labels in the map for (unsigned I = 0; I < ZeroSizedLabels.size() - 1; I++) { - uint64_t Start = ZeroSizedLabels[I]->address(); + MetaAddress Start = ZeroSizedLabels[I]->address(); const SegmentInfo *Segment = findSegment(Start); if (Segment == nullptr) continue; // Limit the symbol to the end of the segment containing it - uint64_t End = std::min(ZeroSizedLabels[I + 1]->address(), - Segment->EndVirtualAddress); + MetaAddress End = std::min(ZeroSizedLabels[I + 1]->address(), + Segment->EndVirtualAddress); revng_assert(Start <= End); // Register virtual size @@ -1403,15 +1453,19 @@ void BinaryFile::rebuildLabelsMap() { // Insert all the other labels in the map for (Label &L : Labels) { - uint64_t Start = L.address(); - uint64_t End = L.address() + L.size(); + MetaAddress Start = L.address(); + MetaAddress End = L.address() + L.size(); LabelsMap += make_pair(Interval::right_open(Start, End), LabelList{ &L }); } // Dump the map out if (LabelsLog.isEnabled()) { for (auto &P : LabelsMap) { - dbg << P.first << "\n"; + dbg << "["; + P.first.lower().dump(dbg); + dbg << ","; + P.first.upper().dump(dbg); + dbg << "]\n"; for (const Label *L : P.second) { dbg << " "; L->dump(dbg); @@ -1429,7 +1483,7 @@ void BinaryFile::rebuildLabelsMap() { template class DwarfReader { public: - DwarfReader(ArrayRef Buffer, uint64_t Address) : + DwarfReader(ArrayRef Buffer, MetaAddress Address) : Address(Address), Start(Buffer.data()), Cursor(Buffer.data()), @@ -1470,13 +1524,14 @@ public: return static_cast(readValue(Encoding)); } - Pointer readPointer(unsigned Encoding, uint64_t Base = 0) { + Pointer + readPointer(unsigned Encoding, MetaAddress Base = MetaAddress::invalid()) { revng_assert((Encoding & ~(0x70 | 0x0F | dwarf::DW_EH_PE_indirect)) == 0); // Handle PC-relative values revng_assert(Cursor >= Start); if ((Encoding & 0x70) == dwarf::DW_EH_PE_pcrel) { - revng_assert(Base == 0); + revng_assert(Base.isInvalid()); Base = Address + (Cursor - Start); } @@ -1565,11 +1620,11 @@ private: } template - Pointer readPointerInternal(T Value, unsigned Encoding, uint64_t Base) { + Pointer readPointerInternal(T Value, unsigned Encoding, MetaAddress Base) { bool IsIndirect = Encoding & dwarf::DW_EH_PE_indirect; - if (Base == 0) { - return Pointer(IsIndirect, Value); + if (Base.isInvalid()) { + return Pointer(IsIndirect, MetaAddress::fromAbsolute(Value)); } else { unsigned EncodingRelative = Encoding & 0x70; revng_assert(EncodingRelative == 0 || EncodingRelative == 0x10); @@ -1580,7 +1635,7 @@ private: bool is64() const; private: - uint64_t Address; + MetaAddress Address; const uint8_t *Start; const uint8_t *Cursor; const uint8_t *End; @@ -1604,8 +1659,8 @@ bool DwarfReader::is64() const { } template -std::pair -BinaryFile::ehFrameFromEhFrameHdr(uint64_t EHFrameHdrAddress) { +std::pair +BinaryFile::ehFrameFromEhFrameHdr(MetaAddress EHFrameHdrAddress) { auto R = getAddressData(EHFrameHdrAddress); revng_assert(R, ".eh_frame_hdr section not available in any segment"); llvm::ArrayRef EHFrameHdr = *R; @@ -1627,11 +1682,12 @@ BinaryFile::ehFrameFromEhFrameHdr(uint64_t EHFrameHdrAddress) { Pointer EHFramePointer = EHFrameHdrReader.readPointer(ExceptionFrameEncoding); Pointer FDEsCountPointer = EHFrameHdrReader.readPointer(FDEsCountEncoding); - return { getPointer(EHFramePointer), getPointer(FDEsCountPointer) }; + return { MetaAddress::fromAbsolute(getPointer(EHFramePointer)), + getPointer(FDEsCountPointer) }; } template -void BinaryFile::parseEHFrame(uint64_t EHFrameAddress, +void BinaryFile::parseEHFrame(MetaAddress EHFrameAddress, Optional FDEsCount, Optional EHFrameSize) { revng_assert(FDEsCount || EHFrameSize); @@ -1737,8 +1793,10 @@ void BinaryFile::parseEHFrame(uint64_t EHFrameAddress, // Personality Pointer Personality; Personality = EHFrameReader.readPointer(*PersonalityEncoding); - uint64_t PersonalityPtr = getPointer(Personality); - revng_log(EhFrameLog, "Personality function: " << PersonalityPtr); + uint64_t RawPersonalityPtr = getPointer(Personality); + auto PersonalityPtr = fromPC(RawPersonalityPtr); + logAddress(EhFrameLog, "Personality function: ", PersonalityPtr); + // TODO: technically this is not a landing pad LandingPads.insert(PersonalityPtr); break; @@ -1778,8 +1836,8 @@ void BinaryFile::parseEHFrame(uint64_t EHFrameAddress, // PCBegin auto PCBeginPointer = EHFrameReader.readPointer(*CIE.FDEPointerEncoding); - uint64_t PCBegin = getPointer(PCBeginPointer); - revng_log(EhFrameLog, "PCBegin: " << std::hex << PCBegin); + MetaAddress PCBegin = fromPC(getPointer(PCBeginPointer)); + logAddress(EhFrameLog, "PCBegin: ", PCBegin); // PCRange EHFrameReader.readPointer(*CIE.FDEPointerEncoding); @@ -1790,7 +1848,8 @@ void BinaryFile::parseEHFrame(uint64_t EHFrameAddress, // Decode the LSDA if the CIE augmentation string said we should. if (CIE.LSDAPointerEncoding) { auto LSDAPointer = EHFrameReader.readPointer(*CIE.LSDAPointerEncoding); - parseLSDA(PCBegin, getPointer(LSDAPointer)); + parseLSDA(PCBegin, + MetaAddress::fromAbsolute(getPointer(LSDAPointer))); } } @@ -1800,8 +1859,8 @@ void BinaryFile::parseEHFrame(uint64_t EHFrameAddress, } template -void BinaryFile::parseLSDA(uint64_t FDEStart, uint64_t LSDAAddress) { - revng_log(EhFrameLog, "LSDAAddress: " << std::hex << LSDAAddress); +void BinaryFile::parseLSDA(MetaAddress FDEStart, MetaAddress LSDAAddress) { + logAddress(EhFrameLog, "LSDAAddress: ", LSDAAddress); auto R = getAddressData(LSDAAddress); revng_assert(R, "LSDA not available in any segment"); @@ -1810,15 +1869,16 @@ void BinaryFile::parseLSDA(uint64_t FDEStart, uint64_t LSDAAddress) { DwarfReader LSDAReader(LSDA, LSDAAddress); uint32_t LandingPadBaseEncoding = LSDAReader.readNextU8(); - uint64_t LandingPadBase = 0; + MetaAddress LandingPadBase = MetaAddress::invalid(); if (LandingPadBaseEncoding != dwarf::DW_EH_PE_omit) { auto LandingPadBasePointer = LSDAReader.readPointer(LandingPadBaseEncoding); - LandingPadBase = getPointer(LandingPadBasePointer); + uint64_t RawLandingPadBase = getPointer(LandingPadBasePointer); + LandingPadBase = MetaAddress::fromAbsolute(RawLandingPadBase); } else { LandingPadBase = FDEStart; } - revng_log(EhFrameLog, "LandingPadBase: " << std::hex << LandingPadBase); + logAddress(EhFrameLog, "LandingPadBase: ", LandingPadBase); uint32_t TypeTableEncoding = LSDAReader.readNextU8(); if (TypeTableEncoding != dwarf::DW_EH_PE_omit) @@ -1838,16 +1898,16 @@ void BinaryFile::parseLSDA(uint64_t FDEStart, uint64_t LSDAAddress) { // LandingPad Pointer LandingPadPointer = LSDAReader.readPointer(CallSiteTableEncoding, LandingPadBase); - uint64_t LandingPad = getPointer(LandingPadPointer); + uint64_t RawLandingPadPointer = getPointer(LandingPadPointer); + MetaAddress LandingPad = fromPC(RawLandingPadPointer); // Action LSDAReader.readULEB128(); - if (LandingPad != 0) { - if (EhFrameLog.isEnabled() and LandingPads.count(LandingPad) == 0) { - EhFrameLog << "New landing pad found: " << std::hex << LandingPad - << DoLog; - } + if (LandingPad.isValid()) { + if (LandingPads.count(LandingPad) == 0) + logAddress(EhFrameLog, "New landing pad found: ", LandingPad); + LandingPads.insert(LandingPad); } } diff --git a/tools/revng-lift/BinaryFile.h b/tools/revng-lift/BinaryFile.h index a3d22a885..64509e51b 100644 --- a/tools/revng-lift/BinaryFile.h +++ b/tools/revng-lift/BinaryFile.h @@ -33,26 +33,36 @@ class MachOBindEntry; /// \brief Simple data structure to describe an ELF segment // TODO: information hiding struct SegmentInfo { - /// Produce a name for this segment suitable for human understanding - std::string generateName(); - llvm::GlobalVariable *Variable; ///< \brief LLVM variable containing this /// segment's data - uint64_t StartVirtualAddress; - uint64_t EndVirtualAddress; + MetaAddress StartVirtualAddress; + MetaAddress EndVirtualAddress; uint64_t StartFileOffset; uint64_t EndFileOffset; bool IsWriteable; bool IsExecutable; bool IsReadable; - std::vector> ExecutableSections; + std::vector> ExecutableSections; llvm::ArrayRef Data; - bool contains(uint64_t Address) const { + 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(); + + bool contains(MetaAddress Address) const { return StartVirtualAddress <= Address && Address < EndVirtualAddress; } - bool contains(uint64_t Start, uint64_t Size) const { + bool contains(MetaAddress Start, uint64_t Size) const { return contains(Start) && contains(Start + Size - 1); } @@ -171,7 +181,7 @@ inline const char *getName(Values V) { class Label { private: LabelType::Values Type; - uint64_t Address; + MetaAddress Address; uint64_t Size; /// Name of the symbol, if any @@ -185,7 +195,7 @@ private: bool SizeIsVirtual; private: - Label(LabelOrigin::Values Origin, uint64_t Address, uint64_t Size) : + Label(LabelOrigin::Values Origin, MetaAddress Address, uint64_t Size) : Type(LabelType::Invalid), Address(Address), Size(Size), @@ -196,10 +206,12 @@ private: SizeIsVirtual(false) {} public: - static Label createInvalid() { return Label(LabelOrigin::Unknown, 0, 0); } + static Label createInvalid() { + return Label(LabelOrigin::Unknown, MetaAddress::invalid(), 0); + } static Label createAbsoluteValue(LabelOrigin::Values Origin, - uint64_t Address, + MetaAddress Address, uint64_t Size, uint64_t Value) { Label Result(Origin, Address, Size); @@ -209,7 +221,7 @@ public: } static Label createBaseRelativeValue(LabelOrigin::Values Origin, - uint64_t Address, + MetaAddress Address, uint64_t Size, uint64_t Value) { Label Result(Origin, Address, Size); @@ -219,7 +231,7 @@ public: } static Label createSymbolRelativeValue(LabelOrigin::Values Origin, - uint64_t Address, + MetaAddress Address, uint64_t Size, llvm::StringRef SymbolName, SymbolType::Values SymbolType, @@ -233,7 +245,7 @@ public: } static Label createSymbol(LabelOrigin::Values Origin, - uint64_t Address, + MetaAddress Address, uint64_t Size, llvm::StringRef SymbolName, SymbolType::Values SymbolType) { @@ -296,10 +308,10 @@ public: bool isCode() const { return SymbolType == SymbolType::Code; } - uint64_t address() const { return Address; } - bool hasValue() const { return isAbsoluteValue() or isBaseRelativeValue(); } + MetaAddress address() const { return Address; } + uint64_t size() const { return Size; } uint64_t value() const { @@ -324,13 +336,15 @@ public: bool isSizeVirtual() const { return SizeIsVirtual; } - bool matches(uint64_t Address, uint64_t Size) const { + bool matches(MetaAddress Address, uint64_t Size) const { return this->Address == Address and this->Size == Size; } - bool contains(uint64_t Address, uint64_t Size) const { - return (this->Address <= Address - and (Address + Size) <= (this->Address + this->Size)); + bool contains(MetaAddress Address, uint64_t Size) const { + auto End = MetaAddress::fromAbsolute(Address.address() + Size); + auto ThisEnd = MetaAddress::fromAbsolute(this->Address.address() + + this->Size); + return (this->Address <= Address and End <= ThisEnd); } void dump() const debug_function { @@ -340,8 +354,9 @@ public: template void dump(T &Output) const { - Output << LabelType::getName(Type) << " @ (0x" << std::hex << Address << "," - << Size << ") "; + Output << LabelType::getName(Type) << " @ ("; + Address.dump(Output); + Output << "," << Size << ") "; if (isSymbolRelativeValue() or isSymbol()) Output << SymbolName.data(); @@ -432,17 +447,17 @@ inline uint64_t readPointer(const uint8_t *Buf) { /// \brief A pair on steroids to wrap a value or a pointer to a value class Pointer { public: - Pointer() {} + Pointer() : IsIndirect(false), Value(MetaAddress::invalid()) {} - Pointer(bool IsIndirect, uint64_t Value) : + Pointer(bool IsIndirect, MetaAddress Value) : IsIndirect(IsIndirect), Value(Value) {} bool isIndirect() const { return IsIndirect; } - uint64_t value() const { return Value; } + MetaAddress value() const { return Value; } private: bool IsIndirect; - uint64_t Value; + MetaAddress Value; }; class FilePortion; @@ -452,7 +467,7 @@ class FilePortion; class BinaryFile { public: using LabelList = llvm::SmallVector