diff options
Diffstat (limited to 'tools')
94 files changed, 4197 insertions, 1722 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 1f415b6..7859b49 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -37,7 +37,7 @@ add_llvm_tool_subdirectory(llvm-readobj) add_llvm_tool_subdirectory(llvm-rtdyld) add_llvm_tool_subdirectory(llvm-dwarfdump) add_llvm_tool_subdirectory(dsymutil) -add_llvm_tool_subdirectory(llvm-vtabledump) +add_llvm_tool_subdirectory(llvm-cxxdump) if( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool_subdirectory(llvm-jitlistener) else() diff --git a/tools/Makefile b/tools/Makefile index fcb6c64..d853486 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -33,7 +33,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \ macho-dump llvm-objdump llvm-readobj llvm-rtdyld \ llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \ llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \ - llvm-vtabledump verify-uselistorder dsymutil llvm-pdbdump + llvm-cxxdump verify-uselistorder dsymutil llvm-pdbdump # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index b8be17e..865cb51 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -16,6 +16,7 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/IR/Module.h" +#include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Linker/Linker.h" #include "llvm/Pass.h" @@ -86,23 +87,28 @@ std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename, LLVMContext &Ctxt) { SMDiagnostic Err; std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt); - if (!Result) + if (!Result) { Err.print("bugpoint", errs()); + return Result; + } + + if (verifyModule(*Result, &errs())) { + errs() << "bugpoint: " << Filename << ": error: does not verify\n"; + return std::unique_ptr<Module>(); + } // If we don't have an override triple, use the first one to configure // bugpoint, or use the host triple if none provided. - if (Result) { - if (TargetTriple.getTriple().empty()) { - Triple TheTriple(Result->getTargetTriple()); + if (TargetTriple.getTriple().empty()) { + Triple TheTriple(Result->getTargetTriple()); - if (TheTriple.getTriple().empty()) - TheTriple.setTriple(sys::getDefaultTargetTriple()); + if (TheTriple.getTriple().empty()) + TheTriple.setTriple(sys::getDefaultTargetTriple()); - TargetTriple.setTriple(TheTriple.getTriple()); - } - - Result->setTargetTriple(TargetTriple.getTriple()); // override the triple + TargetTriple.setTriple(TheTriple.getTriple()); } + + Result->setTargetTriple(TargetTriple.getTriple()); // override the triple return Result; } diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index d71e097..daf502e 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -31,7 +31,7 @@ add_llvm_tool(bugpoint ToolRunner.cpp bugpoint.cpp ) -set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1) +export_executable_symbols(bugpoint) if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) target_link_libraries(bugpoint Polly) diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index ee18169..f9f3f10 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -409,7 +409,6 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*> // Verify that this is still valid. legacy::PassManager Passes; Passes.add(createVerifierPass()); - Passes.add(createDebugInfoVerifierPass()); Passes.run(*M); // Try running on the hacked up program... diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 8cb4583..98061bd 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -975,7 +975,7 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, } if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) { - errs() << "Error writing bitcode to `" << SafeModuleBC.str() + errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; exit(1); } @@ -1050,7 +1050,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { } if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) { - errs() << "Error writing bitcode to `" << TestModuleBC.str() + errs() << "Error writing bitcode to `" << TestModuleBC << "'\nExiting."; exit(1); } @@ -1068,7 +1068,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { } if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) { - errs() << "Error writing bitcode to `" << SafeModuleBC.str() + errs() << "Error writing bitcode to `" << SafeModuleBC << "'\nExiting."; exit(1); } @@ -1079,17 +1079,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { outs() << "You can reproduce the problem with the command line: \n"; if (isExecutingJIT()) { - outs() << " lli -load " << SharedObject << " " << TestModuleBC.str(); + outs() << " lli -load " << SharedObject << " " << TestModuleBC; } else { - outs() << " llc " << TestModuleBC.str() << " -o " << TestModuleBC.str() + outs() << " llc " << TestModuleBC << " -o " << TestModuleBC << ".s\n"; outs() << " gcc " << SharedObject << " " << TestModuleBC.str() - << ".s -o " << TestModuleBC.str() << ".exe"; + << ".s -o " << TestModuleBC << ".exe"; #if defined (HAVE_LINK_R) outs() << " -Wl,-R."; #endif outs() << "\n"; - outs() << " " << TestModuleBC.str() << ".exe"; + outs() << " " << TestModuleBC << ".exe"; } for (unsigned i = 0, e = InputArgv.size(); i != e; ++i) outs() << " " << InputArgv[i]; diff --git a/tools/dsymutil/Android.mk b/tools/dsymutil/Android.mk index 873146e..f141635 100644 --- a/tools/dsymutil/Android.mk +++ b/tools/dsymutil/Android.mk @@ -11,13 +11,48 @@ llvm_dsymutil_SRC_FILES := \ MachODebugMapParser.cpp llvm_dsymutil_STATIC_LIBRARIES := \ + libLLVMARMCodeGen \ + libLLVMARMAsmParser \ + libLLVMARMInfo \ + libLLVMARMDesc \ + libLLVMARMAsmPrinter \ + libLLVMARMDisassembler \ + libLLVMAArch64CodeGen \ + libLLVMAArch64Info \ + libLLVMAArch64AsmParser \ + libLLVMAArch64Desc \ + libLLVMAArch64AsmPrinter \ + libLLVMAArch64Utils \ + libLLVMAArch64Disassembler \ + libLLVMMipsCodeGen \ + libLLVMMipsInfo \ + libLLVMMipsAsmParser \ + libLLVMMipsDesc \ + libLLVMMipsAsmPrinter \ + libLLVMMipsDisassembler \ + libLLVMX86CodeGen \ + libLLVMX86Info \ + libLLVMX86Desc \ + libLLVMX86AsmParser \ + libLLVMX86AsmPrinter \ + libLLVMX86Utils \ + libLLVMX86Disassembler \ + libLLVMX86CodeGen \ + libLLVMAsmPrinter \ + libLLVMSelectionDAG \ + libLLVMCodeGen \ libLLVMDebugInfoDWARF \ - libLLVMObject \ libLLVMMCParser \ - libLLVMMC \ + libLLVMMCDisassembler \ + libLLVMObject \ libLLVMBitReader \ + libLLVMScalarOpts \ + libLLVMTransformUtils \ + libLLVMAnalysis \ + libLLVMTarget \ libLLVMCore \ - libLLVMSupport + libLLVMMC \ + libLLVMSupport \ include $(CLEAR_VARS) diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt index 5e1f37f..59b37a9 100644 --- a/tools/dsymutil/CMakeLists.txt +++ b/tools/dsymutil/CMakeLists.txt @@ -1,5 +1,8 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + AsmPrinter DebugInfoDWARF + MC Object Support ) diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp index c04b2fe..9fa3f78 100644 --- a/tools/dsymutil/DebugMap.cpp +++ b/tools/dsymutil/DebugMap.cpp @@ -23,9 +23,9 @@ DebugMapObject::DebugMapObject(StringRef ObjectFilename) : Filename(ObjectFilename) {} bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress, - uint64_t LinkedAddress) { + uint64_t LinkedAddress, uint32_t Size) { auto InsertResult = Symbols.insert( - std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress))); + std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size))); if (InsertResult.second) AddressToMapping[ObjectAddress] = &*InsertResult.first; @@ -45,9 +45,9 @@ void DebugMapObject::print(raw_ostream &OS) const { Entries.begin(), Entries.end(), [](const Entry &LHS, const Entry &RHS) { return LHS.first < RHS.first; }); for (const auto &Sym : Entries) { - OS << format("\t%016" PRIx64 " => %016" PRIx64 "\t%s\n", + OS << format("\t%016" PRIx64 " => %016" PRIx64 "+0x%x\t%s\n", Sym.second.ObjectAddress, Sym.second.BinaryAddress, - Sym.first.data()); + Sym.second.Size, Sym.first.data()); } OS << '\n'; } diff --git a/tools/dsymutil/DebugMap.h b/tools/dsymutil/DebugMap.h index ff2b27e..ee48b09 100644 --- a/tools/dsymutil/DebugMap.h +++ b/tools/dsymutil/DebugMap.h @@ -83,7 +83,7 @@ public: /// debug map. DebugMapObject &addDebugMapObject(StringRef ObjectFilePath); - const Triple &getTriple() { return BinaryTriple; } + const Triple &getTriple() const { return BinaryTriple; } void print(raw_ostream &OS) const; @@ -101,8 +101,10 @@ public: struct SymbolMapping { uint64_t ObjectAddress; uint64_t BinaryAddress; - SymbolMapping(uint64_t ObjectAddress, uint64_t BinaryAddress) - : ObjectAddress(ObjectAddress), BinaryAddress(BinaryAddress) {} + uint32_t Size; + SymbolMapping(uint64_t ObjectAddress, uint64_t BinaryAddress, uint32_t Size) + : ObjectAddress(ObjectAddress), BinaryAddress(BinaryAddress), + Size(Size) {} }; typedef StringMapEntry<SymbolMapping> DebugMapEntry; @@ -111,7 +113,7 @@ public: /// \returns false if the symbol was already registered. The request /// is discarded in this case. bool addSymbol(llvm::StringRef SymName, uint64_t ObjectAddress, - uint64_t LinkedAddress); + uint64_t LinkedAddress, uint32_t Size); /// \brief Lookup a symbol mapping. /// \returns null if the symbol isn't found. @@ -123,6 +125,10 @@ public: llvm::StringRef getObjectFilename() const { return Filename; } + iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const { + return make_range(Symbols.begin(), Symbols.end()); + } + void print(raw_ostream &OS) const; #ifndef NDEBUG void dump() const; diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index 3c0bc0b..c9c05cd 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -10,19 +10,55 @@ #include "BinaryHolder.h" #include "DebugMap.h" #include "dsymutil.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/DIE.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" #include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include <string> +#include <tuple> namespace llvm { namespace dsymutil { namespace { +void warn(const Twine &Warning, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("warning: ") + Warning + "\n"; +} + +bool error(const Twine &Error, const Twine &Context) { + errs() << Twine("while processing ") + Context + ":\n"; + errs() << Twine("error: ") + Error + "\n"; + return false; +} + +template <typename KeyT, typename ValT> +using HalfOpenIntervalMap = + IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize, + IntervalMapHalfOpenInfo<KeyT>>; + +typedef HalfOpenIntervalMap<uint64_t, int64_t> FunctionIntervals; + /// \brief Stores all information relating to a compile unit, be it in /// its original instance in the object file to its brand new cloned /// and linked DIE tree. @@ -30,26 +66,900 @@ class CompileUnit { public: /// \brief Information gathered about a DIE in the object file. struct DIEInfo { - uint64_t Address; ///< Linked address of the described entity. + int64_t AddrAdjust; ///< Address offset to apply to the described entity. + DIE *Clone; ///< Cloned version of that DIE. uint32_t ParentIdx; ///< The index of this DIE's parent. bool Keep; ///< Is the DIE part of the linked output? bool InDebugMap; ///< Was this DIE's entity found in the map? }; - CompileUnit(DWARFUnit &OrigUnit) : OrigUnit(OrigUnit) { + CompileUnit(DWARFUnit &OrigUnit, unsigned ID) + : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(), + Ranges(RangeAlloc), UnitRangeAttribute(nullptr) { Info.resize(OrigUnit.getNumDIEs()); } + CompileUnit(CompileUnit &&RHS) + : OrigUnit(RHS.OrigUnit), Info(std::move(RHS.Info)), + CUDie(std::move(RHS.CUDie)), StartOffset(RHS.StartOffset), + NextUnitOffset(RHS.NextUnitOffset), RangeAlloc(), Ranges(RangeAlloc) { + // The CompileUnit container has been 'reserve()'d with the right + // size. We cannot move the IntervalMap anyway. + llvm_unreachable("CompileUnits should not be moved."); + } + DWARFUnit &getOrigUnit() const { return OrigUnit; } + unsigned getUniqueID() const { return ID; } + + DIE *getOutputUnitDIE() const { return CUDie.get(); } + void setOutputUnitDIE(DIE *Die) { CUDie.reset(Die); } + DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } + uint64_t getStartOffset() const { return StartOffset; } + uint64_t getNextUnitOffset() const { return NextUnitOffset; } + void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; } + + uint64_t getLowPc() const { return LowPc; } + uint64_t getHighPc() const { return HighPc; } + + DIEInteger *getUnitRangesAttribute() const { return UnitRangeAttribute; } + const FunctionIntervals &getFunctionRanges() const { return Ranges; } + const std::vector<DIEInteger *> &getRangesAttributes() const { + return RangeAttributes; + } + + const std::vector<std::pair<DIEInteger *, int64_t>> & + getLocationAttributes() const { + return LocationAttributes; + } + + /// \brief Compute the end offset for this unit. Must be + /// called after the CU's DIEs have been cloned. + /// \returns the next unit offset (which is also the current + /// debug_info section size). + uint64_t computeNextUnitOffset(); + + /// \brief Keep track of a forward reference to DIE \p Die in \p + /// RefUnit by \p Attr. The attribute should be fixed up later to + /// point to the absolute offset of \p Die in the debug_info section. + void noteForwardReference(DIE *Die, const CompileUnit *RefUnit, + DIEInteger *Attr); + + /// \brief Apply all fixups recored by noteForwardReference(). + void fixupForwardReferences(); + + /// \brief Add a function range [\p LowPC, \p HighPC) that is + /// relocatad by applying offset \p PCOffset. + void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset); + + /// \brief Keep track of a DW_AT_range attribute that we will need to + /// patch up later. + void noteRangeAttribute(const DIE &Die, DIEInteger *Attr); + + /// \brief Keep track of a location attribute pointing to a location + /// list in the debug_loc section. + void noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset); + + /// \brief Add a name accelerator entry for \p Die with \p Name + /// which is stored in the string table at \p Offset. + void addNameAccelerator(const DIE *Die, const char *Name, uint32_t Offset, + bool SkipPubnamesSection = false); + + /// \brief Add a type accelerator entry for \p Die with \p Name + /// which is stored in the string table at \p Offset. + void addTypeAccelerator(const DIE *Die, const char *Name, uint32_t Offset); + + struct AccelInfo { + StringRef Name; ///< Name of the entry. + const DIE *Die; ///< DIE this entry describes. + uint32_t NameOffset; ///< Offset of Name in the string pool. + bool SkipPubSection; ///< Emit this entry only in the apple_* sections. + + AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset, + bool SkipPubSection = false) + : Name(Name), Die(Die), NameOffset(NameOffset), + SkipPubSection(SkipPubSection) {} + }; + + const std::vector<AccelInfo> &getPubnames() const { return Pubnames; } + const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; } + private: DWARFUnit &OrigUnit; - std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. + unsigned ID; + std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index. + std::unique_ptr<DIE> CUDie; ///< Root of the linked DIE tree. + + uint64_t StartOffset; + uint64_t NextUnitOffset; + + uint64_t LowPc; + uint64_t HighPc; + + /// \brief A list of attributes to fixup with the absolute offset of + /// a DIE in the debug_info section. + /// + /// The offsets for the attributes in this array couldn't be set while + /// cloning because for cross-cu forward refences the target DIE's + /// offset isn't known you emit the reference attribute. + std::vector<std::tuple<DIE *, const CompileUnit *, DIEInteger *>> + ForwardDIEReferences; + + FunctionIntervals::Allocator RangeAlloc; + /// \brief The ranges in that interval map are the PC ranges for + /// functions in this unit, associated with the PC offset to apply + /// to the addresses to get the linked address. + FunctionIntervals Ranges; + + /// \brief DW_AT_ranges attributes to patch after we have gathered + /// all the unit's function addresses. + /// @{ + std::vector<DIEInteger *> RangeAttributes; + DIEInteger *UnitRangeAttribute; + /// @} + + /// \brief Location attributes that need to be transfered from th + /// original debug_loc section to the liked one. They are stored + /// along with the PC offset that is to be applied to their + /// function's address. + std::vector<std::pair<DIEInteger *, int64_t>> LocationAttributes; + + /// \brief Accelerator entries for the unit, both for the pub* + /// sections and the apple* ones. + /// @{ + std::vector<AccelInfo> Pubnames; + std::vector<AccelInfo> Pubtypes; + /// @} +}; + +uint64_t CompileUnit::computeNextUnitOffset() { + NextUnitOffset = StartOffset + 11 /* Header size */; + // The root DIE might be null, meaning that the Unit had nothing to + // contribute to the linked output. In that case, we will emit the + // unit header without any actual DIE. + if (CUDie) + NextUnitOffset += CUDie->getSize(); + return NextUnitOffset; +} + +/// \brief Keep track of a forward cross-cu reference from this unit +/// to \p Die that lives in \p RefUnit. +void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit, + DIEInteger *Attr) { + ForwardDIEReferences.emplace_back(Die, RefUnit, Attr); +} + +/// \brief Apply all fixups recorded by noteForwardReference(). +void CompileUnit::fixupForwardReferences() { + for (const auto &Ref : ForwardDIEReferences) { + DIE *RefDie; + const CompileUnit *RefUnit; + DIEInteger *Attr; + std::tie(RefDie, RefUnit, Attr) = Ref; + Attr->setValue(RefDie->getOffset() + RefUnit->getStartOffset()); + } +} + +void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc, + int64_t PcOffset) { + Ranges.insert(FuncLowPc, FuncHighPc, PcOffset); + this->LowPc = std::min(LowPc, FuncLowPc + PcOffset); + this->HighPc = std::max(HighPc, FuncHighPc + PcOffset); +} + +void CompileUnit::noteRangeAttribute(const DIE &Die, DIEInteger *Attr) { + if (Die.getTag() != dwarf::DW_TAG_compile_unit) + RangeAttributes.push_back(Attr); + else + UnitRangeAttribute = Attr; +} + +void CompileUnit::noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset) { + LocationAttributes.emplace_back(Attr, PcOffset); +} + +/// \brief Add a name accelerator entry for \p Die with \p Name +/// which is stored in the string table at \p Offset. +void CompileUnit::addNameAccelerator(const DIE *Die, const char *Name, + uint32_t Offset, bool SkipPubSection) { + Pubnames.emplace_back(Name, Die, Offset, SkipPubSection); +} + +/// \brief Add a type accelerator entry for \p Die with \p Name +/// which is stored in the string table at \p Offset. +void CompileUnit::addTypeAccelerator(const DIE *Die, const char *Name, + uint32_t Offset) { + Pubtypes.emplace_back(Name, Die, Offset, false); +} + +/// \brief A string table that doesn't need relocations. +/// +/// We are doing a final link, no need for a string table that +/// has relocation entries for every reference to it. This class +/// provides this ablitity by just associating offsets with +/// strings. +class NonRelocatableStringpool { +public: + /// \brief Entries are stored into the StringMap and simply linked + /// together through the second element of this pair in order to + /// keep track of insertion order. + typedef StringMap<std::pair<uint32_t, StringMapEntryBase *>, BumpPtrAllocator> + MapTy; + + NonRelocatableStringpool() + : CurrentEndOffset(0), Sentinel(0), Last(&Sentinel) { + // Legacy dsymutil puts an empty string at the start of the line + // table. + getStringOffset(""); + } + + /// \brief Get the offset of string \p S in the string table. This + /// can insert a new element or return the offset of a preexisitng + /// one. + uint32_t getStringOffset(StringRef S); + + /// \brief Get permanent storage for \p S (but do not necessarily + /// emit \p S in the output section). + /// \returns The StringRef that points to permanent storage to use + /// in place of \p S. + StringRef internString(StringRef S); + + // \brief Return the first entry of the string table. + const MapTy::MapEntryTy *getFirstEntry() const { + return getNextEntry(&Sentinel); + } + + // \brief Get the entry following \p E in the string table or null + // if \p E was the last entry. + const MapTy::MapEntryTy *getNextEntry(const MapTy::MapEntryTy *E) const { + return static_cast<const MapTy::MapEntryTy *>(E->getValue().second); + } + + uint64_t getSize() { return CurrentEndOffset; } + +private: + MapTy Strings; + uint32_t CurrentEndOffset; + MapTy::MapEntryTy Sentinel, *Last; +}; + +/// \brief Get the offset of string \p S in the string table. This +/// can insert a new element or return the offset of a preexisitng +/// one. +uint32_t NonRelocatableStringpool::getStringOffset(StringRef S) { + if (S.empty() && !Strings.empty()) + return 0; + + std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr); + MapTy::iterator It; + bool Inserted; + + // A non-empty string can't be at offset 0, so if we have an entry + // with a 0 offset, it must be a previously interned string. + std::tie(It, Inserted) = Strings.insert(std::make_pair(S, Entry)); + if (Inserted || It->getValue().first == 0) { + // Set offset and chain at the end of the entries list. + It->getValue().first = CurrentEndOffset; + CurrentEndOffset += S.size() + 1; // +1 for the '\0'. + Last->getValue().second = &*It; + Last = &*It; + } + return It->getValue().first; +} + +/// \brief Put \p S into the StringMap so that it gets permanent +/// storage, but do not actually link it in the chain of elements +/// that go into the output section. A latter call to +/// getStringOffset() with the same string will chain it though. +StringRef NonRelocatableStringpool::internString(StringRef S) { + std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr); + auto InsertResult = Strings.insert(std::make_pair(S, Entry)); + return InsertResult.first->getKey(); +} + +/// \brief The Dwarf streaming logic +/// +/// All interactions with the MC layer that is used to build the debug +/// information binary representation are handled in this class. +class DwarfStreamer { + /// \defgroup MCObjects MC layer objects constructed by the streamer + /// @{ + std::unique_ptr<MCRegisterInfo> MRI; + std::unique_ptr<MCAsmInfo> MAI; + std::unique_ptr<MCObjectFileInfo> MOFI; + std::unique_ptr<MCContext> MC; + MCAsmBackend *MAB; // Owned by MCStreamer + std::unique_ptr<MCInstrInfo> MII; + std::unique_ptr<MCSubtargetInfo> MSTI; + MCCodeEmitter *MCE; // Owned by MCStreamer + MCStreamer *MS; // Owned by AsmPrinter + std::unique_ptr<TargetMachine> TM; + std::unique_ptr<AsmPrinter> Asm; + /// @} + + /// \brief the file we stream the linked Dwarf to. + std::unique_ptr<raw_fd_ostream> OutFile; + + uint32_t RangesSectionSize; + uint32_t LocSectionSize; + uint32_t LineSectionSize; + + /// \brief Emit the pubnames or pubtypes section contribution for \p + /// Unit into \p Sec. The data is provided in \p Names. + void emitPubSectionForUnit(const MCSection *Sec, StringRef Name, + const CompileUnit &Unit, + const std::vector<CompileUnit::AccelInfo> &Names); + +public: + /// \brief Actually create the streamer and the ouptut file. + /// + /// This could be done directly in the constructor, but it feels + /// more natural to handle errors through return value. + bool init(Triple TheTriple, StringRef OutputFilename); + + /// \brief Dump the file to the disk. + bool finish(); + + AsmPrinter &getAsmPrinter() const { return *Asm; } + + /// \brief Set the current output section to debug_info and change + /// the MC Dwarf version to \p DwarfVersion. + void switchToDebugInfoSection(unsigned DwarfVersion); + + /// \brief Emit the compilation unit header for \p Unit in the + /// debug_info section. + /// + /// As a side effect, this also switches the current Dwarf version + /// of the MC layer to the one of U.getOrigUnit(). + void emitCompileUnitHeader(CompileUnit &Unit); + + /// \brief Recursively emit the DIE tree rooted at \p Die. + void emitDIE(DIE &Die); + + /// \brief Emit the abbreviation table \p Abbrevs to the + /// debug_abbrev section. + void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs); + + /// \brief Emit the string table described by \p Pool. + void emitStrings(const NonRelocatableStringpool &Pool); + + /// \brief Emit debug_ranges for \p FuncRange by translating the + /// original \p Entries. + void emitRangesEntries( + int64_t UnitPcOffset, uint64_t OrigLowPc, + FunctionIntervals::const_iterator FuncRange, + const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries, + unsigned AddressSize); + + /// \brief Emit debug_aranges entries for \p Unit and if \p + /// DoRangesSection is true, also emit the debug_ranges entries for + /// the DW_TAG_compile_unit's DW_AT_ranges attribute. + void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection); + + uint32_t getRangesSectionSize() const { return RangesSectionSize; } + + /// \brief Emit the debug_loc contribution for \p Unit by copying + /// the entries from \p Dwarf and offseting them. Update the + /// location attributes to point to the new entries. + void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf); + + /// \brief Emit the line table described in \p Rows into the + /// debug_line section. + void emitLineTableForUnit(StringRef PrologueBytes, unsigned MinInstLength, + std::vector<DWARFDebugLine::Row> &Rows, + unsigned AdddressSize); + + uint32_t getLineSectionSize() const { return LineSectionSize; } + + /// \brief Emit the .debug_pubnames contribution for \p Unit. + void emitPubNamesForUnit(const CompileUnit &Unit); + + /// \brief Emit the .debug_pubtypes contribution for \p Unit. + void emitPubTypesForUnit(const CompileUnit &Unit); }; +bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) { + std::string ErrorStr; + std::string TripleName; + StringRef Context = "dwarf streamer init"; + + // Get the target. + const Target *TheTarget = + TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr); + if (!TheTarget) + return error(ErrorStr, Context); + TripleName = TheTriple.getTriple(); + + // Create all the MC Objects. + MRI.reset(TheTarget->createMCRegInfo(TripleName)); + if (!MRI) + return error(Twine("no register info for target ") + TripleName, Context); + + MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName)); + if (!MAI) + return error("no asm info for target " + TripleName, Context); + + MOFI.reset(new MCObjectFileInfo); + MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get())); + MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default, + *MC); + + MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, ""); + if (!MAB) + return error("no asm backend for target " + TripleName, Context); + + MII.reset(TheTarget->createMCInstrInfo()); + if (!MII) + return error("no instr info info for target " + TripleName, Context); + + MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", "")); + if (!MSTI) + return error("no subtarget info for target " + TripleName, Context); + + MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC); + if (!MCE) + return error("no code emitter for target " + TripleName, Context); + + // Create the output file. + std::error_code EC; + OutFile = + llvm::make_unique<raw_fd_ostream>(OutputFilename, EC, sys::fs::F_None); + if (EC) + return error(Twine(OutputFilename) + ": " + EC.message(), Context); + + MS = TheTarget->createMCObjectStreamer(TheTriple, *MC, *MAB, *OutFile, MCE, + *MSTI, false, + /*DWARFMustBeAtTheEnd*/ false); + if (!MS) + return error("no object streamer for target " + TripleName, Context); + + // Finally create the AsmPrinter we'll use to emit the DIEs. + TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions())); + if (!TM) + return error("no target machine for target " + TripleName, Context); + + Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS))); + if (!Asm) + return error("no asm printer for target " + TripleName, Context); + + RangesSectionSize = 0; + LocSectionSize = 0; + LineSectionSize = 0; + + return true; +} + +bool DwarfStreamer::finish() { + MS->Finish(); + return true; +} + +/// \brief Set the current output section to debug_info and change +/// the MC Dwarf version to \p DwarfVersion. +void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) { + MS->SwitchSection(MOFI->getDwarfInfoSection()); + MC->setDwarfVersion(DwarfVersion); +} + +/// \brief Emit the compilation unit header for \p Unit in the +/// debug_info section. +/// +/// A Dwarf scetion header is encoded as: +/// uint32_t Unit length (omiting this field) +/// uint16_t Version +/// uint32_t Abbreviation table offset +/// uint8_t Address size +/// +/// Leading to a total of 11 bytes. +void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) { + unsigned Version = Unit.getOrigUnit().getVersion(); + switchToDebugInfoSection(Version); + + // Emit size of content not including length itself. The size has + // already been computed in CompileUnit::computeOffsets(). Substract + // 4 to that size to account for the length field. + Asm->EmitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4); + Asm->EmitInt16(Version); + // We share one abbreviations table across all units so it's always at the + // start of the section. + Asm->EmitInt32(0); + Asm->EmitInt8(Unit.getOrigUnit().getAddressByteSize()); +} + +/// \brief Emit the \p Abbrevs array as the shared abbreviation table +/// for the linked Dwarf file. +void DwarfStreamer::emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs) { + MS->SwitchSection(MOFI->getDwarfAbbrevSection()); + Asm->emitDwarfAbbrevs(Abbrevs); +} + +/// \brief Recursively emit the DIE tree rooted at \p Die. +void DwarfStreamer::emitDIE(DIE &Die) { + MS->SwitchSection(MOFI->getDwarfInfoSection()); + Asm->emitDwarfDIE(Die); +} + +/// \brief Emit the debug_str section stored in \p Pool. +void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) { + Asm->OutStreamer.SwitchSection(MOFI->getDwarfStrSection()); + for (auto *Entry = Pool.getFirstEntry(); Entry; + Entry = Pool.getNextEntry(Entry)) + Asm->OutStreamer.EmitBytes( + StringRef(Entry->getKey().data(), Entry->getKey().size() + 1)); +} + +/// \brief Emit the debug_range section contents for \p FuncRange by +/// translating the original \p Entries. The debug_range section +/// format is totally trivial, consisting just of pairs of address +/// sized addresses describing the ranges. +void DwarfStreamer::emitRangesEntries( + int64_t UnitPcOffset, uint64_t OrigLowPc, + FunctionIntervals::const_iterator FuncRange, + const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries, + unsigned AddressSize) { + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); + + // Offset each range by the right amount. + int64_t PcOffset = FuncRange.value() + UnitPcOffset; + for (const auto &Range : Entries) { + if (Range.isBaseAddressSelectionEntry(AddressSize)) { + warn("unsupported base address selection operation", + "emitting debug_ranges"); + break; + } + // Do not emit empty ranges. + if (Range.StartAddress == Range.EndAddress) + continue; + + // All range entries should lie in the function range. + if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() && + Range.EndAddress + OrigLowPc <= FuncRange.stop())) + warn("inconsistent range data.", "emitting debug_ranges"); + MS->EmitIntValue(Range.StartAddress + PcOffset, AddressSize); + MS->EmitIntValue(Range.EndAddress + PcOffset, AddressSize); + RangesSectionSize += 2 * AddressSize; + } + + // Add the terminator entry. + MS->EmitIntValue(0, AddressSize); + MS->EmitIntValue(0, AddressSize); + RangesSectionSize += 2 * AddressSize; +} + +/// \brief Emit the debug_aranges contribution of a unit and +/// if \p DoDebugRanges is true the debug_range contents for a +/// compile_unit level DW_AT_ranges attribute (Which are basically the +/// same thing with a different base address). +/// Just aggregate all the ranges gathered inside that unit. +void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit, + bool DoDebugRanges) { + unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); + // Gather the ranges in a vector, so that we can simplify them. The + // IntervalMap will have coalesced the non-linked ranges, but here + // we want to coalesce the linked addresses. + std::vector<std::pair<uint64_t, uint64_t>> Ranges; + const auto &FunctionRanges = Unit.getFunctionRanges(); + for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end(); + Range != End; ++Range) + Ranges.push_back(std::make_pair(Range.start() + Range.value(), + Range.stop() + Range.value())); + + // The object addresses where sorted, but again, the linked + // addresses might end up in a different order. + std::sort(Ranges.begin(), Ranges.end()); + + if (!Ranges.empty()) { + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection()); + + MCSymbol *BeginLabel = Asm->createTempSymbol("Barange"); + MCSymbol *EndLabel = Asm->createTempSymbol("Earange"); + + unsigned HeaderSize = + sizeof(int32_t) + // Size of contents (w/o this field + sizeof(int16_t) + // DWARF ARange version number + sizeof(int32_t) + // Offset of CU in the .debug_info section + sizeof(int8_t) + // Pointer Size (in bytes) + sizeof(int8_t); // Segment Size (in bytes) + + unsigned TupleSize = AddressSize * 2; + unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize); + + Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length + Asm->OutStreamer.EmitLabel(BeginLabel); + Asm->EmitInt16(dwarf::DW_ARANGES_VERSION); // Version number + Asm->EmitInt32(Unit.getStartOffset()); // Corresponding unit's offset + Asm->EmitInt8(AddressSize); // Address size + Asm->EmitInt8(0); // Segment size + + Asm->OutStreamer.EmitFill(Padding, 0x0); + + for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; + ++Range) { + uint64_t RangeStart = Range->first; + MS->EmitIntValue(RangeStart, AddressSize); + while ((Range + 1) != End && Range->second == (Range + 1)->first) + ++Range; + MS->EmitIntValue(Range->second - RangeStart, AddressSize); + } + + // Emit terminator + Asm->OutStreamer.EmitIntValue(0, AddressSize); + Asm->OutStreamer.EmitIntValue(0, AddressSize); + Asm->OutStreamer.EmitLabel(EndLabel); + } + + if (!DoDebugRanges) + return; + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection()); + // Offset each range by the right amount. + int64_t PcOffset = -Unit.getLowPc(); + // Emit coalesced ranges. + for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) { + MS->EmitIntValue(Range->first + PcOffset, AddressSize); + while (Range + 1 != End && Range->second == (Range + 1)->first) + ++Range; + MS->EmitIntValue(Range->second + PcOffset, AddressSize); + RangesSectionSize += 2 * AddressSize; + } + + // Add the terminator entry. + MS->EmitIntValue(0, AddressSize); + MS->EmitIntValue(0, AddressSize); + RangesSectionSize += 2 * AddressSize; +} + +/// \brief Emit location lists for \p Unit and update attribtues to +/// point to the new entries. +void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit, + DWARFContext &Dwarf) { + const std::vector<std::pair<DIEInteger *, int64_t>> &Attributes = + Unit.getLocationAttributes(); + + if (Attributes.empty()) + return; + + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection()); + + unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); + const DWARFSection &InputSec = Dwarf.getLocSection(); + DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize); + DWARFUnit &OrigUnit = Unit.getOrigUnit(); + const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false); + int64_t UnitPcOffset = 0; + uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress( + &OrigUnit, dwarf::DW_AT_low_pc, -1ULL); + if (OrigLowPc != -1ULL) + UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc(); + + for (const auto &Attr : Attributes) { + uint32_t Offset = Attr.first->getValue(); + Attr.first->setValue(LocSectionSize); + // This is the quantity to add to the old location address to get + // the correct address for the new one. + int64_t LocPcOffset = Attr.second + UnitPcOffset; + while (Data.isValidOffset(Offset)) { + uint64_t Low = Data.getUnsigned(&Offset, AddressSize); + uint64_t High = Data.getUnsigned(&Offset, AddressSize); + LocSectionSize += 2 * AddressSize; + if (Low == 0 && High == 0) { + Asm->OutStreamer.EmitIntValue(0, AddressSize); + Asm->OutStreamer.EmitIntValue(0, AddressSize); + break; + } + Asm->OutStreamer.EmitIntValue(Low + LocPcOffset, AddressSize); + Asm->OutStreamer.EmitIntValue(High + LocPcOffset, AddressSize); + uint64_t Length = Data.getU16(&Offset); + Asm->OutStreamer.EmitIntValue(Length, 2); + // Just copy the bytes over. + Asm->OutStreamer.EmitBytes( + StringRef(InputSec.Data.substr(Offset, Length))); + Offset += Length; + LocSectionSize += Length + 2; + } + } +} + +void DwarfStreamer::emitLineTableForUnit(StringRef PrologueBytes, + unsigned MinInstLength, + std::vector<DWARFDebugLine::Row> &Rows, + unsigned PointerSize) { + // Switch to the section where the table will be emitted into. + MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection()); + MCSymbol *LineStartSym = MC->CreateTempSymbol(); + MCSymbol *LineEndSym = MC->CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + Asm->EmitLabelDifference(LineEndSym, LineStartSym, 4); + Asm->OutStreamer.EmitLabel(LineStartSym); + // Copy Prologue. + MS->EmitBytes(PrologueBytes); + LineSectionSize += PrologueBytes.size() + 4; + + SmallString<128> EncodingBuffer; + raw_svector_ostream EncodingOS(EncodingBuffer); + + if (Rows.empty()) { + // We only have the dummy entry, dsymutil emits an entry with a 0 + // address in that case. + MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS); + MS->EmitBytes(EncodingOS.str()); + LineSectionSize += EncodingBuffer.size(); + MS->EmitLabel(LineEndSym); + return; + } + + // Line table state machine fields + unsigned FileNum = 1; + unsigned LastLine = 1; + unsigned Column = 0; + unsigned IsStatement = 1; + unsigned Isa = 0; + uint64_t Address = -1ULL; + + unsigned RowsSinceLastSequence = 0; + + for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) { + auto &Row = Rows[Idx]; + + int64_t AddressDelta; + if (Address == -1ULL) { + MS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); + MS->EmitULEB128IntValue(PointerSize + 1); + MS->EmitIntValue(dwarf::DW_LNE_set_address, 1); + MS->EmitIntValue(Row.Address, PointerSize); + LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1); + AddressDelta = 0; + } else { + AddressDelta = (Row.Address - Address) / MinInstLength; + } + + // FIXME: code copied and transfromed from + // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share + // this code, but the current compatibility requirement with + // classic dsymutil makes it hard. Revisit that once this + // requirement is dropped. + + if (FileNum != Row.File) { + FileNum = Row.File; + MS->EmitIntValue(dwarf::DW_LNS_set_file, 1); + MS->EmitULEB128IntValue(FileNum); + LineSectionSize += 1 + getULEB128Size(FileNum); + } + if (Column != Row.Column) { + Column = Row.Column; + MS->EmitIntValue(dwarf::DW_LNS_set_column, 1); + MS->EmitULEB128IntValue(Column); + LineSectionSize += 1 + getULEB128Size(Column); + } + + // FIXME: We should handle the discriminator here, but dsymutil + // doesn' consider it, thus ignore it for now. + + if (Isa != Row.Isa) { + Isa = Row.Isa; + MS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); + MS->EmitULEB128IntValue(Isa); + LineSectionSize += 1 + getULEB128Size(Isa); + } + if (IsStatement != Row.IsStmt) { + IsStatement = Row.IsStmt; + MS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); + LineSectionSize += 1; + } + if (Row.BasicBlock) { + MS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); + LineSectionSize += 1; + } + + if (Row.PrologueEnd) { + MS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); + LineSectionSize += 1; + } + + if (Row.EpilogueBegin) { + MS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); + LineSectionSize += 1; + } + + int64_t LineDelta = int64_t(Row.Line) - LastLine; + if (!Row.EndSequence) { + MCDwarfLineAddr::Encode(*MC, LineDelta, AddressDelta, EncodingOS); + MS->EmitBytes(EncodingOS.str()); + LineSectionSize += EncodingBuffer.size(); + EncodingBuffer.resize(0); + EncodingOS.resync(); + Address = Row.Address; + LastLine = Row.Line; + RowsSinceLastSequence++; + } else { + if (LineDelta) { + MS->EmitIntValue(dwarf::DW_LNS_advance_line, 1); + MS->EmitSLEB128IntValue(LineDelta); + LineSectionSize += 1 + getSLEB128Size(LineDelta); + } + if (AddressDelta) { + MS->EmitIntValue(dwarf::DW_LNS_advance_pc, 1); + MS->EmitULEB128IntValue(AddressDelta); + LineSectionSize += 1 + getULEB128Size(AddressDelta); + } + MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS); + MS->EmitBytes(EncodingOS.str()); + LineSectionSize += EncodingBuffer.size(); + EncodingBuffer.resize(0); + EncodingOS.resync(); + Address = -1ULL; + LastLine = FileNum = IsStatement = 1; + RowsSinceLastSequence = Column = Isa = 0; + } + } + + if (RowsSinceLastSequence) { + MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS); + MS->EmitBytes(EncodingOS.str()); + LineSectionSize += EncodingBuffer.size(); + EncodingBuffer.resize(0); + EncodingOS.resync(); + } + + MS->EmitLabel(LineEndSym); +} + +/// \brief Emit the pubnames or pubtypes section contribution for \p +/// Unit into \p Sec. The data is provided in \p Names. +void DwarfStreamer::emitPubSectionForUnit( + const MCSection *Sec, StringRef SecName, const CompileUnit &Unit, + const std::vector<CompileUnit::AccelInfo> &Names) { + if (Names.empty()) + return; + + // Start the dwarf pubnames section. + Asm->OutStreamer.SwitchSection(Sec); + MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin"); + MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end"); + + bool HeaderEmitted = false; + // Emit the pubnames for this compilation unit. + for (const auto &Name : Names) { + if (Name.SkipPubSection) + continue; + + if (!HeaderEmitted) { + // Emit the header. + Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length + Asm->OutStreamer.EmitLabel(BeginLabel); + Asm->EmitInt16(dwarf::DW_PUBNAMES_VERSION); // Version + Asm->EmitInt32(Unit.getStartOffset()); // Unit offset + Asm->EmitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size + HeaderEmitted = true; + } + Asm->EmitInt32(Name.Die->getOffset()); + Asm->OutStreamer.EmitBytes( + StringRef(Name.Name.data(), Name.Name.size() + 1)); + } + + if (!HeaderEmitted) + return; + Asm->EmitInt32(0); // End marker. + Asm->OutStreamer.EmitLabel(EndLabel); +} + +/// \brief Emit .debug_pubnames for \p Unit. +void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) { + emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(), + "names", Unit, Unit.getPubnames()); +} + +/// \brief Emit .debug_pubtypes for \p Unit. +void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) { + emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(), + "types", Unit, Unit.getPubtypes()); +} + /// \brief The core of the Dwarf linking logic. /// /// The link of the dwarf information from the object files will be @@ -66,15 +976,21 @@ private: /// first step when we start processing a DebugMapObject. class DwarfLinker { public: - DwarfLinker(StringRef OutputFilename, bool Verbose) - : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {} + DwarfLinker(StringRef OutputFilename, const LinkOptions &Options) + : OutputFilename(OutputFilename), Options(Options), + BinHolder(Options.Verbose) {} + + ~DwarfLinker() { + for (auto *Abbrev : Abbreviations) + delete Abbrev; + } /// \brief Link the contents of the DebugMap. bool link(const DebugMap &); private: /// \brief Called at the start of a debug object link. - void startDebugObject(DWARFContext &); + void startDebugObject(DWARFContext &, DebugMapObject &); /// \brief Called at the end of a debug object link. void endDebugObject(); @@ -104,7 +1020,7 @@ private: /// consider. As we walk the DIEs in acsending file offset and as /// ValidRelocs is sorted by file offset, keeping this index /// uptodate is all we have to do to have a cheap lookup during the - /// root DIE selection. + /// root DIE selection and during DIE cloning. unsigned NextValidReloc; bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, @@ -160,6 +1076,114 @@ private: CompileUnit::DIEInfo &Info); /// @} + /// \defgroup Linking Methods used to link the debug information + /// + /// @{ + /// \brief Recursively clone \p InputDIE into an tree of DIE objects + /// where useless (as decided by lookForDIEsToKeep()) bits have been + /// stripped out and addresses have been rewritten according to the + /// debug map. + /// + /// \param OutOffset is the offset the cloned DIE in the output + /// compile unit. + /// \param PCOffset (while cloning a function scope) is the offset + /// applied to the entry point of the function to get the linked address. + /// + /// \returns the root of the cloned tree. + DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U, + int64_t PCOffset, uint32_t OutOffset); + + typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec; + + /// \brief Information gathered and exchanged between the various + /// clone*Attributes helpers about the attributes of a particular DIE. + struct AttributesInfo { + const char *Name, *MangledName; ///< Names. + uint32_t NameOffset, MangledNameOffset; ///< Offsets in the string pool. + + uint64_t OrigHighPc; ///< Value of AT_high_pc in the input DIE + int64_t PCOffset; ///< Offset to apply to PC addresses inside a function. + + bool HasLowPc; ///< Does the DIE have a low_pc attribute? + bool IsDeclaration; ///< Is this DIE only a declaration? + + AttributesInfo() + : Name(nullptr), MangledName(nullptr), NameOffset(0), + MangledNameOffset(0), OrigHighPc(0), PCOffset(0), HasLowPc(false), + IsDeclaration(false) {} + }; + + /// \brief Helper for cloneDIE. + unsigned cloneAttribute(DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, + CompileUnit &U, const DWARFFormValue &Val, + const AttributeSpec AttrSpec, unsigned AttrSize, + AttributesInfo &AttrInfo); + + /// \brief Helper for cloneDIE. + unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, const DWARFUnit &U); + + /// \brief Helper for cloneDIE. + unsigned + cloneDieReferenceAttribute(DIE &Die, + const DWARFDebugInfoEntryMinimal &InputDIE, + AttributeSpec AttrSpec, unsigned AttrSize, + const DWARFFormValue &Val, CompileUnit &Unit); + + /// \brief Helper for cloneDIE. + unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize); + + /// \brief Helper for cloneDIE. + unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + const CompileUnit &Unit, AttributesInfo &Info); + + /// \brief Helper for cloneDIE. + unsigned cloneScalarAttribute(DIE &Die, + const DWARFDebugInfoEntryMinimal &InputDIE, + CompileUnit &U, AttributeSpec AttrSpec, + const DWARFFormValue &Val, unsigned AttrSize, + AttributesInfo &Info); + + /// \brief Helper for cloneDIE. + bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset, + bool isLittleEndian); + + /// \brief Assign an abbreviation number to \p Abbrev + void AssignAbbrev(DIEAbbrev &Abbrev); + + /// \brief FoldingSet that uniques the abbreviations. + FoldingSet<DIEAbbrev> AbbreviationsSet; + /// \brief Storage for the unique Abbreviations. + /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot + /// be changed to a vecot of unique_ptrs. + std::vector<DIEAbbrev *> Abbreviations; + + /// \brief Compute and emit debug_ranges section for \p Unit, and + /// patch the attributes referencing it. + void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf) const; + + /// \brief Generate and emit the DW_AT_ranges attribute for a + /// compile_unit if it had one. + void generateUnitRanges(CompileUnit &Unit) const; + + /// \brief Extract the line tables fromt he original dwarf, extract + /// the relevant parts according to the linked function ranges and + /// emit the result in the debug_line section. + void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf); + + /// \brief Emit the accelerator entries for \p Unit. + void emitAcceleratorEntriesForUnit(CompileUnit &Unit); + + /// \brief DIELoc objects that need to be destructed (but not freed!). + std::vector<DIELoc *> DIELocs; + /// \brief DIEBlock objects that need to be destructed (but not freed!). + std::vector<DIEBlock *> DIEBlocks; + /// \brief Allocator used for all the DIEValue objects. + BumpPtrAllocator DIEAlloc; + /// @} + /// \defgroup Helpers Various helper methods. /// /// @{ @@ -170,20 +1194,37 @@ private: CompileUnit *getUnitForOffset(unsigned Offset); + bool getDIENames(const DWARFDebugInfoEntryMinimal &Die, DWARFUnit &U, + AttributesInfo &Info); + void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr, - const DWARFDebugInfoEntryMinimal *DIE = nullptr); + const DWARFDebugInfoEntryMinimal *DIE = nullptr) const; + + bool createStreamer(Triple TheTriple, StringRef OutputFilename); /// @} private: std::string OutputFilename; - bool Verbose; + LinkOptions Options; BinaryHolder BinHolder; + std::unique_ptr<DwarfStreamer> Streamer; /// The units of the current debug map object. std::vector<CompileUnit> Units; /// The debug map object curently under consideration. DebugMapObject *CurrentDebugObject; + + /// \brief The Dwarf string pool + NonRelocatableStringpool StringPool; + + /// \brief This map is keyed by the entry PC of functions in that + /// debug object and the associated value is a pair storing the + /// corresponding end PC and the offset to apply to get the linked + /// address. + /// + /// See startDebugObject() for a more complete description of its use. + std::map<uint64_t, std::pair<uint64_t, int64_t>> Ranges; }; /// \brief Similar to DWARFUnitSection::getUnitForOffset(), but @@ -215,16 +1256,34 @@ const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference( return nullptr; } +/// \brief Get the potential name and mangled name for the entity +/// described by \p Die and store them in \Info if they are not +/// already there. +/// \returns is a name was found. +bool DwarfLinker::getDIENames(const DWARFDebugInfoEntryMinimal &Die, + DWARFUnit &U, AttributesInfo &Info) { + // FIXME: a bit wastefull as the first getName might return the + // short name. + if (!Info.MangledName && + (Info.MangledName = Die.getName(&U, DINameKind::LinkageName))) + Info.MangledNameOffset = StringPool.getStringOffset(Info.MangledName); + + if (!Info.Name && (Info.Name = Die.getName(&U, DINameKind::ShortName))) + Info.NameOffset = StringPool.getStringOffset(Info.Name); + + return Info.Name || Info.MangledName; +} + /// \brief Report a warning to the user, optionaly including /// information about a specific \p DIE related to the warning. void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit, - const DWARFDebugInfoEntryMinimal *DIE) { + const DWARFDebugInfoEntryMinimal *DIE) const { + StringRef Context = "<debug map>"; if (CurrentDebugObject) - errs() << Twine("while processing ") + - CurrentDebugObject->getObjectFilename() + ":\n"; - errs() << Twine("warning: ") + Warning + "\n"; + Context = CurrentDebugObject->getObjectFilename(); + warn(Warning, Context); - if (!Verbose || !DIE) + if (!Options.Verbose || !DIE) return; errs() << " in DIE:\n"; @@ -232,6 +1291,14 @@ void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit, 6 /* Indent */); } +bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) { + if (Options.NoOutput) + return true; + + Streamer = llvm::make_unique<DwarfStreamer>(); + return Streamer->init(TheTriple, OutputFilename); +} + /// \brief Recursive helper to gather the child->parent relationships in the /// original compile unit. static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, @@ -260,14 +1327,45 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { llvm_unreachable("Invalid Tag"); } -void DwarfLinker::startDebugObject(DWARFContext &Dwarf) { +void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) { Units.reserve(Dwarf.getNumCompileUnits()); NextValidReloc = 0; + // Iterate over the debug map entries and put all the ones that are + // functions (because they have a size) into the Ranges map. This + // map is very similar to the FunctionRanges that are stored in each + // unit, with 2 notable differences: + // - obviously this one is global, while the other ones are per-unit. + // - this one contains not only the functions described in the DIE + // tree, but also the ones that are only in the debug map. + // The latter information is required to reproduce dsymutil's logic + // while linking line tables. The cases where this information + // matters look like bugs that need to be investigated, but for now + // we need to reproduce dsymutil's behavior. + // FIXME: Once we understood exactly if that information is needed, + // maybe totally remove this (or try to use it to do a real + // -gline-tables-only on Darwin. + for (const auto &Entry : Obj.symbols()) { + const auto &Mapping = Entry.getValue(); + if (Mapping.Size) + Ranges[Mapping.ObjectAddress] = std::make_pair( + Mapping.ObjectAddress + Mapping.Size, + int64_t(Mapping.BinaryAddress) - Mapping.ObjectAddress); + } } void DwarfLinker::endDebugObject() { Units.clear(); ValidRelocs.clear(); + Ranges.clear(); + + for (auto *Block : DIEBlocks) + Block->~DIEBlock(); + for (auto *Loc : DIELocs) + Loc->~DIELoc(); + + DIEBlocks.clear(); + DIELocs.clear(); + DIEAlloc.Reset(); } /// \brief Iterate over the relocations of the given \p Section and @@ -378,14 +1476,15 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, return false; const auto &ValidReloc = ValidRelocs[NextValidReloc++]; - if (Verbose) + if (Options.Verbose) outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey() << " " << format("\t%016" PRIx64 " => %016" PRIx64, ValidReloc.Mapping->getValue().ObjectAddress, ValidReloc.Mapping->getValue().BinaryAddress); - Info.Address = - ValidReloc.Mapping->getValue().BinaryAddress + ValidReloc.Addend; + Info.AddrAdjust = int64_t(ValidReloc.Mapping->getValue().BinaryAddress) + + ValidReloc.Addend - + ValidReloc.Mapping->getValue().ObjectAddress; Info.InDebugMap = true; return true; } @@ -442,7 +1541,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE( (Flags & TF_InFunctionScope)) return Flags; - if (Verbose) + if (Options.Verbose) DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */); return Flags | TF_Keep; @@ -474,10 +1573,30 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE( !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo)) return Flags; - if (Verbose) + if (Options.Verbose) DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */); - return Flags | TF_Keep; + Flags |= TF_Keep; + + DWARFFormValue HighPcValue; + if (!DIE.getAttributeValue(&OrigUnit, dwarf::DW_AT_high_pc, HighPcValue)) { + reportWarning("Function without high_pc. Range will be discarded.\n", + &OrigUnit, &DIE); + return Flags; + } + + uint64_t HighPc; + if (HighPcValue.isFormClass(DWARFFormValue::FC_Address)) { + HighPc = *HighPcValue.getAsAddress(&OrigUnit); + } else { + assert(HighPcValue.isFormClass(DWARFFormValue::FC_Constant)); + HighPc = LowPc + *HighPcValue.getAsUnsignedConstant(); + } + + // Replace the debug map range with a more accurate one. + Ranges[LowPc] = std::make_pair(HighPc, MyInfo.AddrAdjust); + Unit.addFunctionRange(LowPc, HighPc, MyInfo.AddrAdjust); + return Flags; } /// \brief Check if a DIE should be kept. @@ -503,7 +1622,6 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, return Flags; } - /// \brief Mark the passed DIE as well as all the ones it depends on /// as kept. /// @@ -601,6 +1719,708 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE, lookForDIEsToKeep(*Child, DMO, CU, Flags); } +/// \brief Assign an abbreviation numer to \p Abbrev. +/// +/// Our DIEs get freed after every DebugMapObject has been processed, +/// thus the FoldingSet we use to unique DIEAbbrevs cannot refer to +/// the instances hold by the DIEs. When we encounter an abbreviation +/// that we don't know, we create a permanent copy of it. +void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) { + // Check the set for priors. + FoldingSetNodeID ID; + Abbrev.Profile(ID); + void *InsertToken; + DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken); + + // If it's newly added. + if (InSet) { + // Assign existing abbreviation number. + Abbrev.setNumber(InSet->getNumber()); + } else { + // Add to abbreviation list. + Abbreviations.push_back( + new DIEAbbrev(Abbrev.getTag(), Abbrev.hasChildren())); + for (const auto &Attr : Abbrev.getData()) + Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm()); + AbbreviationsSet.InsertNode(Abbreviations.back(), InsertToken); + // Assign the unique abbreviation number. + Abbrev.setNumber(Abbreviations.size()); + Abbreviations.back()->setNumber(Abbreviations.size()); + } +} + +/// \brief Clone a string attribute described by \p AttrSpec and add +/// it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + const DWARFUnit &U) { + // Switch everything to out of line strings. + const char *String = *Val.getAsCString(&U); + unsigned Offset = StringPool.getStringOffset(String); + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp, + new (DIEAlloc) DIEInteger(Offset)); + return 4; +} + +/// \brief Clone an attribute referencing another DIE and add +/// it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneDieReferenceAttribute( + DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, + AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val, + CompileUnit &Unit) { + uint32_t Ref = *Val.getAsReference(&Unit.getOrigUnit()); + DIE *NewRefDie = nullptr; + CompileUnit *RefUnit = nullptr; + const DWARFDebugInfoEntryMinimal *RefDie = nullptr; + + if (!(RefUnit = getUnitForOffset(Ref)) || + !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) { + const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr); + if (!AttributeString) + AttributeString = "DW_AT_???"; + reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString + + ". Dropping.", + &Unit.getOrigUnit(), &InputDIE); + return 0; + } + + unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie); + CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx); + if (!RefInfo.Clone) { + assert(Ref > InputDIE.getOffset()); + // We haven't cloned this DIE yet. Just create an empty one and + // store it. It'll get really cloned when we process it. + RefInfo.Clone = new DIE(dwarf::Tag(RefDie->getTag())); + } + NewRefDie = RefInfo.Clone; + + if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) { + // We cannot currently rely on a DIEEntry to emit ref_addr + // references, because the implementation calls back to DwarfDebug + // to find the unit offset. (We don't have a DwarfDebug) + // FIXME: we should be able to design DIEEntry reliance on + // DwarfDebug away. + DIEInteger *Attr; + if (Ref < InputDIE.getOffset()) { + // We must have already cloned that DIE. + uint32_t NewRefOffset = + RefUnit->getStartOffset() + NewRefDie->getOffset(); + Attr = new (DIEAlloc) DIEInteger(NewRefOffset); + } else { + // A forward reference. Note and fixup later. + Attr = new (DIEAlloc) DIEInteger(0xBADDEF); + Unit.noteForwardReference(NewRefDie, RefUnit, Attr); + } + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr, + Attr); + return AttrSize; + } + + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), + new (DIEAlloc) DIEEntry(*NewRefDie)); + return AttrSize; +} + +/// \brief Clone an attribute of block form (locations, constants) and add +/// it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + unsigned AttrSize) { + DIE *Attr; + DIEValue *Value; + DIELoc *Loc = nullptr; + DIEBlock *Block = nullptr; + // Just copy the block data over. + if (AttrSpec.Form == dwarf::DW_FORM_exprloc) { + Loc = new (DIEAlloc) DIELoc(); + DIELocs.push_back(Loc); + } else { + Block = new (DIEAlloc) DIEBlock(); + DIEBlocks.push_back(Block); + } + Attr = Loc ? static_cast<DIE *>(Loc) : static_cast<DIE *>(Block); + Value = Loc ? static_cast<DIEValue *>(Loc) : static_cast<DIEValue *>(Block); + ArrayRef<uint8_t> Bytes = *Val.getAsBlock(); + for (auto Byte : Bytes) + Attr->addValue(static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1, + new (DIEAlloc) DIEInteger(Byte)); + // FIXME: If DIEBlock and DIELoc just reuses the Size field of + // the DIE class, this if could be replaced by + // Attr->setSize(Bytes.size()). + if (Streamer) { + if (Loc) + Loc->ComputeSize(&Streamer->getAsmPrinter()); + else + Block->ComputeSize(&Streamer->getAsmPrinter()); + } + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), + Value); + return AttrSize; +} + +/// \brief Clone an address attribute and add it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec, + const DWARFFormValue &Val, + const CompileUnit &Unit, + AttributesInfo &Info) { + uint64_t Addr = *Val.getAsAddress(&Unit.getOrigUnit()); + if (AttrSpec.Attr == dwarf::DW_AT_low_pc) { + if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine || + Die.getTag() == dwarf::DW_TAG_lexical_block) + Addr += Info.PCOffset; + else if (Die.getTag() == dwarf::DW_TAG_compile_unit) { + Addr = Unit.getLowPc(); + if (Addr == UINT64_MAX) + return 0; + } + Info.HasLowPc = true; + } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) { + if (Die.getTag() == dwarf::DW_TAG_compile_unit) { + if (uint64_t HighPc = Unit.getHighPc()) + Addr = HighPc; + else + return 0; + } else + // If we have a high_pc recorded for the input DIE, use + // it. Otherwise (when no relocations where applied) just use the + // one we just decoded. + Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset; + } + + Die.addValue(static_cast<dwarf::Attribute>(AttrSpec.Attr), + static_cast<dwarf::Form>(AttrSpec.Form), + new (DIEAlloc) DIEInteger(Addr)); + return Unit.getOrigUnit().getAddressByteSize(); +} + +/// \brief Clone a scalar attribute and add it to \p Die. +/// \returns the size of the new attribute. +unsigned DwarfLinker::cloneScalarAttribute( + DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit, + AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize, + AttributesInfo &Info) { + uint64_t Value; + if (AttrSpec.Attr == dwarf::DW_AT_high_pc && + Die.getTag() == dwarf::DW_TAG_compile_unit) { + if (Unit.getLowPc() == -1ULL) + return 0; + // Dwarf >= 4 high_pc is an size, not an address. + Value = Unit.getHighPc() - Unit.getLowPc(); + } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset) + Value = *Val.getAsSectionOffset(); + else if (AttrSpec.Form == dwarf::DW_FORM_sdata) + Value = *Val.getAsSignedConstant(); + else if (auto OptionalValue = Val.getAsUnsignedConstant()) + Value = *OptionalValue; + else { + reportWarning("Unsupported scalar attribute form. Dropping attribute.", + &Unit.getOrigUnit(), &InputDIE); + return 0; + } + DIEInteger *Attr = new (DIEAlloc) DIEInteger(Value); + if (AttrSpec.Attr == dwarf::DW_AT_ranges) + Unit.noteRangeAttribute(Die, Attr); + // A more generic way to check for location attributes would be + // nice, but it's very unlikely that any other attribute needs a + // location list. + else if (AttrSpec.Attr == dwarf::DW_AT_location || + AttrSpec.Attr == dwarf::DW_AT_frame_base) + Unit.noteLocationAttribute(Attr, Info.PCOffset); + else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value) + Info.IsDeclaration = true; + + Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form), + Attr); + return AttrSize; +} + +/// \brief Clone \p InputDIE's attribute described by \p AttrSpec with +/// value \p Val, and add it to \p Die. +/// \returns the size of the cloned attribute. +unsigned DwarfLinker::cloneAttribute(DIE &Die, + const DWARFDebugInfoEntryMinimal &InputDIE, + CompileUnit &Unit, + const DWARFFormValue &Val, + const AttributeSpec AttrSpec, + unsigned AttrSize, AttributesInfo &Info) { + const DWARFUnit &U = Unit.getOrigUnit(); + + switch (AttrSpec.Form) { + case dwarf::DW_FORM_strp: + case dwarf::DW_FORM_string: + return cloneStringAttribute(Die, AttrSpec, Val, U); + case dwarf::DW_FORM_ref_addr: + case dwarf::DW_FORM_ref1: + case dwarf::DW_FORM_ref2: + case dwarf::DW_FORM_ref4: + case dwarf::DW_FORM_ref8: + return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val, + Unit); + case dwarf::DW_FORM_block: + case dwarf::DW_FORM_block1: + case dwarf::DW_FORM_block2: + case dwarf::DW_FORM_block4: + case dwarf::DW_FORM_exprloc: + return cloneBlockAttribute(Die, AttrSpec, Val, AttrSize); + case dwarf::DW_FORM_addr: + return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info); + case dwarf::DW_FORM_data1: + case dwarf::DW_FORM_data2: + case dwarf::DW_FORM_data4: + case dwarf::DW_FORM_data8: + case dwarf::DW_FORM_udata: + case dwarf::DW_FORM_sdata: + case dwarf::DW_FORM_sec_offset: + case dwarf::DW_FORM_flag: + case dwarf::DW_FORM_flag_present: + return cloneScalarAttribute(Die, InputDIE, Unit, AttrSpec, Val, AttrSize, + Info); + default: + reportWarning("Unsupported attribute form in cloneAttribute. Dropping.", &U, + &InputDIE); + } + + return 0; +} + +/// \brief Apply the valid relocations found by findValidRelocs() to +/// the buffer \p Data, taking into account that Data is at \p BaseOffset +/// in the debug_info section. +/// +/// Like for findValidRelocs(), this function must be called with +/// monotonic \p BaseOffset values. +/// +/// \returns wether any reloc has been applied. +bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data, + uint32_t BaseOffset, bool isLittleEndian) { + assert((NextValidReloc == 0 || + BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) && + "BaseOffset should only be increasing."); + if (NextValidReloc >= ValidRelocs.size()) + return false; + + // Skip relocs that haven't been applied. + while (NextValidReloc < ValidRelocs.size() && + ValidRelocs[NextValidReloc].Offset < BaseOffset) + ++NextValidReloc; + + bool Applied = false; + uint64_t EndOffset = BaseOffset + Data.size(); + while (NextValidReloc < ValidRelocs.size() && + ValidRelocs[NextValidReloc].Offset >= BaseOffset && + ValidRelocs[NextValidReloc].Offset < EndOffset) { + const auto &ValidReloc = ValidRelocs[NextValidReloc++]; + assert(ValidReloc.Offset - BaseOffset < Data.size()); + assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size()); + char Buf[8]; + uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress; + Value += ValidReloc.Addend; + for (unsigned i = 0; i != ValidReloc.Size; ++i) { + unsigned Index = isLittleEndian ? i : (ValidReloc.Size - i - 1); + Buf[i] = uint8_t(Value >> (Index * 8)); + } + assert(ValidReloc.Size <= sizeof(Buf)); + memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size); + Applied = true; + } + + return Applied; +} + +static bool isTypeTag(uint16_t Tag) { + switch (Tag) { + case dwarf::DW_TAG_array_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_reference_type: + case dwarf::DW_TAG_string_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_union_type: + case dwarf::DW_TAG_ptr_to_member_type: + case dwarf::DW_TAG_set_type: + case dwarf::DW_TAG_subrange_type: + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_const_type: + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_file_type: + case dwarf::DW_TAG_namelist: + case dwarf::DW_TAG_packed_type: + case dwarf::DW_TAG_volatile_type: + case dwarf::DW_TAG_restrict_type: + case dwarf::DW_TAG_interface_type: + case dwarf::DW_TAG_unspecified_type: + case dwarf::DW_TAG_shared_type: + return true; + default: + break; + } + return false; +} + +/// \brief Recursively clone \p InputDIE's subtrees that have been +/// selected to appear in the linked output. +/// +/// \param OutOffset is the Offset where the newly created DIE will +/// lie in the linked compile unit. +/// +/// \returns the cloned DIE object or null if nothing was selected. +DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, + CompileUnit &Unit, int64_t PCOffset, + uint32_t OutOffset) { + DWARFUnit &U = Unit.getOrigUnit(); + unsigned Idx = U.getDIEIndex(&InputDIE); + CompileUnit::DIEInfo &Info = Unit.getInfo(Idx); + + // Should the DIE appear in the output? + if (!Unit.getInfo(Idx).Keep) + return nullptr; + + uint32_t Offset = InputDIE.getOffset(); + // The DIE might have been already created by a forward reference + // (see cloneDieReferenceAttribute()). + DIE *Die = Info.Clone; + if (!Die) + Die = Info.Clone = new DIE(dwarf::Tag(InputDIE.getTag())); + assert(Die->getTag() == InputDIE.getTag()); + Die->setOffset(OutOffset); + + // Extract and clone every attribute. + DataExtractor Data = U.getDebugInfoExtractor(); + uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset(); + AttributesInfo AttrInfo; + + // We could copy the data only if we need to aply a relocation to + // it. After testing, it seems there is no performance downside to + // doing the copy unconditionally, and it makes the code simpler. + SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset)); + Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize()); + // Modify the copy with relocated addresses. + if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) { + // If we applied relocations, we store the value of high_pc that was + // potentially stored in the input DIE. If high_pc is an address + // (Dwarf version == 2), then it might have been relocated to a + // totally unrelated value (because the end address in the object + // file might be start address of another function which got moved + // independantly by the linker). The computation of the actual + // high_pc value is done in cloneAddressAttribute(). + AttrInfo.OrigHighPc = + InputDIE.getAttributeValueAsAddress(&U, dwarf::DW_AT_high_pc, 0); + } + + // Reset the Offset to 0 as we will be working on the local copy of + // the data. + Offset = 0; + + const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr(); + Offset += getULEB128Size(Abbrev->getCode()); + + // We are entering a subprogram. Get and propagate the PCOffset. + if (Die->getTag() == dwarf::DW_TAG_subprogram) + PCOffset = Info.AddrAdjust; + AttrInfo.PCOffset = PCOffset; + + for (const auto &AttrSpec : Abbrev->attributes()) { + DWARFFormValue Val(AttrSpec.Form); + uint32_t AttrSize = Offset; + Val.extractValue(Data, &Offset, &U); + AttrSize = Offset - AttrSize; + + OutOffset += + cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize, AttrInfo); + } + + // Look for accelerator entries. + uint16_t Tag = InputDIE.getTag(); + // FIXME: This is slightly wrong. An inline_subroutine without a + // low_pc, but with AT_ranges might be interesting to get into the + // accelerator tables too. For now stick with dsymutil's behavior. + if ((Info.InDebugMap || AttrInfo.HasLowPc) && + Tag != dwarf::DW_TAG_compile_unit && + getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) { + if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name) + Unit.addNameAccelerator(Die, AttrInfo.MangledName, + AttrInfo.MangledNameOffset, + Tag == dwarf::DW_TAG_inlined_subroutine); + if (AttrInfo.Name) + Unit.addNameAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset, + Tag == dwarf::DW_TAG_inlined_subroutine); + } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration && + getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) { + Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset); + } + + DIEAbbrev &NewAbbrev = Die->getAbbrev(); + // If a scope DIE is kept, we must have kept at least one child. If + // it's not the case, we'll just be emitting one wasteful end of + // children marker, but things won't break. + if (InputDIE.hasChildren()) + NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes); + // Assign a permanent abbrev number + AssignAbbrev(Die->getAbbrev()); + + // Add the size of the abbreviation number to the output offset. + OutOffset += getULEB128Size(Die->getAbbrevNumber()); + + if (!Abbrev->hasChildren()) { + // Update our size. + Die->setSize(OutOffset - Die->getOffset()); + return Die; + } + + // Recursively clone children. + for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL(); + Child = Child->getSibling()) { + if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset)) { + Die->addChild(std::unique_ptr<DIE>(Clone)); + OutOffset = Clone->getOffset() + Clone->getSize(); + } + } + + // Account for the end of children marker. + OutOffset += sizeof(int8_t); + // Update our size. + Die->setSize(OutOffset - Die->getOffset()); + return Die; +} + +/// \brief Patch the input object file relevant debug_ranges entries +/// and emit them in the output file. Update the relevant attributes +/// to point at the new entries. +void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit, + DWARFContext &OrigDwarf) const { + DWARFDebugRangeList RangeList; + const auto &FunctionRanges = Unit.getFunctionRanges(); + unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize(); + DataExtractor RangeExtractor(OrigDwarf.getRangeSection(), + OrigDwarf.isLittleEndian(), AddressSize); + auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange; + DWARFUnit &OrigUnit = Unit.getOrigUnit(); + const auto *OrigUnitDie = OrigUnit.getCompileUnitDIE(false); + uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress( + &OrigUnit, dwarf::DW_AT_low_pc, -1ULL); + // Ranges addresses are based on the unit's low_pc. Compute the + // offset we need to apply to adapt to the the new unit's low_pc. + int64_t UnitPcOffset = 0; + if (OrigLowPc != -1ULL) + UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc(); + + for (const auto &RangeAttribute : Unit.getRangesAttributes()) { + uint32_t Offset = RangeAttribute->getValue(); + RangeAttribute->setValue(Streamer->getRangesSectionSize()); + RangeList.extract(RangeExtractor, &Offset); + const auto &Entries = RangeList.getEntries(); + const DWARFDebugRangeList::RangeListEntry &First = Entries.front(); + + if (CurrRange == InvalidRange || First.StartAddress < CurrRange.start() || + First.StartAddress >= CurrRange.stop()) { + CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc); + if (CurrRange == InvalidRange || + CurrRange.start() > First.StartAddress + OrigLowPc) { + reportWarning("no mapping for range."); + continue; + } + } + + Streamer->emitRangesEntries(UnitPcOffset, OrigLowPc, CurrRange, Entries, + AddressSize); + } +} + +/// \brief Generate the debug_aranges entries for \p Unit and if the +/// unit has a DW_AT_ranges attribute, also emit the debug_ranges +/// contribution for this attribute. +/// FIXME: this could actually be done right in patchRangesForUnit, +/// but for the sake of initial bit-for-bit compatibility with legacy +/// dsymutil, we have to do it in a delayed pass. +void DwarfLinker::generateUnitRanges(CompileUnit &Unit) const { + DIEInteger *Attr = Unit.getUnitRangesAttribute(); + if (Attr) + Attr->setValue(Streamer->getRangesSectionSize()); + Streamer->emitUnitRangesEntries(Unit, Attr != nullptr); +} + +/// \brief Insert the new line info sequence \p Seq into the current +/// set of already linked line info \p Rows. +static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq, + std::vector<DWARFDebugLine::Row> &Rows) { + if (Seq.empty()) + return; + + if (!Rows.empty() && Rows.back().Address < Seq.front().Address) { + Rows.insert(Rows.end(), Seq.begin(), Seq.end()); + Seq.clear(); + return; + } + + auto InsertPoint = std::lower_bound( + Rows.begin(), Rows.end(), Seq.front(), + [](const DWARFDebugLine::Row &LHS, const DWARFDebugLine::Row &RHS) { + return LHS.Address < RHS.Address; + }); + + // FIXME: this only removes the unneeded end_sequence if the + // sequences have been inserted in order. using a global sort like + // described in patchLineTableForUnit() and delaying the end_sequene + // elimination to emitLineTableForUnit() we can get rid of all of them. + if (InsertPoint != Rows.end() && + InsertPoint->Address == Seq.front().Address && InsertPoint->EndSequence) { + *InsertPoint = Seq.front(); + Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end()); + } else { + Rows.insert(InsertPoint, Seq.begin(), Seq.end()); + } + + Seq.clear(); +} + +/// \brief Extract the line table for \p Unit from \p OrigDwarf, and +/// recreate a relocated version of these for the address ranges that +/// are present in the binary. +void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit, + DWARFContext &OrigDwarf) { + const DWARFDebugInfoEntryMinimal *CUDie = + Unit.getOrigUnit().getCompileUnitDIE(); + uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset( + &Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL); + if (StmtList == -1ULL) + return; + + // Update the cloned DW_AT_stmt_list with the correct debug_line offset. + if (auto *OutputDIE = Unit.getOutputUnitDIE()) { + const auto &Abbrev = OutputDIE->getAbbrev().getData(); + auto Stmt = std::find_if( + Abbrev.begin(), Abbrev.end(), [](const DIEAbbrevData &AbbrevData) { + return AbbrevData.getAttribute() == dwarf::DW_AT_stmt_list; + }); + assert(Stmt < Abbrev.end() && "Didn't find DW_AT_stmt_list in cloned DIE!"); + DIEInteger *StmtAttr = + cast<DIEInteger>(OutputDIE->getValues()[Stmt - Abbrev.begin()]); + StmtAttr->setValue(Streamer->getLineSectionSize()); + } + + // Parse the original line info for the unit. + DWARFDebugLine::LineTable LineTable; + uint32_t StmtOffset = StmtList; + StringRef LineData = OrigDwarf.getLineSection().Data; + DataExtractor LineExtractor(LineData, OrigDwarf.isLittleEndian(), + Unit.getOrigUnit().getAddressByteSize()); + LineTable.parse(LineExtractor, &OrigDwarf.getLineSection().Relocs, + &StmtOffset); + + // This vector is the output line table. + std::vector<DWARFDebugLine::Row> NewRows; + NewRows.reserve(LineTable.Rows.size()); + + // Current sequence of rows being extracted, before being inserted + // in NewRows. + std::vector<DWARFDebugLine::Row> Seq; + const auto &FunctionRanges = Unit.getFunctionRanges(); + auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange; + + // FIXME: This logic is meant to generate exactly the same output as + // Darwin's classic dsynutil. There is a nicer way to implement this + // by simply putting all the relocated line info in NewRows and simply + // sorting NewRows before passing it to emitLineTableForUnit. This + // should be correct as sequences for a function should stay + // together in the sorted output. There are a few corner cases that + // look suspicious though, and that required to implement the logic + // this way. Revisit that once initial validation is finished. + + // Iterate over the object file line info and extract the sequences + // that correspond to linked functions. + for (auto &Row : LineTable.Rows) { + // Check wether we stepped out of the range. The range is + // half-open, but consider accept the end address of the range if + // it is marked as end_sequence in the input (because in that + // case, the relocation offset is accurate and that entry won't + // serve as the start of another function). + if (CurrRange == InvalidRange || Row.Address < CurrRange.start() || + Row.Address > CurrRange.stop() || + (Row.Address == CurrRange.stop() && !Row.EndSequence)) { + // We just stepped out of a known range. Insert a end_sequence + // corresponding to the end of the range. + uint64_t StopAddress = CurrRange != InvalidRange + ? CurrRange.stop() + CurrRange.value() + : -1ULL; + CurrRange = FunctionRanges.find(Row.Address); + bool CurrRangeValid = + CurrRange != InvalidRange && CurrRange.start() <= Row.Address; + if (!CurrRangeValid) { + CurrRange = InvalidRange; + if (StopAddress != -1ULL) { + // Try harder by looking in the DebugMapObject function + // ranges map. There are corner cases where this finds a + // valid entry. It's unclear if this is right or wrong, but + // for now do as dsymutil. + // FIXME: Understand exactly what cases this addresses and + // potentially remove it along with the Ranges map. + auto Range = Ranges.lower_bound(Row.Address); + if (Range != Ranges.begin() && Range != Ranges.end()) + --Range; + + if (Range != Ranges.end() && Range->first <= Row.Address && + Range->second.first >= Row.Address) { + StopAddress = Row.Address + Range->second.second; + } + } + } + if (StopAddress != -1ULL && !Seq.empty()) { + // Insert end sequence row with the computed end address, but + // the same line as the previous one. + Seq.emplace_back(Seq.back()); + Seq.back().Address = StopAddress; + Seq.back().EndSequence = 1; + Seq.back().PrologueEnd = 0; + Seq.back().BasicBlock = 0; + Seq.back().EpilogueBegin = 0; + insertLineSequence(Seq, NewRows); + } + + if (!CurrRangeValid) + continue; + } + + // Ignore empty sequences. + if (Row.EndSequence && Seq.empty()) + continue; + + // Relocate row address and add it to the current sequence. + Row.Address += CurrRange.value(); + Seq.emplace_back(Row); + + if (Row.EndSequence) + insertLineSequence(Seq, NewRows); + } + + // Finished extracting, now emit the line tables. + uint32_t PrologueEnd = StmtList + 10 + LineTable.Prologue.PrologueLength; + // FIXME: LLVM hardcodes it's prologue values. We just copy the + // prologue over and that works because we act as both producer and + // consumer. It would be nicer to have a real configurable line + // table emitter. + if (LineTable.Prologue.Version != 2 || + LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT || + LineTable.Prologue.LineBase != -5 || LineTable.Prologue.LineRange != 14 || + LineTable.Prologue.OpcodeBase != 13) + reportWarning("line table paramters mismatch. Cannot emit."); + else + Streamer->emitLineTableForUnit(LineData.slice(StmtList + 4, PrologueEnd), + LineTable.Prologue.MinInstLength, NewRows, + Unit.getOrigUnit().getAddressByteSize()); +} + +void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) { + Streamer->emitPubNamesForUnit(Unit); + Streamer->emitPubTypesForUnit(Unit); +} + bool DwarfLinker::link(const DebugMap &Map) { if (Map.begin() == Map.end()) { @@ -608,10 +2428,17 @@ bool DwarfLinker::link(const DebugMap &Map) { return false; } + if (!createStreamer(Map.getTriple(), OutputFilename)) + return false; + + // Size of the DIEs (and headers) generated for the linked output. + uint64_t OutputDebugInfoSize = 0; + // A unique ID that identifies each compile unit. + unsigned UnitID = 0; for (const auto &Obj : Map.objects()) { CurrentDebugObject = Obj.get(); - if (Verbose) + if (Options.Verbose) outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename()); if (std::error_code EC = ErrOrObj.getError()) { @@ -621,24 +2448,24 @@ bool DwarfLinker::link(const DebugMap &Map) { // Look for relocations that correspond to debug map entries. if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { - if (Verbose) + if (Options.Verbose) outs() << "No valid relocations found. Skipping.\n"; continue; } // Setup access to the debug info. DWARFContextInMemory DwarfContext(*ErrOrObj); - startDebugObject(DwarfContext); + startDebugObject(DwarfContext, *Obj); // In a first phase, just read in the debug info and store the DIE // parent links that we will use during the next phase. for (const auto &CU : DwarfContext.compile_units()) { auto *CUDie = CU->getCompileUnitDIE(false); - if (Verbose) { + if (Options.Verbose) { outs() << "Input compilation unit:"; CUDie->dump(outs(), CU.get(), 0); } - Units.emplace_back(*CU); + Units.emplace_back(*CU, UnitID++); gatherDIEParents(CUDie, 0, Units.back()); } @@ -651,16 +2478,63 @@ bool DwarfLinker::link(const DebugMap &Map) { lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj, CurrentUnit, 0); + // The calls to applyValidRelocs inside cloneDIE will walk the + // reloc array again (in the same way findValidRelocsInDebugInfo() + // did). We need to reset the NextValidReloc index to the beginning. + NextValidReloc = 0; + + // Construct the output DIE tree by cloning the DIEs we chose to + // keep above. If there are no valid relocs, then there's nothing + // to clone/emit. + if (!ValidRelocs.empty()) + for (auto &CurrentUnit : Units) { + const auto *InputDIE = CurrentUnit.getOrigUnit().getCompileUnitDIE(); + CurrentUnit.setStartOffset(OutputDebugInfoSize); + DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */, + 11 /* Unit Header size */); + CurrentUnit.setOutputUnitDIE(OutputDIE); + OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset(); + if (Options.NoOutput) + continue; + // FIXME: for compatibility with the classic dsymutil, we emit + // an empty line table for the unit, even if the unit doesn't + // actually exist in the DIE tree. + patchLineTableForUnit(CurrentUnit, DwarfContext); + if (!OutputDIE) + continue; + patchRangesForUnit(CurrentUnit, DwarfContext); + Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext); + emitAcceleratorEntriesForUnit(CurrentUnit); + } + + // Emit all the compile unit's debug information. + if (!ValidRelocs.empty() && !Options.NoOutput) + for (auto &CurrentUnit : Units) { + generateUnitRanges(CurrentUnit); + CurrentUnit.fixupForwardReferences(); + Streamer->emitCompileUnitHeader(CurrentUnit); + if (!CurrentUnit.getOutputUnitDIE()) + continue; + Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE()); + } + // Clean-up before starting working on the next object. endDebugObject(); } - return true; + // Emit everything that's global. + if (!Options.NoOutput) { + Streamer->emitAbbrevs(Abbreviations); + Streamer->emitStrings(StringPool); + } + + return Options.NoOutput ? true : Streamer->finish(); } } -bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) { - DwarfLinker Linker(OutputFilename, Verbose); +bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, + const LinkOptions &Options) { + DwarfLinker Linker(OutputFilename, Options); return Linker.link(DM); } } diff --git a/tools/dsymutil/LLVMBuild.txt b/tools/dsymutil/LLVMBuild.txt index c995291..99b0b44 100644 --- a/tools/dsymutil/LLVMBuild.txt +++ b/tools/dsymutil/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-dsymutil parent = Tools -required_libraries = DebugInfoDWARF Object Support +required_libraries = AsmPrinter DebugInfoDWARF MC Object Support all-targets diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp index 7bb0011..bf64303 100644 --- a/tools/dsymutil/MachODebugMapParser.cpp +++ b/tools/dsymutil/MachODebugMapParser.cpp @@ -51,6 +51,10 @@ private: /// Element of the debug map corresponfing to the current object file. DebugMapObject *CurrentDebugMapObject; + /// Holds function info while function scope processing. + const char *CurrentFunctionName; + uint64_t CurrentFunctionAddress; + void switchToNewDebugMapObject(StringRef Filename); void resetParserState(); uint64_t getMainBinarySymbolAddress(StringRef Name); @@ -149,6 +153,7 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, if (!CurrentDebugMapObject) return; + uint32_t Size = 0; switch (Type) { case MachO::N_GSYM: // This is a global variable. We need to query the main binary @@ -159,11 +164,18 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, return; break; case MachO::N_FUN: - // Functions are scopes in STABS. They have an end marker that we - // need to ignore. - if (Name[0] == '\0') + // Functions are scopes in STABS. They have an end marker that + // contains the function size. + if (Name[0] == '\0') { + Size = Value; + Value = CurrentFunctionAddress; + Name = CurrentFunctionName; + break; + } else { + CurrentFunctionName = Name; + CurrentFunctionAddress = Value; return; - break; + } case MachO::N_STSYM: break; default: @@ -174,7 +186,8 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, if (ObjectSymIt == CurrentObjectAddresses.end()) return Warning("could not find object file symbol for symbol " + Twine(Name)); - if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value)) + if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value, + Size)) return Warning(Twine("failed to insert symbol '") + Name + "' in the debug map."); } @@ -231,9 +244,8 @@ void MachODebugMapParser::loadMainBinarySymbols() { namespace llvm { namespace dsymutil { -llvm::ErrorOr<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile, - StringRef PrependPath, - bool Verbose) { +llvm::ErrorOr<std::unique_ptr<DebugMap>> +parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose) { MachODebugMapParser Parser(InputFile, PrependPath, Verbose); return Parser.parse(); } diff --git a/tools/dsymutil/Makefile b/tools/dsymutil/Makefile index e8dc569..c4365e0 100644 --- a/tools/dsymutil/Makefile +++ b/tools/dsymutil/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-dsymutil -LINK_COMPONENTS := DebugInfoDWARF Object Support +LINK_COMPONENTS := all-targets AsmPrinter DebugInfoDWARF MC Object Support # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp index 2b4fcfe..4fc91b0 100644 --- a/tools/dsymutil/dsymutil.cpp +++ b/tools/dsymutil/dsymutil.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.h" #include <string> using namespace llvm::dsymutil; @@ -29,6 +30,10 @@ using namespace llvm::cl; static opt<std::string> InputFile(Positional, desc("<input file>"), init("a.out")); +static opt<std::string> OutputFileOpt("o", desc("Specify the output file." + " default: <input file>.dwarf"), + value_desc("filename")); + static opt<std::string> OsoPrependPath("oso-prepend-path", desc("Specify a directory to prepend " "to the paths of object files."), @@ -36,6 +41,10 @@ static opt<std::string> OsoPrependPath("oso-prepend-path", static opt<bool> Verbose("v", desc("Verbosity level"), init(false)); +static opt<bool> NoOutput("no-output", desc("Do the link in memory, but do " + "not emit the result file."), + init(false)); + static opt<bool> ParseOnly("parse-only", desc("Only parse the debug map, do not actaully link " @@ -47,10 +56,19 @@ int main(int argc, char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram StackPrinter(argc, argv); llvm::llvm_shutdown_obj Shutdown; + LinkOptions Options; llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n"); auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose); + Options.Verbose = Verbose; + Options.NoOutput = NoOutput; + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllTargets(); + llvm::InitializeAllAsmPrinters(); + if (auto EC = DebugMapPtrOrErr.getError()) { llvm::errs() << "error: cannot parse the debug map for \"" << InputFile << "\": " << EC.message() << '\n'; @@ -63,9 +81,15 @@ int main(int argc, char **argv) { if (ParseOnly) return 0; - std::string OutputBasename(InputFile); - if (OutputBasename == "-") - OutputBasename = "a.out"; + std::string OutputFile; + if (OutputFileOpt.empty()) { + if (InputFile == "-") + OutputFile = "a.out.dwarf"; + else + OutputFile = InputFile + ".dwarf"; + } else { + OutputFile = OutputFileOpt; + } - return !linkDwarf(OutputBasename + ".dwarf", **DebugMapPtrOrErr, Verbose); + return !linkDwarf(OutputFile, **DebugMapPtrOrErr, Options); } diff --git a/tools/dsymutil/dsymutil.h b/tools/dsymutil/dsymutil.h index 9203bea..e9f7cd9 100644 --- a/tools/dsymutil/dsymutil.h +++ b/tools/dsymutil/dsymutil.h @@ -23,6 +23,14 @@ namespace llvm { namespace dsymutil { + +struct LinkOptions { + bool Verbose; ///< Verbosity + bool NoOutput; ///< Skip emitting output + + LinkOptions() : Verbose(false), NoOutput(false) {} +}; + /// \brief Extract the DebugMap from the given file. /// The file has to be a MachO object file. llvm::ErrorOr<std::unique_ptr<DebugMap>> @@ -33,7 +41,7 @@ parseDebugMap(StringRef InputFile, StringRef PrependPath = "", /// \p DM into a DwarfFile named \p OutputFilename. /// \returns false if the link failed. bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, - bool Verbose = false); + const LinkOptions &Options); } } #endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index e3a57b5..93ce3bc 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -91,6 +91,7 @@ namespace options { }; static bool generate_api_file = false; static OutputType TheOutputType = OT_NORMAL; + static unsigned OptLevel = 2; static std::string obj_path; static std::string extra_library_path; static std::string triple; @@ -124,6 +125,10 @@ namespace options { TheOutputType = OT_SAVE_TEMPS; } else if (opt == "disable-output") { TheOutputType = OT_DISABLE; + } else if (opt.size() == 2 && opt[0] == 'O') { + if (opt[1] < '0' || opt[1] > '3') + report_fatal_error("Optimization level must be between 0 and 3"); + OptLevel = opt[1] - '0'; } else { // Save this option to pass to the code generator. // ParseCommandLineOptions() expects argv[0] to be program name. Lazily @@ -295,8 +300,8 @@ static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) { case DS_Warning: Level = LDPL_WARNING; break; - case DS_Remark: case DS_Note: + case DS_Remark: Level = LDPL_INFO; break; } @@ -598,6 +603,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, Module &M = Obj.getModule(); + M.materializeMetadata(); UpgradeDebugInfo(M); SmallPtrSet<GlobalValue *, 8> Used; @@ -711,10 +717,9 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, static void runLTOPasses(Module &M, TargetMachine &TM) { if (const DataLayout *DL = TM.getDataLayout()) - M.setDataLayout(DL); + M.setDataLayout(*DL); legacy::PassManager passes; - passes.add(new DataLayoutPass()); passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); PassManagerBuilder PMB; @@ -724,6 +729,7 @@ static void runLTOPasses(Module &M, TargetMachine &TM) { PMB.VerifyOutput = true; PMB.LoopVectorize = true; PMB.SLPVectorize = true; + PMB.OptLevel = options::OptLevel; PMB.populateLTOPassManager(passes); passes.run(M); } @@ -754,9 +760,24 @@ static void codegen(Module &M) { Features.AddFeature(A); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + CodeGenOpt::Level CGOptLevel; + switch (options::OptLevel) { + case 0: + CGOptLevel = CodeGenOpt::None; + break; + case 1: + CGOptLevel = CodeGenOpt::Less; + break; + case 2: + CGOptLevel = CodeGenOpt::Default; + break; + case 3: + CGOptLevel = CodeGenOpt::Aggressive; + break; + } std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine( TripleStr, options::mcpu, Features.getString(), Options, RelocationModel, - CodeModel::Default, CodeGenOpt::Aggressive)); + CodeModel::Default, CGOptLevel)); runLTOPasses(M, *TM); @@ -764,7 +785,6 @@ static void codegen(Module &M) { saveBCFile(output_name + ".opt.bc", M); legacy::PassManager CodeGenPasses; - CodeGenPasses.add(new DataLayoutPass()); SmallString<128> Filename; int FD; @@ -809,7 +829,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { return LDPS_OK; LLVMContext Context; - Context.setDiagnosticHandler(diagnosticHandler); + Context.setDiagnosticHandler(diagnosticHandler, nullptr, true); std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context)); Linker L(Combined.get()); diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index 484ff40..dcbcf9d 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -17,4 +17,4 @@ set(LLVM_NO_DEAD_STRIP 1) add_llvm_tool(llc llc.cpp ) -set_target_properties(llc PROPERTIES ENABLE_EXPORTS 1) +export_executable_symbols(llc) diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index efa1422..55a45dc 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/CommandFlags.h" @@ -305,8 +306,7 @@ static int compileModule(char **argv, LLVMContext &Context) { // Add the target data from the target machine, if it exists, or the module. if (const DataLayout *DL = Target->getDataLayout()) - M->setDataLayout(DL); - PM.add(new DataLayoutPass()); + M->setDataLayout(*DL); if (RelaxAll.getNumOccurrences() > 0 && FileType != TargetMachine::CGFT_ObjectFile) diff --git a/tools/lli/Android.mk b/tools/lli/Android.mk index d771e56..a67c969 100644 --- a/tools/lli/Android.mk +++ b/tools/lli/Android.mk @@ -9,6 +9,7 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../.. lli_SRC_FILES := \ lli.cpp \ + OrcLazyJIT.cpp \ RemoteMemoryManager.cpp \ RemoteTarget.cpp \ RemoteTargetExternal.cpp \ diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 463c853..f98275b 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -35,8 +35,9 @@ endif( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool(lli lli.cpp + OrcLazyJIT.cpp RemoteMemoryManager.cpp RemoteTarget.cpp RemoteTargetExternal.cpp ) -set_target_properties(lli PROPERTIES ENABLE_EXPORTS 1) +export_executable_symbols(lli) diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp new file mode 100644 index 0000000..4a8d3b9 --- /dev/null +++ b/tools/lli/OrcLazyJIT.cpp @@ -0,0 +1,53 @@ +//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "OrcLazyJIT.h" +#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h" + +using namespace llvm; + +std::unique_ptr<OrcLazyJIT::CompileCallbackMgr> +OrcLazyJIT::createCallbackMgr(Triple T, LLVMContext &Context) { + switch (T.getArch()) { + default: + // Flag error. + Error = true; + return nullptr; + + case Triple::x86_64: { + typedef orc::JITCompileCallbackManager<CompileLayerT, + orc::OrcX86_64> CCMgrT; + return make_unique<CCMgrT>(CompileLayer, Context, 0, 64); + } + } +} + +int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) { + OrcLazyJIT J(std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget()), + getGlobalContext()); + + if (!J.Ok()) { + errs() << "Could not construct JIT.\n"; + return 1; + } + + auto MainHandle = J.addModule(std::move(M)); + auto MainSym = J.findSymbolIn(MainHandle, "main"); + + if (!MainSym) { + errs() << "Could not find main function.\n"; + return 1; + } + + typedef int (*MainFnPtr)(int, char*[]); + auto Main = reinterpret_cast<MainFnPtr>( + static_cast<uintptr_t>(MainSym.getAddress())); + + return Main(ArgC, ArgV); +} diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h new file mode 100644 index 0000000..76e1ac6 --- /dev/null +++ b/tools/lli/OrcLazyJIT.h @@ -0,0 +1,97 @@ +//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Simple Orc-based JIT. Uses the compile-on-demand layer to break up and +// lazily compile modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H +#define LLVM_TOOLS_LLI_ORCLAZYJIT_H + +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" +#include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h" +#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" +#include "llvm/IR/LLVMContext.h" + +namespace llvm { + +class OrcLazyJIT { +public: + + typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr; + typedef orc::ObjectLinkingLayer<> ObjLayerT; + typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT; + typedef orc::LazyEmittingLayer<CompileLayerT> LazyEmitLayerT; + typedef orc::CompileOnDemandLayer<LazyEmitLayerT, + CompileCallbackMgr> CODLayerT; + typedef CODLayerT::ModuleSetHandleT ModuleHandleT; + + OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context) + : Error(false), TM(std::move(TM)), + Mang(this->TM->getDataLayout()), + ObjectLayer([](){ return llvm::make_unique<SectionMemoryManager>(); }), + CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)), + LazyEmitLayer(CompileLayer), + CCMgr(createCallbackMgr(Triple(this->TM->getTargetTriple()), Context)), + CODLayer(LazyEmitLayer, *CCMgr) { } + + bool Ok() const { return !Error; } + + ModuleHandleT addModule(std::unique_ptr<Module> M) { + // Attach a data-layout if one isn't already present. + if (M->getDataLayout().isDefault()) + M->setDataLayout(*TM->getDataLayout()); + + std::vector<std::unique_ptr<Module>> S; + S.push_back(std::move(M)); + return CODLayer.addModuleSet(std::move(S)); + } + + orc::JITSymbol findSymbol(const std::string &Name) { + return CODLayer.findSymbol(mangle(Name), true); + } + + orc::JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) { + return CODLayer.findSymbolIn(H, mangle(Name), true); + } + +private: + + std::unique_ptr<CompileCallbackMgr> + createCallbackMgr(Triple T, LLVMContext &Context); + + std::string mangle(const std::string &Name) { + std::string MangledName; + { + raw_string_ostream MangledNameStream(MangledName); + Mang.getNameWithPrefix(MangledNameStream, Name); + } + return MangledName; + } + + bool Error; + std::unique_ptr<TargetMachine> TM; + Mangler Mang; + + ObjLayerT ObjectLayer; + CompileLayerT CompileLayer; + LazyEmitLayerT LazyEmitLayer; + std::unique_ptr<CompileCallbackMgr> CCMgr; + CODLayerT CODLayer; +}; + +int runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]); + +} // end namespace llvm + +#endif diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp index 47da8fb..0a16210 100644 --- a/tools/lli/RemoteMemoryManager.cpp +++ b/tools/lli/RemoteMemoryManager.cpp @@ -16,6 +16,7 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 9c2b781..47ce2c0 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "llvm/IR/LLVMContext.h" +#include "OrcLazyJIT.h" #include "RemoteMemoryManager.h" #include "RemoteTarget.h" #include "RemoteTargetExternal.h" @@ -42,6 +43,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" @@ -65,6 +67,9 @@ using namespace llvm; #define DEBUG_TYPE "lli" namespace { + + enum class JITKind { MCJIT, OrcMCJITReplacement, OrcLazy }; + cl::opt<std::string> InputFile(cl::desc("<input bitcode>"), cl::Positional, cl::init("-")); @@ -75,12 +80,19 @@ namespace { cl::desc("Force interpretation: disable JIT"), cl::init(false)); - cl::opt<bool> UseOrcMCJITReplacement("use-orcmcjit", - cl::desc("Use the experimental " - "OrcMCJITReplacement as a " - "drop-in replacement for " - "MCJIT."), - cl::init(false)); + cl::opt<JITKind> UseJITKind("jit-kind", + cl::desc("Choose underlying JIT kind."), + cl::init(JITKind::MCJIT), + cl::values( + clEnumValN(JITKind::MCJIT, "mcjit", + "MCJIT"), + clEnumValN(JITKind::OrcMCJITReplacement, + "orc-mcjit", + "Orc-based MCJIT replacement"), + clEnumValN(JITKind::OrcLazy, + "orc-lazy", + "Orc-based lazy JIT."), + clEnumValEnd)); // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying @@ -403,6 +415,9 @@ int main(int argc, char **argv, char * const *envp) { return 1; } + if (UseJITKind == JITKind::OrcLazy) + return runOrcLazyJIT(std::move(Owner), argc, argv); + if (EnableCacheManager) { std::string CacheName("file:"); CacheName.append(InputFile); @@ -429,7 +444,7 @@ int main(int argc, char **argv, char * const *envp) { builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter : EngineKind::JIT); - builder.setUseOrcMCJITReplacement(UseOrcMCJITReplacement); + builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement); // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 2f1eb3b..f813465 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/LineIterator.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 50c84e6..d2ef45a 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -44,7 +44,7 @@ if(CMAKE_CROSSCOMPILING) WORKING_DIRECTORY ${LLVM_NATIVE_BUILD} COMMENT "Building native llvm-config...") add_custom_target(${project}NativeLLVMConfig DEPENDS ${${project}_LLVM_CONFIG_EXE}) - add_dependencies(${project}NativeLLVMConfig ConfigureNativeLLVM) + add_dependencies(${project}NativeLLVMConfig CONFIGURE_LLVM_NATIVE) add_dependencies(llvm-config ${project}NativeLLVMConfig) endif(CMAKE_CROSSCOMPILING) diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index 224035a..879b9ab 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -91,9 +91,9 @@ static void VisitComponent(StringRef Name, /// are required to link the given components. /// \param IncludeNonInstalled - Whether non-installed components should be /// reported. -void ComputeLibsForComponents(const std::vector<StringRef> &Components, - std::vector<StringRef> &RequiredLibs, - bool IncludeNonInstalled) { +static void ComputeLibsForComponents(const std::vector<StringRef> &Components, + std::vector<StringRef> &RequiredLibs, + bool IncludeNonInstalled) { std::set<AvailableComponent*> VisitedComponents; // Build a map of component names to information. @@ -126,7 +126,7 @@ void ComputeLibsForComponents(const std::vector<StringRef> &Components, /* *** */ -void usage() { +static void usage() { errs() << "\ usage: llvm-config <OPTION>... [<COMPONENT>...]\n\ \n\ diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index cf8ab33..0331a02 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -20,6 +20,7 @@ #include "SourceCoverageView.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" #include "llvm/ProfileData/CoverageMapping.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CommandLine.h" @@ -28,6 +29,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include <functional> #include <system_error> @@ -87,6 +89,7 @@ public: LoadedSourceFiles; bool CompareFilenamesOnly; StringMap<std::string> RemappedFilenames; + llvm::Triple::ArchType CoverageArch; }; } @@ -193,7 +196,8 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile, } std::unique_ptr<CoverageMapping> CodeCoverageTool::load() { - auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename); + auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename, + CoverageArch); if (std::error_code EC = CoverageOrErr.getError()) { colored_ostream(errs(), raw_ostream::RED) << "error: Failed to load coverage: " << EC.message(); @@ -242,6 +246,9 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { cl::desc( "File with the profile data obtained after an instrumented run")); + cl::opt<std::string> Arch( + "arch", cl::desc("architecture of the coverage mapping binary")); + cl::opt<bool> DebugDump("dump", cl::Optional, cl::desc("Show internal debug dump")); @@ -287,11 +294,19 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { "greater than the given threshold"), cl::cat(FilteringCategory)); + cl::opt<cl::boolOrDefault> UseColor( + "use-color", cl::desc("Emit colored output (default=autodetect)"), + cl::init(cl::BOU_UNSET)); + auto commandLineParser = [&, this](int argc, const char **argv) -> int { cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); ViewOpts.Debug = DebugDump; CompareFilenamesOnly = FilenameEquivalence; + ViewOpts.Colors = UseColor == cl::BOU_UNSET + ? sys::Process::StandardOutHasColors() + : UseColor == cl::BOU_TRUE; + // Create the function filters if (!NameFilters.empty() || !NameRegexFilters.empty()) { auto NameFilterer = new CoverageFilters; @@ -322,6 +337,16 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer)); } + if (Arch.empty()) + CoverageArch = llvm::Triple::ArchType::UnknownArch; + else { + CoverageArch = Triple(Arch).getArch(); + if (CoverageArch == llvm::Triple::ArchType::UnknownArch) { + errs() << "error: Unknown architecture: " << Arch << "\n"; + return 1; + } + } + for (const auto &File : InputSourceFiles) { SmallString<128> Path(File); if (!CompareFilenamesOnly) @@ -372,15 +397,10 @@ int CodeCoverageTool::show(int argc, const char **argv, cl::desc("Show function instantiations"), cl::cat(ViewCategory)); - cl::opt<bool> NoColors("no-colors", cl::Optional, - cl::desc("Don't show text colors"), cl::init(false), - cl::cat(ViewCategory)); - auto Err = commandLineParser(argc, argv); if (Err) return Err; - ViewOpts.Colors = !NoColors; ViewOpts.ShowLineNumbers = true; ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 || !ShowRegions || ShowBestLineRegionsCounts; @@ -446,15 +466,10 @@ int CodeCoverageTool::show(int argc, const char **argv, int CodeCoverageTool::report(int argc, const char **argv, CommandLineParserType commandLineParser) { - cl::opt<bool> NoColors("no-colors", cl::Optional, - cl::desc("Don't show text colors"), cl::init(false)); - auto Err = commandLineParser(argc, argv); if (Err) return Err; - ViewOpts.Colors = !NoColors; - auto Coverage = load(); if (!Coverage) return 1; diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp index c0a48f8..4377a50 100644 --- a/tools/llvm-cov/gcov.cpp +++ b/tools/llvm-cov/gcov.cpp @@ -23,9 +23,10 @@ #include <system_error> using namespace llvm; -void reportCoverage(StringRef SourceFile, StringRef ObjectDir, - const std::string &InputGCNO, const std::string &InputGCDA, - bool DumpGCOV, const GCOVOptions &Options) { +static void reportCoverage(StringRef SourceFile, StringRef ObjectDir, + const std::string &InputGCNO, + const std::string &InputGCDA, bool DumpGCOV, + const GCOVOptions &Options) { SmallString<128> CoverageFileStem(ObjectDir); if (CoverageFileStem.empty()) { // If no directory was specified with -o, look next to the source file. diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 86ec26d..bf66f58 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -14,6 +14,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" #include <string> @@ -32,9 +33,13 @@ int convertForTestingMain(int argc, const char *argv[]); int gcovMain(int argc, const char *argv[]); /// \brief Top level help. -int helpMain(int argc, const char *argv[]) { - errs() << "OVERVIEW: LLVM code coverage tool\n\n" - << "USAGE: llvm-cov {gcov|report|show}\n"; +static int helpMain(int argc, const char *argv[]) { + errs() << "Usage: llvm-cov {gcov|report|show} [OPTION]...\n\n" + << "Shows code coverage information.\n\n" + << "Subcommands:\n" + << " gcov: Work with the gcov format.\n" + << " show: Annotate source files using instrprof style coverage.\n" + << " report: Summarize instrprof style coverage information.\n"; return 0; } @@ -61,18 +66,13 @@ int main(int argc, const char **argv) { } } - // Give a warning and fall back to gcov - errs().changeColor(raw_ostream::RED); - errs() << "warning:"; - // Assume that argv[1] wasn't a command when it stats with a '-' or is a - // filename (i.e. contains a '.') - if (argc > 1 && !StringRef(argv[1]).startswith("-") && - StringRef(argv[1]).find(".") == StringRef::npos) - errs() << " Unrecognized command '" << argv[1] << "'."; - errs() << " Using the gcov compatible mode " - "(this behaviour may be dropped in the future)."; - errs().resetColor(); - errs() << "\n"; - - return gcovMain(argc, argv); + if (argc > 1) { + if (sys::Process::StandardErrHasColors()) + errs().changeColor(raw_ostream::RED); + errs() << "Unrecognized command: " << argv[1] << ".\n\n"; + if (sys::Process::StandardErrHasColors()) + errs().resetColor(); + } + helpMain(argc, argv); + return 1; } diff --git a/tools/llvm-vtabledump/Android.mk b/tools/llvm-cxxdump/Android.mk index c3309e4..b45912c 100644 --- a/tools/llvm-vtabledump/Android.mk +++ b/tools/llvm-cxxdump/Android.mk @@ -3,11 +3,11 @@ LOCAL_PATH := $(call my-dir) LLVM_ROOT_PATH := $(LOCAL_PATH)/../.. include $(LLVM_ROOT_PATH)/llvm.mk -llvm_vtabledump_SRC_FILES := \ +llvm_cxxdump_SRC_FILES := \ Error.cpp \ - llvm-vtabledump.cpp + llvm-cxxdump.cpp -llvm_vtabledump_STATIC_LIBRARIES := \ +llvm_cxxdump_STATIC_LIBRARIES := \ libLLVMARMAsmParser \ libLLVMARMInfo \ libLLVMARMDesc \ @@ -47,13 +47,13 @@ llvm_vtabledump_STATIC_LIBRARIES := \ include $(CLEAR_VARS) -LOCAL_MODULE := llvm-vtabledump +LOCAL_MODULE := llvm-cxxdump LOCAL_MODULE_CLASS := EXECUTABLES LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES := $(llvm_vtabledump_SRC_FILES) +LOCAL_SRC_FILES := $(llvm_cxxdump_SRC_FILES) LOCAL_LDLIBS += -lpthread -lm -ldl -LOCAL_STATIC_LIBRARIES := $(llvm_vtabledump_STATIC_LIBRARIES) +LOCAL_STATIC_LIBRARIES := $(llvm_cxxdump_STATIC_LIBRARIES) include $(LLVM_HOST_BUILD_MK) include $(LLVM_GEN_INTRINSICS_MK) diff --git a/tools/llvm-vtabledump/CMakeLists.txt b/tools/llvm-cxxdump/CMakeLists.txt index 4fe205b..ada886e 100644 --- a/tools/llvm-vtabledump/CMakeLists.txt +++ b/tools/llvm-cxxdump/CMakeLists.txt @@ -4,7 +4,7 @@ set(LLVM_LINK_COMPONENTS Support ) -add_llvm_tool(llvm-vtabledump - llvm-vtabledump.cpp +add_llvm_tool(llvm-cxxdump + llvm-cxxdump.cpp Error.cpp ) diff --git a/tools/llvm-vtabledump/Error.cpp b/tools/llvm-cxxdump/Error.cpp index c5de895..16fed96 100644 --- a/tools/llvm-vtabledump/Error.cpp +++ b/tools/llvm-cxxdump/Error.cpp @@ -1,4 +1,4 @@ -//===- Error.cpp - system_error extensions for llvm-vtabledump --*- C++ -*-===// +//===- Error.cxx - system_error extensions for llvm-cxxdump -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This defines a new error_category for the llvm-vtabledump tool. +// This defines a new error_category for the llvm-cxxdump tool. // //===----------------------------------------------------------------------===// @@ -17,27 +17,27 @@ using namespace llvm; namespace { -class vtabledump_error_category : public std::error_category { +class cxxdump_error_category : public std::error_category { public: - const char *name() const LLVM_NOEXCEPT override { return "llvm.vtabledump"; } + const char *name() const LLVM_NOEXCEPT override { return "llvm.cxxdump"; } std::string message(int ev) const override { - switch (static_cast<vtabledump_error>(ev)) { - case vtabledump_error::success: + switch (static_cast<cxxdump_error>(ev)) { + case cxxdump_error::success: return "Success"; - case vtabledump_error::file_not_found: + case cxxdump_error::file_not_found: return "No such file."; - case vtabledump_error::unrecognized_file_format: + case cxxdump_error::unrecognized_file_format: return "Unrecognized file type."; } llvm_unreachable( - "An enumerator of vtabledump_error does not have a message defined."); + "An enumerator of cxxdump_error does not have a message defined."); } }; } // namespace namespace llvm { -const std::error_category &vtabledump_category() { - static vtabledump_error_category o; +const std::error_category &cxxdump_category() { + static cxxdump_error_category o; return o; } } // namespace llvm diff --git a/tools/llvm-vtabledump/Error.h b/tools/llvm-cxxdump/Error.h index fd8bb18..7caf6d6 100644 --- a/tools/llvm-vtabledump/Error.h +++ b/tools/llvm-cxxdump/Error.h @@ -1,4 +1,4 @@ -//===- Error.h - system_error extensions for llvm-vtabledump ----*- C++ -*-===// +//===- Error.h - system_error extensions for llvm-cxxdump -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,33 +7,33 @@ // //===----------------------------------------------------------------------===// // -// This declares a new error_category for the llvm-vtabledump tool. +// This declares a new error_category for the llvm-cxxdump tool. // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H -#define LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H +#ifndef LLVM_TOOLS_LLVM_CXXDUMP_ERROR_H +#define LLVM_TOOLS_LLVM_CXXDUMP_ERROR_H #include <system_error> namespace llvm { -const std::error_category &vtabledump_category(); +const std::error_category &cxxdump_category(); -enum class vtabledump_error { +enum class cxxdump_error { success = 0, file_not_found, unrecognized_file_format, }; -inline std::error_code make_error_code(vtabledump_error e) { - return std::error_code(static_cast<int>(e), vtabledump_category()); +inline std::error_code make_error_code(cxxdump_error e) { + return std::error_code(static_cast<int>(e), cxxdump_category()); } } // namespace llvm namespace std { template <> -struct is_error_code_enum<llvm::vtabledump_error> : std::true_type {}; +struct is_error_code_enum<llvm::cxxdump_error> : std::true_type {}; } #endif diff --git a/tools/llvm-vtabledump/LLVMBuild.txt b/tools/llvm-cxxdump/LLVMBuild.txt index 6a3cbff..4e08815 100644 --- a/tools/llvm-vtabledump/LLVMBuild.txt +++ b/tools/llvm-cxxdump/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./tools/llvm-vtabledump/LLVMBuild.txt --------------------*- Conf -*--===; +;===- ./tools/llvm-cxxdump/LLVMBuild.txt -----------------------*- Conf -*--===; ; ; The LLVM Compiler Infrastructure ; @@ -17,6 +17,6 @@ [component_0] type = Tool -name = llvm-vtabledump +name = llvm-cxxdump parent = Tools required_libraries = all-targets BitReader Object diff --git a/tools/llvm-vtabledump/Makefile b/tools/llvm-cxxdump/Makefile index 596c64c..02e8e5f 100644 --- a/tools/llvm-vtabledump/Makefile +++ b/tools/llvm-cxxdump/Makefile @@ -1,4 +1,4 @@ -##===- tools/llvm-vtabledump/Makefile ----------------------*- Makefile -*-===## +##===- tools/llvm-cxxdump/Makefile -------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -8,7 +8,7 @@ ##===----------------------------------------------------------------------===## LEVEL := ../.. -TOOLNAME := llvm-vtabledump +TOOLNAME := llvm-cxxdump LINK_COMPONENTS := bitreader object all-targets # This tool has no plugins, optimize startup time. diff --git a/tools/llvm-vtabledump/llvm-vtabledump.cpp b/tools/llvm-cxxdump/llvm-cxxdump.cpp index a21acae..aeb977a 100644 --- a/tools/llvm-vtabledump/llvm-vtabledump.cpp +++ b/tools/llvm-cxxdump/llvm-cxxdump.cpp @@ -1,4 +1,4 @@ -//===- llvm-vtabledump.cpp - Dump vtables in an Object File -----*- C++ -*-===// +//===- llvm-cxxdump.cpp - Dump C++ data in an Object File -------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,12 +7,11 @@ // //===----------------------------------------------------------------------===// // -// Dumps VTables resident in object files and archives. Note, it currently only -// supports MS-ABI style object files. +// Dumps C++ data resident in object files and archives. // //===----------------------------------------------------------------------===// -#include "llvm-vtabledump.h" +#include "llvm-cxxdump.h" #include "Error.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/Archive.h" @@ -25,6 +24,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" #include <map> #include <string> #include <system_error> @@ -43,7 +43,7 @@ static int ReturnValue = EXIT_SUCCESS; namespace llvm { -bool error(std::error_code EC) { +static bool error(std::error_code EC) { if (!EC) return false; @@ -135,7 +135,7 @@ static bool collectRelocationOffsets( return false; } -static void dumpVTables(const ObjectFile *Obj) { +static void dumpCXXData(const ObjectFile *Obj) { struct CompleteObjectLocator { StringRef Symbols[2]; ArrayRef<little32_t> Data; @@ -153,13 +153,32 @@ static void dumpVTables(const ObjectFile *Obj) { uint64_t AlwaysZero; StringRef MangledName; }; + struct ThrowInfo { + uint32_t Flags; + }; + struct CatchableTypeArray { + uint32_t NumEntries; + }; + struct CatchableType { + uint32_t Flags; + uint32_t NonVirtualBaseAdjustmentOffset; + int32_t VirtualBasePointerOffset; + uint32_t VirtualBaseAdjustmentOffset; + uint32_t Size; + StringRef Symbols[2]; + }; std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries; + std::map<std::pair<StringRef, uint64_t>, StringRef> TIEntries; + std::map<std::pair<StringRef, uint64_t>, StringRef> CTAEntries; std::map<StringRef, ArrayRef<little32_t>> VBTables; std::map<StringRef, CompleteObjectLocator> COLs; std::map<StringRef, ClassHierarchyDescriptor> CHDs; std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries; std::map<StringRef, BaseClassDescriptor> BCDs; std::map<StringRef, TypeDescriptor> TDs; + std::map<StringRef, ThrowInfo> TIs; + std::map<StringRef, CatchableTypeArray> CTAs; + std::map<StringRef, CatchableType> CTs; std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries; std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries; @@ -265,6 +284,39 @@ static void dumpVTables(const ObjectFile *Obj) { return; TDs[SymName] = TD; } + // Throw descriptors in the MS-ABI start with '_TI' + else if (SymName.startswith("_TI") || SymName.startswith("__TI")) { + ThrowInfo TI; + TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data()); + collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, + SymName, TIEntries); + TIs[SymName] = TI; + } + // Catchable type arrays in the MS-ABI start with _CTA or __CTA. + else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) { + CatchableTypeArray CTA; + CTA.NumEntries = + *reinterpret_cast<const little32_t *>(SymContents.data()); + collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, + SymName, CTAEntries); + CTAs[SymName] = CTA; + } + // Catchable types in the MS-ABI start with _CT or __CT. + else if (SymName.startswith("_CT") || SymName.startswith("__CT")) { + const little32_t *DataPtr = + reinterpret_cast<const little32_t *>(SymContents.data()); + CatchableType CT; + CT.Flags = DataPtr[0]; + CT.NonVirtualBaseAdjustmentOffset = DataPtr[2]; + CT.VirtualBasePointerOffset = DataPtr[3]; + CT.VirtualBaseAdjustmentOffset = DataPtr[4]; + CT.Size = DataPtr[5]; + StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols); + if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I, + E)) + return; + CTs[SymName] = CT; + } // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'. else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) { collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize, @@ -282,7 +334,8 @@ static void dumpVTables(const ObjectFile *Obj) { auto Key = std::make_pair(SymName, SymOffI); if (VTableSymEntries.count(Key)) continue; - const char *DataPtr = SymContents.substr(SymOffI, BytesInAddress).data(); + const char *DataPtr = + SymContents.substr(SymOffI, BytesInAddress).data(); int64_t VData; if (BytesInAddress == 8) VData = *reinterpret_cast<const little64_t *>(DataPtr); @@ -296,8 +349,7 @@ static void dumpVTables(const ObjectFile *Obj) { // FIXME: Do something with these! } } - for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VFTableEntry : - VFTableEntries) { + for (const auto &VFTableEntry : VFTableEntries) { StringRef VFTableName = VFTableEntry.first.first; uint64_t Offset = VFTableEntry.first.second; StringRef SymName = VFTableEntry.second; @@ -318,7 +370,8 @@ static void dumpVTables(const ObjectFile *Obj) { outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n'; outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n'; outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n'; - outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] << '\n'; + outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] + << '\n'; } for (const std::pair<StringRef, ClassHierarchyDescriptor> &CHDPair : CHDs) { StringRef CHDName = CHDPair.first; @@ -344,7 +397,8 @@ static void dumpVTables(const ObjectFile *Obj) { outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n'; outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n'; outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n'; - outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n'; + outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] + << '\n'; } for (const std::pair<StringRef, TypeDescriptor> &TDPair : TDs) { StringRef TDName = TDPair.first; @@ -356,6 +410,60 @@ static void dumpVTables(const ObjectFile *Obj) { /*UseHexEscapes=*/true) << '\n'; } + for (const std::pair<StringRef, ThrowInfo> &TIPair : TIs) { + StringRef TIName = TIPair.first; + const ThrowInfo &TI = TIPair.second; + auto dumpThrowInfoFlag = [&](const char *Name, uint32_t Flag) { + outs() << TIName << "[Flags." << Name + << "]: " << (TI.Flags & Flag ? "true" : "false") << '\n'; + }; + auto dumpThrowInfoSymbol = [&](const char *Name, int Offset) { + outs() << TIName << '[' << Name << "]: "; + auto Entry = TIEntries.find(std::make_pair(TIName, Offset)); + outs() << (Entry == TIEntries.end() ? "null" : Entry->second) << '\n'; + }; + outs() << TIName << "[Flags]: " << TI.Flags << '\n'; + dumpThrowInfoFlag("Const", 1); + dumpThrowInfoFlag("Volatile", 2); + dumpThrowInfoSymbol("CleanupFn", 4); + dumpThrowInfoSymbol("ForwardCompat", 8); + dumpThrowInfoSymbol("CatchableTypeArray", 12); + } + for (const std::pair<StringRef, CatchableTypeArray> &CTAPair : CTAs) { + StringRef CTAName = CTAPair.first; + const CatchableTypeArray &CTA = CTAPair.second; + + outs() << CTAName << "[NumEntries]: " << CTA.NumEntries << '\n'; + + unsigned Idx = 0; + for (auto I = CTAEntries.lower_bound(std::make_pair(CTAName, 0)), + E = CTAEntries.upper_bound(std::make_pair(CTAName, UINT64_MAX)); + I != E; ++I) + outs() << CTAName << '[' << Idx++ << "]: " << I->second << '\n'; + } + for (const std::pair<StringRef, CatchableType> &CTPair : CTs) { + StringRef CTName = CTPair.first; + const CatchableType &CT = CTPair.second; + auto dumpCatchableTypeFlag = [&](const char *Name, uint32_t Flag) { + outs() << CTName << "[Flags." << Name + << "]: " << (CT.Flags & Flag ? "true" : "false") << '\n'; + }; + outs() << CTName << "[Flags]: " << CT.Flags << '\n'; + dumpCatchableTypeFlag("ScalarType", 1); + dumpCatchableTypeFlag("VirtualInheritance", 4); + outs() << CTName << "[TypeDescriptor]: " << CT.Symbols[0] << '\n'; + outs() << CTName << "[NonVirtualBaseAdjustmentOffset]: " + << CT.NonVirtualBaseAdjustmentOffset << '\n'; + outs() << CTName + << "[VirtualBasePointerOffset]: " << CT.VirtualBasePointerOffset + << '\n'; + outs() << CTName << "[VirtualBaseAdjustmentOffset]: " + << CT.VirtualBaseAdjustmentOffset << '\n'; + outs() << CTName << "[Size]: " << CT.Size << '\n'; + outs() << CTName + << "[CopyCtor]: " << (CT.Symbols[1].empty() ? "null" : CT.Symbols[1]) + << '\n'; + } for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VTTPair : VTTEntries) { StringRef VTTName = VTTPair.first.first; @@ -410,17 +518,16 @@ static void dumpArchive(const Archive *Arc) { } if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) - dumpVTables(Obj); + dumpCXXData(Obj); else - reportError(Arc->getFileName(), - vtabledump_error::unrecognized_file_format); + reportError(Arc->getFileName(), cxxdump_error::unrecognized_file_format); } } static void dumpInput(StringRef File) { // If file isn't stdin, check that it exists. if (File != "-" && !sys::fs::exists(File)) { - reportError(File, vtabledump_error::file_not_found); + reportError(File, cxxdump_error::file_not_found); return; } @@ -435,9 +542,9 @@ static void dumpInput(StringRef File) { if (Archive *Arc = dyn_cast<Archive>(&Binary)) dumpArchive(Arc); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) - dumpVTables(Obj); + dumpCXXData(Obj); else - reportError(File, vtabledump_error::unrecognized_file_format); + reportError(File, cxxdump_error::unrecognized_file_format); } int main(int argc, const char *argv[]) { @@ -451,7 +558,7 @@ int main(int argc, const char *argv[]) { // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - cl::ParseCommandLineOptions(argc, argv, "LLVM VTable Dumper\n"); + cl::ParseCommandLineOptions(argc, argv, "LLVM C++ ABI Data Dumper\n"); // Default to stdin if no filename is specified. if (opts::InputFilenames.size() == 0) diff --git a/tools/llvm-vtabledump/llvm-vtabledump.h b/tools/llvm-cxxdump/llvm-cxxdump.h index 62f7557..daa05cb 100644 --- a/tools/llvm-vtabledump/llvm-vtabledump.h +++ b/tools/llvm-cxxdump/llvm-cxxdump.h @@ -1,4 +1,4 @@ -//===-- llvm-vtabledump.h ---------------------------------------*- C++ -*-===// +//===-- llvm-cxxdump.h ------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -7,8 +7,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_TOOLS_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H -#define LLVM_TOOLS_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H +#ifndef LLVM_TOOLS_LLVM_CXXDUMP_LLVM_CXXDUMP_H +#define LLVM_TOOLS_LLVM_CXXDUMP_LLVM_CXXDUMP_H #include "llvm/Support/CommandLine.h" #include <string> @@ -17,7 +17,7 @@ namespace opts { extern llvm::cl::list<std::string> InputFilenames; } // namespace opts -#define LLVM_VTABLEDUMP_ENUM_ENT(ns, enum) \ +#define LLVM_CXXDUMP_ENUM_ENT(ns, enum) \ { #enum, ns::enum } #endif diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 8cbcdc5..8bfd319 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -247,7 +247,6 @@ int main(int argc, char **argv) { // In addition to deleting all other functions, we also want to spiff it // up a little bit. Do this now. legacy::PassManager Passes; - Passes.add(new DataLayoutPass()); // Use correct DataLayout std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end()); diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index c3091a5..af1a59b 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -13,12 +13,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/LLVMContext.h" #include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" @@ -30,6 +30,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" #include <string> using namespace llvm; diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 828b9bb..e52191a 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Linker/Linker.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -111,6 +112,12 @@ int main(int argc, char **argv) { return 1; } + if (verifyModule(*M)) { + errs() << argv[0] << ": input module '" << InputFilenames[i] + << "' is broken!\n"; + return 1; + } + if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n"; if (L.linkInModule(M.get())) diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 32b3134..9cd6587 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -26,9 +26,13 @@ using namespace llvm; -static cl::opt<bool> -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); +static cl::opt<char> +OptLevel("O", + cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default = '-O2')"), + cl::Prefix, + cl::ZeroOrMore, + cl::init('2')); static cl::opt<bool> DisableInline("disable-inlining", cl::init(false), @@ -79,8 +83,8 @@ struct ModuleInfo { }; } -void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, - const char *Msg, void *) { +static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, + const char *Msg, void *) { switch (Severity) { case LTO_DS_NOTE: errs() << "note: "; @@ -98,7 +102,7 @@ void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, errs() << Msg << "\n"; } -std::unique_ptr<LTOModule> +static std::unique_ptr<LTOModule> getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer, const TargetOptions &Options, std::string &Error) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = @@ -118,7 +122,7 @@ getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer, /// functionality that's exposed by the C API to list symbols. Moreover, this /// provides testing coverage for modules that have been created in their own /// contexts. -int listSymbols(StringRef Command, const TargetOptions &Options) { +static int listSymbols(StringRef Command, const TargetOptions &Options) { for (auto &Filename : InputFilenames) { std::string Error; std::unique_ptr<MemoryBuffer> Buffer; @@ -146,6 +150,11 @@ int main(int argc, char **argv) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n"); + if (OptLevel < '0' || OptLevel > '3') { + errs() << argv[0] << ": optimization level must be between 0 and 3\n"; + return 1; + } + // Initialize the configured targets. InitializeAllTargets(); InitializeAllTargetMCs(); @@ -231,6 +240,8 @@ int main(int argc, char **argv) { // Set cpu and attrs strings for the default target/subtarget. CodeGen.setCpu(MCPU.c_str()); + CodeGen.setOptLevel(OptLevel - '0'); + std::string attrs; for (unsigned i = 0; i < MAttrs.size(); ++i) { if (i > 0) @@ -245,7 +256,7 @@ int main(int argc, char **argv) { size_t len = 0; std::string ErrorInfo; const void *Code = - CodeGen.compile(&len, DisableOpt, DisableInline, DisableGVNLoadPRE, + CodeGen.compile(&len, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo); if (!Code) { errs() << argv[0] @@ -265,7 +276,7 @@ int main(int argc, char **argv) { } else { std::string ErrorInfo; const char *OutputName = nullptr; - if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline, + if (!CodeGen.compile_to_file(&OutputName, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, ErrorInfo)) { errs() << argv[0] diff --git a/tools/llvm-mc/Android.mk b/tools/llvm-mc/Android.mk index ad83637..e7e29ee 100644 --- a/tools/llvm-mc/Android.mk +++ b/tools/llvm-mc/Android.mk @@ -38,8 +38,8 @@ llvm_mc_STATIC_LIBRARIES := \ libLLVMAsmPrinter \ libLLVMCodeGen \ libLLVMTransformUtils \ - libLLVMAnalysis \ libLLVMTarget \ + libLLVMAnalysis \ libLLVMMC \ libLLVMObject \ libLLVMBitReader \ diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 91bacc0..4f9b6fc 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -357,6 +357,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); TripleName = Triple::normalize(TripleName); + Triple TheTriple(TripleName); setDwarfDebugFlags(argc, argv); setDwarfDebugProducer(); @@ -457,7 +458,7 @@ int main(int argc, char **argv) { MCCodeEmitter *CE = nullptr; MCAsmBackend *MAB = nullptr; if (ShowEncoding) { - CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); + CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); } Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/ true, @@ -468,10 +469,11 @@ int main(int argc, char **argv) { Str.reset(TheTarget->createNullStreamer(Ctx)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); - MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); + MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); - Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, FOS, CE, - *STI, RelaxAll)); + Str.reset(TheTarget->createMCObjectStreamer(TheTriple, Ctx, *MAB, FOS, CE, + *STI, RelaxAll, + /*DWARFMustBeAtTheEnd*/ false)); if (NoExecStack) Str->InitSections(true); } diff --git a/tools/llvm-nm/Android.mk b/tools/llvm-nm/Android.mk index e3b66f0..4510fa9 100644 --- a/tools/llvm-nm/Android.mk +++ b/tools/llvm-nm/Android.mk @@ -39,8 +39,8 @@ llvm_nm_STATIC_LIBRARIES := \ libLLVMX86Disassembler \ libLLVMCodeGen \ libLLVMTransformUtils \ - libLLVMAnalysis \ libLLVMTarget \ + libLLVMAnalysis \ libLLVMObject \ libLLVMBitReader \ libLLVMMC \ diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index f911c72..b62b547 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -188,85 +188,77 @@ static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) { if (!ReverseSort) { if (A.Address < B.Address) return true; - else if (A.Address == B.Address && A.Name < B.Name) + if (A.Address == B.Address && A.Name < B.Name) return true; - else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) + if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) return true; - else - return false; - } else { - if (A.Address > B.Address) - return true; - else if (A.Address == B.Address && A.Name > B.Name) - return true; - else if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size) - return true; - else - return false; + return false; } + + if (A.Address > B.Address) + return true; + if (A.Address == B.Address && A.Name > B.Name) + return true; + if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size) + return true; + return false; } static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) { if (!ReverseSort) { if (A.Size < B.Size) return true; - else if (A.Size == B.Size && A.Name < B.Name) - return true; - else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) - return true; - else - return false; - } else { - if (A.Size > B.Size) + if (A.Size == B.Size && A.Name < B.Name) return true; - else if (A.Size == B.Size && A.Name > B.Name) + if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) return true; - else if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address) - return true; - else - return false; + return false; } + + if (A.Size > B.Size) + return true; + if (A.Size == B.Size && A.Name > B.Name) + return true; + if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address) + return true; + return false; } static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) { if (!ReverseSort) { if (A.Name < B.Name) return true; - else if (A.Name == B.Name && A.Size < B.Size) - return true; - else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) - return true; - else - return false; - } else { - if (A.Name > B.Name) + if (A.Name == B.Name && A.Size < B.Size) return true; - else if (A.Name == B.Name && A.Size > B.Size) + if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) return true; - else if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address) - return true; - else - return false; + return false; } + if (A.Name > B.Name) + return true; + if (A.Name == B.Name && A.Size > B.Size) + return true; + if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address) + return true; + return false; } static char isSymbolList64Bit(SymbolicFile &Obj) { if (isa<IRObjectFile>(Obj)) return false; - else if (isa<COFFObjectFile>(Obj)) + if (isa<COFFObjectFile>(Obj)) return false; - else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj)) return MachO->is64Bit(); - else if (isa<ELF32LEObjectFile>(Obj)) + if (isa<ELF32LEObjectFile>(Obj)) return false; - else if (isa<ELF64LEObjectFile>(Obj)) + if (isa<ELF64LEObjectFile>(Obj)) return true; - else if (isa<ELF32BEObjectFile>(Obj)) + if (isa<ELF32BEObjectFile>(Obj)) return false; - else if (isa<ELF64BEObjectFile>(Obj)) + if (isa<ELF64BEObjectFile>(Obj)) return true; - else - return false; + return false; } static StringRef CurrentFilename; @@ -973,30 +965,26 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName, // architectures was specificed. If not then an error is generated and this // routine returns false. Else it returns true. static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) { - if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) { - MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O); - bool ArchFound = false; - MachO::mach_header H; - MachO::mach_header_64 H_64; - Triple T; - if (MachO->is64Bit()) { - H_64 = MachO->MachOObjectFile::getHeader64(); - T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); - } else { - H = MachO->MachOObjectFile::getHeader(); - T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); - } - unsigned i; - for (i = 0; i < ArchFlags.size(); ++i) { - if (ArchFlags[i] == T.getArchName()) - ArchFound = true; - break; - } - if (!ArchFound) { - error(ArchFlags[i], - "file: " + Filename + " does not contain architecture"); - return false; - } + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O); + + if (!MachO || ArchAll || ArchFlags.size() == 0) + return true; + + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + } + if (std::none_of( + ArchFlags.begin(), ArchFlags.end(), + [&](const std::string &Name) { return Name == T.getArchName(); })) { + error("No architecture specified", Filename); + return false; } return true; } diff --git a/tools/llvm-objdump/Android.mk b/tools/llvm-objdump/Android.mk index 3b5eafd..847f932 100644 --- a/tools/llvm-objdump/Android.mk +++ b/tools/llvm-objdump/Android.mk @@ -42,8 +42,8 @@ llvm_objdump_STATIC_LIBRARIES := \ libLLVMAsmPrinter \ libLLVMCodeGen \ libLLVMTransformUtils \ - libLLVMAnalysis \ libLLVMTarget \ + libLLVMAnalysis \ libLLVMObject \ libLLVMMCParser \ libLLVMMC \ diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index cae4356..86504e6 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -63,6 +63,9 @@ static cl::opt<std::string> DSYMFile("dsym", static cl::opt<bool> FullLeadingAddr("full-leading-addr", cl::desc("Print full leading address")); +static cl::opt<bool> NoLeadingAddr("no-leading-addr", + cl::desc("Print no leading address")); + static cl::opt<bool> PrintImmHex("print-imm-hex", cl::desc("Use hex format for immediate values")); @@ -96,6 +99,35 @@ cl::list<std::string> cl::desc("Prints the specified segment,section for " "Mach-O objects (requires -macho)")); +cl::opt<bool> + llvm::InfoPlist("info-plist", + cl::desc("Print the info plist section as strings for " + "Mach-O objects (requires -macho)")); + +cl::opt<bool> + llvm::DylibsUsed("dylibs-used", + cl::desc("Print the shared libraries used for linked " + "Mach-O files (requires -macho)")); + +cl::opt<bool> + llvm::DylibId("dylib-id", + cl::desc("Print the shared library's id for the dylib Mach-O " + "file (requires -macho)")); + +cl::opt<bool> + llvm::NonVerbose("non-verbose", + cl::desc("Print the info for Mach-O objects in " + "non-verbose or numeric form (requires -macho)")); + +cl::opt<std::string> llvm::DisSymName( + "dis-symname", + cl::desc("disassemble just this symbol's instructions (requires -macho")); + +static cl::opt<bool> NoSymbolicOperands( + "no-symbolic-operands", + cl::desc("do not symbolic operands when disassembling (requires -macho)")); + + static cl::list<std::string> ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), cl::ZeroOrMore); @@ -173,7 +205,7 @@ static bool compareDiceTableEntries(const DiceTableEntry &i, return j.first >= i.first && j.first < i.first + Length; } -static uint64_t DumpDataInCode(const char *bytes, uint64_t Length, +static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length, unsigned short Kind) { uint32_t Value, Size = 1; @@ -182,19 +214,19 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length, case MachO::DICE_KIND_DATA: if (Length >= 4) { if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 4)); + DumpBytes(ArrayRef<uint8_t>(bytes, 4)); Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; outs() << "\t.long " << Value; Size = 4; } else if (Length >= 2) { if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 2)); + DumpBytes(ArrayRef<uint8_t>(bytes, 2)); Value = bytes[1] << 8 | bytes[0]; outs() << "\t.short " << Value; Size = 2; } else { if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 2)); + DumpBytes(ArrayRef<uint8_t>(bytes, 2)); Value = bytes[0]; outs() << "\t.byte " << Value; Size = 1; @@ -206,14 +238,14 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length, break; case MachO::DICE_KIND_JUMP_TABLE8: if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 1)); + DumpBytes(ArrayRef<uint8_t>(bytes, 1)); Value = bytes[0]; outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n"; Size = 1; break; case MachO::DICE_KIND_JUMP_TABLE16: if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 2)); + DumpBytes(ArrayRef<uint8_t>(bytes, 2)); Value = bytes[1] << 8 | bytes[0]; outs() << "\t.short " << format("%5u", Value & 0xffff) << "\t@ KIND_JUMP_TABLE16\n"; @@ -222,7 +254,7 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length, case MachO::DICE_KIND_JUMP_TABLE32: case MachO::DICE_KIND_ABS_JUMP_TABLE32: if (!NoShowRawInsn) - DumpBytes(StringRef(bytes, 4)); + DumpBytes(ArrayRef<uint8_t>(bytes, 4)); Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]; outs() << "\t.long " << Value; if (Kind == MachO::DICE_KIND_JUMP_TABLE32) @@ -323,15 +355,17 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, continue; } outs() << format("%5u ", indirect_symbol); - MachO::symtab_command Symtab = O->getSymtabLoadCommand(); - if (indirect_symbol < Symtab.nsyms) { - symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol); - SymbolRef Symbol = *Sym; - StringRef SymName; - Symbol.getName(SymName); - outs() << SymName; - } else { - outs() << "?"; + if (verbose) { + MachO::symtab_command Symtab = O->getSymtabLoadCommand(); + if (indirect_symbol < Symtab.nsyms) { + symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol); + SymbolRef Symbol = *Sym; + StringRef SymName; + Symbol.getName(SymName); + outs() << SymName; + } else { + outs() << "?"; + } } outs() << "\n"; } @@ -504,6 +538,59 @@ static void PrintLinkOptHints(MachOObjectFile *O) { } } +static void PrintDylibs(MachOObjectFile *O, bool JustId) { + uint32_t LoadCommandCount = O->getHeader().ncmds; + MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo(); + for (unsigned I = 0;; ++I) { + if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) || + (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB || + Load.C.cmd == MachO::LC_LOAD_DYLIB || + Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || + Load.C.cmd == MachO::LC_REEXPORT_DYLIB || + Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB || + Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) { + MachO::dylib_command dl = O->getDylibIDLoadCommand(Load); + if (dl.dylib.name < dl.cmdsize) { + const char *p = (const char *)(Load.Ptr) + dl.dylib.name; + if (JustId) + outs() << p << "\n"; + else { + outs() << "\t" << p; + outs() << " (compatibility version " + << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "." + << ((dl.dylib.compatibility_version >> 8) & 0xff) << "." + << (dl.dylib.compatibility_version & 0xff) << ","; + outs() << " current version " + << ((dl.dylib.current_version >> 16) & 0xffff) << "." + << ((dl.dylib.current_version >> 8) & 0xff) << "." + << (dl.dylib.current_version & 0xff) << ")\n"; + } + } else { + outs() << "\tBad offset (" << dl.dylib.name << ") for name of "; + if (Load.C.cmd == MachO::LC_ID_DYLIB) + outs() << "LC_ID_DYLIB "; + else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) + outs() << "LC_LOAD_DYLIB "; + else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) + outs() << "LC_LOAD_WEAK_DYLIB "; + else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) + outs() << "LC_LAZY_LOAD_DYLIB "; + else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) + outs() << "LC_REEXPORT_DYLIB "; + else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) + outs() << "LC_LOAD_UPWARD_DYLIB "; + else + outs() << "LC_??? "; + outs() << "command " << I << "\n"; + } + } + if (I == LoadCommandCount - 1) + break; + else + Load = O->getNextLoadCommandInfo(Load); + } +} + typedef DenseMap<uint64_t, StringRef> SymbolAddressMap; static void CreateSymbolAddressMap(MachOObjectFile *O, @@ -749,103 +836,103 @@ static void DumpLiteralPointerSection(MachOObjectFile *O, } // First look for an external relocation entry for this literal pointer. - bool reloc_found = false; - for (unsigned j = 0, e = Relocs.size(); j != e; ++j) { - if (Relocs[i].first == i) { - symbol_iterator RelocSym = Relocs[j].second; - StringRef SymName; - RelocSym->getName(SymName); - outs() << "external relocation entry for symbol:" << SymName << "\n"; - reloc_found = true; - } - } - if (reloc_found == true) + auto Reloc = std::find_if( + Relocs.begin(), Relocs.end(), + [&](const std::pair<uint64_t, SymbolRef> &P) { return P.first == i; }); + if (Reloc != Relocs.end()) { + symbol_iterator RelocSym = Reloc->second; + StringRef SymName; + RelocSym->getName(SymName); + outs() << "external relocation entry for symbol:" << SymName << "\n"; continue; + } // For local references see what the section the literal pointer points to. - bool found = false; - for (unsigned SectIdx = 0; SectIdx != LiteralSections.size(); SectIdx++) { - uint64_t SectAddress = LiteralSections[SectIdx].getAddress(); - uint64_t SectSize = LiteralSections[SectIdx].getSize(); - if (lp >= SectAddress && lp < SectAddress + SectSize) { - found = true; - - StringRef SectName; - LiteralSections[SectIdx].getName(SectName); - DataRefImpl Ref = LiteralSections[SectIdx].getRawDataRefImpl(); - StringRef SegmentName = O->getSectionFinalSegmentName(Ref); - outs() << SegmentName << ":" << SectName << ":"; - - uint32_t section_type; - if (O->is64Bit()) { - const MachO::section_64 Sec = O->getSection64(Ref); - section_type = Sec.flags & MachO::SECTION_TYPE; - } else { - const MachO::section Sec = O->getSection(Ref); - section_type = Sec.flags & MachO::SECTION_TYPE; - } + auto Sect = std::find_if(LiteralSections.begin(), LiteralSections.end(), + [&](const SectionRef &R) { + return lp >= R.getAddress() && + lp < R.getAddress() + R.getSize(); + }); + if (Sect == LiteralSections.end()) { + outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n"; + continue; + } - StringRef BytesStr; - LiteralSections[SectIdx].getContents(BytesStr); - const char *Contents = reinterpret_cast<const char *>(BytesStr.data()); - - switch (section_type) { - case MachO::S_CSTRING_LITERALS: - for (uint64_t i = lp - SectAddress; - i < SectSize && Contents[i] != '\0'; i++) { - DumpCstringChar(Contents[i]); - } - outs() << "\n"; - break; - case MachO::S_4BYTE_LITERALS: - float f; - memcpy(&f, Contents + (lp - SectAddress), sizeof(float)); - uint32_t l; - memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t)); - if (O->isLittleEndian() != sys::IsLittleEndianHost) { - sys::swapByteOrder(f); - sys::swapByteOrder(l); - } - DumpLiteral4(l, f); - break; - case MachO::S_8BYTE_LITERALS: { - double d; - memcpy(&d, Contents + (lp - SectAddress), sizeof(double)); - uint32_t l0, l1; - memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t)); - memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t), - sizeof(uint32_t)); - if (O->isLittleEndian() != sys::IsLittleEndianHost) { - sys::swapByteOrder(f); - sys::swapByteOrder(l0); - sys::swapByteOrder(l1); - } - DumpLiteral8(O, l0, l1, d); - break; - } - case MachO::S_16BYTE_LITERALS: { - uint32_t l0, l1, l2, l3; - memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t)); - memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t), - sizeof(uint32_t)); - memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t), - sizeof(uint32_t)); - memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t), - sizeof(uint32_t)); - if (O->isLittleEndian() != sys::IsLittleEndianHost) { - sys::swapByteOrder(l0); - sys::swapByteOrder(l1); - sys::swapByteOrder(l2); - sys::swapByteOrder(l3); - } - DumpLiteral16(l0, l1, l2, l3); - break; - } - } + uint64_t SectAddress = Sect->getAddress(); + uint64_t SectSize = Sect->getSize(); + + StringRef SectName; + Sect->getName(SectName); + DataRefImpl Ref = Sect->getRawDataRefImpl(); + StringRef SegmentName = O->getSectionFinalSegmentName(Ref); + outs() << SegmentName << ":" << SectName << ":"; + + uint32_t section_type; + if (O->is64Bit()) { + const MachO::section_64 Sec = O->getSection64(Ref); + section_type = Sec.flags & MachO::SECTION_TYPE; + } else { + const MachO::section Sec = O->getSection(Ref); + section_type = Sec.flags & MachO::SECTION_TYPE; + } + + StringRef BytesStr; + Sect->getContents(BytesStr); + const char *Contents = reinterpret_cast<const char *>(BytesStr.data()); + + switch (section_type) { + case MachO::S_CSTRING_LITERALS: + for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0'; + i++) { + DumpCstringChar(Contents[i]); + } + outs() << "\n"; + break; + case MachO::S_4BYTE_LITERALS: + float f; + memcpy(&f, Contents + (lp - SectAddress), sizeof(float)); + uint32_t l; + memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) { + sys::swapByteOrder(f); + sys::swapByteOrder(l); + } + DumpLiteral4(l, f); + break; + case MachO::S_8BYTE_LITERALS: { + double d; + memcpy(&d, Contents + (lp - SectAddress), sizeof(double)); + uint32_t l0, l1; + memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t)); + memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t), + sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) { + sys::swapByteOrder(f); + sys::swapByteOrder(l0); + sys::swapByteOrder(l1); } + DumpLiteral8(O, l0, l1, d); + break; + } + case MachO::S_16BYTE_LITERALS: { + uint32_t l0, l1, l2, l3; + memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t)); + memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t), + sizeof(uint32_t)); + memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t), + sizeof(uint32_t)); + memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t), + sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) { + sys::swapByteOrder(l0); + sys::swapByteOrder(l1); + sys::swapByteOrder(l2); + sys::swapByteOrder(l3); + } + DumpLiteral16(l0, l1, l2, l3); + break; + } } - if (found == false) - outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n"; } } @@ -894,7 +981,7 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, if (O->is64Bit()) outs() << format("%016" PRIx64, addr) << "\t"; else - outs() << format("%08" PRIx64, sect) << "\t"; + outs() << format("%08" PRIx64, addr) << "\t"; for (j = 0; j < 16 && i + j < size; j++) { uint8_t byte_word = *(sect + i + j); outs() << format("%02" PRIx32, (uint32_t)byte_word) << " "; @@ -981,6 +1068,10 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, DisassembleMachO(Filename, O, SegName, SectName); continue; } + if (SegName == "__TEXT" && SectName == "__info_plist") { + outs() << sect; + continue; + } switch (section_type) { case MachO::S_REGULAR: DumpRawSectionContents(O, sect, sect_size, sect_addr); @@ -989,20 +1080,20 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, outs() << "zerofill section and has no contents in the file\n"; break; case MachO::S_CSTRING_LITERALS: - DumpCstringSection(O, sect, sect_size, sect_addr, verbose); + DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr); break; case MachO::S_4BYTE_LITERALS: - DumpLiteral4Section(O, sect, sect_size, sect_addr, verbose); + DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); break; case MachO::S_8BYTE_LITERALS: - DumpLiteral8Section(O, sect, sect_size, sect_addr, verbose); + DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); break; case MachO::S_16BYTE_LITERALS: - DumpLiteral16Section(O, sect, sect_size, sect_addr, verbose); - break; + DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr); + break; case MachO::S_LITERAL_POINTERS: DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr, - verbose); + !NoLeadingAddr); break; case MachO::S_MOD_INIT_FUNC_POINTERS: case MachO::S_MOD_TERM_FUNC_POINTERS: @@ -1026,6 +1117,24 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, } } +static void DumpInfoPlistSectionContents(StringRef Filename, + MachOObjectFile *O) { + for (const SectionRef &Section : O->sections()) { + StringRef SectName; + Section.getName(SectName); + DataRefImpl Ref = Section.getRawDataRefImpl(); + StringRef SegName = O->getSectionFinalSegmentName(Ref); + if (SegName == "__TEXT" && SectName == "__info_plist") { + outs() << "Contents of (" << SegName << "," << SectName << ") section\n"; + StringRef BytesStr; + Section.getContents(BytesStr); + const char *sect = reinterpret_cast<const char *>(BytesStr.data()); + outs() << sect; + return; + } + } +} + // checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file // and if it is and there is a list of architecture flags is specified then // check to make sure this Mach-O file is one of those architectures or all @@ -1072,7 +1181,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, // UniversalHeaders or ArchiveHeaders. if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || - DumpSections.size() != 0) { + DylibsUsed || DylibId || DumpSections.size() != 0) { outs() << Filename; if (!ArchiveMemberName.empty()) outs() << '(' << ArchiveMemberName << ')'; @@ -1084,9 +1193,9 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, if (Disassemble) DisassembleMachO(Filename, MachOOF, "__TEXT", "__text"); if (IndirectSymbols) - PrintIndirectSymbols(MachOOF, true); + PrintIndirectSymbols(MachOOF, !NonVerbose); if (DataInCode) - PrintDataInCodeTable(MachOOF, true); + PrintDataInCodeTable(MachOOF, !NonVerbose); if (LinkOptHints) PrintLinkOptHints(MachOOF); if (Relocations) @@ -1096,7 +1205,13 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, if (SectionContents) PrintSectionContents(MachOOF); if (DumpSections.size() != 0) - DumpSectionContents(Filename, MachOOF, true); + DumpSectionContents(Filename, MachOOF, !NonVerbose); + if (InfoPlist) + DumpInfoPlistSectionContents(Filename, MachOOF); + if (DylibsUsed) + PrintDylibs(MachOOF, false); + if (DylibId) + PrintDylibs(MachOOF, true); if (SymbolTable) PrintSymbolTable(MachOOF); if (UnwindInfo) @@ -1433,7 +1548,7 @@ void llvm::ParseInputMachO(StringRef Filename) { } if (UniversalHeaders) { if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) - printMachOUniversalHeaders(UB, true); + printMachOUniversalHeaders(UB, !NonVerbose); } if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) { // If we have a list of architecture flags specified dump only those. @@ -1608,8 +1723,8 @@ struct DisassembleInfo { // names and addends of the symbolic expression to add for the operand. The // value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic // information is returned then this function returns 1 else it returns 0. -int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, - uint64_t Size, int TagType, void *TagBuf) { +static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, + uint64_t Size, int TagType, void *TagBuf) { struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo; struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf; uint64_t value = op_info->Value; @@ -1621,7 +1736,7 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // If the TagType is not the value 1 which it code knows about or if no // verbose symbolic information is wanted then just return 0, indicating no // information is being returned. - if (TagType != 1 || info->verbose == false) + if (TagType != 1 || !info->verbose) return 0; unsigned int Arch = info->O->getArch(); @@ -1704,7 +1819,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // (if any) for an entry that matches this segment offset. // uint32_t seg_offset = (Pc + Offset); return 0; - } else if (Arch == Triple::x86_64) { + } + if (Arch == Triple::x86_64) { if (Size != 1 && Size != 2 && Size != 4 && Size != 0) return 0; // First search the section's relocation entries (if any) for an entry @@ -1770,56 +1886,60 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // (if any) for an entry that matches this segment offset. // uint64_t seg_offset = (Pc + Offset); return 0; - } else if (Arch == Triple::arm) { + } + if (Arch == Triple::arm) { if (Offset != 0 || (Size != 4 && Size != 2)) return 0; // First search the section's relocation entries (if any) for an entry // for this section offset. uint32_t sect_addr = info->S.getAddress(); uint32_t sect_offset = (Pc + Offset) - sect_addr; - bool reloc_found = false; DataRefImpl Rel; MachO::any_relocation_info RE; bool isExtern = false; SymbolRef Symbol; bool r_scattered = false; uint32_t r_value, pair_r_value, r_type, r_length, other_half; - for (const RelocationRef &Reloc : info->S.relocations()) { - uint64_t RelocOffset; - Reloc.getOffset(RelocOffset); - if (RelocOffset == sect_offset) { - Rel = Reloc.getRawDataRefImpl(); - RE = info->O->getRelocation(Rel); - r_length = info->O->getAnyRelocationLength(RE); - r_scattered = info->O->isRelocationScattered(RE); - if (r_scattered) { - r_value = info->O->getScatteredRelocationValue(RE); - r_type = info->O->getScatteredRelocationType(RE); - } else { - r_type = info->O->getAnyRelocationType(RE); - isExtern = info->O->getPlainRelocationExternal(RE); - if (isExtern) { - symbol_iterator RelocSym = Reloc.getSymbol(); - Symbol = *RelocSym; - } - } - if (r_type == MachO::ARM_RELOC_HALF || - r_type == MachO::ARM_RELOC_SECTDIFF || - r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF || - r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { - DataRefImpl RelNext = Rel; - info->O->moveRelocationNext(RelNext); - MachO::any_relocation_info RENext; - RENext = info->O->getRelocation(RelNext); - other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff; - if (info->O->isRelocationScattered(RENext)) - pair_r_value = info->O->getScatteredRelocationValue(RENext); - } - reloc_found = true; - break; + auto Reloc = + std::find_if(info->S.relocations().begin(), info->S.relocations().end(), + [&](const RelocationRef &Reloc) { + uint64_t RelocOffset; + Reloc.getOffset(RelocOffset); + return RelocOffset == sect_offset; + }); + + if (Reloc == info->S.relocations().end()) + return 0; + + Rel = Reloc->getRawDataRefImpl(); + RE = info->O->getRelocation(Rel); + r_length = info->O->getAnyRelocationLength(RE); + r_scattered = info->O->isRelocationScattered(RE); + if (r_scattered) { + r_value = info->O->getScatteredRelocationValue(RE); + r_type = info->O->getScatteredRelocationType(RE); + } else { + r_type = info->O->getAnyRelocationType(RE); + isExtern = info->O->getPlainRelocationExternal(RE); + if (isExtern) { + symbol_iterator RelocSym = Reloc->getSymbol(); + Symbol = *RelocSym; } } - if (reloc_found && isExtern) { + if (r_type == MachO::ARM_RELOC_HALF || + r_type == MachO::ARM_RELOC_SECTDIFF || + r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF || + r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { + DataRefImpl RelNext = Rel; + info->O->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext; + RENext = info->O->getRelocation(RelNext); + other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff; + if (info->O->isRelocationScattered(RENext)) + pair_r_value = info->O->getScatteredRelocationValue(RENext); + } + + if (isExtern) { StringRef SymName; Symbol.getName(SymName); const char *name = SymName.data(); @@ -1844,27 +1964,25 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, // return 0 so the code in tryAddingSymbolicOperand() can use the // SymbolLookUp call back with the branch target address to look up the // symbol and possiblity add an annotation for a symbol stub. - if (reloc_found && isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 || - r_type == MachO::ARM_THUMB_RELOC_BR22)) + if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 || + r_type == MachO::ARM_THUMB_RELOC_BR22)) return 0; uint32_t offset = 0; - if (reloc_found) { - if (r_type == MachO::ARM_RELOC_HALF || - r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { - if ((r_length & 0x1) == 1) - value = value << 16 | other_half; - else - value = other_half << 16 | value; - } - if (r_scattered && (r_type != MachO::ARM_RELOC_HALF && - r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) { - offset = value - r_value; - value = r_value; - } + if (r_type == MachO::ARM_RELOC_HALF || + r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { + if ((r_length & 0x1) == 1) + value = value << 16 | other_half; + else + value = other_half << 16 | value; + } + if (r_scattered && (r_type != MachO::ARM_RELOC_HALF && + r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) { + offset = value - r_value; + value = r_value; } - if (reloc_found && r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { + if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) { if ((r_length & 0x1) == 1) op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; else @@ -1886,18 +2004,13 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, return 1; } - if (reloc_found == false) - return 0; - op_info->AddSymbol.Present = 1; op_info->Value = offset; - if (reloc_found) { - if (r_type == MachO::ARM_RELOC_HALF) { - if ((r_length & 0x1) == 1) - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; - else - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; - } + if (r_type == MachO::ARM_RELOC_HALF) { + if ((r_length & 0x1) == 1) + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; + else + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; } const char *add = GuessSymbolName(value, info->AddrMap); if (add != nullptr) { @@ -1906,95 +2019,86 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } op_info->AddSymbol.Value = value; return 1; - } else if (Arch == Triple::aarch64) { + } + if (Arch == Triple::aarch64) { if (Offset != 0 || Size != 4) return 0; // First search the section's relocation entries (if any) for an entry // for this section offset. uint64_t sect_addr = info->S.getAddress(); uint64_t sect_offset = (Pc + Offset) - sect_addr; - bool reloc_found = false; - DataRefImpl Rel; - MachO::any_relocation_info RE; - bool isExtern = false; - SymbolRef Symbol; - uint32_t r_type = 0; - for (const RelocationRef &Reloc : info->S.relocations()) { - uint64_t RelocOffset; - Reloc.getOffset(RelocOffset); - if (RelocOffset == sect_offset) { - Rel = Reloc.getRawDataRefImpl(); - RE = info->O->getRelocation(Rel); - r_type = info->O->getAnyRelocationType(RE); - if (r_type == MachO::ARM64_RELOC_ADDEND) { - DataRefImpl RelNext = Rel; - info->O->moveRelocationNext(RelNext); - MachO::any_relocation_info RENext = info->O->getRelocation(RelNext); - if (value == 0) { - value = info->O->getPlainRelocationSymbolNum(RENext); - op_info->Value = value; - } - } - // NOTE: Scattered relocations don't exist on arm64. - isExtern = info->O->getPlainRelocationExternal(RE); - if (isExtern) { - symbol_iterator RelocSym = Reloc.getSymbol(); - Symbol = *RelocSym; - } - reloc_found = true; - break; + auto Reloc = + std::find_if(info->S.relocations().begin(), info->S.relocations().end(), + [&](const RelocationRef &Reloc) { + uint64_t RelocOffset; + Reloc.getOffset(RelocOffset); + return RelocOffset == sect_offset; + }); + + if (Reloc == info->S.relocations().end()) + return 0; + + DataRefImpl Rel = Reloc->getRawDataRefImpl(); + MachO::any_relocation_info RE = info->O->getRelocation(Rel); + uint32_t r_type = info->O->getAnyRelocationType(RE); + if (r_type == MachO::ARM64_RELOC_ADDEND) { + DataRefImpl RelNext = Rel; + info->O->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext = info->O->getRelocation(RelNext); + if (value == 0) { + value = info->O->getPlainRelocationSymbolNum(RENext); + op_info->Value = value; } } - if (reloc_found && isExtern) { - StringRef SymName; - Symbol.getName(SymName); - const char *name = SymName.data(); - op_info->AddSymbol.Present = 1; - op_info->AddSymbol.Name = name; + // NOTE: Scattered relocations don't exist on arm64. + if (!info->O->getPlainRelocationExternal(RE)) + return 0; + StringRef SymName; + Reloc->getSymbol()->getName(SymName); + const char *name = SymName.data(); + op_info->AddSymbol.Present = 1; + op_info->AddSymbol.Name = name; - switch (r_type) { - case MachO::ARM64_RELOC_PAGE21: - /* @page */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE; - break; - case MachO::ARM64_RELOC_PAGEOFF12: - /* @pageoff */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF; - break; - case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: - /* @gotpage */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE; - break; - case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: - /* @gotpageoff */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF; - break; - case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: - /* @tvlppage is not implemented in llvm-mc */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP; - break; - case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: - /* @tvlppageoff is not implemented in llvm-mc */ - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF; - break; - default: - case MachO::ARM64_RELOC_BRANCH26: - op_info->VariantKind = LLVMDisassembler_VariantKind_None; - break; - } - return 1; + switch (r_type) { + case MachO::ARM64_RELOC_PAGE21: + /* @page */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE; + break; + case MachO::ARM64_RELOC_PAGEOFF12: + /* @pageoff */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF; + break; + case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: + /* @gotpage */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE; + break; + case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: + /* @gotpageoff */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF; + break; + case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: + /* @tvlppage is not implemented in llvm-mc */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP; + break; + case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: + /* @tvlppageoff is not implemented in llvm-mc */ + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF; + break; + default: + case MachO::ARM64_RELOC_BRANCH26: + op_info->VariantKind = LLVMDisassembler_VariantKind_None; + break; } - return 0; - } else { - return 0; + return 1; } + return 0; } // GuessCstringPointer is passed the address of what might be a pointer to a // literal string in a cstring section. If that address is in a cstring section // it returns a pointer to that string. Else it returns nullptr. -const char *GuessCstringPointer(uint64_t ReferenceValue, - struct DisassembleInfo *info) { +static const char *GuessCstringPointer(uint64_t ReferenceValue, + struct DisassembleInfo *info) { uint32_t LoadCommandCount = info->O->getHeader().ncmds; MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo(); for (unsigned I = 0;; ++I) { @@ -2279,8 +2383,9 @@ static uint64_t GuessPointerPointer(uint64_t ReferenceValue, // offset into the section, number of bytes left in the section past the offset // and which section is was being referenced. If the Address is not in a // section nullptr is returned. -const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left, - SectionRef &S, DisassembleInfo *info) { +static const char *get_pointer_64(uint64_t Address, uint32_t &offset, + uint32_t &left, SectionRef &S, + DisassembleInfo *info) { offset = 0; left = 0; S = SectionRef(); @@ -2302,10 +2407,10 @@ const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left, // get_symbol_64() returns the name of a symbol (or nullptr) and the address of // the symbol indirectly through n_value. Based on the relocation information // for the specified section offset in the specified section reference. -const char *get_symbol_64(uint32_t sect_offset, SectionRef S, - DisassembleInfo *info, uint64_t &n_value) { +static const char *get_symbol_64(uint32_t sect_offset, SectionRef S, + DisassembleInfo *info, uint64_t &n_value) { n_value = 0; - if (info->verbose == false) + if (!info->verbose) return nullptr; // See if there is an external relocation entry at the sect_offset. @@ -2437,9 +2542,9 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue, // address of the pointer, so when the pointer is zero as it can be in an .o // file, that is used to look for an external relocation entry with a symbol // name. -const char *get_objc2_64bit_class_name(uint64_t pointer_value, - uint64_t ReferenceValue, - struct DisassembleInfo *info) { +static const char *get_objc2_64bit_class_name(uint64_t pointer_value, + uint64_t ReferenceValue, + struct DisassembleInfo *info) { const char *r; uint32_t offset, left; SectionRef S; @@ -2488,8 +2593,8 @@ const char *get_objc2_64bit_class_name(uint64_t pointer_value, // get_objc2_64bit_cfstring_name is used for disassembly and is passed a // pointer to a cfstring and returns its name or nullptr. -const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue, - struct DisassembleInfo *info) { +static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue, + struct DisassembleInfo *info) { const char *r, *name; uint32_t offset, left; SectionRef S; @@ -2522,8 +2627,8 @@ const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue, // who's symbol's n_value is the real pointer to the selector name. If that is // the case the real pointer to the selector name is returned else 0 is // returned -uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue, - struct DisassembleInfo *info) { +static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue, + struct DisassembleInfo *info) { uint32_t offset, left; SectionRef S; @@ -2555,9 +2660,10 @@ uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue, // // If there is no item in the Mach-O file for the address passed in as // ReferenceValue nullptr is returned and ReferenceType is unchanged. -const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, - uint64_t *ReferenceType, - struct DisassembleInfo *info) { +static const char *GuessLiteralPointer(uint64_t ReferenceValue, + uint64_t ReferencePC, + uint64_t *ReferenceType, + struct DisassembleInfo *info) { // First see if there is an external relocation entry at the ReferencePC. uint64_t sect_addr = info->S.getAddress(); uint64_t sect_offset = ReferencePC - sect_addr; @@ -2599,7 +2705,7 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, bool classref, selref, msgref, cfstring; uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref, selref, msgref, cfstring); - if (classref == true && pointer_value == 0) { + if (classref && pointer_value == 0) { // Note the ReferenceValue is a pointer into the __objc_classrefs section. // And the pointer_value in that section is typically zero as it will be // set by dyld as part of the "bind information". @@ -2615,7 +2721,7 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, } } - if (classref == true) { + if (classref) { *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref; const char *name = get_objc2_64bit_class_name(pointer_value, ReferenceValue, info); @@ -2626,13 +2732,13 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, return name; } - if (cfstring == true) { + if (cfstring) { *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref; const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info); return name; } - if (selref == true && pointer_value == 0) + if (selref && pointer_value == 0) pointer_value = get_objc2_64bit_selref(ReferenceValue, info); if (pointer_value != 0) @@ -2640,10 +2746,10 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, const char *name = GuessCstringPointer(ReferenceValue, info); if (name) { - if (pointer_value != 0 && selref == true) { + if (pointer_value != 0 && selref) { *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref; info->selector_name = name; - } else if (pointer_value != 0 && msgref == true) { + } else if (pointer_value != 0 && msgref) { info->class_name = nullptr; *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref; info->selector_name = name; @@ -2691,13 +2797,14 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC, // SymbolValue is checked to be an address of literal pointer, symbol pointer, // or an Objective-C meta data reference. If so the output ReferenceType is // set to correspond to that as well as setting the ReferenceName. -const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue, - uint64_t *ReferenceType, - uint64_t ReferencePC, - const char **ReferenceName) { +static const char *SymbolizerSymbolLookUp(void *DisInfo, + uint64_t ReferenceValue, + uint64_t *ReferenceType, + uint64_t ReferencePC, + const char **ReferenceName) { struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo; // If no verbose symbolic information is wanted then just return nullptr. - if (info->verbose == false) { + if (!info->verbose) { *ReferenceName = nullptr; *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None; return nullptr; @@ -3075,6 +3182,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, // Create a map of symbol addresses to symbol names for use by // the SymbolizerSymbolLookUp() routine. SymbolAddressMap AddrMap; + bool DisSymNameFound = false; for (const SymbolRef &Symbol : MachOOF->symbols()) { SymbolRef::Type ST; Symbol.getType(ST); @@ -3085,10 +3193,16 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, StringRef SymName; Symbol.getName(SymName); AddrMap[Address] = SymName; + if (!DisSymName.empty() && DisSymName == SymName) + DisSymNameFound = true; } } + if (!DisSymName.empty() && !DisSymNameFound) { + outs() << "Can't find -dis-symname: " << DisSymName << "\n"; + return; + } // Set up the block of info used by the Symbolizer call backs. - SymbolizerInfo.verbose = true; + SymbolizerInfo.verbose = !NoSymbolicOperands; SymbolizerInfo.O = MachOOF; SymbolizerInfo.S = Sections[SectIdx]; SymbolizerInfo.AddrMap = &AddrMap; @@ -3101,7 +3215,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, SymbolizerInfo.adrp_addr = 0; SymbolizerInfo.adrp_inst = 0; // Same for the ThumbSymbolizer - ThumbSymbolizerInfo.verbose = true; + ThumbSymbolizerInfo.verbose = !NoSymbolicOperands; ThumbSymbolizerInfo.O = MachOOF; ThumbSymbolizerInfo.S = Sections[SectIdx]; ThumbSymbolizerInfo.AddrMap = &AddrMap; @@ -3129,6 +3243,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, if (!containsSym) continue; + // If we are only disassembling one symbol see if this is that symbol. + if (!DisSymName.empty() && DisSymName != SymName) + continue; + // Start at the address of the symbol relative to the section's address. uint64_t Start = 0; uint64_t SectionAddress = Sections[SectIdx].getAddress(); @@ -3169,13 +3287,15 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, MCInst Inst; uint64_t PC = SectAddress + Index; - if (FullLeadingAddr) { - if (MachOOF->is64Bit()) - outs() << format("%016" PRIx64, PC); - else - outs() << format("%08" PRIx64, PC); - } else { - outs() << format("%8" PRIx64 ":", PC); + if (!NoLeadingAddr) { + if (FullLeadingAddr) { + if (MachOOF->is64Bit()) + outs() << format("%016" PRIx64, PC); + else + outs() << format("%08" PRIx64, PC); + } else { + outs() << format("%8" PRIx64 ":", PC); + } } if (!NoShowRawInsn) outs() << "\t"; @@ -3192,9 +3312,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, DTI->second.getLength(Length); uint16_t Kind; DTI->second.getKind(Kind); - Size = DumpDataInCode(reinterpret_cast<const char *>(Bytes.data()) + - Index, - Length, Kind); + Size = DumpDataInCode(Bytes.data() + Index, Length, Kind); if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) && (PC == (DTI->first + Length - 1)) && (Length & 1)) Size++; @@ -3213,8 +3331,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, DebugOut, Annotations); if (gotInst) { if (!NoShowRawInsn) { - DumpBytes(StringRef( - reinterpret_cast<const char *>(Bytes.data()) + Index, Size)); + DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size)); } formatted_raw_ostream FormattedOS(outs()); Annotations.flush(); @@ -3267,19 +3384,19 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, uint64_t PC = SectAddress + Index; if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC, DebugOut, nulls())) { - if (FullLeadingAddr) { - if (MachOOF->is64Bit()) - outs() << format("%016" PRIx64, PC); - else - outs() << format("%08" PRIx64, PC); - } else { - outs() << format("%8" PRIx64 ":", PC); + if (!NoLeadingAddr) { + if (FullLeadingAddr) { + if (MachOOF->is64Bit()) + outs() << format("%016" PRIx64, PC); + else + outs() << format("%08" PRIx64, PC); + } else { + outs() << format("%8" PRIx64 ":", PC); + } } if (!NoShowRawInsn) { outs() << "\t"; - DumpBytes( - StringRef(reinterpret_cast<const char *>(Bytes.data()) + Index, - InstSize)); + DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, InstSize)); } IP->printInst(&Inst, outs(), ""); outs() << "\n"; @@ -5429,8 +5546,8 @@ void llvm::printMachOFileHeader(const object::ObjectFile *Obj) { uint32_t ncmds = 0; uint32_t filetype = 0; uint32_t cputype = 0; - getAndPrintMachHeader(file, ncmds, filetype, cputype, true); - PrintLoadCommands(file, ncmds, filetype, cputype, true); + getAndPrintMachHeader(file, ncmds, filetype, cputype, !NonVerbose); + PrintLoadCommands(file, ncmds, filetype, cputype, !NonVerbose); } //===----------------------------------------------------------------------===// diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 6e62aaa..7bec062 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -194,30 +194,17 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { return TheTarget; } -void llvm::DumpBytes(StringRef bytes) { +void llvm::DumpBytes(ArrayRef<uint8_t> bytes) { static const char hex_rep[] = "0123456789abcdef"; - // FIXME: The real way to do this is to figure out the longest instruction - // and align to that size before printing. I'll fix this when I get - // around to outputting relocations. - // 15 is the longest x86 instruction - // 3 is for the hex rep of a byte + a space. - // 1 is for the null terminator. - enum { OutputSize = (15 * 3) + 1 }; - char output[OutputSize]; - - assert(bytes.size() <= 15 - && "DumpBytes only supports instructions of up to 15 bytes"); - memset(output, ' ', sizeof(output)); - unsigned index = 0; - for (StringRef::iterator i = bytes.begin(), - e = bytes.end(); i != e; ++i) { - output[index] = hex_rep[(*i & 0xF0) >> 4]; - output[index + 1] = hex_rep[*i & 0xF]; - index += 3; + SmallString<64> output; + + for (char i: bytes) { + output.push_back(hex_rep[(i & 0xF0) >> 4]); + output.push_back(hex_rep[i & 0xF]); + output.push_back(' '); } - output[sizeof(output) - 1] = 0; - outs() << output; + outs() << output.c_str(); } bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) { @@ -412,8 +399,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { outs() << format("%8" PRIx64 ":", SectionAddr + Index); if (!NoShowRawInsn) { outs() << "\t"; - DumpBytes(StringRef( - reinterpret_cast<const char *>(Bytes.data()) + Index, Size)); + DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size)); } IP->printInst(&Inst, outs(), ""); outs() << CommentStream.str(); @@ -907,6 +893,9 @@ int main(int argc, char **argv) { && !(IndirectSymbols && MachOOpt) && !(DataInCode && MachOOpt) && !(LinkOptHints && MachOOpt) + && !(InfoPlist && MachOOpt) + && !(DylibsUsed && MachOOpt) + && !(DylibId && MachOOpt) && !(DumpSections.size() != 0 && MachOOpt)) { cl::PrintHelpMessage(); return 2; diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index 19f842f..c1d5ff8 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -40,6 +40,11 @@ extern cl::opt<bool> ArchiveHeaders; extern cl::opt<bool> IndirectSymbols; extern cl::opt<bool> DataInCode; extern cl::opt<bool> LinkOptHints; +extern cl::opt<bool> InfoPlist; +extern cl::opt<bool> DylibsUsed; +extern cl::opt<bool> DylibId; +extern cl::opt<std::string> DisSymName; +extern cl::opt<bool> NonVerbose; extern cl::opt<bool> Relocations; extern cl::opt<bool> SectionHeaders; extern cl::opt<bool> SectionContents; @@ -49,7 +54,7 @@ extern cl::opt<bool> UnwindInfo; // Various helper functions. bool error(std::error_code ec); bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); -void DumpBytes(StringRef bytes); +void DumpBytes(ArrayRef<uint8_t> bytes); void ParseInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printMachOUnwindInfo(const object::MachOObjectFile* o); diff --git a/tools/llvm-pdbdump/Android.mk b/tools/llvm-pdbdump/Android.mk index 82a406a..313e9a4 100644 --- a/tools/llvm-pdbdump/Android.mk +++ b/tools/llvm-pdbdump/Android.mk @@ -4,10 +4,13 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../.. include $(LLVM_ROOT_PATH)/llvm.mk llvm_pdbdump_SRC_FILES := \ + llvm-pdbdump.cpp \ + BuiltinDumper.cpp \ ClassDefinitionDumper.cpp \ CompilandDumper.cpp \ + EnumDumper.cpp \ FunctionDumper.cpp \ - llvm-pdbdump.cpp \ + LinePrinter.cpp \ TypedefDumper.cpp \ TypeDumper.cpp \ VariableDumper.cpp diff --git a/tools/llvm-pdbdump/BuiltinDumper.cpp b/tools/llvm-pdbdump/BuiltinDumper.cpp new file mode 100644 index 0000000..d808298 --- /dev/null +++ b/tools/llvm-pdbdump/BuiltinDumper.cpp @@ -0,0 +1,87 @@ +//===- BuiltinDumper.cpp ---------------------------------------- *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BuiltinDumper.h" +#include "LinePrinter.h" +#include "llvm-pdbdump.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" + +using namespace llvm; + +BuiltinDumper::BuiltinDumper(LinePrinter &P) + : PDBSymDumper(false), Printer(P) {} + +void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) { + PDB_BuiltinType Type = Symbol.getBuiltinType(); + switch (Type) { + case PDB_BuiltinType::Float: + if (Symbol.getLength() == 4) + WithColor(Printer, PDB_ColorItem::Type).get() << "float"; + else + WithColor(Printer, PDB_ColorItem::Type).get() << "double"; + break; + case PDB_BuiltinType::UInt: + WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned"; + if (Symbol.getLength() == 8) + WithColor(Printer, PDB_ColorItem::Type).get() << " __int64"; + break; + case PDB_BuiltinType::Int: + if (Symbol.getLength() == 4) + WithColor(Printer, PDB_ColorItem::Type).get() << "int"; + else + WithColor(Printer, PDB_ColorItem::Type).get() << "__int64"; + break; + case PDB_BuiltinType::Char: + WithColor(Printer, PDB_ColorItem::Type).get() << "char"; + break; + case PDB_BuiltinType::WCharT: + WithColor(Printer, PDB_ColorItem::Type).get() << "wchar_t"; + break; + case PDB_BuiltinType::Void: + WithColor(Printer, PDB_ColorItem::Type).get() << "void"; + break; + case PDB_BuiltinType::Long: + WithColor(Printer, PDB_ColorItem::Type).get() << "long"; + break; + case PDB_BuiltinType::ULong: + WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned long"; + break; + case PDB_BuiltinType::Bool: + WithColor(Printer, PDB_ColorItem::Type).get() << "bool"; + break; + case PDB_BuiltinType::Currency: + WithColor(Printer, PDB_ColorItem::Type).get() << "CURRENCY"; + break; + case PDB_BuiltinType::Date: + WithColor(Printer, PDB_ColorItem::Type).get() << "DATE"; + break; + case PDB_BuiltinType::Variant: + WithColor(Printer, PDB_ColorItem::Type).get() << "VARIANT"; + break; + case PDB_BuiltinType::Complex: + WithColor(Printer, PDB_ColorItem::Type).get() << "complex"; + break; + case PDB_BuiltinType::Bitfield: + WithColor(Printer, PDB_ColorItem::Type).get() << "bitfield"; + break; + case PDB_BuiltinType::BSTR: + WithColor(Printer, PDB_ColorItem::Type).get() << "BSTR"; + break; + case PDB_BuiltinType::HResult: + WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT"; + break; + case PDB_BuiltinType::BCD: + WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT"; + break; + default: + WithColor(Printer, PDB_ColorItem::Type).get() << "void"; + break; + } +} diff --git a/tools/llvm-pdbdump/BuiltinDumper.h b/tools/llvm-pdbdump/BuiltinDumper.h new file mode 100644 index 0000000..8cf984a --- /dev/null +++ b/tools/llvm-pdbdump/BuiltinDumper.h @@ -0,0 +1,30 @@ +//===- BuiltinDumper.h ---------------------------------------- *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class LinePrinter; + +class BuiltinDumper : public PDBSymDumper { +public: + BuiltinDumper(LinePrinter &P); + + void start(const PDBSymbolTypeBuiltin &Symbol); + +private: + LinePrinter &Printer; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt index 0519bf0..4dd339c 100644 --- a/tools/llvm-pdbdump/CMakeLists.txt +++ b/tools/llvm-pdbdump/CMakeLists.txt @@ -5,9 +5,12 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-pdbdump llvm-pdbdump.cpp + BuiltinDumper.cpp ClassDefinitionDumper.cpp CompilandDumper.cpp + EnumDumper.cpp FunctionDumper.cpp + LinePrinter.cpp TypeDumper.cpp TypedefDumper.cpp VariableDumper.cpp diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp index edf6eb4..8abf3fa 100644 --- a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #include "ClassDefinitionDumper.h" +#include "EnumDumper.h" #include "FunctionDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "TypedefDumper.h" #include "VariableDumper.h" @@ -27,14 +29,38 @@ using namespace llvm; -ClassDefinitionDumper::ClassDefinitionDumper() : PDBSymDumper(true) {} +ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} + +void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) { + std::string Name = Class.getName(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " "; + WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName(); + + auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>(); + if (Bases->getChildCount() > 0) { + Printer.Indent(); + Printer.NewLine(); + Printer << ":"; + uint32_t BaseIndex = 0; + while (auto Base = Bases->getNext()) { + Printer << " "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess(); + if (Base->isVirtualBaseClass()) + WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual"; + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName(); + if (++BaseIndex < Bases->getChildCount()) { + Printer.NewLine(); + Printer << ","; + } + } + Printer.Unindent(); + } -void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class, - raw_ostream &OS, int Indent) { - OS << "class " << Class.getName() << " {"; + Printer << " {"; auto Children = Class.findAllChildren(); if (Children->getChildCount() == 0) { - OS << "}"; + Printer << "}"; return; } @@ -58,9 +84,10 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class, auto &AccessGroup = Groups.find((int)Access)->second; if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) { - if (Func->isCompilerGenerated()) + if (Func->isCompilerGenerated() && opts::ExcludeCompilerGenerated) continue; - if (Func->getLength() == 0 && !Func->isPureVirtual()) + if (Func->getLength() == 0 && !Func->isPureVirtual() && + !Func->isIntroVirtualFunction()) continue; Child.release(); AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func)); @@ -73,80 +100,91 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class, } int Count = 0; - Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0], OS, Indent); + Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]); Count += dumpAccessGroup(PDB_MemberAccess::Public, - Groups[(int)PDB_MemberAccess::Public], OS, Indent); - Count += - dumpAccessGroup(PDB_MemberAccess::Protected, - Groups[(int)PDB_MemberAccess::Protected], OS, Indent); + Groups[(int)PDB_MemberAccess::Public]); + Count += dumpAccessGroup(PDB_MemberAccess::Protected, + Groups[(int)PDB_MemberAccess::Protected]); Count += dumpAccessGroup(PDB_MemberAccess::Private, - Groups[(int)PDB_MemberAccess::Private], OS, Indent); - + Groups[(int)PDB_MemberAccess::Private]); if (Count > 0) - OS << newline(Indent); - OS << "}"; + Printer.NewLine(); + Printer << "}"; } int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access, - const SymbolGroup &Group, - raw_ostream &OS, int Indent) { + const SymbolGroup &Group) { if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty()) return 0; int Count = 0; - if (Access == PDB_MemberAccess::Private) - OS << newline(Indent) << "private:"; - else if (Access == PDB_MemberAccess::Protected) - OS << newline(Indent) << "protected:"; - else if (Access == PDB_MemberAccess::Public) - OS << newline(Indent) << "public:"; + if (Access == PDB_MemberAccess::Private) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "private"; + Printer << ":"; + } else if (Access == PDB_MemberAccess::Protected) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected"; + Printer << ":"; + } else if (Access == PDB_MemberAccess::Public) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "public"; + Printer << ":"; + } + Printer.Indent(); for (auto iter = Group.Functions.begin(), end = Group.Functions.end(); iter != end; ++iter) { ++Count; - (*iter)->dump(OS, Indent + 2, *this); + (*iter)->dump(*this); } for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end; ++iter) { ++Count; - (*iter)->dump(OS, Indent + 2, *this); + (*iter)->dump(*this); } for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end(); iter != end; ++iter) { ++Count; - (*iter)->dump(OS, Indent + 2, *this); + (*iter)->dump(*this); } + Printer.Unindent(); return Count; } -void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol, - raw_ostream &OS, int Indent) {} +void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {} -void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS, - int Indent) { - VariableDumper Dumper; - Dumper.start(Symbol, OS, Indent); +void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) { + VariableDumper Dumper(Printer); + Dumper.start(Symbol); } -void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, - int Indent) { - FunctionDumper Dumper; - Dumper.start(Symbol, FunctionDumper::PointerType::None, OS, Indent); +void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); } -void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol, - raw_ostream &OS, int Indent) {} +void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {} + +void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) { + if (Printer.IsTypeExcluded(Symbol.getName())) + return; -void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol, - raw_ostream &OS, int Indent) { - OS << newline(Indent) << "enum " << Symbol.getName(); + Printer.NewLine(); + EnumDumper Dumper(Printer); + Dumper.start(Symbol); } -void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol, - raw_ostream &OS, int Indent) { - OS << newline(Indent); - TypedefDumper Dumper; - Dumper.start(Symbol, OS, Indent); +void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + if (Printer.IsTypeExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); } -void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol, - raw_ostream &OS, int Indent) {} +void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {} diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.h b/tools/llvm-pdbdump/ClassDefinitionDumper.h index aaf0376..5b48ba8 100644 --- a/tools/llvm-pdbdump/ClassDefinitionDumper.h +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.h @@ -20,26 +20,25 @@ namespace llvm { +class LinePrinter; + class ClassDefinitionDumper : public PDBSymDumper { public: - ClassDefinitionDumper(); + ClassDefinitionDumper(LinePrinter &P); - void start(const PDBSymbolTypeUDT &Exe, raw_ostream &OS, int Indent); + void start(const PDBSymbolTypeUDT &Exe); - void dump(const PDBSymbolTypeBaseClass &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolData &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeVTable &Symbol, raw_ostream &OS, - int Indent) override; + void dump(const PDBSymbolTypeBaseClass &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + void dump(const PDBSymbolTypeVTable &Symbol) override; private: + LinePrinter &Printer; + struct SymbolGroup { SymbolGroup() {} SymbolGroup(SymbolGroup &&Other) { @@ -56,8 +55,7 @@ private: }; typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess; - int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group, - raw_ostream &OS, int Indent); + int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group); }; } diff --git a/tools/llvm-pdbdump/CompilandDumper.cpp b/tools/llvm-pdbdump/CompilandDumper.cpp index 852ddfa..86bf32d 100644 --- a/tools/llvm-pdbdump/CompilandDumper.cpp +++ b/tools/llvm-pdbdump/CompilandDumper.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "CompilandDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" @@ -34,84 +35,106 @@ using namespace llvm; -CompilandDumper::CompilandDumper() : PDBSymDumper(true) {} +CompilandDumper::CompilandDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} -void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol, - raw_ostream &OS, int Indent) {} +void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {} -void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol, raw_ostream &OS, - int Indent) {} +void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {} -void CompilandDumper::start(const PDBSymbolCompiland &Symbol, raw_ostream &OS, - int Indent, bool Children) { +void CompilandDumper::start(const PDBSymbolCompiland &Symbol, bool Children) { std::string FullName = Symbol.getName(); - OS << newline(Indent) << FullName; + if (Printer.IsCompilandExcluded(FullName)) + return; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Path).get() << FullName; if (!Children) return; auto ChildrenEnum = Symbol.findAllChildren(); + Printer.Indent(); while (auto Child = ChildrenEnum->getNext()) - Child->dump(OS, Indent + 2, *this); + Child->dump(*this); + Printer.Unindent(); } -void CompilandDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS, - int Indent) { - OS << newline(Indent); +void CompilandDumper::dump(const PDBSymbolData &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + switch (auto LocType = Symbol.getLocationType()) { case PDB_LocType::Static: - OS << "data: ["; - OS << format_hex(Symbol.getRelativeVirtualAddress(), 10); - OS << "]"; + Printer << "data: "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "]"; break; case PDB_LocType::Constant: - OS << "constant: [" << Symbol.getValue() << "]"; + Printer << "constant: "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << "[" << Symbol.getValue() << "]"; break; default: - OS << "data(unexpected type=" << LocType << ")"; + Printer << "data(unexpected type=" << LocType << ")"; } - OS << " " << Symbol.getName(); + Printer << " "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } -void CompilandDumper::dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, - int Indent) { +void CompilandDumper::dump(const PDBSymbolFunc &Symbol) { if (Symbol.getLength() == 0) return; + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; - FunctionDumper Dumper; - Dumper.start(Symbol, FunctionDumper::PointerType::None, OS, Indent); + Printer.NewLine(); + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, FunctionDumper::PointerType::None); } -void CompilandDumper::dump(const PDBSymbolLabel &Symbol, raw_ostream &OS, - int Indent) { - OS << newline(Indent); - OS << "label [" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "] " - << Symbol.getName(); +void CompilandDumper::dump(const PDBSymbolLabel &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "label "; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "] "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } -void CompilandDumper::dump(const PDBSymbolThunk &Symbol, raw_ostream &OS, - int Indent) { - OS << newline(Indent) << "thunk "; +void CompilandDumper::dump(const PDBSymbolThunk &Symbol) { + if (Printer.IsSymbolExcluded(Symbol.getName())) + return; + + Printer.NewLine(); + Printer << "thunk "; PDB_ThunkOrdinal Ordinal = Symbol.getThunkOrdinal(); uint32_t RVA = Symbol.getRelativeVirtualAddress(); if (Ordinal == PDB_ThunkOrdinal::TrampIncremental) { - OS << format_hex(RVA, 10); - OS << " -> " << format_hex(Symbol.getTargetRelativeVirtualAddress(), 10); + uint32_t Target = Symbol.getTargetRelativeVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(RVA, 10); + Printer << " -> "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10); } else { - OS << "[" << format_hex(RVA, 10); - OS << " - " << format_hex(RVA + Symbol.getLength(), 10) << "]"; + WithColor(Printer, PDB_ColorItem::Address).get() + << "[" << format_hex(RVA, 10) << " - " + << format_hex(RVA + Symbol.getLength(), 10) << "]"; } - OS << " (" << Ordinal << ") "; + Printer << " ("; + WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal; + Printer << ") "; std::string Name = Symbol.getName(); if (!Name.empty()) - OS << Name; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; } -void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) {} +void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {} -void CompilandDumper::dump(const PDBSymbolUnknown &Symbol, raw_ostream &OS, - int Indent) { - OS << newline(Indent); - OS << "unknown (" << Symbol.getSymTag() << ")"; +void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) { + Printer.NewLine(); + Printer << "unknown (" << Symbol.getSymTag() << ")"; } diff --git a/tools/llvm-pdbdump/CompilandDumper.h b/tools/llvm-pdbdump/CompilandDumper.h index abcebc2..0d1d27c 100644 --- a/tools/llvm-pdbdump/CompilandDumper.h +++ b/tools/llvm-pdbdump/CompilandDumper.h @@ -14,25 +14,25 @@ namespace llvm { +class LinePrinter; + class CompilandDumper : public PDBSymDumper { public: - CompilandDumper(); - - void start(const PDBSymbolCompiland &Symbol, raw_ostream &OS, int Indent, - bool Children); - - void dump(const PDBSymbolCompilandDetails &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolCompilandEnv &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolData &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolLabel &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolThunk &Symbol, raw_ostream &OS, int Indent) override; - void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolUnknown &Symbol, raw_ostream &OS, - int Indent) override; + CompilandDumper(LinePrinter &P); + + void start(const PDBSymbolCompiland &Symbol, bool Children); + + void dump(const PDBSymbolCompilandDetails &Symbol) override; + void dump(const PDBSymbolCompilandEnv &Symbol) override; + void dump(const PDBSymbolData &Symbol) override; + void dump(const PDBSymbolFunc &Symbol) override; + void dump(const PDBSymbolLabel &Symbol) override; + void dump(const PDBSymbolThunk &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolUnknown &Symbol) override; + +private: + LinePrinter &Printer; }; } diff --git a/tools/llvm-pdbdump/EnumDumper.cpp b/tools/llvm-pdbdump/EnumDumper.cpp new file mode 100644 index 0000000..3514c39 --- /dev/null +++ b/tools/llvm-pdbdump/EnumDumper.cpp @@ -0,0 +1,52 @@ +//===- EnumDumper.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "EnumDumper.h" + +#include "BuiltinDumper.h" +#include "LinePrinter.h" +#include "llvm-pdbdump.h" + +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" + +using namespace llvm; + +EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} + +void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); + if (!opts::NoEnumDefs) { + auto BuiltinType = Symbol.getUnderlyingType(); + if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int || + BuiltinType->getLength() != 4) { + Printer << " : "; + BuiltinDumper Dumper(Printer); + Dumper.start(*BuiltinType); + } + Printer << " {"; + Printer.Indent(); + auto EnumValues = Symbol.findAllChildren<PDBSymbolData>(); + while (auto EnumValue = EnumValues->getNext()) { + if (EnumValue->getDataKind() != PDB_DataKind::Constant) + continue; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() + << EnumValue->getName(); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() + << EnumValue->getValue(); + } + Printer.Unindent(); + Printer.NewLine(); + Printer << "}"; + } +} diff --git a/tools/llvm-pdbdump/EnumDumper.h b/tools/llvm-pdbdump/EnumDumper.h new file mode 100644 index 0000000..23de061 --- /dev/null +++ b/tools/llvm-pdbdump/EnumDumper.h @@ -0,0 +1,30 @@ +//===- EnumDumper.h - -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class LinePrinter; + +class EnumDumper : public PDBSymDumper { +public: + EnumDumper(LinePrinter &P); + + void start(const PDBSymbolTypeEnum &Symbol); + +private: + LinePrinter &Printer; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/FunctionDumper.cpp b/tools/llvm-pdbdump/FunctionDumper.cpp index e659830..419f888 100644 --- a/tools/llvm-pdbdump/FunctionDumper.cpp +++ b/tools/llvm-pdbdump/FunctionDumper.cpp @@ -8,6 +8,8 @@ //===----------------------------------------------------------------------===// #include "FunctionDumper.h" +#include "BuiltinDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" @@ -16,7 +18,6 @@ #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" #include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" @@ -29,7 +30,7 @@ using namespace llvm; namespace { template <class T> -void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS, +void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer, llvm::FunctionDumper &Dumper) { uint32_t ClassParentId = Symbol.getClassParentId(); auto ClassParent = @@ -38,17 +39,19 @@ void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS, if (!ClassParent) return; - OS << ClassParent->getName() << "::"; + WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName(); + Printer << "::"; } } -FunctionDumper::FunctionDumper() : PDBSymDumper(true) {} +FunctionDumper::FunctionDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, - PointerType Pointer, raw_ostream &OS) { + const char *Name, PointerType Pointer) { auto ReturnType = Symbol.getReturnType(); - ReturnType->dump(OS, 0, *this); - OS << " "; + ReturnType->dump(*this); + Printer << " "; uint32_t ClassParentId = Symbol.getClassParentId(); auto ClassParent = Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>( @@ -63,181 +66,189 @@ void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, if (Pointer == PointerType::None) { if (ShouldDumpCallingConvention) - OS << CC << " "; - if (ClassParent) - OS << "(" << ClassParent->getName() << "::)"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + Printer << "("; + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::)"; + } } else { - OS << "("; + Printer << "("; if (ShouldDumpCallingConvention) - OS << CC << " "; - OS << Symbol.getCallingConvention() << " "; - if (ClassParent) - OS << ClassParent->getName() << "::"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " "; + if (ClassParent) { + WithColor(Printer, PDB_ColorItem::Identifier).get() + << ClassParent->getName(); + Printer << "::"; + } if (Pointer == PointerType::Reference) - OS << "&"; + Printer << "&"; else - OS << "*"; - OS << ")"; + Printer << "*"; + if (Name) + WithColor(Printer, PDB_ColorItem::Identifier).get() << Name; + Printer << ")"; } - OS << "("; + Printer << "("; if (auto ChildEnum = Symbol.getArguments()) { uint32_t Index = 0; while (auto Arg = ChildEnum->getNext()) { - Arg->dump(OS, 0, *this); + Arg->dump(*this); if (++Index < ChildEnum->getChildCount()) - OS << ", "; + Printer << ", "; } } - OS << ")"; + Printer << ")"; if (Symbol.isConstType()) - OS << " const"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; if (Symbol.isVolatileType()) - OS << " volatile"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; } -void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer, - raw_ostream &OS, int Indent) { +void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) { uint32_t FuncStart = Symbol.getRelativeVirtualAddress(); uint32_t FuncEnd = FuncStart + Symbol.getLength(); - OS << newline(Indent); - - OS << "func [" << format_hex(FuncStart, 8); - if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) - OS << "+" << DebugStart->getRelativeVirtualAddress() - FuncStart; - OS << " - " << format_hex(FuncEnd, 8); - if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) - OS << "-" << FuncEnd - DebugEnd->getRelativeVirtualAddress(); - OS << "] "; + Printer << "func ["; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10); + if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) { + uint32_t Prologue = DebugStart->getRelativeVirtualAddress() - FuncStart; + WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << Prologue; + } + Printer << " - "; + WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10); + if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) { + uint32_t Epilogue = FuncEnd - DebugEnd->getRelativeVirtualAddress(); + WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue; + } + Printer << "] ("; - if (Symbol.hasFramePointer()) - OS << "(" << Symbol.getLocalBasePointerRegisterId() << ")"; - else - OS << "(FPO)"; + if (Symbol.hasFramePointer()) { + WithColor(Printer, PDB_ColorItem::Register).get() + << Symbol.getLocalBasePointerRegisterId(); + } else { + WithColor(Printer, PDB_ColorItem::Register).get() << "FPO"; + } + Printer << ") "; - OS << " "; if (Symbol.isVirtual() || Symbol.isPureVirtual()) - OS << "virtual "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual "; auto Signature = Symbol.getSignature(); if (!Signature) { - OS << Symbol.getName(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); if (Pointer == PointerType::Pointer) - OS << "*"; + Printer << "*"; else if (Pointer == FunctionDumper::PointerType::Reference) - OS << "&"; + Printer << "&"; return; } auto ReturnType = Signature->getReturnType(); - ReturnType->dump(OS, 0, *this); - OS << " "; + ReturnType->dump(*this); + Printer << " "; auto ClassParent = Symbol.getClassParent(); PDB_CallingConv CC = Signature->getCallingConvention(); if (Pointer != FunctionDumper::PointerType::None) - OS << "("; + Printer << "("; if ((ClassParent && CC != PDB_CallingConv::Thiscall) || - (!ClassParent && CC != PDB_CallingConv::NearStdcall)) - OS << Signature->getCallingConvention() << " "; - OS << Symbol.getName(); + (!ClassParent && CC != PDB_CallingConv::NearStdcall)) { + WithColor(Printer, PDB_ColorItem::Keyword).get() + << Signature->getCallingConvention() << " "; + } + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); if (Pointer != FunctionDumper::PointerType::None) { if (Pointer == PointerType::Pointer) - OS << "*"; + Printer << "*"; else if (Pointer == FunctionDumper::PointerType::Reference) - OS << "&"; - OS << ")"; + Printer << "&"; + Printer << ")"; } - OS << "("; + Printer << "("; if (auto Arguments = Symbol.getArguments()) { uint32_t Index = 0; while (auto Arg = Arguments->getNext()) { auto ArgType = Arg->getType(); - ArgType->dump(OS, 0, *this); - OS << " " << Arg->getName(); + ArgType->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " + << Arg->getName(); if (++Index < Arguments->getChildCount()) - OS << ", "; + Printer << ", "; } } - OS << ")"; + Printer << ")"; if (Symbol.isConstType()) - OS << " const"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << " const"; if (Symbol.isVolatileType()) - OS << " volatile"; + WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile"; if (Symbol.isPureVirtual()) - OS << " = 0"; + Printer << " = 0"; } -void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, - int Indent) { +void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) { uint32_t ElementTypeId = Symbol.getTypeId(); auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId); if (!ElementType) return; - ElementType->dump(OS, 0, *this); - OS << "[" << Symbol.getLength() << "]"; + ElementType->dump(*this); + Printer << "["; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength(); + Printer << "]"; } -void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) { - PDB_BuiltinType Type = Symbol.getBuiltinType(); - OS << Type; - if (Type == PDB_BuiltinType::UInt || Type == PDB_BuiltinType::Int) - OS << (8 * Symbol.getLength()) << "_t"; +void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); } -void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) { - dumpClassParentWithScopeOperator(Symbol, OS, *this); - OS << Symbol.getName(); +void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } -void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol, - raw_ostream &OS, int Indent) { +void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) { // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill // through to the real thing and dump it. - Symbol.defaultDump(OS, Indent); uint32_t TypeId = Symbol.getTypeId(); auto Type = Symbol.getSession().getSymbolById(TypeId); if (!Type) return; - Type->dump(OS, 0, *this); + Type->dump(*this); } -void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) { - dumpClassParentWithScopeOperator(Symbol, OS, *this); - OS << Symbol.getName(); +void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + dumpClassParentWithScopeOperator(Symbol, Printer, *this); + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } -void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) { +void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) { uint32_t PointeeId = Symbol.getTypeId(); auto PointeeType = Symbol.getSession().getSymbolById(PointeeId); if (!PointeeType) return; if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) { - FunctionDumper NestedDumper; + FunctionDumper NestedDumper(Printer); PointerType Pointer = Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; - NestedDumper.start(*FuncSig, Pointer, OS); + NestedDumper.start(*FuncSig, nullptr, Pointer); } else { if (Symbol.isConstType()) - OS << "const "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; if (Symbol.isVolatileType()) - OS << "volatile "; - PointeeType->dump(OS, Indent, *this); - OS << (Symbol.isReference() ? "&" : "*"); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + PointeeType->dump(*this); + Printer << (Symbol.isReference() ? "&" : "*"); } } -void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) { - OS << Symbol.getName(); +void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } diff --git a/tools/llvm-pdbdump/FunctionDumper.h b/tools/llvm-pdbdump/FunctionDumper.h index f9338cb..19a0014 100644 --- a/tools/llvm-pdbdump/FunctionDumper.h +++ b/tools/llvm-pdbdump/FunctionDumper.h @@ -14,31 +14,28 @@ namespace llvm { +class LinePrinter; + class FunctionDumper : public PDBSymDumper { public: - FunctionDumper(); + FunctionDumper(LinePrinter &P); enum class PointerType { None, Pointer, Reference }; - void start(const PDBSymbolTypeFunctionSig &Symbol, PointerType Pointer, - raw_ostream &OS); - void start(const PDBSymbolFunc &Symbol, PointerType Pointer, raw_ostream &OS, - int Indent); - - void dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeFunctionArg &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) override; + void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name, + PointerType Pointer); + void start(const PDBSymbolFunc &Symbol, PointerType Pointer); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionArg &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; }; } diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp new file mode 100644 index 0000000..6bbc403 --- /dev/null +++ b/tools/llvm-pdbdump/LinePrinter.cpp @@ -0,0 +1,124 @@ +//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LinePrinter.h" + +#include "llvm-pdbdump.h" + +#include "llvm/Support/Regex.h" + +#include <algorithm> + +using namespace llvm; + +LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream) + : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) { + SetFilters(TypeFilters, opts::ExcludeTypes.begin(), opts::ExcludeTypes.end()); + SetFilters(SymbolFilters, opts::ExcludeSymbols.begin(), + opts::ExcludeSymbols.end()); + SetFilters(CompilandFilters, opts::ExcludeCompilands.begin(), + opts::ExcludeCompilands.end()); +} + +void LinePrinter::Indent() { CurrentIndent += IndentSpaces; } + +void LinePrinter::Unindent() { + CurrentIndent = std::max(0, CurrentIndent - IndentSpaces); +} + +void LinePrinter::NewLine() { + OS << "\n"; + OS.indent(CurrentIndent); +} + +bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) { + if (TypeName.empty()) + return false; + + for (auto &Expr : TypeFilters) { + if (Expr.match(TypeName)) + return true; + } + return false; +} + +bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) { + if (SymbolName.empty()) + return false; + + for (auto &Expr : SymbolFilters) { + if (Expr.match(SymbolName)) + return true; + } + return false; +} + +bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) { + if (CompilandName.empty()) + return false; + + for (auto &Expr : CompilandFilters) { + if (Expr.match(CompilandName)) + return true; + } + return false; +} + +WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) : OS(P.OS) { + if (C == PDB_ColorItem::None) + OS.resetColor(); + else { + raw_ostream::Colors Color; + bool Bold; + translateColor(C, Color, Bold); + OS.changeColor(Color, Bold); + } +} + +WithColor::~WithColor() { OS.resetColor(); } + +void WithColor::translateColor(PDB_ColorItem C, raw_ostream::Colors &Color, + bool &Bold) const { + switch (C) { + case PDB_ColorItem::Address: + Color = raw_ostream::YELLOW; + Bold = true; + return; + case PDB_ColorItem::Keyword: + Color = raw_ostream::MAGENTA; + Bold = true; + return; + case PDB_ColorItem::Register: + case PDB_ColorItem::Offset: + Color = raw_ostream::YELLOW; + Bold = false; + return; + case PDB_ColorItem::Type: + Color = raw_ostream::CYAN; + Bold = true; + return; + case PDB_ColorItem::Identifier: + Color = raw_ostream::CYAN; + Bold = false; + return; + case PDB_ColorItem::Path: + Color = raw_ostream::CYAN; + Bold = false; + return; + case PDB_ColorItem::SectionHeader: + Color = raw_ostream::RED; + Bold = true; + return; + case PDB_ColorItem::LiteralValue: + Color = raw_ostream::GREEN; + Bold = true; + default: + return; + } +} diff --git a/tools/llvm-pdbdump/LinePrinter.h b/tools/llvm-pdbdump/LinePrinter.h new file mode 100644 index 0000000..c2a3ab6 --- /dev/null +++ b/tools/llvm-pdbdump/LinePrinter.h @@ -0,0 +1,89 @@ +//===- LinePrinter.h ------------------------------------------ *- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H +#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Regex.h" + +#include <list> + +namespace llvm { + +class LinePrinter { + friend class WithColor; + +public: + LinePrinter(int Indent, raw_ostream &Stream); + + void Indent(); + void Unindent(); + void NewLine(); + + raw_ostream &getStream() { return OS; } + int getIndentLevel() const { return CurrentIndent; } + + bool IsTypeExcluded(llvm::StringRef TypeName); + bool IsSymbolExcluded(llvm::StringRef SymbolName); + bool IsCompilandExcluded(llvm::StringRef CompilandName); + +private: + template <typename Iter> + void SetFilters(std::list<Regex> &List, Iter Begin, Iter End) { + List.clear(); + for (; Begin != End; ++Begin) + List.push_back(StringRef(*Begin)); + } + + raw_ostream &OS; + int IndentSpaces; + int CurrentIndent; + + std::list<Regex> CompilandFilters; + std::list<Regex> TypeFilters; + std::list<Regex> SymbolFilters; +}; + +template <class T> +inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) { + Printer.getStream() << Item; + return Printer.getStream(); +} + +enum class PDB_ColorItem { + None, + Address, + Type, + Keyword, + Offset, + Identifier, + Path, + SectionHeader, + LiteralValue, + Register, +}; + +class WithColor { +public: + WithColor(LinePrinter &P, PDB_ColorItem C); + ~WithColor(); + + raw_ostream &get() { return OS; } + +private: + void translateColor(PDB_ColorItem C, raw_ostream::Colors &Color, + bool &Bold) const; + raw_ostream &OS; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/TypeDumper.cpp b/tools/llvm-pdbdump/TypeDumper.cpp index 3131e9f..88c0bd6 100644 --- a/tools/llvm-pdbdump/TypeDumper.cpp +++ b/tools/llvm-pdbdump/TypeDumper.cpp @@ -9,88 +9,89 @@ #include "TypeDumper.h" +#include "BuiltinDumper.h" #include "ClassDefinitionDumper.h" -#include "FunctionDumper.h" +#include "EnumDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "TypedefDumper.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace llvm; -TypeDumper::TypeDumper(bool Inline, bool ClassDefs) - : PDBSymDumper(true), InlineDump(Inline), FullClassDefs(ClassDefs) {} +TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} -void TypeDumper::start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent) { +void TypeDumper::start(const PDBSymbolExe &Exe) { auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>(); - OS << newline(Indent) << "Enums: (" << Enums->getChildCount() << " items)"; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums"; + Printer << ": (" << Enums->getChildCount() << " items)"; + Printer.Indent(); while (auto Enum = Enums->getNext()) - Enum->dump(OS, Indent + 2, *this); - - auto FuncSigs = Exe.findAllChildren<PDBSymbolTypeFunctionSig>(); - OS << newline(Indent); - OS << "Function Signatures: (" << FuncSigs->getChildCount() << " items)"; - while (auto Sig = FuncSigs->getNext()) - Sig->dump(OS, Indent + 2, *this); + Enum->dump(*this); + Printer.Unindent(); auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>(); - OS << newline(Indent) << "Typedefs: (" << Typedefs->getChildCount() - << " items)"; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs"; + Printer << ": (" << Typedefs->getChildCount() << " items)"; + Printer.Indent(); while (auto Typedef = Typedefs->getNext()) - Typedef->dump(OS, Indent + 2, *this); + Typedef->dump(*this); + Printer.Unindent(); auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>(); - OS << newline(Indent) << "Classes: (" << Classes->getChildCount() - << " items)"; + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes"; + Printer << ": (" << Classes->getChildCount() << " items)"; + Printer.Indent(); while (auto Class = Classes->getNext()) - Class->dump(OS, Indent + 2, *this); + Class->dump(*this); + Printer.Unindent(); } -void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) { +void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) { if (Symbol.getUnmodifiedTypeId() != 0) return; + if (Printer.IsTypeExcluded(Symbol.getName())) + return; + // Dump member enums when dumping their class definition. + if (Symbol.isNested()) + return; - if (!InlineDump) - OS << newline(Indent); - - OS << "enum " << Symbol.getName(); -} - -void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS, - int Indent) { - if (!InlineDump) - OS << newline(Indent); - - FunctionDumper Dumper; - Dumper.start(Symbol, FunctionDumper::PointerType::None, OS); + Printer.NewLine(); + EnumDumper Dumper(Printer); + Dumper.start(Symbol); } -void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) { - if (!InlineDump) - OS << newline(Indent); +void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + if (Printer.IsTypeExcluded(Symbol.getName())) + return; - TypedefDumper Dumper; - Dumper.start(Symbol, OS, Indent); + Printer.NewLine(); + TypedefDumper Dumper(Printer); + Dumper.start(Symbol); } -void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) { +void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) { if (Symbol.getUnmodifiedTypeId() != 0) return; - if (!InlineDump) - OS << newline(Indent); + if (Printer.IsTypeExcluded(Symbol.getName())) + return; + + Printer.NewLine(); - if (FullClassDefs) { - ClassDefinitionDumper Dumper; - Dumper.start(Symbol, OS, Indent); + if (opts::NoClassDefs) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName(); } else { - OS << "class " << Symbol.getName(); + ClassDefinitionDumper Dumper(Printer); + Dumper.start(Symbol); } } diff --git a/tools/llvm-pdbdump/TypeDumper.h b/tools/llvm-pdbdump/TypeDumper.h index d96c24c..5c0832e 100644 --- a/tools/llvm-pdbdump/TypeDumper.h +++ b/tools/llvm-pdbdump/TypeDumper.h @@ -14,24 +14,20 @@ namespace llvm { +class LinePrinter; + class TypeDumper : public PDBSymDumper { public: - TypeDumper(bool Inline, bool ClassDefs); + TypeDumper(LinePrinter &P); - void start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent); + void start(const PDBSymbolExe &Exe); - void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; private: - bool InlineDump; - bool FullClassDefs; + LinePrinter &Printer; }; } diff --git a/tools/llvm-pdbdump/TypedefDumper.cpp b/tools/llvm-pdbdump/TypedefDumper.cpp index 6eea6b6..a6b5c53 100644 --- a/tools/llvm-pdbdump/TypedefDumper.cpp +++ b/tools/llvm-pdbdump/TypedefDumper.cpp @@ -9,12 +9,13 @@ #include "TypedefDumper.h" +#include "BuiltinDumper.h" #include "FunctionDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDBExtras.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" @@ -23,39 +24,34 @@ using namespace llvm; -TypedefDumper::TypedefDumper() : PDBSymDumper(true) {} +TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {} -void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) { - OS << "typedef "; +void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; uint32_t TargetId = Symbol.getTypeId(); if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId)) - TypeSymbol->dump(OS, 0, *this); - OS << " " << Symbol.getName(); + TypeSymbol->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " + << Symbol.getName(); } -void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, - int Indent) {} +void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {} -void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) { - PDB_BuiltinType Type = Symbol.getBuiltinType(); - OS << Type; - if (Type == PDB_BuiltinType::UInt || Type == PDB_BuiltinType::Int) - OS << (8 * Symbol.getLength()) << "_t"; +void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); } -void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) { - OS << "enum " << Symbol.getName(); +void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum "; + WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName(); } -void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) { +void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) { if (Symbol.isConstType()) - OS << "const "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; if (Symbol.isVolatileType()) - OS << "volatile "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; uint32_t PointeeId = Symbol.getTypeId(); auto PointeeType = Symbol.getSession().getSymbolById(PointeeId); if (!PointeeType) @@ -64,21 +60,20 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; if (Symbol.isReference()) Pointer = FunctionDumper::PointerType::Reference; - FunctionDumper NestedDumper; - NestedDumper.start(*FuncSig, Pointer, OS); + FunctionDumper NestedDumper(Printer); + NestedDumper.start(*FuncSig, nullptr, Pointer); } else { - PointeeType->dump(OS, Indent, *this); - OS << ((Symbol.isReference()) ? "&" : "*"); + PointeeType->dump(*this); + Printer << ((Symbol.isReference()) ? "&" : "*"); } } -void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol, - raw_ostream &OS, int Indent) { - FunctionDumper Dumper; - Dumper.start(Symbol, FunctionDumper::PointerType::None, OS); +void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) { + FunctionDumper Dumper(Printer); + Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None); } -void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) { - OS << "class " << Symbol.getName(); +void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "class "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } diff --git a/tools/llvm-pdbdump/TypedefDumper.h b/tools/llvm-pdbdump/TypedefDumper.h index e6211a8..8cd578c 100644 --- a/tools/llvm-pdbdump/TypedefDumper.h +++ b/tools/llvm-pdbdump/TypedefDumper.h @@ -14,24 +14,23 @@ namespace llvm { +class LinePrinter; + class TypedefDumper : public PDBSymDumper { public: - TypedefDumper(); - - void start(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, int Indent); - - void dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) override; + TypedefDumper(LinePrinter &P); + + void start(const PDBSymbolTypeTypedef &Symbol); + + void dump(const PDBSymbolTypeArray &Symbol) override; + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; + +private: + LinePrinter &Printer; }; } diff --git a/tools/llvm-pdbdump/VariableDumper.cpp b/tools/llvm-pdbdump/VariableDumper.cpp index 913cfee..030610c 100644 --- a/tools/llvm-pdbdump/VariableDumper.cpp +++ b/tools/llvm-pdbdump/VariableDumper.cpp @@ -9,13 +9,16 @@ #include "VariableDumper.h" +#include "BuiltinDumper.h" +#include "LinePrinter.h" #include "llvm-pdbdump.h" #include "FunctionDumper.h" #include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h" -#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" @@ -25,96 +28,143 @@ using namespace llvm; -VariableDumper::VariableDumper() : PDBSymDumper(true) {} +VariableDumper::VariableDumper(LinePrinter &P) + : PDBSymDumper(true), Printer(P) {} -void VariableDumper::start(const PDBSymbolData &Var, raw_ostream &OS, - int Indent) { - OS << newline(Indent); - OS << "data "; +void VariableDumper::start(const PDBSymbolData &Var) { + if (Var.isCompilerGenerated() && opts::ExcludeCompilerGenerated) + return; + if (Printer.IsSymbolExcluded(Var.getName())) + return; auto VarType = Var.getType(); switch (auto LocType = Var.getLocationType()) { case PDB_LocType::Static: - OS << "[" << format_hex(Var.getRelativeVirtualAddress(), 10) << "] "; - OS << "static "; - dumpSymbolTypeAndName(*VarType, Var.getName(), OS); + Printer.NewLine(); + Printer << "data ["; + WithColor(Printer, PDB_ColorItem::Address).get() + << format_hex(Var.getRelativeVirtualAddress(), 10); + Printer << "] "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "static "; + dumpSymbolTypeAndName(*VarType, Var.getName()); break; case PDB_LocType::Constant: - OS << "const "; - dumpSymbolTypeAndName(*VarType, Var.getName(), OS); - OS << "[" << Var.getValue() << "]"; + if (isa<PDBSymbolTypeEnum>(*VarType)) + break; + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " = "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue(); break; case PDB_LocType::ThisRel: - OS << "+" << format_hex(Var.getOffset(), 4) << " "; - dumpSymbolTypeAndName(*VarType, Var.getName(), OS); + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Var.getOffset(), 4) << " "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + break; + case PDB_LocType::BitField: + Printer.NewLine(); + Printer << "data "; + WithColor(Printer, PDB_ColorItem::Offset).get() + << "+" << format_hex(Var.getOffset(), 4) << " "; + dumpSymbolTypeAndName(*VarType, Var.getName()); + Printer << " : "; + WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength(); break; default: + Printer.NewLine(); + Printer << "data "; + Printer << "unknown(" << LocType << ") "; + WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName(); break; - OS << "unknown(" << LocType << ") " << Var.getName(); } } -void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) { - OS << Symbol.getBuiltinType(); +void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) { + BuiltinDumper Dumper(Printer); + Dumper.start(Symbol); } -void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) { - OS << Symbol.getName(); +void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } -void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol, - raw_ostream &OS, int Indent) {} +void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {} -void VariableDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) { +void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) { auto PointeeType = Symbol.getPointeeType(); if (!PointeeType) return; if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) { - FunctionDumper NestedDumper; + FunctionDumper NestedDumper(Printer); FunctionDumper::PointerType Pointer = Symbol.isReference() ? FunctionDumper::PointerType::Reference : FunctionDumper::PointerType::Pointer; - NestedDumper.start(*Func, Pointer, OS, Indent); + NestedDumper.start(*Func, Pointer); } else { if (Symbol.isConstType()) - OS << "const "; + WithColor(Printer, PDB_ColorItem::Keyword).get() << "const "; if (Symbol.isVolatileType()) - OS << "volatile "; - PointeeType->dump(OS, Indent, *this); - OS << (Symbol.isReference() ? "&" : "*"); + WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile "; + PointeeType->dump(*this); + Printer << (Symbol.isReference() ? "&" : "*"); } } -void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) { - OS << "typedef " << Symbol.getName(); +void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) { + WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef "; + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } -void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) { - OS << Symbol.getName(); +void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) { + WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName(); } void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type, - StringRef Name, raw_ostream &OS) { + StringRef Name) { if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) { std::string IndexSpec; raw_string_ostream IndexStream(IndexSpec); std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType(); while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) { - IndexStream << "[" << NestedArray->getCount() << "]"; + IndexStream << "["; + IndexStream << NestedArray->getCount(); + IndexStream << "]"; ElementType = NestedArray->getElementType(); } IndexStream << "[" << ArrayType->getCount() << "]"; - ElementType->dump(OS, 0, *this); - OS << " " << Name << IndexStream.str(); + ElementType->dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name; + Printer << IndexStream.str(); } else { - Type.dump(OS, 0, *this); - OS << " " << Name; + if (!tryDumpFunctionPointer(Type, Name)) { + Type.dump(*this); + WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name; + } + } +} + +bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type, + StringRef Name) { + // Function pointers come across as pointers to function signatures. But the + // signature carries no name, so we have to handle this case separately. + if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) { + auto PointeeType = PointerType->getPointeeType(); + if (auto *FunctionSig = + dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) { + FunctionDumper Dumper(Printer); + FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer; + if (PointerType->isReference()) + PT = FunctionDumper::PointerType::Reference; + std::string NameStr(Name.begin(), Name.end()); + Dumper.start(*FunctionSig, NameStr.c_str(), PT); + return true; + } } + return false; } diff --git a/tools/llvm-pdbdump/VariableDumper.h b/tools/llvm-pdbdump/VariableDumper.h index e6e71fa..db8d8ea 100644 --- a/tools/llvm-pdbdump/VariableDumper.h +++ b/tools/llvm-pdbdump/VariableDumper.h @@ -15,28 +15,26 @@ namespace llvm { +class LinePrinter; + class VariableDumper : public PDBSymDumper { public: - VariableDumper(); - - void start(const PDBSymbolData &Var, raw_ostream &OS, int Indent); - - void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, - int Indent) override; - void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, - int Indent) override; + VariableDumper(LinePrinter &P); + + void start(const PDBSymbolData &Var); + + void dump(const PDBSymbolTypeBuiltin &Symbol) override; + void dump(const PDBSymbolTypeEnum &Symbol) override; + void dump(const PDBSymbolTypeFunctionSig &Symbol) override; + void dump(const PDBSymbolTypePointer &Symbol) override; + void dump(const PDBSymbolTypeTypedef &Symbol) override; + void dump(const PDBSymbolTypeUDT &Symbol) override; private: - void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name, - raw_ostream &OS); + void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name); + bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name); + + LinePrinter &Printer; }; } diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp index e33e715..78535ec 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.cpp +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -15,7 +15,10 @@ #include "llvm-pdbdump.h" #include "CompilandDumper.h" +#include "FunctionDumper.h" +#include "LinePrinter.h" #include "TypeDumper.h" +#include "VariableDumper.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" @@ -25,7 +28,10 @@ #include "llvm/DebugInfo/PDB/IPDBSession.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" #include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/FileSystem.h" @@ -50,53 +56,164 @@ cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input PDB files>"), cl::OneOrMore); -cl::opt<bool> DumpCompilands("compilands", cl::desc("Display compilands")); -cl::opt<bool> DumpSymbols("symbols", - cl::desc("Display symbols (implies --compilands")); -cl::opt<bool> DumpTypes("types", cl::desc("Display types")); -cl::opt<bool> DumpClassDefs("class-definitions", - cl::desc("Display full class definitions")); +cl::OptionCategory TypeCategory("Symbol Type Options"); +cl::OptionCategory FilterCategory("Filtering Options"); + +cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"), + cl::cat(TypeCategory)); +cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"), + cl::cat(TypeCategory)); +cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"), + cl::cat(TypeCategory)); +cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory)); +cl::opt<bool> + All("all", cl::desc("Implies all other options in 'Symbol Types' category"), + cl::cat(TypeCategory)); + +cl::list<std::string> + ExcludeTypes("exclude-types", + cl::desc("Exclude types by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); +cl::list<std::string> + ExcludeSymbols("exclude-symbols", + cl::desc("Exclude symbols by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); +cl::list<std::string> + ExcludeCompilands("exclude-compilands", + cl::desc("Exclude compilands by regular expression"), + cl::ZeroOrMore, cl::cat(FilterCategory)); +cl::opt<bool> ExcludeCompilerGenerated( + "no-compiler-generated", + cl::desc("Don't show compiler generated types and symbols"), + cl::cat(FilterCategory)); +cl::opt<bool> + ExcludeSystemLibraries("no-system-libs", + cl::desc("Don't show symbols from system libraries"), + cl::cat(FilterCategory)); +cl::opt<bool> NoClassDefs("no-class-definitions", + cl::desc("Don't display full class definitions"), + cl::cat(FilterCategory)); +cl::opt<bool> NoEnumDefs("no-enum-definitions", + cl::desc("Don't display full enum definitions"), + cl::cat(FilterCategory)); } static void dumpInput(StringRef Path) { - std::unique_ptr<IPDBSession> Session( - llvm::createPDBReader(PDB_ReaderType::DIA, Path)); - if (!Session) { - outs() << "Unable to create PDB reader. Check that a valid implementation"; - outs() << " is available for your platform."; + std::unique_ptr<IPDBSession> Session; + PDB_ErrorCode Error = + llvm::createPDBReader(PDB_ReaderType::DIA, Path, Session); + switch (Error) { + case PDB_ErrorCode::Success: + break; + case PDB_ErrorCode::NoPdbImpl: + outs() << "Reading PDBs is not supported on this platform.\n"; + return; + case PDB_ErrorCode::InvalidPath: + outs() << "Unable to load PDB at '" << Path + << "'. Check that the file exists and is readable.\n"; + return; + case PDB_ErrorCode::InvalidFileFormat: + outs() << "Unable to load PDB at '" << Path + << "'. The file has an unrecognized format.\n"; + return; + default: + outs() << "Unable to load PDB at '" << Path + << "'. An unknown error occured.\n"; return; } + LinePrinter Printer(2, outs()); + auto GlobalScope(Session->getGlobalScope()); std::string FileName(GlobalScope->getSymbolsFileName()); - outs() << "Summary for " << FileName; + WithColor(Printer, PDB_ColorItem::None).get() << "Summary for "; + WithColor(Printer, PDB_ColorItem::Path).get() << FileName; + Printer.Indent(); uint64_t FileSize = 0; - if (!llvm::sys::fs::file_size(FileName, FileSize)) - outs() << newline(2) << "Size: " << FileSize << " bytes"; - else - outs() << newline(2) << "Size: (Unable to obtain file size)"; - - outs() << newline(2) << "Guid: " << GlobalScope->getGuid(); - outs() << newline(2) << "Age: " << GlobalScope->getAge(); - outs() << newline(2) << "Attributes: "; + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size"; + if (!llvm::sys::fs::file_size(FileName, FileSize)) { + Printer << ": " << FileSize << " bytes"; + } else { + Printer << ": (Unable to obtain file size)"; + } + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid"; + Printer << ": " << GlobalScope->getGuid(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age"; + Printer << ": " << GlobalScope->getAge(); + + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes"; + Printer << ": "; if (GlobalScope->hasCTypes()) outs() << "HasCTypes "; if (GlobalScope->hasPrivateSymbols()) outs() << "HasPrivateSymbols "; + Printer.Unindent(); + + if (opts::Compilands) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() + << "---COMPILANDS---"; + Printer.Indent(); + auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); + CompilandDumper Dumper(Printer); + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, false); + Printer.Unindent(); + } - if (opts::DumpTypes) { - outs() << "\nDumping types"; - TypeDumper Dumper(false, opts::DumpClassDefs); - Dumper.start(*GlobalScope, outs(), 2); + if (opts::Types) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---"; + Printer.Indent(); + TypeDumper Dumper(Printer); + Dumper.start(*GlobalScope); + Printer.Unindent(); } - if (opts::DumpSymbols || opts::DumpCompilands) { - outs() << "\nDumping compilands"; + if (opts::Symbols) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---"; + Printer.Indent(); auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>(); - CompilandDumper Dumper; + CompilandDumper Dumper(Printer); while (auto Compiland = Compilands->getNext()) - Dumper.start(*Compiland, outs(), 2, opts::DumpSymbols); + Dumper.start(*Compiland, true); + Printer.Unindent(); + } + + if (opts::Globals) { + Printer.NewLine(); + WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---"; + Printer.Indent(); + { + FunctionDumper Dumper(Printer); + auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>(); + while (auto Function = Functions->getNext()) { + Printer.NewLine(); + Dumper.start(*Function, FunctionDumper::PointerType::None); + } + } + { + auto Vars = GlobalScope->findAllChildren<PDBSymbolData>(); + VariableDumper Dumper(Printer); + while (auto Var = Vars->getNext()) + Dumper.start(*Var); + } + { + auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>(); + CompilandDumper Dumper(Printer); + while (auto Thunk = Thunks->getNext()) + Dumper.dump(*Thunk); + } + Printer.Unindent(); } outs().flush(); } @@ -118,6 +235,20 @@ int main(int argc_, const char *argv_[]) { llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); + if (opts::All) { + opts::Compilands = true; + opts::Symbols = true; + opts::Globals = true; + opts::Types = true; + } + if (opts::ExcludeCompilerGenerated) { + opts::ExcludeTypes.push_back("__vc_attributes"); + opts::ExcludeCompilands.push_back("* Linker *"); + } + if (opts::ExcludeSystemLibraries) { + opts::ExcludeCompilands.push_back( + "f:\\binaries\\Intermediate\\vctools\\crt_bld"); + } #if defined(HAVE_DIA_SDK) CoInitializeEx(nullptr, COINIT_MULTITHREADED); diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h index 74a1718..586a9ea 100644 --- a/tools/llvm-pdbdump/llvm-pdbdump.h +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -10,19 +10,23 @@ #ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H #define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H +#include "llvm/Support/CommandLine.h" #include "llvm/Support/raw_ostream.h" -namespace llvm { -struct newline { - newline(int IndentWidth) : Width(IndentWidth) {} - int Width; -}; +namespace opts { +extern llvm::cl::opt<bool> Compilands; +extern llvm::cl::opt<bool> Symbols; +extern llvm::cl::opt<bool> Globals; +extern llvm::cl::opt<bool> Types; +extern llvm::cl::opt<bool> All; -inline raw_ostream &operator<<(raw_ostream &OS, const newline &Indent) { - OS << "\n"; - OS.indent(Indent.Width); - return OS; -} +extern llvm::cl::opt<bool> ExcludeCompilerGenerated; + +extern llvm::cl::opt<bool> NoClassDefs; +extern llvm::cl::opt<bool> NoEnumDefs; +extern llvm::cl::list<std::string> ExcludeTypes; +extern llvm::cl::list<std::string> ExcludeSymbols; +extern llvm::cl::list<std::string> ExcludeCompilands; } #endif
\ No newline at end of file diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index 0137e35..1bfdb18 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" @@ -38,8 +39,8 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") { enum ProfileKinds { instr, sample }; -void mergeInstrProfile(const cl::list<std::string> &Inputs, - StringRef OutputFilename) { +static void mergeInstrProfile(const cl::list<std::string> &Inputs, + StringRef OutputFilename) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); @@ -65,9 +66,9 @@ void mergeInstrProfile(const cl::list<std::string> &Inputs, Writer.write(Output); } -void mergeSampleProfile(const cl::list<std::string> &Inputs, - StringRef OutputFilename, - sampleprof::SampleProfileFormat OutputFormat) { +static void mergeSampleProfile(const cl::list<std::string> &Inputs, + StringRef OutputFilename, + sampleprof::SampleProfileFormat OutputFormat) { using namespace sampleprof; auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); if (std::error_code EC = WriterOrErr.getError()) @@ -97,7 +98,7 @@ void mergeSampleProfile(const cl::list<std::string> &Inputs, Writer->write(ProfileMap); } -int merge_main(int argc, const char *argv[]) { +static int merge_main(int argc, const char *argv[]) { cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore, cl::desc("<filenames...>")); @@ -130,9 +131,9 @@ int merge_main(int argc, const char *argv[]) { return 0; } -int showInstrProfile(std::string Filename, bool ShowCounts, - bool ShowAllFunctions, std::string ShowFunction, - raw_fd_ostream &OS) { +static int showInstrProfile(std::string Filename, bool ShowCounts, + bool ShowAllFunctions, std::string ShowFunction, + raw_fd_ostream &OS) { auto ReaderOrErr = InstrProfReader::create(Filename); if (std::error_code EC = ReaderOrErr.getError()) exitWithError(EC.message(), Filename); @@ -183,9 +184,9 @@ int showInstrProfile(std::string Filename, bool ShowCounts, return 0; } -int showSampleProfile(std::string Filename, bool ShowCounts, - bool ShowAllFunctions, std::string ShowFunction, - raw_fd_ostream &OS) { +static int showSampleProfile(std::string Filename, bool ShowCounts, + bool ShowAllFunctions, std::string ShowFunction, + raw_fd_ostream &OS) { using namespace sampleprof; auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext()); if (std::error_code EC = ReaderOrErr.getError()) @@ -201,7 +202,7 @@ int showSampleProfile(std::string Filename, bool ShowCounts, return 0; } -int show_main(int argc, const char *argv[]) { +static int show_main(int argc, const char *argv[]) { cl::opt<std::string> Filename(cl::Positional, cl::Required, cl::desc("<profdata-file>")); diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index e4b7601..39fb065 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -207,6 +207,7 @@ static const EnumEntry<unsigned> ElfOSABI[] = { { "NSK", ELF::ELFOSABI_NSK }, { "AROS", ELF::ELFOSABI_AROS }, { "FenixOS", ELF::ELFOSABI_FENIXOS }, + { "CloudABI", ELF::ELFOSABI_CLOUDABI }, { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI }, { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX }, { "ARM", ELF::ELFOSABI_ARM }, diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index f8f3086..32db723 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -25,6 +25,7 @@ #include "StreamWriter.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -320,6 +321,19 @@ static void dumpArchive(const Archive *Arc) { } } +/// @brief Dumps each object file in \a MachO Universal Binary; +static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { + for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { + ErrorOr<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile(); + if (std::error_code EC = ObjOrErr.getError()) { + reportError(UBinary->getFileName(), EC.message()); + continue; + } + + if (MachOObjectFile *MachOObj = ObjOrErr.get().get()) + dumpObject(MachOObj); + } +} /// @brief Opens \a File and dumps it. static void dumpInput(StringRef File) { @@ -339,6 +353,9 @@ static void dumpInput(StringRef File) { if (Archive *Arc = dyn_cast<Archive>(&Binary)) dumpArchive(Arc); + else if (MachOUniversalBinary *UBinary = + dyn_cast<MachOUniversalBinary>(&Binary)) + dumpMachOUniversalBinary(UBinary); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) dumpObject(Obj); else diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 58bf206..9462015 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -298,7 +298,7 @@ static int executeInput() { // FIXME: Error out if there are unresolved relocations. // Get the address of the entry point (_main by default). - void *MainAddress = Dyld.getSymbolAddress(EntryPoint); + void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint); if (!MainAddress) return Error("no definition for '" + EntryPoint + "'"); @@ -339,7 +339,7 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) { return 0; } -std::map<void*, uint64_t> +static std::map<void *, uint64_t> applySpecificSectionMappings(RuntimeDyldChecker &Checker) { std::map<void*, uint64_t> SpecificMappings; @@ -397,9 +397,9 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) { // Defaults to zero. Set to something big // (e.g. 1 << 32) to stress-test stubs, GOTs, etc. // -void remapSections(const llvm::Triple &TargetTriple, - const TrivialMemoryManager &MemMgr, - RuntimeDyldChecker &Checker) { +static void remapSections(const llvm::Triple &TargetTriple, + const TrivialMemoryManager &MemMgr, + RuntimeDyldChecker &Checker) { // Set up a work list (section addr/size pairs). typedef std::list<std::pair<void*, uint64_t>> WorklistT; diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt index 9a8cd4a..08dafe1 100644 --- a/tools/llvm-shlib/CMakeLists.txt +++ b/tools/llvm-shlib/CMakeLists.txt @@ -90,7 +90,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # FIXME: It should be "GNU ld for el set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive) endif() -target_link_libraries(LLVM ${cmake_2_8_12_PRIVATE} ${LIB_NAMES}) +target_link_libraries(LLVM PRIVATE ${LIB_NAMES}) add_dependencies(LLVM libLLVMExports) diff --git a/tools/llvm-stress/CMakeLists.txt b/tools/llvm-stress/CMakeLists.txt index 106ced1..d5c10e1 100644 --- a/tools/llvm-stress/CMakeLists.txt +++ b/tools/llvm-stress/CMakeLists.txt @@ -7,4 +7,4 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-stress llvm-stress.cpp ) -set_target_properties(llvm-stress PROPERTIES ENABLE_EXPORTS 1) +export_executable_symbols(llvm-stress) diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index 05ceeb5..f5e718b 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -713,7 +713,6 @@ int main(int argc, char **argv) { legacy::PassManager Passes; Passes.add(createVerifierPass()); - Passes.add(createDebugInfoVerifierPass()); Passes.add(createPrintModulePass(Out->os())); Passes.run(*M.get()); Out->keep(); diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp index d554022..cb40472 100644 --- a/tools/llvm-symbolizer/llvm-symbolizer.cpp +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 714b8e0..cc4169f 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/LLVMContext.h" #include "llvm/LTO/LTOCodeGenerator.h" @@ -22,9 +23,13 @@ #include "llvm/Support/TargetSelect.h" // extra command-line flags needed for LTOCodeGenerator -static cl::opt<bool> -DisableOpt("disable-opt", cl::init(false), - cl::desc("Do not run any optimization passes")); +static cl::opt<char> +OptLevel("O", + cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] " + "(default = '-O2')"), + cl::Prefix, + cl::ZeroOrMore, + cl::init('2')); static cl::opt<bool> DisableInline("disable-inlining", cl::init(false), @@ -84,6 +89,10 @@ static void lto_add_attrs(lto_code_gen_t cg) { CG->setAttr(attrs.c_str()); } + + if (OptLevel < '0' || OptLevel > '3') + report_fatal_error("Optimization level must be between 0 and 3"); + CG->setOptLevel(OptLevel - '0'); } extern const char* lto_get_version() { @@ -280,54 +289,42 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, unwrap(cg)->addMustPreserveSymbol(symbol); } -bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { +static void maybeParseOptions(lto_code_gen_t cg) { if (!parsedOptions) { unwrap(cg)->parseCodeGenDebugOptions(); lto_add_attrs(cg); parsedOptions = true; } +} + +bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { + maybeParseOptions(cg); return !unwrap(cg)->writeMergedModules(path, sLastErrorString); } const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { - if (!parsedOptions) { - unwrap(cg)->parseCodeGenDebugOptions(); - lto_add_attrs(cg); - parsedOptions = true; - } - return unwrap(cg)->compile(length, DisableOpt, DisableInline, + maybeParseOptions(cg); + return unwrap(cg)->compile(length, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, sLastErrorString); } bool lto_codegen_optimize(lto_code_gen_t cg) { - if (!parsedOptions) { - unwrap(cg)->parseCodeGenDebugOptions(); - lto_add_attrs(cg); - parsedOptions = true; - } - return !unwrap(cg)->optimize(DisableOpt, DisableInline, + maybeParseOptions(cg); + return !unwrap(cg)->optimize(DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, sLastErrorString); } const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) { - if (!parsedOptions) { - unwrap(cg)->parseCodeGenDebugOptions(); - lto_add_attrs(cg); - parsedOptions = true; - } + maybeParseOptions(cg); return unwrap(cg)->compileOptimized(length, sLastErrorString); } bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) { - if (!parsedOptions) { - unwrap(cg)->parseCodeGenDebugOptions(); - lto_add_attrs(cg); - parsedOptions = true; - } + maybeParseOptions(cg); return !unwrap(cg)->compile_to_file( - name, DisableOpt, DisableInline, DisableGVNLoadPRE, + name, DisableInline, DisableGVNLoadPRE, DisableLTOVectorization, sLastErrorString); } diff --git a/tools/opt/Android.mk b/tools/opt/Android.mk index 7220575..814fabc 100644 --- a/tools/opt/Android.mk +++ b/tools/opt/Android.mk @@ -12,7 +12,6 @@ llvm_opt_SRC_FILES := \ BreakpointPrinter.cpp \ GraphPrinters.cpp \ NewPMDriver.cpp \ - Passes.cpp \ PassPrinters.cpp \ PrintSCC.cpp \ opt.cpp \ @@ -51,6 +50,7 @@ llvm_opt_STATIC_LIBRARIES := \ libLLVMVectorize \ libLLVMScalarOpts \ libLLVMTransformUtils \ + libLLVMPasses \ libLLVMAnalysis \ libLLVMipo \ libLLVMipa \ diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index 1d3f08d..5f82522 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -16,6 +16,7 @@ set(LLVM_LINK_COMPONENTS Target TransformUtils Vectorize + Passes ) # Support plugins. @@ -26,12 +27,11 @@ add_llvm_tool(opt BreakpointPrinter.cpp GraphPrinters.cpp NewPMDriver.cpp - Passes.cpp PassPrinters.cpp PrintSCC.cpp opt.cpp ) -set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1) +export_executable_symbols(opt) if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS) target_link_libraries(opt Polly) diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt index b3589f8..b162ab6 100644 --- a/tools/opt/LLVMBuild.txt +++ b/tools/opt/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = opt parent = Tools -required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Scalar ObjCARC all-targets +required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Scalar ObjCARC Passes all-targets diff --git a/tools/opt/Makefile b/tools/opt/Makefile index cfa9c31..2422eb4 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := opt -LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets codegen +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets codegen passes # Support plugins. NO_DEAD_STRIP := 1 diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp index a73750d..9216d5c 100644 --- a/tools/opt/NewPMDriver.cpp +++ b/tools/opt/NewPMDriver.cpp @@ -14,7 +14,6 @@ //===----------------------------------------------------------------------===// #include "NewPMDriver.h" -#include "Passes.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Bitcode/BitcodeWriterPass.h" @@ -24,6 +23,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/Verifier.h" +#include "llvm/Passes/PassBuilder.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" @@ -40,16 +40,16 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, TargetMachine *TM, tool_output_file *Out, StringRef PassPipeline, OutputKind OK, VerifierKind VK) { - Passes P(TM); + PassBuilder PB(TM); FunctionAnalysisManager FAM(DebugPM); CGSCCAnalysisManager CGAM(DebugPM); ModuleAnalysisManager MAM(DebugPM); // Register all the basic analyses with the managers. - P.registerModuleAnalyses(MAM); - P.registerCGSCCAnalyses(CGAM); - P.registerFunctionAnalyses(FAM); + PB.registerModuleAnalyses(MAM); + PB.registerCGSCCAnalyses(CGAM); + PB.registerFunctionAnalyses(FAM); // Cross register the analysis managers through their proxies. MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); @@ -63,8 +63,8 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, if (VK > VK_NoVerifier) MPM.addPass(VerifierPass()); - if (!P.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, - DebugPM)) { + if (!PB.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, + DebugPM)) { errs() << Arg0 << ": unable to parse pass pipeline description.\n"; return false; } diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def deleted file mode 100644 index d768a3a..0000000 --- a/tools/opt/PassRegistry.def +++ /dev/null @@ -1,77 +0,0 @@ -//===- PassRegistry.def - Registry of passes --------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file is used as the registry of passes that are part of the core LLVM -// libraries. This file describes both transformation passes and analyses -// Analyses are registered while transformation passes have names registered -// that can be used when providing a textual pass pipeline. -// -//===----------------------------------------------------------------------===// - -// NOTE: NO INCLUDE GUARD DESIRED! - -#ifndef MODULE_ANALYSIS -#define MODULE_ANALYSIS(NAME, CREATE_PASS) -#endif -MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis()) -MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis()) -MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis()) -#undef MODULE_ANALYSIS - -#ifndef MODULE_PASS -#define MODULE_PASS(NAME, CREATE_PASS) -#endif -MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass()) -MODULE_PASS("no-op-module", NoOpModulePass()) -MODULE_PASS("print", PrintModulePass(dbgs())) -MODULE_PASS("print-cg", LazyCallGraphPrinterPass(dbgs())) -MODULE_PASS("verify", VerifierPass()) -#undef MODULE_PASS - -#ifndef CGSCC_ANALYSIS -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) -#endif -CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis()) -#undef CGSCC_ANALYSIS - -#ifndef CGSCC_PASS -#define CGSCC_PASS(NAME, CREATE_PASS) -#endif -CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass()) -CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass()) -#undef CGSCC_PASS - -#ifndef FUNCTION_ANALYSIS -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) -#endif -FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis()) -FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis()) -FUNCTION_ANALYSIS("loops", LoopAnalysis()) -FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis()) -FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis()) -FUNCTION_ANALYSIS("targetir", - TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()) -#undef FUNCTION_ANALYSIS - -#ifndef FUNCTION_PASS -#define FUNCTION_PASS(NAME, CREATE_PASS) -#endif -FUNCTION_PASS("early-cse", EarlyCSEPass()) -FUNCTION_PASS("instcombine", InstCombinePass()) -FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass()) -FUNCTION_PASS("no-op-function", NoOpFunctionPass()) -FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass()) -FUNCTION_PASS("print", PrintFunctionPass(dbgs())) -FUNCTION_PASS("print<assumptions>", AssumptionPrinterPass(dbgs())) -FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs())) -FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs())) -FUNCTION_PASS("simplify-cfg", SimplifyCFGPass()) -FUNCTION_PASS("verify", VerifierPass()) -FUNCTION_PASS("verify<domtree>", DominatorTreeVerifierPass()) -#undef FUNCTION_PASS diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp deleted file mode 100644 index e5ad5c0..0000000 --- a/tools/opt/Passes.cpp +++ /dev/null @@ -1,406 +0,0 @@ -//===- Passes.cpp - Parsing, selection, and running of passes -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// \file -/// -/// This file provides the infrastructure to parse and build a custom pass -/// manager based on a commandline flag. It also provides helpers to aid in -/// analyzing, debugging, and testing pass structures. -/// -//===----------------------------------------------------------------------===// - -#include "Passes.h" -#include "llvm/Analysis/AssumptionCache.h" -#include "llvm/Analysis/CGSCCPassManager.h" -#include "llvm/Analysis/LazyCallGraph.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/IRPrintingPasses.h" -#include "llvm/IR/PassManager.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/Debug.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Transforms/InstCombine/InstCombine.h" -#include "llvm/Transforms/Scalar/EarlyCSE.h" -#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" -#include "llvm/Transforms/Scalar/SimplifyCFG.h" - -using namespace llvm; - -namespace { - -/// \brief No-op module pass which does nothing. -struct NoOpModulePass { - PreservedAnalyses run(Module &M) { return PreservedAnalyses::all(); } - static StringRef name() { return "NoOpModulePass"; } -}; - -/// \brief No-op module analysis. -struct NoOpModuleAnalysis { - struct Result {}; - Result run(Module &) { return Result(); } - static StringRef name() { return "NoOpModuleAnalysis"; } - static void *ID() { return (void *)&PassID; } -private: - static char PassID; -}; - -char NoOpModuleAnalysis::PassID; - -/// \brief No-op CGSCC pass which does nothing. -struct NoOpCGSCCPass { - PreservedAnalyses run(LazyCallGraph::SCC &C) { - return PreservedAnalyses::all(); - } - static StringRef name() { return "NoOpCGSCCPass"; } -}; - -/// \brief No-op CGSCC analysis. -struct NoOpCGSCCAnalysis { - struct Result {}; - Result run(LazyCallGraph::SCC &) { return Result(); } - static StringRef name() { return "NoOpCGSCCAnalysis"; } - static void *ID() { return (void *)&PassID; } -private: - static char PassID; -}; - -char NoOpCGSCCAnalysis::PassID; - -/// \brief No-op function pass which does nothing. -struct NoOpFunctionPass { - PreservedAnalyses run(Function &F) { return PreservedAnalyses::all(); } - static StringRef name() { return "NoOpFunctionPass"; } -}; - -/// \brief No-op function analysis. -struct NoOpFunctionAnalysis { - struct Result {}; - Result run(Function &) { return Result(); } - static StringRef name() { return "NoOpFunctionAnalysis"; } - static void *ID() { return (void *)&PassID; } -private: - static char PassID; -}; - -char NoOpFunctionAnalysis::PassID; - -} // End anonymous namespace. - -void Passes::registerModuleAnalyses(ModuleAnalysisManager &MAM) { -#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ - MAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" -} - -void Passes::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) { -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ - CGAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" -} - -void Passes::registerFunctionAnalyses(FunctionAnalysisManager &FAM) { -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ - FAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" -} - -#ifndef NDEBUG -static bool isModulePassName(StringRef Name) { -#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) return true; -#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \ - return true; -#include "PassRegistry.def" - - return false; -} -#endif - -static bool isCGSCCPassName(StringRef Name) { -#define CGSCC_PASS(NAME, CREATE_PASS) if (Name == NAME) return true; -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \ - return true; -#include "PassRegistry.def" - - return false; -} - -static bool isFunctionPassName(StringRef Name) { -#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) return true; -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \ - return true; -#include "PassRegistry.def" - - return false; -} - -bool Passes::parseModulePassName(ModulePassManager &MPM, StringRef Name) { -#define MODULE_PASS(NAME, CREATE_PASS) \ - if (Name == NAME) { \ - MPM.addPass(CREATE_PASS); \ - return true; \ - } -#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">") { \ - MPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } \ - if (Name == "invalidate<" NAME ">") { \ - MPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } -#include "PassRegistry.def" - - return false; -} - -bool Passes::parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name) { -#define CGSCC_PASS(NAME, CREATE_PASS) \ - if (Name == NAME) { \ - CGPM.addPass(CREATE_PASS); \ - return true; \ - } -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">") { \ - CGPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } \ - if (Name == "invalidate<" NAME ">") { \ - CGPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } -#include "PassRegistry.def" - - return false; -} - -bool Passes::parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) { -#define FUNCTION_PASS(NAME, CREATE_PASS) \ - if (Name == NAME) { \ - FPM.addPass(CREATE_PASS); \ - return true; \ - } -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ - if (Name == "require<" NAME ">") { \ - FPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } \ - if (Name == "invalidate<" NAME ">") { \ - FPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \ - return true; \ - } -#include "PassRegistry.def" - - return false; -} - -bool Passes::parseFunctionPassPipeline(FunctionPassManager &FPM, - StringRef &PipelineText, - bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - FPM.addPass(std::move(NestedFPM)); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseFunctionPassName(FPM, PipelineText.substr(0, End))) - return false; - if (VerifyEachPass) - FPM.addPass(VerifierPass()); - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); - } -} - -bool Passes::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, - StringRef &PipelineText, - bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM(DebugLogging); - - // Parse the inner pipeline into the nested manager. - PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass(std::move(NestedCGPM)); - } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(NestedFPM))); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseCGSCCPassName(CGPM, PipelineText.substr(0, End))) - return false; - // FIXME: No verifier support for CGSCC passes! - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); - } -} - -bool Passes::parseModulePassPipeline(ModulePassManager &MPM, - StringRef &PipelineText, - bool VerifyEachPass, bool DebugLogging) { - for (;;) { - // Parse nested pass managers by recursing. - if (PipelineText.startswith("module(")) { - ModulePassManager NestedMPM(DebugLogging); - - // Parse the inner pipeline into the nested manager. - PipelineText = PipelineText.substr(strlen("module(")); - if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Now add the nested manager as a module pass. - MPM.addPass(std::move(NestedMPM)); - } else if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - MPM.addPass( - createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM))); - } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM(DebugLogging); - - // Parse the inner pipeline inte the nested manager. - PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, - DebugLogging) || - PipelineText.empty()) - return false; - assert(PipelineText[0] == ')'); - PipelineText = PipelineText.substr(1); - - // Add the nested pass manager with the appropriate adaptor. - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(NestedFPM))); - } else { - // Otherwise try to parse a pass name. - size_t End = PipelineText.find_first_of(",)"); - if (!parseModulePassName(MPM, PipelineText.substr(0, End))) - return false; - if (VerifyEachPass) - MPM.addPass(VerifierPass()); - - PipelineText = PipelineText.substr(End); - } - - if (PipelineText.empty() || PipelineText[0] == ')') - return true; - - assert(PipelineText[0] == ','); - PipelineText = PipelineText.substr(1); - } -} - -// Primary pass pipeline description parsing routine. -// FIXME: Should this routine accept a TargetMachine or require the caller to -// pre-populate the analysis managers with target-specific stuff? -bool Passes::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, - bool VerifyEachPass, bool DebugLogging) { - // By default, try to parse the pipeline as-if it were within an implicit - // 'module(...)' pass pipeline. If this will parse at all, it needs to - // consume the entire string. - if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass, DebugLogging)) - return PipelineText.empty(); - - // This isn't parsable as a module pipeline, look for the end of a pass name - // and directly drop down to that layer. - StringRef FirstName = - PipelineText.substr(0, PipelineText.find_first_of(",)")); - assert(!isModulePassName(FirstName) && - "Already handled all module pipeline options."); - - // If this looks like a CGSCC pass, parse the whole thing as a CGSCC - // pipeline. - if (isCGSCCPassName(FirstName)) { - CGSCCPassManager CGPM(DebugLogging); - if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass, - DebugLogging) || - !PipelineText.empty()) - return false; - MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); - return true; - } - - // Similarly, if this looks like a Function pass, parse the whole thing as - // a Function pipelien. - if (isFunctionPassName(FirstName)) { - FunctionPassManager FPM(DebugLogging); - if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass, - DebugLogging) || - !PipelineText.empty()) - return false; - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - return true; - } - - return false; -} diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h deleted file mode 100644 index d3cb628..0000000 --- a/tools/opt/Passes.h +++ /dev/null @@ -1,105 +0,0 @@ -//===- Passes.h - Utilities for manipulating all passes ---------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// \file -/// -/// Interfaces for registering passes, producing common pass manager -/// configurations, and parsing of pass pipelines. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_OPT_PASSES_H -#define LLVM_TOOLS_OPT_PASSES_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Analysis/CGSCCPassManager.h" -#include "llvm/IR/PassManager.h" - -namespace llvm { -class TargetMachine; - -/// \brief This class provides access to all of LLVM's passes. -/// -/// It's members provide the baseline state available to passes during their -/// construction. The \c PassRegistry.def file specifies how to construct all -/// of the built-in passes, and those may reference these members during -/// construction. -class Passes { - TargetMachine *TM; - -public: - explicit Passes(TargetMachine *TM = nullptr) : TM(TM) {} - - /// \brief Registers all available module analysis passes. - /// - /// This is an interface that can be used to populate a \c - /// ModuleAnalysisManager with all registered module analyses. Callers can - /// still manually register any additional analyses. - void registerModuleAnalyses(ModuleAnalysisManager &MAM); - - /// \brief Registers all available CGSCC analysis passes. - /// - /// This is an interface that can be used to populate a \c CGSCCAnalysisManager - /// with all registered CGSCC analyses. Callers can still manually register any - /// additional analyses. - void registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM); - - /// \brief Registers all available function analysis passes. - /// - /// This is an interface that can be used to populate a \c - /// FunctionAnalysisManager with all registered function analyses. Callers can - /// still manually register any additional analyses. - void registerFunctionAnalyses(FunctionAnalysisManager &FAM); - - /// \brief Parse a textual pass pipeline description into a \c ModulePassManager. - /// - /// The format of the textual pass pipeline description looks something like: - /// - /// module(function(instcombine,sroa),dce,cgscc(inliner,function(...)),...) - /// - /// Pass managers have ()s describing the nest structure of passes. All passes - /// are comma separated. As a special shortcut, if the very first pass is not - /// a module pass (as a module pass manager is), this will automatically form - /// the shortest stack of pass managers that allow inserting that first pass. - /// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and loop passes - /// 'lpassN', all of these are valid: - /// - /// fpass1,fpass2,fpass3 - /// cgpass1,cgpass2,cgpass3 - /// lpass1,lpass2,lpass3 - /// - /// And they are equivalent to the following (resp.): - /// - /// module(function(fpass1,fpass2,fpass3)) - /// module(cgscc(cgpass1,cgpass2,cgpass3)) - /// module(function(loop(lpass1,lpass2,lpass3))) - /// - /// This shortcut is especially useful for debugging and testing small pass - /// combinations. Note that these shortcuts don't introduce any other magic. If - /// the sequence of passes aren't all the exact same kind of pass, it will be - /// an error. You cannot mix different levels implicitly, you must explicitly - /// form a pass manager in which to nest passes. - bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, - bool VerifyEachPass = true, bool DebugLogging = false); - -private: - bool parseModulePassName(ModulePassManager &MPM, StringRef Name); - bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name); - bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name); - bool parseFunctionPassPipeline(FunctionPassManager &FPM, - StringRef &PipelineText, bool VerifyEachPass, - bool DebugLogging); - bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, StringRef &PipelineText, - bool VerifyEachPass, bool DebugLogging); - bool parseModulePassPipeline(ModulePassManager &MPM, StringRef &PipelineText, - bool VerifyEachPass, bool DebugLogging); -}; - -} - -#endif diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index d952525..c1e120a 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -185,10 +185,8 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { PM.add(P); // If we are verifying all of the intermediate steps, add the verifier... - if (VerifyEach) { + if (VerifyEach) PM.add(createVerifierPass()); - PM.add(createDebugInfoVerifierPass()); - } } /// This routine adds optimization passes based on selected optimization level, @@ -198,8 +196,7 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { static void AddOptimizationPasses(legacy::PassManagerBase &MPM, legacy::FunctionPassManager &FPM, unsigned OptLevel, unsigned SizeLevel) { - FPM.add(createVerifierPass()); // Verify that input is correct - MPM.add(createDebugInfoVerifierPass()); // Verify that debug info is correct + FPM.add(createVerifierPass()); // Verify that input is correct PassManagerBuilder Builder; Builder.OptLevel = OptLevel; @@ -234,7 +231,6 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM, static void AddStandardLinkPasses(legacy::PassManagerBase &PM) { PassManagerBuilder Builder; Builder.VerifyInput = true; - Builder.StripDebug = StripDebug; if (DisableOptimizations) Builder.OptLevel = 0; @@ -247,7 +243,7 @@ static void AddStandardLinkPasses(legacy::PassManagerBase &PM) { // CodeGen-related helper functions. // -CodeGenOpt::Level GetCodeGenOptLevel() { +static CodeGenOpt::Level GetCodeGenOptLevel() { if (OptLevelO1) return CodeGenOpt::Less; if (OptLevelO2) @@ -419,15 +415,11 @@ int main(int argc, char **argv) { Passes.add(new TargetLibraryInfoWrapperPass(TLII)); // Add an appropriate DataLayout instance for this module. - const DataLayout *DL = M->getDataLayout(); - if (!DL && !DefaultDataLayout.empty()) { + const DataLayout &DL = M->getDataLayout(); + if (DL.isDefault() && !DefaultDataLayout.empty()) { M->setDataLayout(DefaultDataLayout); - DL = M->getDataLayout(); } - if (DL) - Passes.add(new DataLayoutPass()); - // Add internal analysis passes from the target machine. Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())); @@ -435,8 +427,6 @@ int main(int argc, char **argv) { std::unique_ptr<legacy::FunctionPassManager> FPasses; if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { FPasses.reset(new legacy::FunctionPassManager(M.get())); - if (DL) - FPasses->add(new DataLayoutPass()); FPasses->add(createTargetTransformInfoWrapperPass( TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())); } @@ -565,10 +555,8 @@ int main(int argc, char **argv) { } // Check that the module is well formed on completion of optimization - if (!NoVerify && !VerifyEach) { + if (!NoVerify && !VerifyEach) Passes.add(createVerifierPass()); - Passes.add(createDebugInfoVerifierPass()); - } // Write bitcode or assembly to the output as the last step... if (!NoOutput && !AnalyzeOnly) { diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp index a653608..ef3d5b3 100644 --- a/tools/verify-uselistorder/verify-uselistorder.cpp +++ b/tools/verify-uselistorder/verify-uselistorder.cpp @@ -47,6 +47,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" +#include "llvm/Support/raw_ostream.h" #include <random> #include <vector> diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index 8322b2f..6939bc4 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -282,7 +282,7 @@ raw_ostream &operator<<(raw_ostream &OS, const num_zeros_impl &NZI) { return OS; } -num_zeros_impl num_zeros(size_t N) { +static num_zeros_impl num_zeros(size_t N) { num_zeros_impl NZI(N); return NZI; } diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index 375cd89..af4d868 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -62,7 +62,8 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), typedef int (*ConvertFuncPtr)(yaml::Input & YIn, raw_ostream &Out); -int convertYAML(yaml::Input & YIn, raw_ostream &Out, ConvertFuncPtr Convert) { +static int convertYAML(yaml::Input &YIn, raw_ostream &Out, + ConvertFuncPtr Convert) { unsigned CurDocNum = 0; do { if (++CurDocNum == DocNum) |