diff --git a/codegenerator.cpp b/codegenerator.cpp index a3b816bdc..27211c281 100644 --- a/codegenerator.cpp +++ b/codegenerator.cpp @@ -36,6 +36,7 @@ #include "ir-helpers.h" #include "jumptargetmanager.h" #include "ptcinterface.h" +#include "revamb.h" #include "variablemanager.h" using namespace llvm; @@ -102,6 +103,18 @@ CodeGenerator::CodeGenerator(std::string Input, } } +std::string SegmentInfo::generateName() { + // Create name from start and size + std::stringstream NameStream; + NameStream << ".o_" + << (IsReadable ? "r" : "") + << (IsWriteable ? "w" : "") + << (IsExecutable ? "x" : "") + << "_0x" << std::hex << StartVirtualAddress; + + return NameStream.str(); +} + template void CodeGenerator::parseELF(object::ObjectFile *TheBinary, std::string LinkingInfoPath) { @@ -135,14 +148,17 @@ void CodeGenerator::parseELF(object::ObjectFile *TheBinary, // CSV for (auto &ProgramHeader : TheELF.program_headers()) if (ProgramHeader.p_type == ELF::PT_LOAD) { - auto EndAddress = ProgramHeader.p_vaddr + ProgramHeader.p_memsz; + SegmentInfo Segment; + Segment.StartVirtualAddress = ProgramHeader.p_vaddr; + Segment.EndVirtualAddress = ProgramHeader.p_vaddr + ProgramHeader.p_memsz; + Segment.IsReadable = ProgramHeader.p_flags & ELF::PF_R; + Segment.IsWriteable = ProgramHeader.p_flags & ELF::PF_W; + Segment.IsExecutable = ProgramHeader.p_flags & ELF::PF_X; + auto ActualStartAddress = TheELF.base() + ProgramHeader.p_offset; // If it's executable register it as a valid code area - if (ProgramHeader.p_flags & ELF::PF_X) { - ExecutableRanges.push_back(std::make_pair(ProgramHeader.p_vaddr, - EndAddress)); - + if (Segment.IsExecutable) { // We ignore possible p_filesz-p_memsz mismatches, zeros wouldn't be // useful code anyway ptc.mmap(static_cast(ProgramHeader.p_vaddr), @@ -150,14 +166,7 @@ void CodeGenerator::parseELF(object::ObjectFile *TheBinary, static_cast(ProgramHeader.p_filesz)); } - // Create name from start and size - std::stringstream NameStream; - NameStream << ".o_" - << (ProgramHeader.p_flags & ELF::PF_R ? "r" : "") - << (ProgramHeader.p_flags & ELF::PF_W ? "w" : "") - << (ProgramHeader.p_flags & ELF::PF_X ? "x" : "") - << "_0x" << std::hex << ProgramHeader.p_vaddr; - std::string Name = NameStream.str(); + std::string Name = Segment.generateName(); // Get data and size auto *DataType = ArrayType::get(Uint8Ty, @@ -182,26 +191,25 @@ void CodeGenerator::parseELF(object::ObjectFile *TheBinary, TheData = ConstantDataArray::get(Context, DataRef); } - // Check if it's writable - bool IsConstant = !(ProgramHeader.p_flags & ELF::PF_W); - // Create a new global variable - auto *GlobalDataVar = new GlobalVariable(*TheModule, - DataType, - IsConstant, - GlobalValue::InternalLinkage, - TheData, - ""); + Segment.Variable = new GlobalVariable(*TheModule, + DataType, + !Segment.IsWriteable, + GlobalValue::InternalLinkage, + TheData, + ""); // Force alignment to 1 and assign the variable to a specific section - GlobalDataVar->setAlignment(1); - GlobalDataVar->setSection(Name); + Segment.Variable->setAlignment(1); + Segment.Variable->setSection(Name); // Write the linking info CSV LinkingInfoStream << Name - << ",0x" << std::hex << ProgramHeader.p_vaddr - << ",0x" << std::hex << EndAddress + << ",0x" << std::hex << Segment.StartVirtualAddress + << ",0x" << std::hex << Segment.EndVirtualAddress << std::endl; + + Segments.push_back(Segment); } } @@ -533,10 +541,10 @@ void CodeGenerator::translate(uint64_t VirtualAddress, GlobalVariable *PCReg = Variables.getByEnvOffset(ptc.pc, "pc"); - JumpTargetManager JumpTargets(*TheModule, + JumpTargetManager JumpTargets(MainFunction, PCReg, - MainFunction, - ExecutableRanges); + SourceArchitecture, + Segments); JumpTargets.getBlockAt(VirtualAddress); std::tie(VirtualAddress, Entry) = JumpTargets.peek(); diff --git a/codegenerator.h b/codegenerator.h index cf0b9a78c..1bd06d00e 100644 --- a/codegenerator.h +++ b/codegenerator.h @@ -16,6 +16,7 @@ namespace llvm { class LLVMContext; class Function; +class GlobalVariable; class Module; class Value; class StructType; @@ -78,7 +79,7 @@ private: std::string OutputPath; std::unique_ptr Debug; llvm::object::OwningBinary BinaryHandle; - std::vector> ExecutableRanges; + std::vector Segments; uint64_t EntryPoint; unsigned OriginalInstrMDKind; diff --git a/jumptargetmanager.cpp b/jumptargetmanager.cpp index 7ad6bbf90..89e50d86b 100644 --- a/jumptargetmanager.cpp +++ b/jumptargetmanager.cpp @@ -16,8 +16,11 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Value.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" // Local includes +#include "revamb.h" #include "ir-helpers.h" #include "jumptargetmanager.h" @@ -70,18 +73,17 @@ bool JumpTargetsFromConstantsPass::runOnFunction(Function &F) { return false; } -JumpTargetManager::JumpTargetManager(Module& TheModule, +JumpTargetManager::JumpTargetManager(Function *TheFunction, Value *PCReg, - Function *TheFunction, - RangesVector& ExecutableRanges) : - TheModule(TheModule), + Architecture& SourceArchitecture, + std::vector& Segments) : + TheModule(*TheFunction->getParent()), Context(TheModule.getContext()), TheFunction(TheFunction), OriginalInstructionAddresses(), JumpTargets(), PCReg(PCReg), ExitTB(nullptr), - ExecutableRanges(ExecutableRanges), Dispatcher(nullptr), DispatcherSwitch(nullptr) { FunctionType *ExitTBTy = FunctionType::get(Type::getVoidTy(Context), @@ -89,6 +91,13 @@ JumpTargetManager::JumpTargetManager(Module& TheModule, false); ExitTB = cast(TheModule.getOrInsertFunction("exitTB", ExitTBTy)); createDispatcher(TheFunction, PCReg, true); + + for (auto& Segment : Segments) { + if (Segment.IsExecutable) { + ExecutableRanges.push_back(std::make_pair(Segment.StartVirtualAddress, + Segment.EndVirtualAddress)); + } + } } /// Handle a new program counter. We might already have a basic block for that diff --git a/jumptargetmanager.h b/jumptargetmanager.h index a427aa70a..3471bc898 100644 --- a/jumptargetmanager.h +++ b/jumptargetmanager.h @@ -43,10 +43,10 @@ public: public: using RangesVector = std::vector>; - JumpTargetManager(llvm::Module& TheModule, + JumpTargetManager(llvm::Function *TheFunction, llvm::Value *PCReg, - llvm::Function *TheFunction, - RangesVector& ExecutableRanges); + Architecture& SourceArchitecture, + std::vector& Segments); /// Handle a new program counter. We might already have a basic block for that /// program counter, or we could even have a translation for it. Return one @@ -131,7 +131,7 @@ private: std::vector Unexplored; llvm::Value *PCReg; llvm::Function *ExitTB; - RangesVector& ExecutableRanges; + RangesVector ExecutableRanges; llvm::BasicBlock *Dispatcher; llvm::SwitchInst *DispatcherSwitch; }; diff --git a/revamb.h b/revamb.h index 2ca4218e5..422ab13dd 100644 --- a/revamb.h +++ b/revamb.h @@ -9,6 +9,10 @@ # define QEMU_LIB_PATH "/usr/lib" #endif +namespace llvm { +class GlobalVariable; +}; + enum class DebugInfoType { None, OriginalAssembly, @@ -16,6 +20,17 @@ enum class DebugInfoType { LLVMIR }; +struct SegmentInfo { + std::string generateName(); + + llvm::GlobalVariable *Variable; + uint64_t StartVirtualAddress; + uint64_t EndVirtualAddress; + bool IsWriteable; + bool IsExecutable; + bool IsReadable; +}; + class Architecture { public: