diff --git a/ARM/ARMMachineInstructionRaiser.cpp b/ARM/ARMMachineInstructionRaiser.cpp index 1187abcd..79597705 100644 --- a/ARM/ARMMachineInstructionRaiser.cpp +++ b/ARM/ARMMachineInstructionRaiser.cpp @@ -29,7 +29,7 @@ ARMMachineInstructionRaiser::ARMMachineInstructionRaiser( MachineFunction &MF, const ModuleRaiser *MR, MCInstRaiser *MCIR) : MachineInstructionRaiser(MF, MR, MCIR), MachineRegInfo(MF.getRegInfo()) {} -bool ARMMachineInstructionRaiser::raiseMachineFunction() { +bool ARMMachineInstructionRaiser::raise() { const ARMModuleRaiser *ConstAMR = dyn_cast(MR); assert(ConstAMR != nullptr && "The ARM module raiser is not initialized!"); ARMModuleRaiser &AMR = const_cast(*ConstAMR); @@ -60,11 +60,6 @@ bool ARMMachineInstructionRaiser::raiseMachineFunction() { return true; } -bool ARMMachineInstructionRaiser::raise() { - return raiseMachineFunction(); - // return true; -} - int ARMMachineInstructionRaiser::getArgumentNumber(unsigned PReg) { // NYI assert(false && diff --git a/ARM/ARMMachineInstructionRaiser.h b/ARM/ARMMachineInstructionRaiser.h index 4d18fba7..389a718a 100644 --- a/ARM/ARMMachineInstructionRaiser.h +++ b/ARM/ARMMachineInstructionRaiser.h @@ -34,7 +34,6 @@ class ARMMachineInstructionRaiser : public MachineInstructionRaiser { std::vector JTList; private: - bool raiseMachineFunction(); // Commonly used LLVM data structures during this phase MachineRegisterInfo &MachineRegInfo; }; diff --git a/ARM/ARMModuleRaiser.cpp b/ARM/ARMModuleRaiser.cpp index 8f2a4e0b..bb891310 100644 --- a/ARM/ARMModuleRaiser.cpp +++ b/ARM/ARMModuleRaiser.cpp @@ -73,6 +73,10 @@ void ARMModuleRaiser::addRODataValueAt(Value *V, uint64_t Offset) const { GlobalRODataValues.emplace(Offset, V); } +bool ARMModuleRaiser::addPasses(PassManagerBase &PM) { + return true; +} + void registerARMModuleRaiser() { registerModuleRaiser(new ARMModuleRaiser()); } diff --git a/ARM/ARMModuleRaiser.h b/ARM/ARMModuleRaiser.h index cba92ef2..0e61e6db 100644 --- a/ARM/ARMModuleRaiser.h +++ b/ARM/ARMModuleRaiser.h @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_MCTOLL_ARM_ARMMODULERAISER_H -#define LLVM_TOOLS_LLVM_MCTOLL_ARM_ARMMODULERAISER_H +#ifndef LLVM_TOOLS_LLVM_MCTOLL_ARM_ARM_MODULE_RAISER_H +#define LLVM_TOOLS_LLVM_MCTOLL_ARM_ARM_MODULE_RAISER_H #include "Raiser/ModuleRaiser.h" @@ -30,23 +30,24 @@ class ARMModuleRaiser : public ModuleRaiser { // Create a new MachineFunctionRaiser object and add it to the list of // MachineFunction raiser objects of this module. MachineFunctionRaiser * - CreateAndAddMachineFunctionRaiser(Function *f, const ModuleRaiser *mr, - uint64_t start, uint64_t end) override; + CreateAndAddMachineFunctionRaiser(Function *Fn, const ModuleRaiser *MR, + uint64_t Start, uint64_t End) override; bool collectDynamicRelocations() override; + bool addPasses(PassManagerBase &PM) override; - void collectRodataInstAddr(uint64_t instAddr) { - InstArgCollect.push_back(instAddr); + void collectRodataInstAddr(uint64_t InstAddr) { + InstArgCollect.push_back(InstAddr); } - void fillInstArgMap(uint64_t rodataAddr, uint64_t argNum) { - InstArgNumMap[rodataAddr] = argNum; + void fillInstArgMap(uint64_t RodataAddr, uint64_t ArgNum) { + InstArgNumMap[RodataAddr] = ArgNum; } - void fillInstAddrFuncMap(uint64_t callAddr, Function *func) { - InstAddrFuncMap[callAddr] = func; + void fillInstAddrFuncMap(uint64_t CallAddr, Function *Fn) { + InstAddrFuncMap[CallAddr] = Fn; } - Function *getCallFunc(uint64_t callAddr) { return InstAddrFuncMap[callAddr]; } + Function *getCallFunc(uint64_t CallAddr) { return InstAddrFuncMap[CallAddr]; } // Get function arg number. uint64_t getFunctionArgNum(uint64_t); @@ -54,9 +55,9 @@ class ARMModuleRaiser : public ModuleRaiser { // Accoring call instruction to get the rodata instruction addr. uint64_t getArgNumInstrAddr(uint64_t); // Method to map syscall. - void setSyscallMapping(uint64_t idx, Function *fn) { SyscallMap[idx] = fn; } + void setSyscallMapping(uint64_t Idx, Function *Fn) { SyscallMap[Idx] = Fn; } - Function *getSyscallFunc(uint64_t idx) { return SyscallMap[idx]; } + Function *getSyscallFunc(uint64_t Idx) { return SyscallMap[Idx]; } const Value *getRODataValueAt(uint64_t Offset) const; @@ -86,4 +87,4 @@ class ARMModuleRaiser : public ModuleRaiser { extern "C" void registerARMModuleRaiser(); -#endif // LLVM_TOOLS_LLVM_MCTOLL_ARM_ARMMODULERAISER_H +#endif // LLVM_TOOLS_LLVM_MCTOLL_ARM_ARM_MODULE_RAISER_H diff --git a/Raiser/FunctionFilter.cpp b/Raiser/FunctionFilter.cpp index 2ecd24ce..a3d1a30d 100644 --- a/Raiser/FunctionFilter.cpp +++ b/Raiser/FunctionFilter.cpp @@ -262,7 +262,7 @@ void FunctionFilter::eraseFunctionBySymbol(StringRef &Sym, /// Read the function symbol set from the configuration file of filter /// functions. -bool FunctionFilter::readFilterFunctionConfigFile( +bool FunctionFilter::readFunctionFilterConfigFile( std::string &FunctionFilterFilename) { if (FunctionFilterFilename.size() == 0) @@ -362,3 +362,78 @@ void FunctionFilter::dump(FilterType FT) { }); } } + +/// Check if function is needs raising +bool FunctionFilter::checkFunctionFilter(StringRef &PrototypeStr, uint64_t Start) { + bool RaiseFunc = true; + // Check the symbol name whether it should be excluded or not. + // Check in a non-empty exclude list + if (!isFilterSetEmpty(FunctionFilter::FILTER_EXCLUDE)) { + FunctionFilter::FuncInfo *FI = findFuncInfoBySymbol( + PrototypeStr, FunctionFilter::FILTER_EXCLUDE); + if (FI != nullptr) { + // Record the function start index. + FI->StartIdx = Start; + // Skip raising this function symbol + RaiseFunc = false; + } + } + + if (!isFilterSetEmpty(FunctionFilter::FILTER_INCLUDE)) { + // Include list specified. Unless the current function symbol is + // specified in the include list, skip raising it. + RaiseFunc = false; + // Check the symbol name whether it should be included or not. + if (findFuncInfoBySymbol( + PrototypeStr, FunctionFilter::FILTER_INCLUDE) != nullptr) + RaiseFunc = true; + } + return RaiseFunc; +} + +/* + A list of symbol entries corresponding to CRT functions added by + the linker while creating an ELF executable. It is not necessary to + disassemble and translate these functions. +*/ + +static std::set ELFCRTSymbols = { + "call_weak_fn", + "deregister_tm_clones", + "__do_global_dtors_aux", + "__do_global_dtors_aux_fini_array_entry", + "_fini", + "frame_dummy", + "__frame_dummy_init_array_entry", + "_init", + "__init_array_end", + "__init_array_start", + "__libc_csu_fini", + "__libc_csu_init", + "register_tm_clones", + "_start", + "_dl_relocate_static_pie"}; + +/* + A list of symbol entries corresponding to CRT functions added by + the linker while creating an MachO executable. It is not necessary + to disassemble and translate these functions. +*/ + +static std::set MachOCRTSymbols = {"__mh_execute_header", + "dyld_stub_binder", "__text", + "__stubs", "__stub_helper"}; + +/// Check if function is CRT function. +bool FunctionFilter::isCRTFunction(const ObjectFile *Obj, StringRef &Sym) { + if (Obj->isELF()) { + return (ELFCRTSymbols.find(Sym) != ELFCRTSymbols.end()); + } + if (Obj->isMachO()) { + // If Symbol is not in the MachOCRTSymbol list return true indicating that + // this is a symbol of a function we are interested in disassembling and + // raising. + return (MachOCRTSymbols.find(Sym) != MachOCRTSymbols.end()); + } + return false; +} diff --git a/Raiser/FunctionFilter.h b/Raiser/FunctionFilter.h index 6525a44a..b0fa785b 100644 --- a/Raiser/FunctionFilter.h +++ b/Raiser/FunctionFilter.h @@ -18,10 +18,14 @@ #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/Module.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" namespace llvm { namespace mctoll { +using namespace object; + /// Class encapsulating lists of function specifications to be included and /// excluded along with methods to maintain and query the lists. class FunctionFilter { @@ -80,9 +84,13 @@ class FunctionFilter { /// Get the data type corresponding to type string. Type *getPrimitiveDataType(const StringRef &TypeStr); /// Read user-specified include and exclude functions from file - bool readFilterFunctionConfigFile(std::string &FunctionFilterFilename); + bool readFunctionFilterConfigFile(std::string &FunctionFilterFilename); /// Test if the list of specified list is empty. bool isFilterSetEmpty(FilterType); + /// Check if function is needs raising. + bool checkFunctionFilter(StringRef &PrototypeStr, uint64_t Start); + /// Check if function is CRT function. + bool isCRTFunction(const ObjectFile *Obj, StringRef &Sym); /// Dump the list of specified list; dump both include and exclude lists if no /// argument is specified. void dump(FilterType FT = FILTER_NONE); diff --git a/Raiser/ModuleRaiser.cpp b/Raiser/ModuleRaiser.cpp index 2bbd8c53..56820922 100644 --- a/Raiser/ModuleRaiser.cpp +++ b/Raiser/ModuleRaiser.cpp @@ -10,7 +10,11 @@ #include "ModuleRaiser.h" #include "MachineFunctionRaiser.h" #include "MachineInstructionRaiser.h" +#include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Debug.h" #include "llvm/Support/WithColor.h" @@ -230,8 +234,8 @@ bool ModuleRaiser::runMachineFunctionPasses() { return Success; } -// Get the MachineFunction associated with the placeholder -// function corresponding to raised function. +/// Get the MachineFunction associated with the placeholder +/// function corresponding to raised function. MachineFunction *ModuleRaiser::getMachineFunction(Function *RF) { auto V = PlaceholderRaisedFunctionMap.find(RF); assert(V != PlaceholderRaisedFunctionMap.end() && @@ -411,3 +415,573 @@ bool ModuleRaiser::changeRaisedFunctionReturnType(Function *TargetFunc, } return Changed; } + +static bool isArmElf(const ObjectFile *Obj) { + return (Obj->isELF() && + (Obj->getArch() == Triple::aarch64 || + Obj->getArch() == Triple::aarch64_be || + Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb || + Obj->getArch() == Triple::thumb || + Obj->getArch() == Triple::thumbeb)); +} + +static bool isAFunctionSymbol(const ObjectFile *Obj, SymbolInfoTy &Symbol) { + if (Obj->isELF()) { + return (Symbol.Type == ELF::STT_FUNC); + } + return false; +} + +static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) { + assert(Obj->isELF()); + auto SymbImpl = Sym.getRawDataRefImpl(); + if (auto *Elf32LEObj = dyn_cast(Obj)) { + auto SymbOrErr = Elf32LEObj->getSymbol(SymbImpl); + if (!SymbOrErr) + reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); + return SymbOrErr.get()->getType(); + } + if (auto *Elf64LEObj = dyn_cast(Obj)) { + auto SymbOrErr = Elf64LEObj->getSymbol(SymbImpl); + if (!SymbOrErr) + reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); + return SymbOrErr.get()->getType(); + } + if (auto *Elf32BEObj = dyn_cast(Obj)) { + auto SymbOrErr = Elf32BEObj->getSymbol(SymbImpl); + if (!SymbOrErr) + reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); + return SymbOrErr.get()->getType(); + } + if (auto *Elf64BEObj = dyn_cast(Obj)) { + auto SymbOrErr = Elf64BEObj->getSymbol(SymbImpl); + if (!SymbOrErr) + reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); + return SymbOrErr.get()->getType(); + } + llvm_unreachable("Unsupported binary format"); + // Keep the code analyzer happy + return ELF::STT_NOTYPE; +} + +template +static void +addDynamicElfSymbols(const ELFObjectFile *Obj, + std::map &AllSymbols) { + for (auto Symbol : Obj->getDynamicSymbolIterators()) { + uint8_t SymbolType = Symbol.getELFType(); + if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0) + continue; + + Expected AddressOrErr = Symbol.getAddress(); + if (!AddressOrErr) + reportError(AddressOrErr.takeError(), Obj->getFileName()); + uint64_t Address = *AddressOrErr; + + Expected Name = Symbol.getName(); + if (!Name) + reportError(Name.takeError(), Obj->getFileName()); + if (Name->empty()) + continue; + + Expected SectionOrErr = Symbol.getSection(); + if (!SectionOrErr) + reportError(SectionOrErr.takeError(), Obj->getFileName()); + section_iterator SecI = *SectionOrErr; + if (SecI == Obj->section_end()) + continue; + + AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); + } +} + +static void +addDynamicElfSymbols(const ObjectFile *Obj, + std::map &AllSymbols) { + assert(Obj->isELF()); + if (auto *Elf32LEObj = dyn_cast(Obj)) + addDynamicElfSymbols(Elf32LEObj, AllSymbols); + else if (auto *Elf64LEObj = dyn_cast(Obj)) + addDynamicElfSymbols(Elf64LEObj, AllSymbols); + else if (auto *Elf32BEObj = dyn_cast(Obj)) + addDynamicElfSymbols(Elf32BEObj, AllSymbols); + else if (auto *Elf64BEObj = dyn_cast(Obj)) + addDynamicElfSymbols(Elf64BEObj, AllSymbols); + else + llvm_unreachable("Unsupported binary format"); +} + +/// Load data from object file. +void ModuleRaiser::load(uint64_t StartAddress, uint64_t StopAddress, + SmallVector &FilteredSections) { + // Collect dynamic relocations. + collectDynamicRelocations(); + + // Create a mapping, RelocSecs = SectionRelocMap[S], where sections + // in RelocSecs contain the relocations for section S. + std::map> SectionRelocMap; + for (const SectionRef &Section : FilteredSections) { + Expected SecOrErr = Section.getRelocatedSection(); + if (!SecOrErr) { + break; + } + section_iterator Sec2 = *SecOrErr; + if (Sec2 != Obj->section_end()) + SectionRelocMap[*Sec2].push_back(Section); + } + + // Create a mapping from virtual address to symbol name. This is used to + // pretty print the symbols while disassembling. + std::map AllSymbols; + for (const SymbolRef &Symbol : Obj->symbols()) { + Expected AddressOrErr = Symbol.getAddress(); + if (!AddressOrErr) + reportError(AddressOrErr.takeError(), Obj->getFileName()); + uint64_t Address = *AddressOrErr; + + Expected Name = Symbol.getName(); + if (!Name) + reportError(Name.takeError(), Obj->getFileName()); + if (Name->empty()) + continue; + + Expected SectionOrErr = Symbol.getSection(); + if (!SectionOrErr) + reportError(SectionOrErr.takeError(), Obj->getFileName()); + section_iterator SecI = *SectionOrErr; + if (SecI == Obj->section_end()) + continue; + + uint8_t SymbolType = ELF::STT_NOTYPE; + if (Obj->isELF()) + SymbolType = getElfSymbolType(Obj, Symbol); + + AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); + } + if (AllSymbols.empty() && Obj->isELF()) + addDynamicElfSymbols(Obj, AllSymbols); + + // Sort all the symbols, this allows us to use a simple binary search to find + // a symbol near an address. + for (std::pair &SecSyms : AllSymbols) + array_pod_sort(SecSyms.second.begin(), SecSyms.second.end()); + + for (const SectionRef &Section : FilteredSections) { + if ((!Section.isText() || Section.isVirtual())) + continue; + + uint64_t SectionAddr = Section.getAddress(); + uint64_t SectSize = Section.getSize(); + if (!SectSize) + return; + + // Get the list of all the symbols in this section. + SectionSymbolsTy &Symbols = AllSymbols[Section]; + + // If the section has no symbol at the start, just insert a dummy one. + StringRef DummyName; + if (Symbols.empty() || Symbols[0].Addr != 0) { + Symbols.insert( + Symbols.begin(), + SymbolInfoTy(SectionAddr, DummyName, + Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT)); + } + + StringRef SectionName; + if (auto NameOrErr = Section.getName()) + SectionName = *NameOrErr; + else + consumeError(NameOrErr.takeError()); + + SmallString<40> Comments; + raw_svector_ostream CommentStream(Comments); + + StringRef BytesStr = + unwrapOrError(Section.getContents(), Obj->getFileName()); + ArrayRef Bytes(reinterpret_cast(BytesStr.data()), + BytesStr.size()); + + uint64_t Size; + uint64_t Index; + + // Create a mapping from virtual address to section. + std::vector> SectionAddresses; + for (SectionRef Sec : Obj->sections()) + SectionAddresses.emplace_back(Sec.getAddress(), Sec); + array_pod_sort(SectionAddresses.begin(), SectionAddresses.end()); + + // Linked executables (.exe and .dll files) typically don't include a real + // symbol table, but they might contain an export table. + if (const auto *COFFObj = dyn_cast(Obj)) { + for (const auto &ExportEntry : COFFObj->export_directories()) { + StringRef Name; + error(ExportEntry.getSymbolName(Name)); + if (Name.empty()) + continue; + + uint32_t RVA; + error(ExportEntry.getExportRVA(RVA)); + + uint64_t VA = COFFObj->getImageBase() + RVA; + auto Sec = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), VA, + [](uint64_t LHS, const std::pair &RHS) { + return LHS < RHS.first; + }); + if (Sec != SectionAddresses.begin()) + --Sec; + else + Sec = SectionAddresses.end(); + + if (Sec != SectionAddresses.end()) + AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE); + } + } + + std::vector DataMappingSymsAddr; + std::vector TextMappingSymsAddr; + if (isArmElf(Obj)) { + for (const auto &Symb : Symbols) { + uint64_t Address = Symb.Addr; + StringRef Name = Symb.Name; + if (Name.startswith("$d")) + DataMappingSymsAddr.push_back(Address - SectionAddr); + if (Name.startswith("$x")) + TextMappingSymsAddr.push_back(Address - SectionAddr); + if (Name.startswith("$a")) + TextMappingSymsAddr.push_back(Address - SectionAddr); + if (Name.startswith("$t")) + TextMappingSymsAddr.push_back(Address - SectionAddr); + } + } + + std::sort(DataMappingSymsAddr.begin(), DataMappingSymsAddr.end()); + std::sort(TextMappingSymsAddr.begin(), TextMappingSymsAddr.end()); + + // Build a map of relocations (if they exist in the binary) of text + // section whose instructions are being raised. + collectTextSectionRelocs(Section); + + // Set used to record all branch targets of a function. + std::set BranchTargetSet; + MachineFunctionRaiser *CurMFRaiser = nullptr; + + // Disassemble symbol by symbol and fill MR->MFRaiserVector by + // MachineFunctionRaiser for each function + LLVM_DEBUG(dbgs() << "BEGIN Disassembly of Functions in Section : " + << SectionName.data() << "\n"); + for (unsigned SI = 0, SSize = Symbols.size(); SI != SSize; ++SI) { + uint64_t Start = Symbols[SI].Addr - SectionAddr; + // The end is either the section end or the beginning of the next + // symbol. + uint64_t End = + (SI == SSize - 1) ? SectSize : Symbols[SI + 1].Addr - SectionAddr; + // Don't try to disassemble beyond the end of section contents. + if (End > SectSize) + End = SectSize; + // If this symbol has the same address as the next symbol, then skip it. + if (Start >= End) + continue; + + // Check if we need to skip symbol + // Skip if the symbol's data is not between StartAddress and StopAddress + if (End + SectionAddr < StartAddress || + Start + SectionAddr > StopAddress) { + continue; + } + + // Stop disassembly at the stop address specified + if (End + SectionAddr > StopAddress) + End = StopAddress - SectionAddr; + + if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) { + // make size 4 bytes folded + End = Start + ((End - Start) & ~0x3ull); + if (Symbols[SI].Type == ELF::STT_AMDGPU_HSA_KERNEL) { + // skip amd_kernel_code_t at the begining of kernel symbol (256 bytes) + Start += 256; + } + if (SI == SSize - 1 || + Symbols[SI + 1].Type == ELF::STT_AMDGPU_HSA_KERNEL) { + // cut trailing zeroes at the end of kernel + // cut up to 256 bytes + const uint64_t EndAlign = 256; + const auto Limit = End - (std::min)(EndAlign, End - Start); + while (End > Limit && *reinterpret_cast( + &Bytes[End - 4]) == 0) + End -= 4; + } + } + + if (isAFunctionSymbol(Obj, Symbols[SI])) { + auto &SymStr = Symbols[SI].Name; + + // Check the symbol name by the function filter. + if (!FFT->checkFunctionFilter(SymStr, Start)) + continue; + + // If Symbol is in the CRTSymbol list return this is a symbol of a + // function we are not interested in disassembling and raising. + if (FFT->isCRTFunction(Obj, SymStr)) + continue; + + // Note that since LLVM infrastructure was built to be used to build a + // conventional compiler pipeline, MachineFunction is built well after + // Function object was created and populated fully. Hence, creation of + // a Function object is necessary to build MachineFunction. + // However, in a raiser, we are conceptually walking the traditional + // compiler pipeline backwards. So we build MachineFunction from + // the binary before building Function object. Given the dependency, + // build a placeholder Function object to allow for building the + // MachineFunction object. + // This Function object is NOT populated when raising MachineFunction + // abstraction of the binary function. Instead, a new Function is + // created using the LLVMContext and name of this Function object. + FunctionType *FTy = FunctionType::get(Type::getVoidTy(M->getContext()), false); + StringRef FunctionName(Symbols[SI].Name); + // Strip leading underscore if the binary is MachO + if (Obj->isMachO()) { + FunctionName.consume_front("_"); + } + Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, + FunctionName, M); + + // New function symbol encountered. Record all targets collected to + // current MachineFunctionRaiser before we start parsing the new + // function bytes. + CurMFRaiser = getCurrentMachineFunctionRaiser(); + for (auto TargetIdx : BranchTargetSet) { + assert(CurMFRaiser != nullptr && + "Encountered uninitialized MachineFunction raiser object"); + CurMFRaiser->getMCInstRaiser()->addTarget(TargetIdx); + } + + // Clear the set used to record all branch targets of this function. + BranchTargetSet.clear(); + // Create a new MachineFunction raiser + CurMFRaiser = + CreateAndAddMachineFunctionRaiser(Func, this, Start, End); + LLVM_DEBUG(dbgs() << "\nFunction " << Symbols[SI].Name << ":\n"); + } else { + // Continue using to the most recent MachineFunctionRaiser + // Get current MachineFunctionRaiser + CurMFRaiser = getCurrentMachineFunctionRaiser(); + // assert(curMFRaiser != nullptr && "Current Machine Function Raiser not + // initialized"); + if (CurMFRaiser == nullptr) { + // At this point in the instruction stream, we do not have a function + // symbol to which the bytes being parsed can be made part of. So skip + // parsing the bytes of this symbol. + continue; + } + + // Adjust function end to represent the addition of the content of the + // current symbol. This represents a situation where we have discovered + // bytes (most likely data bytes) that belong to the most recent + // function being parsed. + MCInstRaiser *InstRaiser = CurMFRaiser->getMCInstRaiser(); + if (InstRaiser->getFuncEnd() < End) { + assert(InstRaiser->adjustFuncEnd(End) && + "Unable to adjust function end value"); + } + } + + // Get the associated MCInstRaiser + MCInstRaiser *InstRaiser = CurMFRaiser->getMCInstRaiser(); + + // Start new basic block at the symbol. + BranchTargetSet.insert(Start); + + for (Index = Start; Index < End; Index += Size) { + MCInst Inst; + + if (Index + SectionAddr < StartAddress || + Index + SectionAddr > StopAddress) { + // skip byte by byte till StartAddress is reached + Size = 1; + continue; + } + + // AArch64 ELF binaries can interleave data and text in the + // same section. We rely on the markers introduced to + // understand what we need to dump. If the data marker is within a + // function, it is denoted as a word/short etc + if (isArmElf(Obj) && Symbols[SI].Type != ELF::STT_OBJECT) { + uint64_t Stride = 0; + + auto DAI = std::lower_bound(DataMappingSymsAddr.begin(), + DataMappingSymsAddr.end(), Index); + if (DAI != DataMappingSymsAddr.end() && *DAI == Index) { + // Switch to data. + while (Index < End) { + if (Index + 4 <= End) { + Stride = 4; + uint32_t Data = 0; + if (Obj->isLittleEndian()) { + const auto *const Word = + reinterpret_cast( + Bytes.data() + Index); + Data = *Word; + } else { + const auto *const Word = + reinterpret_cast(Bytes.data() + + Index); + Data = *Word; + } + InstRaiser->addMCInstOrData(Index, Data); + } else if (Index + 2 <= End) { + Stride = 2; + uint16_t Data = 0; + if (Obj->isLittleEndian()) { + const auto *const Short = + reinterpret_cast( + Bytes.data() + Index); + Data = *Short; + } else { + const auto *const Short = + reinterpret_cast(Bytes.data() + + Index); + Data = *Short; + } + InstRaiser->addMCInstOrData(Index, Data); + } else { + Stride = 1; + InstRaiser->addMCInstOrData(Index, Bytes.slice(Index, 1)[0]); + } + Index += Stride; + + auto TAI = std::lower_bound(TextMappingSymsAddr.begin(), + TextMappingSymsAddr.end(), Index); + if (TAI != TextMappingSymsAddr.end() && *TAI == Index) + break; + } + } + } + + // If there is a data symbol inside an ELF text section and we are + // only disassembling text, we are in a situation where we must print + // the data and not disassemble it. + // TODO : Get rid of the following code in the if-block. + if (Obj->isELF() && Symbols[SI].Type == ELF::STT_OBJECT && + Section.isText()) { + // parse data up to 8 bytes at a time + uint8_t AsciiData[9] = {'\0'}; + uint8_t Byte; + int NumBytes = 0; + + for (Index = Start; Index < End; Index += 1) { + if (((SectionAddr + Index) < StartAddress) || + ((SectionAddr + Index) > StopAddress)) + continue; + if (NumBytes == 0) { + outs() << format("%8" PRIx64 ":", SectionAddr + Index); + outs() << "\t"; + } + Byte = Bytes.slice(Index)[0]; + outs() << format(" %02x", Byte); + AsciiData[NumBytes] = isprint(Byte) ? Byte : '.'; + + uint8_t IndentOffset = 0; + NumBytes++; + if (Index == End - 1 || NumBytes > 8) { + // Indent the space for less than 8 bytes data. + // 2 spaces for byte and one for space between bytes + IndentOffset = 3 * (8 - NumBytes); + for (int Excess = 8 - NumBytes; Excess < 8; Excess++) + AsciiData[Excess] = '\0'; + NumBytes = 8; + } + if (NumBytes == 8) { + AsciiData[8] = '\0'; + outs() << std::string(IndentOffset, ' ') << " "; + outs() << reinterpret_cast(AsciiData); + outs() << '\n'; + NumBytes = 0; + } + } + } + + if (Index >= End) + break; + + // Disassemble a real instruction or a data + bool Disassembled = DisAsm->getInstruction( + Inst, Size, Bytes.slice(Index), SectionAddr + Index, CommentStream); + if (Size == 0) + Size = 1; + + if (!Disassembled) { + errs() << "**** Warning: Failed to decode instruction\n"; + errs() << format("%8" PRIx64 ":", SectionAddr + Index); + errs() << "\t"; + dumpBytes(Bytes, errs()); + errs() << CommentStream.str(); + Comments.clear(); + errs() << "\n"; + } + + // Add MCInst to the list if all instructions were decoded + // successfully till now. Else, do not bother adding since no attempt + // will be made to raise this function. + if (Disassembled) { + InstRaiser->addMCInstOrData(Index, Inst); + + // Find branch target and record it. Call targets are not + // recorded as they are not needed to build per-function CFG. + if (MIA && MIA->isBranch(Inst)) { + uint64_t BranchTarget; + if (MIA->evaluateBranch(Inst, Index, Size, BranchTarget)) { + // In a relocatable object, the target's section must reside in + // the same section as the call instruction, or it is accessed + // through a relocation. + // + // In a non-relocatable object, the target may be in any + // section. + // + // N.B. We don't walk the relocations in the relocatable case + // yet. + if (!Obj->isRelocatableObject()) { + auto SectionAddress = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), + BranchTarget, + [](uint64_t LHS, + const std::pair &RHS) { + return LHS < RHS.first; + }); + if (SectionAddress != SectionAddresses.begin()) { + --SectionAddress; + } + } + // Add the index Target to target indices set. + BranchTargetSet.insert(BranchTarget); + } + + // Mark the next instruction as a target, if it is not beyond the + // function end + uint64_t FallThruIndex = Index + Size; + if (FallThruIndex < End) { + BranchTargetSet.insert(FallThruIndex); + } + } + } + } + FFT->eraseFunctionBySymbol(Symbols[SI].Name, + FunctionFilter::FILTER_INCLUDE); + } + LLVM_DEBUG(dbgs() << "END Disassembly of Functions in Section : " + << SectionName.data() << "\n"); + + // Record all targets of the last function parsed + CurMFRaiser = getCurrentMachineFunctionRaiser(); + for (auto TargetIdx : BranchTargetSet) + CurMFRaiser->getMCInstRaiser()->addTarget(TargetIdx); + + runMachineFunctionPasses(); + + if (!FFT->isFilterSetEmpty(FunctionFilter::FILTER_INCLUDE)) { + errs() << "***** WARNING: The following include filter symbol(s) are not " + "found :\n"; + FFT->dump(FunctionFilter::FILTER_INCLUDE); + } + } +} diff --git a/Raiser/ModuleRaiser.h b/Raiser/ModuleRaiser.h index 4c341180..27c2e25f 100644 --- a/Raiser/ModuleRaiser.h +++ b/Raiser/ModuleRaiser.h @@ -94,7 +94,6 @@ class ModuleRaiser { /// Insert the map of raised function R to place-holder function PH pointer /// that inturn has the to corresponding MachineFunction. - bool insertPlaceholderRaisedFunctionMap(Function *R, Function *PH) { auto V = PlaceholderRaisedFunctionMap.insert(std::make_pair(R, PH)); return V.second; @@ -103,6 +102,8 @@ class ModuleRaiser { bool collectTextSectionRelocs(const SectionRef &); virtual bool collectDynamicRelocations() = 0; + /// Get the MachineFunction associated with the placeholder + /// function corresponding to raised function. MachineFunction *getMachineFunction(Function *); // Member getters @@ -145,8 +146,18 @@ class ModuleRaiser { } /// Get the function filter for current Module. FunctionFilter *getFunctionFilter() const { return FFT; } + /// Read user-specified include and exclude functions from file. + bool readFunctionFilterConfigFile(std::string &FunctionFilterFilename) { + return FFT->readFunctionFilterConfigFile(FunctionFilterFilename); + } /// Get the current architecture type. Triple::ArchType getArch() const { return Arch; } + /// Load data from object file. + void load(uint64_t StartAddress, uint64_t StopAddress, + SmallVector &FilteredSections); + /// Add raise passes to the specified pass manager. + virtual bool + addPasses(PassManagerBase &PM) { return true; } protected: /// A sequential list of MachineFunctionRaiser objects created diff --git a/X86/X86MachineInstructionRaiser.cpp b/X86/X86MachineInstructionRaiser.cpp index 7f08bf1b..78ade92e 100644 --- a/X86/X86MachineInstructionRaiser.cpp +++ b/X86/X86MachineInstructionRaiser.cpp @@ -11,10 +11,10 @@ // //===----------------------------------------------------------------------===// -#include "X86MachineInstructionRaiser.h" #include "IncludedFileInfo.h" #include "Raiser/MachineFunctionRaiser.h" #include "X86InstrBuilder.h" +#include "X86MachineInstructionRaiser.h" #include "X86ModuleRaiser.h" #include "X86RaisedValueTracker.h" #include "X86RegisterUtils.h" @@ -5582,9 +5582,8 @@ bool X86MachineInstructionRaiser::raiseMachineInstr(MachineInstr &MI) { return Success; } -// Raise MachineInstr in MachineFunction to MachineInstruction - -bool X86MachineInstructionRaiser::raiseMachineFunction() { +/// Raise MachineInstr in MachineFunction to MachineInstruction +bool X86MachineInstructionRaiser::raise() { Function *CurFunction = getRaisedFunction(); LLVMContext &Ctx(CurFunction->getContext()); @@ -5660,28 +5659,11 @@ bool X86MachineInstructionRaiser::raiseMachineFunction() { } } } - return createFunctionStackFrame() && raiseBranchMachineInstrs() && - handleUnpromotedReachingDefs() && handleUnterminatedBlocks(); -} - -bool X86MachineInstructionRaiser::raise() { - bool Success = raiseMachineFunction(); - if (Success) { - // Delete empty basic blocks with no predecessors - SmallVector UnConnectedBEmptyBs; - for (BasicBlock &BB : *RaisedFunction) { - if (BB.hasNPredecessors(0) && BB.size() == 0) - UnConnectedBEmptyBs.push_back(&BB); - } - - DeleteDeadBlocks(ArrayRef(UnConnectedBEmptyBs)); - - // Unify all exit nodes of the raised function - legacy::PassManager PM; - PM.add(createUnifyFunctionExitNodesPass()); - PM.run(*(RaisedFunction->getParent())); - } - return Success; + return createFunctionStackFrame() && + raiseBranchMachineInstrs() && + handleUnpromotedReachingDefs() && + handleUnterminatedBlocks() && + deleteEmptyBlocks(); } // NOTE : The following X86ModuleRaiser class function is defined here as diff --git a/X86/X86MachineInstructionRaiser.h b/X86/X86MachineInstructionRaiser.h index 5a850d11..7d630dad 100644 --- a/X86/X86MachineInstructionRaiser.h +++ b/X86/X86MachineInstructionRaiser.h @@ -109,7 +109,6 @@ class X86MachineInstructionRaiser : public MachineInstructionRaiser { std::vector &) override; Value *getRegOrArgValue(unsigned PReg, int MBBNo) override; - bool raiseMachineFunction(); FunctionType *getRaisedFunctionPrototype() override; // This raises MachineInstr to MachineInstruction bool raiseMachineInstr(MachineInstr &); @@ -206,6 +205,7 @@ class X86MachineInstructionRaiser : public MachineInstructionRaiser { bool handleUnpromotedReachingDefs(); bool handleUnterminatedBlocks(); + bool deleteEmptyBlocks(); const MachineInstr * getPhysRegDefiningInstInBlock(int PhysReg, const MachineInstr *StartMI, diff --git a/X86/X86MachineInstructionRaiserUtils.cpp b/X86/X86MachineInstructionRaiserUtils.cpp index fd87b342..926f95ba 100644 --- a/X86/X86MachineInstructionRaiserUtils.cpp +++ b/X86/X86MachineInstructionRaiserUtils.cpp @@ -1069,7 +1069,7 @@ bool X86MachineInstructionRaiser::handleUnpromotedReachingDefs() { return true; } -// Check for unterminated basic blocks. +/// Check for unterminated basic blocks. bool X86MachineInstructionRaiser::handleUnterminatedBlocks() { auto *RaisedFunction = getRaisedFunction(); LLVMContext &Ctx(RaisedFunction->getContext()); @@ -1094,6 +1094,18 @@ bool X86MachineInstructionRaiser::handleUnterminatedBlocks() { return true; } +/// Delete empty basic blocks with no predecessors +bool X86MachineInstructionRaiser::deleteEmptyBlocks() { + SmallVector UnConnectedBEmptyBs; + for (BasicBlock &BB : *RaisedFunction) { + if (BB.hasNPredecessors(0) && BB.size() == 0) + UnConnectedBEmptyBs.push_back(&BB); + } + + DeleteDeadBlocks(ArrayRef(UnConnectedBEmptyBs)); + return true; +} + // Create a single stack frame based on stack allocations of the Function. // The single stack frame thus created is expected to preserve the frame layout // of the source binary - as represented by the various stack allocations. This diff --git a/X86/X86ModuleRaiser.cpp b/X86/X86ModuleRaiser.cpp index ac2b5e93..eea78b06 100644 --- a/X86/X86ModuleRaiser.cpp +++ b/X86/X86ModuleRaiser.cpp @@ -12,7 +12,9 @@ //===----------------------------------------------------------------------===// #include "X86ModuleRaiser.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h" using namespace llvm; using namespace llvm::mctoll; @@ -34,6 +36,11 @@ bool X86ModuleRaiser::collectDynamicRelocations() { return true; } +bool X86ModuleRaiser::addPasses(PassManagerBase &PM) { + PM.add(createUnifyFunctionExitNodesPass()); + return true; +} + void registerX86ModuleRaiser() { registerModuleRaiser(new X86ModuleRaiser()); } diff --git a/X86/X86ModuleRaiser.h b/X86/X86ModuleRaiser.h index a0cbac28..6d32175c 100644 --- a/X86/X86ModuleRaiser.h +++ b/X86/X86ModuleRaiser.h @@ -31,6 +31,7 @@ class X86ModuleRaiser : public ModuleRaiser { CreateAndAddMachineFunctionRaiser(Function *F, const ModuleRaiser *MR, uint64_t Start, uint64_t End) override; bool collectDynamicRelocations() override; + bool addPasses(PassManagerBase &PM) override; }; } // end namespace mctoll diff --git a/llvm-mctoll.cpp b/llvm-mctoll.cpp index ecea0fb5..99eab904 100644 --- a/llvm-mctoll.cpp +++ b/llvm-mctoll.cpp @@ -191,74 +191,6 @@ struct RunPassOption { }; } // namespace -namespace { -typedef std::function FilterPredicate; - -class SectionFilterIterator { -public: - SectionFilterIterator(FilterPredicate P, - llvm::object::section_iterator const &I, - llvm::object::section_iterator const &E) - : Predicate(std::move(P)), Iterator(I), End(E) { - scanPredicate(); - } - const llvm::object::SectionRef &operator*() const { return *Iterator; } - SectionFilterIterator &operator++() { - ++Iterator; - scanPredicate(); - return *this; - } - bool operator!=(SectionFilterIterator const &Other) const { - return Iterator != Other.Iterator; - } - -private: - void scanPredicate() { - while (Iterator != End && !Predicate(*Iterator)) { - ++Iterator; - } - } - FilterPredicate Predicate; - llvm::object::section_iterator Iterator; - llvm::object::section_iterator End; -}; - -class SectionFilter { -public: - SectionFilter(FilterPredicate P, llvm::object::ObjectFile const &O) - : Predicate(std::move(P)), Object(O) {} - SectionFilterIterator begin() { - return SectionFilterIterator(Predicate, Object.section_begin(), - Object.section_end()); - } - SectionFilterIterator end() { - return SectionFilterIterator(Predicate, Object.section_end(), - Object.section_end()); - } - -private: - FilterPredicate Predicate; - llvm::object::ObjectFile const &Object; -}; -SectionFilter toolSectionFilter(llvm::object::ObjectFile const &O) { - return SectionFilter( - [](llvm::object::SectionRef const &S) { - if (FilterSections.empty()) - return true; - llvm::StringRef String; - if (auto NameOrErr = S.getName()) - String = *NameOrErr; - else { - consumeError(NameOrErr.takeError()); - return false; - } - - return is_contained(FilterSections, String); - }, - O); -} -} // namespace - static const Target *getTarget(const ObjectFile *Obj = nullptr) { // Figure out the target triple. llvm::Triple TheTriple("unknown-unknown-unknown"); @@ -391,43 +323,6 @@ static bool addPass(PassManagerBase &PM, StringRef Argv0, StringRef PassName, return false; } -bool mctoll::RelocAddressLess(RelocationRef A, RelocationRef B) { - return A.getOffset() < B.getOffset(); -} - -namespace { -static bool isArmElf(const ObjectFile *Obj) { - return (Obj->isELF() && - (Obj->getArch() == Triple::aarch64 || - Obj->getArch() == Triple::aarch64_be || - Obj->getArch() == Triple::arm || Obj->getArch() == Triple::armeb || - Obj->getArch() == Triple::thumb || - Obj->getArch() == Triple::thumbeb)); -} - -class PrettyPrinter { -public: - virtual ~PrettyPrinter() {} - virtual void printInst(MCInstPrinter &IP, const MCInst *MI, - ArrayRef Bytes, uint64_t Address, - raw_ostream &OS, StringRef Annot, - MCSubtargetInfo const &STI) { - OS << format("%8" PRIx64 ":", Address); - OS << "\t"; - dumpBytes(Bytes, OS); - if (MI) - IP.printInst(MI, 0, "", STI, OS); - else - OS << " "; - } -}; -PrettyPrinter PrettyPrinterInst; - -PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { - return PrettyPrinterInst; -} -} // namespace - bool mctoll::isRelocAddressLess(RelocationRef A, RelocationRef B) { return A.getOffset() < B.getOffset(); } @@ -551,118 +446,6 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, return std::error_code(); } -static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) { - assert(Obj->isELF()); - auto SymbImpl = Sym.getRawDataRefImpl(); - if (auto *Elf32LEObj = dyn_cast(Obj)) { - auto SymbOrErr = Elf32LEObj->getSymbol(SymbImpl); - if (!SymbOrErr) - reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); - return SymbOrErr.get()->getType(); - } - if (auto *Elf64LEObj = dyn_cast(Obj)) { - auto SymbOrErr = Elf64LEObj->getSymbol(SymbImpl); - if (!SymbOrErr) - reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); - return SymbOrErr.get()->getType(); - } - if (auto *Elf32BEObj = dyn_cast(Obj)) { - auto SymbOrErr = Elf32BEObj->getSymbol(SymbImpl); - if (!SymbOrErr) - reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); - return SymbOrErr.get()->getType(); - } - if (auto *Elf64BEObj = dyn_cast(Obj)) { - auto SymbOrErr = Elf64BEObj->getSymbol(SymbImpl); - if (!SymbOrErr) - reportError(SymbOrErr.takeError(), "ELF32 symbol not found"); - return SymbOrErr.get()->getType(); - } - llvm_unreachable("Unsupported binary format"); - // Keep the code analyzer happy - return ELF::STT_NOTYPE; -} - -template -static void -addDynamicElfSymbols(const ELFObjectFile *Obj, - std::map &AllSymbols) { - for (auto Symbol : Obj->getDynamicSymbolIterators()) { - uint8_t SymbolType = Symbol.getELFType(); - if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0) - continue; - - Expected AddressOrErr = Symbol.getAddress(); - if (!AddressOrErr) - reportError(AddressOrErr.takeError(), Obj->getFileName()); - uint64_t Address = *AddressOrErr; - - Expected Name = Symbol.getName(); - if (!Name) - reportError(Name.takeError(), Obj->getFileName()); - if (Name->empty()) - continue; - - Expected SectionOrErr = Symbol.getSection(); - if (!SectionOrErr) - reportError(SectionOrErr.takeError(), Obj->getFileName()); - section_iterator SecI = *SectionOrErr; - if (SecI == Obj->section_end()) - continue; - - AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); - } -} - -static void -addDynamicElfSymbols(const ObjectFile *Obj, - std::map &AllSymbols) { - assert(Obj->isELF()); - if (auto *Elf32LEObj = dyn_cast(Obj)) - addDynamicElfSymbols(Elf32LEObj, AllSymbols); - else if (auto *Elf64LEObj = dyn_cast(Obj)) - addDynamicElfSymbols(Elf64LEObj, AllSymbols); - else if (auto *Elf32BEObj = dyn_cast(Obj)) - addDynamicElfSymbols(Elf32BEObj, AllSymbols); - else if (auto *Elf64BEObj = dyn_cast(Obj)) - addDynamicElfSymbols(Elf64BEObj, AllSymbols); - else - llvm_unreachable("Unsupported binary format"); -} - -/* - A list of symbol entries corresponding to CRT functions added by - the linker while creating an ELF executable. It is not necessary to - disassemble and translate these functions. -*/ - -static std::set ELFCRTSymbols = { - "call_weak_fn", - "deregister_tm_clones", - "__do_global_dtors_aux", - "__do_global_dtors_aux_fini_array_entry", - "_fini", - "frame_dummy", - "__frame_dummy_init_array_entry", - "_init", - "__init_array_end", - "__init_array_start", - "__libc_csu_fini", - "__libc_csu_init", - "register_tm_clones", - "_start", - "_dl_relocate_static_pie"}; - -/* - A list of symbol entries corresponding to CRT functions added by - the linker while creating an MachO executable. It is not necessary - to disassemble and translate these functions. -*/ - -static std::set MachOCRTSymbols = {"__mh_execute_header", - "dyld_stub_binder", "__text", - "__stubs", "__stub_helper"}; - /* A list of sections whose contents are to be disassembled as code */ @@ -679,19 +462,6 @@ static std::set MachOSectionsToDisassemble = {}; table. For now assuming global linkage */ -static bool isAFunctionSymbol(const ObjectFile *Obj, SymbolInfoTy &Symbol) { - if (Obj->isELF()) { - return (Symbol.Type == ELF::STT_FUNC); - } - if (Obj->isMachO()) { - // If Symbol is not in the MachOCRTSymbol list return true indicating that - // this is a symbol of a function we are interested in disassembling and - // raising. - return (MachOCRTSymbols.find(Symbol.Name) == MachOCRTSymbols.end()); - } - return false; -} - #define MODULE_RAISER(TargetName) \ extern "C" void register##TargetName##ModuleRaiser(); #include "Raisers.def" @@ -753,7 +523,6 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { reportError(Obj->getFileName(), "no instruction printer for target " + TripleName); IP->setPrintImmHex(PrintImmHex); - PrettyPrinter &PIP = selectPrettyPrinter(Triple(TripleName)); LLVMContext LlvmCtx; std::unique_ptr Target( @@ -780,513 +549,36 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { MIA.get(), MII.get(), MRI.get(), IP.get(), Obj, DisAsm.get()); - // Collect dynamic relocations. - MR->collectDynamicRelocations(); - - // Create a mapping, RelocSecs = SectionRelocMap[S], where sections - // in RelocSecs contain the relocations for section S. - std::error_code EC; - std::map> SectionRelocMap; - for (const SectionRef &Section : toolSectionFilter(*Obj)) { - Expected SecOrErr = Section.getRelocatedSection(); - if (!SecOrErr) { - break; - } - section_iterator Sec2 = *SecOrErr; - if (Sec2 != Obj->section_end()) - SectionRelocMap[*Sec2].push_back(Section); - } - - // Create a mapping from virtual address to symbol name. This is used to - // pretty print the symbols while disassembling. - std::map AllSymbols; - for (const SymbolRef &Symbol : Obj->symbols()) { - Expected AddressOrErr = Symbol.getAddress(); - if (!AddressOrErr) - reportError(AddressOrErr.takeError(), Obj->getFileName()); - uint64_t Address = *AddressOrErr; - - Expected Name = Symbol.getName(); - if (!Name) - reportError(Name.takeError(), Obj->getFileName()); - if (Name->empty()) - continue; - - Expected SectionOrErr = Symbol.getSection(); - if (!SectionOrErr) - reportError(SectionOrErr.takeError(), Obj->getFileName()); - section_iterator SecI = *SectionOrErr; - if (SecI == Obj->section_end()) - continue; - - uint8_t SymbolType = ELF::STT_NOTYPE; - if (Obj->isELF()) - SymbolType = getElfSymbolType(Obj, Symbol); - - AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); - } - if (AllSymbols.empty() && Obj->isELF()) - addDynamicElfSymbols(Obj, AllSymbols); - - // Create a mapping from virtual address to section. - std::vector> SectionAddresses; - for (SectionRef Sec : Obj->sections()) - SectionAddresses.emplace_back(Sec.getAddress(), Sec); - array_pod_sort(SectionAddresses.begin(), SectionAddresses.end()); - - // Linked executables (.exe and .dll files) typically don't include a real - // symbol table, but they might contain an export table. - if (const auto *COFFObj = dyn_cast(Obj)) { - for (const auto &ExportEntry : COFFObj->export_directories()) { - StringRef Name; - error(ExportEntry.getSymbolName(Name)); - if (Name.empty()) - continue; - - uint32_t RVA; - error(ExportEntry.getExportRVA(RVA)); - - uint64_t VA = COFFObj->getImageBase() + RVA; - auto Sec = std::upper_bound( - SectionAddresses.begin(), SectionAddresses.end(), VA, - [](uint64_t LHS, const std::pair &RHS) { - return LHS < RHS.first; - }); - if (Sec != SectionAddresses.begin()) - --Sec; - else - Sec = SectionAddresses.end(); - - if (Sec != SectionAddresses.end()) - AllSymbols[Sec->second].emplace_back(VA, Name, ELF::STT_NOTYPE); + if (!FilterConfigFileName.empty()) { + if (!MR->readFunctionFilterConfigFile(FilterConfigFileName)) { + dbgs() << "Unable to read function filter configuration file " + << FilterConfigFileName << ". Ignoring\n"; } } - // Sort all the symbols, this allows us to use a simple binary search to find - // a symbol near an address. - for (std::pair &SecSyms : AllSymbols) - array_pod_sort(SecSyms.second.begin(), SecSyms.second.end()); - - for (const SectionRef &Section : toolSectionFilter(*Obj)) { - if ((!Section.isText() || Section.isVirtual())) - continue; - - StringRef SectionName; - if (auto NameOrErr = Section.getName()) - SectionName = *NameOrErr; - else - consumeError(NameOrErr.takeError()); - - uint64_t SectionAddr = Section.getAddress(); - uint64_t SectSize = Section.getSize(); - if (!SectSize) - continue; - - // Get the list of all the symbols in this section. - SectionSymbolsTy &Symbols = AllSymbols[Section]; - std::vector DataMappingSymsAddr; - std::vector TextMappingSymsAddr; - if (isArmElf(Obj)) { - for (const auto &Symb : Symbols) { - uint64_t Address = Symb.Addr; - StringRef Name = Symb.Name; - if (Name.startswith("$d")) - DataMappingSymsAddr.push_back(Address - SectionAddr); - if (Name.startswith("$x")) - TextMappingSymsAddr.push_back(Address - SectionAddr); - if (Name.startswith("$a")) - TextMappingSymsAddr.push_back(Address - SectionAddr); - if (Name.startswith("$t")) - TextMappingSymsAddr.push_back(Address - SectionAddr); - } - } - - std::sort(DataMappingSymsAddr.begin(), DataMappingSymsAddr.end()); - std::sort(TextMappingSymsAddr.begin(), TextMappingSymsAddr.end()); - - // If the section has no symbol at the start, just insert a dummy one. - StringRef DummyName; - if (Symbols.empty() || Symbols[0].Addr != 0) { - Symbols.insert( - Symbols.begin(), - SymbolInfoTy(SectionAddr, DummyName, - Section.isText() ? ELF::STT_FUNC : ELF::STT_OBJECT)); - } - - SmallString<40> Comments; - raw_svector_ostream CommentStream(Comments); - - StringRef BytesStr = - unwrapOrError(Section.getContents(), Obj->getFileName()); - ArrayRef Bytes(reinterpret_cast(BytesStr.data()), - BytesStr.size()); - - uint64_t Size; - uint64_t Index; - - FunctionFilter *FuncFilter = MR->getFunctionFilter(); - if (!FilterConfigFileName.empty()) { - if (!FuncFilter->readFilterFunctionConfigFile(FilterConfigFileName)) { - dbgs() << "Unable to read function filter configuration file " - << FilterConfigFileName << ". Ignoring\n"; - } - } - - // Build a map of relocations (if they exist in the binary) of text - // section whose instructions are being raised. - MR->collectTextSectionRelocs(Section); - - // Set used to record all branch targets of a function. - std::set BranchTargetSet; - MachineFunctionRaiser *CurMFRaiser = nullptr; - - // Disassemble symbol by symbol and fill MR->MFRaiserVector by - // MachineFunctionRaiser for each function - LLVM_DEBUG(dbgs() << "BEGIN Disassembly of Functions in Section : " - << SectionName.data() << "\n"); - for (unsigned SI = 0, SSize = Symbols.size(); SI != SSize; ++SI) { - uint64_t Start = Symbols[SI].Addr - SectionAddr; - // The end is either the section end or the beginning of the next - // symbol. - uint64_t End = - (SI == SSize - 1) ? SectSize : Symbols[SI + 1].Addr - SectionAddr; - // Don't try to disassemble beyond the end of section contents. - if (End > SectSize) - End = SectSize; - // If this symbol has the same address as the next symbol, then skip it. - if (Start >= End) - continue; - - // Check if we need to skip symbol - // Skip if the symbol's data is not between StartAddress and StopAddress - if (End + SectionAddr < StartAddress || - Start + SectionAddr > StopAddress) { - continue; - } - - // Stop disassembly at the stop address specified - if (End + SectionAddr > StopAddress) - End = StopAddress - SectionAddr; - - if (Obj->isELF() && Obj->getArch() == Triple::amdgcn) { - // make size 4 bytes folded - End = Start + ((End - Start) & ~0x3ull); - if (Symbols[SI].Type == ELF::STT_AMDGPU_HSA_KERNEL) { - // skip amd_kernel_code_t at the begining of kernel symbol (256 bytes) - Start += 256; - } - if (SI == SSize - 1 || - Symbols[SI + 1].Type == ELF::STT_AMDGPU_HSA_KERNEL) { - // cut trailing zeroes at the end of kernel - // cut up to 256 bytes - const uint64_t EndAlign = 256; - const auto Limit = End - (std::min)(EndAlign, End - Start); - while (End > Limit && *reinterpret_cast( - &Bytes[End - 4]) == 0) - End -= 4; - } - } - - if (isAFunctionSymbol(Obj, Symbols[SI])) { - auto &SymStr = Symbols[SI].Name; - - bool RaiseFuncSymbol = true; - if ((!FilterConfigFileName.empty())) { - // Check the symbol name whether it should be excluded or not. - // Check in a non-empty exclude list - if (!FuncFilter->isFilterSetEmpty(FunctionFilter::FILTER_EXCLUDE)) { - FunctionFilter::FuncInfo *FI = FuncFilter->findFuncInfoBySymbol( - SymStr, FunctionFilter::FILTER_EXCLUDE); - if (FI != nullptr) { - // Record the function start index. - FI->StartIdx = Start; - // Skip raising this function symbol - RaiseFuncSymbol = false; - } - } - - if (!FuncFilter->isFilterSetEmpty(FunctionFilter::FILTER_INCLUDE)) { - // Include list specified. Unless the current function symbol is - // specified in the include list, skip raising it. - RaiseFuncSymbol = false; - // Check the symbol name whether it should be included or not. - if (FuncFilter->findFuncInfoBySymbol( - SymStr, FunctionFilter::FILTER_INCLUDE) != nullptr) - RaiseFuncSymbol = true; - } - } - - // If Symbol is in the ELFCRTSymbol list return this is a symbol of a - // function we are not interested in disassembling and raising. - if (ELFCRTSymbols.find(SymStr) != ELFCRTSymbols.end()) - RaiseFuncSymbol = false; - - // Check if raising function symbol should be skipped - if (!RaiseFuncSymbol) - continue; - - // Note that since LLVM infrastructure was built to be used to build a - // conventional compiler pipeline, MachineFunction is built well after - // Function object was created and populated fully. Hence, creation of - // a Function object is necessary to build MachineFunction. - // However, in a raiser, we are conceptually walking the traditional - // compiler pipeline backwards. So we build MachineFunction from - // the binary before building Function object. Given the dependency, - // build a placeholder Function object to allow for building the - // MachineFunction object. - // This Function object is NOT populated when raising MachineFunction - // abstraction of the binary function. Instead, a new Function is - // created using the LLVMContext and name of this Function object. - FunctionType *FTy = FunctionType::get(Type::getVoidTy(LlvmCtx), false); - StringRef FunctionName(Symbols[SI].Name); - // Strip leading underscore if the binary is MachO - if (Obj->isMachO()) { - FunctionName.consume_front("_"); - } - Function *Func = Function::Create(FTy, GlobalValue::ExternalLinkage, - FunctionName, &M); - - // New function symbol encountered. Record all targets collected to - // current MachineFunctionRaiser before we start parsing the new - // function bytes. - CurMFRaiser = MR->getCurrentMachineFunctionRaiser(); - for (auto TargetIdx : BranchTargetSet) { - assert(CurMFRaiser != nullptr && - "Encountered uninitialized MachineFunction raiser object"); - CurMFRaiser->getMCInstRaiser()->addTarget(TargetIdx); - } - - // Clear the set used to record all branch targets of this function. - BranchTargetSet.clear(); - // Create a new MachineFunction raiser - CurMFRaiser = - MR->CreateAndAddMachineFunctionRaiser(Func, MR, Start, End); - LLVM_DEBUG(dbgs() << "\nFunction " << Symbols[SI].Name << ":\n"); - } else { - // Continue using to the most recent MachineFunctionRaiser - // Get current MachineFunctionRaiser - CurMFRaiser = MR->getCurrentMachineFunctionRaiser(); - // assert(curMFRaiser != nullptr && "Current Machine Function Raiser not - // initialized"); - if (CurMFRaiser == nullptr) { - // At this point in the instruction stream, we do not have a function - // symbol to which the bytes being parsed can be made part of. So skip - // parsing the bytes of this symbol. - continue; - } - - // Adjust function end to represent the addition of the content of the - // current symbol. This represents a situation where we have discovered - // bytes (most likely data bytes) that belong to the most recent - // function being parsed. - MCInstRaiser *InstRaiser = CurMFRaiser->getMCInstRaiser(); - if (InstRaiser->getFuncEnd() < End) { - assert(InstRaiser->adjustFuncEnd(End) && - "Unable to adjust function end value"); - } - } - - // Get the associated MCInstRaiser - MCInstRaiser *InstRaiser = CurMFRaiser->getMCInstRaiser(); - - // Start new basic block at the symbol. - BranchTargetSet.insert(Start); - - for (Index = Start; Index < End; Index += Size) { - MCInst Inst; - - if (Index + SectionAddr < StartAddress || - Index + SectionAddr > StopAddress) { - // skip byte by byte till StartAddress is reached - Size = 1; - continue; - } - - // AArch64 ELF binaries can interleave data and text in the - // same section. We rely on the markers introduced to - // understand what we need to dump. If the data marker is within a - // function, it is denoted as a word/short etc - if (isArmElf(Obj) && Symbols[SI].Type != ELF::STT_OBJECT) { - uint64_t Stride = 0; - - auto DAI = std::lower_bound(DataMappingSymsAddr.begin(), - DataMappingSymsAddr.end(), Index); - if (DAI != DataMappingSymsAddr.end() && *DAI == Index) { - // Switch to data. - while (Index < End) { - if (Index + 4 <= End) { - Stride = 4; - uint32_t Data = 0; - if (Obj->isLittleEndian()) { - const auto *const Word = - reinterpret_cast( - Bytes.data() + Index); - Data = *Word; - } else { - const auto *const Word = - reinterpret_cast(Bytes.data() + - Index); - Data = *Word; - } - InstRaiser->addMCInstOrData(Index, Data); - } else if (Index + 2 <= End) { - Stride = 2; - uint16_t Data = 0; - if (Obj->isLittleEndian()) { - const auto *const Short = - reinterpret_cast( - Bytes.data() + Index); - Data = *Short; - } else { - const auto *const Short = - reinterpret_cast(Bytes.data() + - Index); - Data = *Short; - } - InstRaiser->addMCInstOrData(Index, Data); - } else { - Stride = 1; - InstRaiser->addMCInstOrData(Index, Bytes.slice(Index, 1)[0]); - } - Index += Stride; - - auto TAI = std::lower_bound(TextMappingSymsAddr.begin(), - TextMappingSymsAddr.end(), Index); - if (TAI != TextMappingSymsAddr.end() && *TAI == Index) - break; - } - } - } - - // If there is a data symbol inside an ELF text section and we are - // only disassembling text, we are in a situation where we must print - // the data and not disassemble it. - // TODO : Get rid of the following code in the if-block. - if (Obj->isELF() && Symbols[SI].Type == ELF::STT_OBJECT && - Section.isText()) { - // parse data up to 8 bytes at a time - uint8_t AsciiData[9] = {'\0'}; - uint8_t Byte; - int NumBytes = 0; - - for (Index = Start; Index < End; Index += 1) { - if (((SectionAddr + Index) < StartAddress) || - ((SectionAddr + Index) > StopAddress)) - continue; - if (NumBytes == 0) { - outs() << format("%8" PRIx64 ":", SectionAddr + Index); - outs() << "\t"; - } - Byte = Bytes.slice(Index)[0]; - outs() << format(" %02x", Byte); - AsciiData[NumBytes] = isprint(Byte) ? Byte : '.'; - - uint8_t IndentOffset = 0; - NumBytes++; - if (Index == End - 1 || NumBytes > 8) { - // Indent the space for less than 8 bytes data. - // 2 spaces for byte and one for space between bytes - IndentOffset = 3 * (8 - NumBytes); - for (int Excess = 8 - NumBytes; Excess < 8; Excess++) - AsciiData[Excess] = '\0'; - NumBytes = 8; - } - if (NumBytes == 8) { - AsciiData[8] = '\0'; - outs() << std::string(IndentOffset, ' ') << " "; - outs() << reinterpret_cast(AsciiData); - outs() << '\n'; - NumBytes = 0; - } - } - } - - if (Index >= End) - break; - - // Disassemble a real instruction or a data - bool Disassembled = DisAsm->getInstruction( - Inst, Size, Bytes.slice(Index), SectionAddr + Index, CommentStream); - if (Size == 0) - Size = 1; - - if (!Disassembled) { - errs() << "**** Warning: Failed to decode instruction\n"; - PIP.printInst(*IP, Disassembled ? &Inst : nullptr, - Bytes.slice(Index, Size), SectionAddr + Index, outs(), - "", *STI); - outs() << CommentStream.str(); - Comments.clear(); - errs() << "\n"; - } - - // Add MCInst to the list if all instructions were decoded - // successfully till now. Else, do not bother adding since no attempt - // will be made to raise this function. - if (Disassembled) { - InstRaiser->addMCInstOrData(Index, Inst); - - // Find branch target and record it. Call targets are not - // recorded as they are not needed to build per-function CFG. - if (MIA && MIA->isBranch(Inst)) { - uint64_t BranchTarget; - if (MIA->evaluateBranch(Inst, Index, Size, BranchTarget)) { - // In a relocatable object, the target's section must reside in - // the same section as the call instruction, or it is accessed - // through a relocation. - // - // In a non-relocatable object, the target may be in any - // section. - // - // N.B. We don't walk the relocations in the relocatable case - // yet. - if (!Obj->isRelocatableObject()) { - auto SectionAddress = std::upper_bound( - SectionAddresses.begin(), SectionAddresses.end(), - BranchTarget, - [](uint64_t LHS, - const std::pair &RHS) { - return LHS < RHS.first; - }); - if (SectionAddress != SectionAddresses.begin()) { - --SectionAddress; - } - } - // Add the index Target to target indices set. - BranchTargetSet.insert(BranchTarget); - } - - // Mark the next instruction as a target, if it is not beyond the - // function end - uint64_t FallThruIndex = Index + Size; - if (FallThruIndex < End) { - BranchTargetSet.insert(FallThruIndex); - } - } + // Filtered sections list + SmallVector FilteredSections; + copy_if(Obj->sections(), std::back_inserter(FilteredSections), + [](llvm::object::SectionRef const &S) { + if (FilterSections.empty()) + return true; + llvm::StringRef String; + if (auto NameOrErr = S.getName()) + String = *NameOrErr; + else { + consumeError(NameOrErr.takeError()); + return false; } - } - FuncFilter->eraseFunctionBySymbol(Symbols[SI].Name, - FunctionFilter::FILTER_INCLUDE); - } - LLVM_DEBUG(dbgs() << "END Disassembly of Functions in Section : " - << SectionName.data() << "\n"); - // Record all targets of the last function parsed - CurMFRaiser = MR->getCurrentMachineFunctionRaiser(); - for (auto TargetIdx : BranchTargetSet) - CurMFRaiser->getMCInstRaiser()->addTarget(TargetIdx); + return is_contained(FilterSections, String); + }); - MR->runMachineFunctionPasses(); - - if (!FuncFilter->isFilterSetEmpty(FunctionFilter::FILTER_INCLUDE)) { - errs() << "***** WARNING: The following include filter symbol(s) are not " - "found :\n"; - FuncFilter->dump(FunctionFilter::FILTER_INCLUDE); - } - } + // Load data + MR->load(StartAddress, StopAddress, FilteredSections); // Add the pass manager - Triple TheTriple = Triple(TripleName); + legacy::PassManager PM; + MR->addPasses(PM); // Decide where to send the output. std::unique_ptr Out = getOutputStream(Obj->getFileName()); @@ -1298,9 +590,7 @@ static void disassembleObject(const ObjectFile *Obj, bool InlineRelocs) { auto *OS = &Out->os(); - legacy::PassManager PM; - - LLVMTargetMachine &LLVMTM = static_cast(*Target); + LLVMTargetMachine &LLVMTM = static_cast(*Target); CodeGenFileType OutputFileType; diff --git a/llvm-mctoll.h b/llvm-mctoll.h index efc71b4c..55778ac3 100644 --- a/llvm-mctoll.h +++ b/llvm-mctoll.h @@ -40,19 +40,13 @@ extern std::string CompilationDBDir; // Various helper functions. bool isRelocAddressLess(object::RelocationRef A, object::RelocationRef B); -bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void parseInputMachO(StringRef Filename); -void printCOFFUnwindInfo(const object::COFFObjectFile *o); -void printMachOUnwindInfo(const object::MachOObjectFile *o); -void printELFFileHeader(const object::ObjectFile *o); -void printCOFFFileHeader(const object::ObjectFile *o); -void printCOFFSymbolTable(const object::COFFImportFile *i); -void printCOFFSymbolTable(const object::COFFObjectFile *o); -void printMachOFileHeader(const object::ObjectFile *o); -void printMachOLoadCommands(const object::ObjectFile *o); -void printWasmFileHeader(const object::ObjectFile *o); -void PrintSymbolTable(const object::ObjectFile *o, StringRef ArchiveName, - StringRef ArchitectureName = StringRef()); +void printCOFFUnwindInfo(const object::COFFObjectFile *O); +void printCOFFFileHeader(const object::ObjectFile *O); +void printCOFFSymbolTable(const object::COFFImportFile *I); +void printCOFFSymbolTable(const object::COFFObjectFile *O); +void printMachOFileHeader(const object::ObjectFile *O); +void printMachOLoadCommands(const object::ObjectFile *O); } // end namespace mctoll } // end namespace llvm