From ebe69fe11e48d322045d5949c83283927a0d790b Mon Sep 17 00:00:00 2001 From: Stephen Hines Date: Mon, 23 Mar 2015 12:10:34 -0700 Subject: Update aosp/master LLVM for rebase to r230699. Change-Id: I2b5be30509658cb8266be782de0ab24f9099f9b9 --- tools/CMakeLists.txt | 16 +- tools/LLVMBuild.txt | 2 +- tools/Makefile | 2 +- tools/bugpoint/CrashDebugger.cpp | 4 +- tools/bugpoint/ExtractFunction.cpp | 6 +- tools/bugpoint/OptimizerDriver.cpp | 2 +- tools/bugpoint/bugpoint.cpp | 4 +- tools/dsymutil/BinaryHolder.cpp | 111 ++ tools/dsymutil/BinaryHolder.h | 104 + tools/dsymutil/CMakeLists.txt | 14 + tools/dsymutil/DebugMap.cpp | 92 + tools/dsymutil/DebugMap.h | 142 ++ tools/dsymutil/DwarfLinker.cpp | 667 +++++++ tools/dsymutil/LLVMBuild.txt | 22 + tools/dsymutil/MachODebugMapParser.cpp | 241 +++ tools/dsymutil/Makefile | 17 + tools/dsymutil/dsymutil.cpp | 71 + tools/dsymutil/dsymutil.h | 39 + tools/gold/CMakeLists.txt | 9 +- tools/gold/gold-plugin.cpp | 275 ++- tools/llc/CMakeLists.txt | 2 +- tools/llc/llc.cpp | 53 +- tools/lli/Android.mk | 3 +- tools/lli/CMakeLists.txt | 4 +- tools/lli/ChildTarget/ChildTarget.cpp | 14 +- tools/lli/Makefile | 4 +- tools/lli/RemoteMemoryManager.cpp | 3 +- tools/lli/RemoteMemoryManager.h | 3 +- tools/lli/lli.cpp | 26 +- tools/llvm-ar/CMakeLists.txt | 15 +- tools/llvm-ar/install_symlink.cmake | 25 + tools/llvm-ar/llvm-ar.cpp | 68 +- tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp | 14 +- tools/llvm-c-test/Android.mk | 1 + tools/llvm-c-test/CMakeLists.txt | 25 +- tools/llvm-c-test/llvm-c-test.h | 4 + tools/llvm-c-test/main.c | 4 + tools/llvm-c-test/metadata.c | 43 + tools/llvm-config/BuildVariables.inc.in | 1 + tools/llvm-config/Makefile | 2 + tools/llvm-config/llvm-config.cpp | 10 +- tools/llvm-cov/Android.mk | 1 - tools/llvm-cov/CMakeLists.txt | 1 - tools/llvm-cov/CodeCoverage.cpp | 36 +- tools/llvm-cov/CoverageFilters.h | 2 +- tools/llvm-cov/CoverageReport.cpp | 42 +- tools/llvm-cov/CoverageReport.h | 11 +- tools/llvm-cov/CoverageSummary.cpp | 64 - tools/llvm-cov/CoverageSummary.h | 45 - tools/llvm-cov/CoverageSummaryInfo.cpp | 25 - tools/llvm-cov/CoverageSummaryInfo.h | 53 +- tools/llvm-cov/RenderingSupport.h | 2 +- tools/llvm-cov/SourceCoverageView.h | 7 +- tools/llvm-cov/TestingSupport.cpp | 9 +- tools/llvm-cov/gcov.cpp | 3 +- tools/llvm-cov/llvm-cov.cpp | 2 +- tools/llvm-dis/llvm-dis.cpp | 46 +- tools/llvm-dwarfdump/Android.mk | 3 +- tools/llvm-dwarfdump/CMakeLists.txt | 2 +- tools/llvm-dwarfdump/LLVMBuild.txt | 2 +- tools/llvm-dwarfdump/Makefile | 2 +- tools/llvm-dwarfdump/llvm-dwarfdump.cpp | 3 +- tools/llvm-extract/llvm-extract.cpp | 4 +- tools/llvm-go/llvm-go.go | 30 +- tools/llvm-jitlistener/Makefile | 2 +- tools/llvm-jitlistener/llvm-jitlistener.cpp | 6 +- tools/llvm-lto/llvm-lto.cpp | 69 +- tools/llvm-mc/Android.mk | 1 + tools/llvm-mc/Disassembler.cpp | 1 - tools/llvm-mc/llvm-mc.cpp | 103 +- tools/llvm-nm/Android.mk | 1 + tools/llvm-nm/llvm-nm.cpp | 16 +- tools/llvm-objdump/Android.mk | 4 +- tools/llvm-objdump/CMakeLists.txt | 2 +- tools/llvm-objdump/LLVMBuild.txt | 2 +- tools/llvm-objdump/MachODump.cpp | 2098 +++++++++++++++++++-- tools/llvm-objdump/Makefile | 2 +- tools/llvm-objdump/llvm-objdump.cpp | 104 +- tools/llvm-objdump/llvm-objdump.h | 29 +- tools/llvm-pdbdump/CMakeLists.txt | 14 + tools/llvm-pdbdump/ClassDefinitionDumper.cpp | 152 ++ tools/llvm-pdbdump/ClassDefinitionDumper.h | 64 + tools/llvm-pdbdump/CompilandDumper.cpp | 117 ++ tools/llvm-pdbdump/CompilandDumper.h | 39 + tools/llvm-pdbdump/FunctionDumper.cpp | 243 +++ tools/llvm-pdbdump/FunctionDumper.h | 45 + tools/llvm-pdbdump/LLVMBuild.txt | 23 + tools/llvm-pdbdump/Makefile | 17 + tools/llvm-pdbdump/TypeDumper.cpp | 96 + tools/llvm-pdbdump/TypeDumper.h | 38 + tools/llvm-pdbdump/TypedefDumper.cpp | 84 + tools/llvm-pdbdump/TypedefDumper.h | 38 + tools/llvm-pdbdump/VariableDumper.cpp | 120 ++ tools/llvm-pdbdump/VariableDumper.h | 43 + tools/llvm-pdbdump/llvm-pdbdump.cpp | 134 ++ tools/llvm-pdbdump/llvm-pdbdump.h | 28 + tools/llvm-profdata/llvm-profdata.cpp | 8 +- tools/llvm-readobj/ARMAttributeParser.cpp | 2 +- tools/llvm-readobj/ARMWinEHPrinter.cpp | 2 +- tools/llvm-readobj/COFFDumper.cpp | 55 +- tools/llvm-readobj/ELFDumper.cpp | 7 +- tools/llvm-readobj/ObjDumper.h | 1 + tools/llvm-readobj/llvm-readobj.cpp | 17 +- tools/llvm-readobj/llvm-readobj.h | 3 +- tools/llvm-rtdyld/Android.mk | 3 +- tools/llvm-rtdyld/CMakeLists.txt | 3 +- tools/llvm-rtdyld/Makefile | 2 +- tools/llvm-rtdyld/llvm-rtdyld.cpp | 62 +- tools/llvm-shlib/CMakeLists.txt | 6 +- tools/llvm-shlib/libllvm.cpp | 7 + tools/llvm-size/llvm-size.cpp | 19 +- tools/llvm-stress/llvm-stress.cpp | 4 +- tools/llvm-symbolizer/Android.mk | 3 +- tools/llvm-symbolizer/CMakeLists.txt | 2 +- tools/llvm-symbolizer/LLVMSymbolize.h | 2 +- tools/llvm-symbolizer/Makefile | 2 +- tools/lto/CMakeLists.txt | 1 + tools/lto/lto.cpp | 48 +- tools/lto/lto.exports | 7 + tools/macho-dump/macho-dump.cpp | 8 +- tools/obj2yaml/elf2yaml.cpp | 46 +- tools/opt/NewPMDriver.cpp | 40 +- tools/opt/NewPMDriver.h | 6 +- tools/opt/PassRegistry.def | 26 + tools/opt/Passes.cpp | 236 ++- tools/opt/Passes.h | 114 +- tools/opt/opt.cpp | 67 +- tools/verify-uselistorder/verify-uselistorder.cpp | 10 +- tools/yaml2obj/yaml2coff.cpp | 4 +- tools/yaml2obj/yaml2elf.cpp | 54 +- 130 files changed, 6223 insertions(+), 948 deletions(-) create mode 100644 tools/dsymutil/BinaryHolder.cpp create mode 100644 tools/dsymutil/BinaryHolder.h create mode 100644 tools/dsymutil/CMakeLists.txt create mode 100644 tools/dsymutil/DebugMap.cpp create mode 100644 tools/dsymutil/DebugMap.h create mode 100644 tools/dsymutil/DwarfLinker.cpp create mode 100644 tools/dsymutil/LLVMBuild.txt create mode 100644 tools/dsymutil/MachODebugMapParser.cpp create mode 100644 tools/dsymutil/Makefile create mode 100644 tools/dsymutil/dsymutil.cpp create mode 100644 tools/dsymutil/dsymutil.h create mode 100644 tools/llvm-ar/install_symlink.cmake create mode 100644 tools/llvm-c-test/metadata.c delete mode 100644 tools/llvm-cov/CoverageSummary.cpp delete mode 100644 tools/llvm-cov/CoverageSummary.h create mode 100644 tools/llvm-pdbdump/CMakeLists.txt create mode 100644 tools/llvm-pdbdump/ClassDefinitionDumper.cpp create mode 100644 tools/llvm-pdbdump/ClassDefinitionDumper.h create mode 100644 tools/llvm-pdbdump/CompilandDumper.cpp create mode 100644 tools/llvm-pdbdump/CompilandDumper.h create mode 100644 tools/llvm-pdbdump/FunctionDumper.cpp create mode 100644 tools/llvm-pdbdump/FunctionDumper.h create mode 100644 tools/llvm-pdbdump/LLVMBuild.txt create mode 100644 tools/llvm-pdbdump/Makefile create mode 100644 tools/llvm-pdbdump/TypeDumper.cpp create mode 100644 tools/llvm-pdbdump/TypeDumper.h create mode 100644 tools/llvm-pdbdump/TypedefDumper.cpp create mode 100644 tools/llvm-pdbdump/TypedefDumper.h create mode 100644 tools/llvm-pdbdump/VariableDumper.cpp create mode 100644 tools/llvm-pdbdump/VariableDumper.h create mode 100644 tools/llvm-pdbdump/llvm-pdbdump.cpp create mode 100644 tools/llvm-pdbdump/llvm-pdbdump.h (limited to 'tools') diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index fd761ec..1f415b6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -36,6 +36,7 @@ add_llvm_tool_subdirectory(llvm-objdump) 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) if( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool_subdirectory(llvm-jitlistener) @@ -60,6 +61,8 @@ add_llvm_tool_subdirectory(yaml2obj) add_llvm_tool_subdirectory(llvm-go) +add_llvm_tool_subdirectory(llvm-pdbdump) + if(NOT CYGWIN AND LLVM_ENABLE_PIC) add_llvm_tool_subdirectory(lto) add_llvm_tool_subdirectory(llvm-lto) @@ -68,19 +71,10 @@ else() ignore_llvm_tool_subdirectory(llvm-lto) endif() -if( LLVM_ENABLE_PIC ) - # TODO: support other systems: - if( (CMAKE_SYSTEM_NAME STREQUAL "Linux") - OR (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ) - add_llvm_tool_subdirectory(gold) - else() - ignore_llvm_tool_subdirectory(gold) - endif() -else() - ignore_llvm_tool_subdirectory(gold) -endif() +add_llvm_tool_subdirectory(gold) add_llvm_external_project(clang) +add_llvm_external_project(llgo) if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" ) add_llvm_external_project(lld) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 13a08b2..e7b81bb 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-pdbdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index 4b8923a..fcb6c64 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 + llvm-vtabledump 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/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index bac948a..ee18169 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -19,11 +19,11 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/IR/Verifier.h" #include "llvm/Pass.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Transforms/Scalar.h" @@ -407,7 +407,7 @@ bool ReduceCrashingInstructions::TestInsts(std::vector } // Verify that this is still valid. - PassManager Passes; + legacy::PassManager Passes; Passes.add(createVerifierPass()); Passes.add(createDebugInfoVerifierPass()); Passes.run(*M); diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 34fe53c..238cbbc 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -17,10 +17,10 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/Pass.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" @@ -195,9 +195,9 @@ static Constant *GetTorInit(std::vector > &TorList) { assert(!TorList.empty() && "Don't create empty tor list!"); std::vector ArrayElts; Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext()); - + StructType *STy = - StructType::get(Int32Ty, TorList[0].first->getType(), NULL); + StructType::get(Int32Ty, TorList[0].first->getType(), nullptr); for (unsigned i = 0, e = TorList.size(); i != e; ++i) { Constant *Elts[] = { ConstantInt::get(Int32Ty, TorList[i].second), diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index f197cc5..481f343 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -18,9 +18,9 @@ #include "BugDriver.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index d0bade5..0ee3784 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -16,10 +16,10 @@ #include "BugDriver.h" #include "ToolRunner.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" @@ -92,7 +92,7 @@ static void BugpointInterruptFunction() { // Hack to capture a pass list. namespace { - class AddToDriver : public FunctionPassManager { + class AddToDriver : public legacy::FunctionPassManager { BugDriver &D; public: AddToDriver(BugDriver &_D) : FunctionPassManager(nullptr), D(_D) {} diff --git a/tools/dsymutil/BinaryHolder.cpp b/tools/dsymutil/BinaryHolder.cpp new file mode 100644 index 0000000..ad66105 --- /dev/null +++ b/tools/dsymutil/BinaryHolder.cpp @@ -0,0 +1,111 @@ +//===-- BinaryHolder.cpp --------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// + +#include "BinaryHolder.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace dsymutil { + +ErrorOr +BinaryHolder::GetMemoryBufferForFile(StringRef Filename) { + if (Verbose) + outs() << "trying to open '" << Filename << "'\n"; + + // Try that first as it doesn't involve any filesystem access. + if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename)) + return *ErrOrArchiveMember; + + // If the name ends with a closing paren, there is a huge chance + // it is an archive member specification. + if (Filename.endswith(")")) + if (auto ErrOrArchiveMember = MapArchiveAndGetMemberBuffer(Filename)) + return *ErrOrArchiveMember; + + // Otherwise, just try opening a standard file. If this is an + // archive member specifiaction and any of the above didn't handle it + // (either because the archive is not there anymore, or because the + // archive doesn't contain the requested member), this will still + // provide a sensible error message. + auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename); + if (auto Err = ErrOrFile.getError()) + return Err; + + if (Verbose) + outs() << "\tloaded file.\n"; + CurrentArchive.reset(); + CurrentMemoryBuffer = std::move(ErrOrFile.get()); + return CurrentMemoryBuffer->getMemBufferRef(); +} + +ErrorOr +BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { + if (!CurrentArchive) + return make_error_code(errc::no_such_file_or_directory); + + StringRef CurArchiveName = CurrentArchive->getFileName(); + if (!Filename.startswith(Twine(CurArchiveName, "(").str())) + return make_error_code(errc::no_such_file_or_directory); + + // Remove the archive name and the parens around the archive member name. + Filename = Filename.substr(CurArchiveName.size() + 1).drop_back(); + + for (const auto &Child : CurrentArchive->children()) { + if (auto NameOrErr = Child.getName()) + if (*NameOrErr == Filename) { + if (Verbose) + outs() << "\tfound member in current archive.\n"; + return Child.getMemoryBufferRef(); + } + } + + return make_error_code(errc::no_such_file_or_directory); +} + +ErrorOr +BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) { + StringRef ArchiveFilename = Filename.substr(0, Filename.find('(')); + + auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename); + if (auto Err = ErrOrBuff.getError()) + return Err; + + if (Verbose) + outs() << "\topened new archive '" << ArchiveFilename << "'\n"; + auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef()); + if (auto Err = ErrOrArchive.getError()) + return Err; + + CurrentArchive = std::move(*ErrOrArchive); + CurrentMemoryBuffer = std::move(*ErrOrBuff); + + return GetArchiveMemberBuffer(Filename); +} + +ErrorOr +BinaryHolder::GetObjectFile(StringRef Filename) { + auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename); + if (auto Err = ErrOrMemBufferRef.getError()) + return Err; + + auto ErrOrObjectFile = + object::ObjectFile::createObjectFile(*ErrOrMemBufferRef); + if (auto Err = ErrOrObjectFile.getError()) + return Err; + + CurrentObjectFile = std::move(*ErrOrObjectFile); + return *CurrentObjectFile; +} +} +} diff --git a/tools/dsymutil/BinaryHolder.h b/tools/dsymutil/BinaryHolder.h new file mode 100644 index 0000000..04871b5 --- /dev/null +++ b/tools/dsymutil/BinaryHolder.h @@ -0,0 +1,104 @@ +//===-- BinaryHolder.h - Utility class for accessing binaries -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H +#define LLVM_TOOLS_DSYMUTIL_BINARYHOLDER_H + +#include "llvm/Object/Archive.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace dsymutil { + +/// \brief The BinaryHolder class is responsible for creating and +/// owning ObjectFile objects and their underlying MemoryBuffer. This +/// is different from a simple OwningBinary in that it handles +/// accessing to archive members. +/// +/// As an optimization, this class will reuse an already mapped and +/// parsed Archive object if 2 successive requests target the same +/// archive file (Which is always the case in debug maps). +/// Currently it only owns one memory buffer at any given time, +/// meaning that a mapping request will invalidate the previous memory +/// mapping. +class BinaryHolder { + std::unique_ptr CurrentArchive; + std::unique_ptr CurrentMemoryBuffer; + std::unique_ptr CurrentObjectFile; + bool Verbose; + + /// \brief Get the MemoryBufferRef for the file specification in \p + /// Filename from the current archive. + /// + /// This function performs no system calls, it just looks up a + /// potential match for the given \p Filename in the currently + /// mapped archive if there is one. + ErrorOr GetArchiveMemberBuffer(StringRef Filename); + + /// \brief Interpret Filename as an archive member specification, + /// map the corresponding archive to memory and return the + /// MemoryBufferRef corresponding to the described member. + ErrorOr MapArchiveAndGetMemberBuffer(StringRef Filename); + + /// \brief Return the MemoryBufferRef that holds the memory + /// mapping for the given \p Filename. This function will try to + /// parse archive member specifications of the form + /// /path/to/archive.a(member.o). + /// + /// The returned MemoryBufferRef points to a buffer owned by this + /// object. The buffer is valid until the next call to + /// GetMemoryBufferForFile() on this object. + ErrorOr GetMemoryBufferForFile(StringRef Filename); + +public: + BinaryHolder(bool Verbose) : Verbose(Verbose) {} + + /// \brief Get the ObjectFile designated by the \p Filename. This + /// might be an archive member specification of the form + /// /path/to/archive.a(member.o). + /// + /// Calling this function invalidates the previous mapping owned by + /// the BinaryHolder. + ErrorOr GetObjectFile(StringRef Filename); + + /// \brief Wraps GetObjectFile() to return a derived ObjectFile type. + template + ErrorOr GetFileAs(StringRef Filename) { + auto ErrOrObjFile = GetObjectFile(Filename); + if (auto Err = ErrOrObjFile.getError()) + return Err; + if (const auto *Derived = dyn_cast(CurrentObjectFile.get())) + return *Derived; + return make_error_code(object::object_error::invalid_file_type); + } + + /// \brief Access the currently owned ObjectFile. As successfull + /// call to GetObjectFile() or GetFileAs() must have been performed + /// before calling this. + const object::ObjectFile &Get() { + assert(CurrentObjectFile); + return *CurrentObjectFile; + } + + /// \brief Access to a derived version of the currently owned + /// ObjectFile. The conversion must be known to be valid. + template const ObjectFileType &GetAs() { + return cast(*CurrentObjectFile); + } +}; +} +} +#endif diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt new file mode 100644 index 0000000..5e1f37f --- /dev/null +++ b/tools/dsymutil/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + DebugInfoDWARF + Object + Support + ) + +add_llvm_tool(llvm-dsymutil + dsymutil.cpp + BinaryHolder.cpp + DebugMap.cpp + DwarfLinker.cpp + MachODebugMapParser.cpp + ) + diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp new file mode 100644 index 0000000..c04b2fe --- /dev/null +++ b/tools/dsymutil/DebugMap.cpp @@ -0,0 +1,92 @@ +//===- tools/dsymutil/DebugMap.cpp - Generic debug map representation -----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "DebugMap.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include + +namespace llvm { +namespace dsymutil { + +using namespace llvm::object; + +DebugMapObject::DebugMapObject(StringRef ObjectFilename) + : Filename(ObjectFilename) {} + +bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress, + uint64_t LinkedAddress) { + auto InsertResult = Symbols.insert( + std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress))); + + if (InsertResult.second) + AddressToMapping[ObjectAddress] = &*InsertResult.first; + return InsertResult.second; +} + +void DebugMapObject::print(raw_ostream &OS) const { + OS << getObjectFilename() << ":\n"; + // Sort the symbols in alphabetical order, like llvm-nm (and to get + // deterministic output for testing). + typedef std::pair Entry; + std::vector Entries; + Entries.reserve(Symbols.getNumItems()); + for (const auto &Sym : make_range(Symbols.begin(), Symbols.end())) + Entries.push_back(std::make_pair(Sym.getKey(), Sym.getValue())); + std::sort( + 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", + Sym.second.ObjectAddress, Sym.second.BinaryAddress, + Sym.first.data()); + } + OS << '\n'; +} + +#ifndef NDEBUG +void DebugMapObject::dump() const { print(errs()); } +#endif + +DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath) { + Objects.emplace_back(new DebugMapObject(ObjectFilePath)); + return *Objects.back(); +} + +const DebugMapObject::DebugMapEntry * +DebugMapObject::lookupSymbol(StringRef SymbolName) const { + StringMap::const_iterator Sym = Symbols.find(SymbolName); + if (Sym == Symbols.end()) + return nullptr; + return &*Sym; +} + +const DebugMapObject::DebugMapEntry * +DebugMapObject::lookupObjectAddress(uint64_t Address) const { + auto Mapping = AddressToMapping.find(Address); + if (Mapping == AddressToMapping.end()) + return nullptr; + return Mapping->getSecond(); +} + +void DebugMap::print(raw_ostream &OS) const { + OS << "DEBUG MAP: " << BinaryTriple.getTriple() + << "\n\tobject addr => executable addr\tsymbol name\n"; + for (const auto &Obj : objects()) + Obj->print(OS); + OS << "END DEBUG MAP\n"; +} + +#ifndef NDEBUG +void DebugMap::dump() const { print(errs()); } +#endif +} +} diff --git a/tools/dsymutil/DebugMap.h b/tools/dsymutil/DebugMap.h new file mode 100644 index 0000000..ff2b27e --- /dev/null +++ b/tools/dsymutil/DebugMap.h @@ -0,0 +1,142 @@ +//===- tools/dsymutil/DebugMap.h - Generic debug map representation -------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains the class declaration of the DebugMap +/// entity. A DebugMap lists all the object files linked together to +/// produce an executable along with the linked address of all the +/// atoms used in these object files. +/// The DebugMap is an input to the DwarfLinker class that will +/// extract the Dwarf debug information from the referenced object +/// files and link their usefull debug info together. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H +#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/Format.h" +#include + +namespace llvm { +class raw_ostream; + +namespace dsymutil { +class DebugMapObject; + +/// \brief The DebugMap object stores the list of object files to +/// query for debug information along with the mapping between the +/// symbols' addresses in the object file to their linked address in +/// the linked binary. +/// +/// A DebugMap producer could look like this: +/// DebugMap *DM = new DebugMap(); +/// for (const auto &Obj: LinkedObjects) { +/// DebugMapObject &DMO = DM->addDebugMapObject(Obj.getPath()); +/// for (const auto &Sym: Obj.getLinkedSymbols()) +/// DMO.addSymbol(Sym.getName(), Sym.getObjectFileAddress(), +/// Sym.getBinaryAddress()); +/// } +/// +/// A DebugMap consumer can then use the map to link the debug +/// information. For example something along the lines of: +/// for (const auto &DMO: DM->objects()) { +/// auto Obj = createBinary(DMO.getObjectFilename()); +/// for (auto &DIE: Obj.getDwarfDIEs()) { +/// if (SymbolMapping *Sym = DMO.lookup(DIE.getName())) +/// DIE.relocate(Sym->ObjectAddress, Sym->BinaryAddress); +/// else +/// DIE.discardSubtree(); +/// } +/// } +class DebugMap { + Triple BinaryTriple; + typedef std::vector> ObjectContainer; + ObjectContainer Objects; + +public: + DebugMap(const Triple &BinaryTriple) : BinaryTriple(BinaryTriple) {} + + typedef ObjectContainer::const_iterator const_iterator; + + iterator_range objects() const { + return make_range(begin(), end()); + } + + const_iterator begin() const { return Objects.begin(); } + + const_iterator end() const { return Objects.end(); } + + /// This function adds an DebugMapObject to the list owned by this + /// debug map. + DebugMapObject &addDebugMapObject(StringRef ObjectFilePath); + + const Triple &getTriple() { return BinaryTriple; } + + void print(raw_ostream &OS) const; + +#ifndef NDEBUG + void dump() const; +#endif +}; + +/// \brief The DebugMapObject represents one object file described by +/// the DebugMap. It contains a list of mappings between addresses in +/// the object file and in the linked binary for all the linked atoms +/// in this object file. +class DebugMapObject { +public: + struct SymbolMapping { + uint64_t ObjectAddress; + uint64_t BinaryAddress; + SymbolMapping(uint64_t ObjectAddress, uint64_t BinaryAddress) + : ObjectAddress(ObjectAddress), BinaryAddress(BinaryAddress) {} + }; + + typedef StringMapEntry DebugMapEntry; + + /// \brief Adds a symbol mapping to this DebugMapObject. + /// \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); + + /// \brief Lookup a symbol mapping. + /// \returns null if the symbol isn't found. + const DebugMapEntry *lookupSymbol(StringRef SymbolName) const; + + /// \brief Lookup an objectfile address. + /// \returns null if the address isn't found. + const DebugMapEntry *lookupObjectAddress(uint64_t Address) const; + + llvm::StringRef getObjectFilename() const { return Filename; } + + void print(raw_ostream &OS) const; +#ifndef NDEBUG + void dump() const; +#endif +private: + friend class DebugMap; + /// DebugMapObjects can only be constructed by the owning DebugMap. + DebugMapObject(StringRef ObjectFilename); + + std::string Filename; + StringMap Symbols; + DenseMap AddressToMapping; +}; +} +} + +#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp new file mode 100644 index 0000000..3c0bc0b --- /dev/null +++ b/tools/dsymutil/DwarfLinker.cpp @@ -0,0 +1,667 @@ +//===- tools/dsymutil/DwarfLinker.cpp - Dwarf debug info linker -----------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#include "DebugMap.h" +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "dsymutil.h" +#include "llvm/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h" +#include "llvm/DebugInfo/DWARF/DWARFFormValue.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/LEB128.h" +#include + +namespace llvm { +namespace dsymutil { + +namespace { + +/// \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. +class CompileUnit { +public: + /// \brief Information gathered about a DIE in the object file. + struct DIEInfo { + uint64_t Address; ///< Linked address of the described entity. + 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) { + Info.resize(OrigUnit.getNumDIEs()); + } + + DWARFUnit &getOrigUnit() const { return OrigUnit; } + + DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; } + const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; } + +private: + DWARFUnit &OrigUnit; + std::vector Info; ///< DIE info indexed by DIE index. +}; + +/// \brief The core of the Dwarf linking logic. +/// +/// The link of the dwarf information from the object files will be +/// driven by the selection of 'root DIEs', which are DIEs that +/// describe variables or functions that are present in the linked +/// binary (and thus have entries in the debug map). All the debug +/// information that will be linked (the DIEs, but also the line +/// tables, ranges, ...) is derived from that set of root DIEs. +/// +/// The root DIEs are identified because they contain relocations that +/// correspond to a debug map entry at specific places (the low_pc for +/// a function, the location for a variable). These relocations are +/// called ValidRelocs in the DwarfLinker and are gathered as a very +/// first step when we start processing a DebugMapObject. +class DwarfLinker { +public: + DwarfLinker(StringRef OutputFilename, bool Verbose) + : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {} + + /// \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 &); + + /// \brief Called at the end of a debug object link. + void endDebugObject(); + + /// \defgroup FindValidRelocations Translate debug map into a list + /// of relevant relocations + /// + /// @{ + struct ValidReloc { + uint32_t Offset; + uint32_t Size; + uint64_t Addend; + const DebugMapObject::DebugMapEntry *Mapping; + + ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend, + const DebugMapObject::DebugMapEntry *Mapping) + : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {} + + bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; } + }; + + /// \brief The valid relocations for the current DebugMapObject. + /// This vector is sorted by relocation offset. + std::vector ValidRelocs; + + /// \brief Index into ValidRelocs of the next relocation to + /// 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. + unsigned NextValidReloc; + + bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj, + const DebugMapObject &DMO); + + bool findValidRelocs(const object::SectionRef &Section, + const object::ObjectFile &Obj, + const DebugMapObject &DMO); + + void findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, + const DebugMapObject &DMO); + /// @} + + /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries. + /// + /// @{ + /// \brief Recursively walk the \p DIE tree and look for DIEs to + /// keep. Store that information in \p CU's DIEInfo. + void lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE, + const DebugMapObject &DMO, CompileUnit &CU, + unsigned Flags); + + /// \brief Flags passed to DwarfLinker::lookForDIEsToKeep + enum TravesalFlags { + TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept. + TF_InFunctionScope = 1 << 1, ///< Current scope is a fucntion scope. + TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE. + TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE. + }; + + /// \brief Mark the passed DIE as well as all the ones it depends on + /// as kept. + void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit::DIEInfo &MyInfo, + const DebugMapObject &DMO, CompileUnit &CU, + unsigned Flags); + + unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo, + unsigned Flags); + + unsigned shouldKeepVariableDIE(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, unsigned Flags); + + unsigned shouldKeepSubprogramDIE(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, + unsigned Flags); + + bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, + CompileUnit::DIEInfo &Info); + /// @} + + /// \defgroup Helpers Various helper methods. + /// + /// @{ + const DWARFDebugInfoEntryMinimal * + resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit, + const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit *&ReferencedCU); + + CompileUnit *getUnitForOffset(unsigned Offset); + + void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr, + const DWARFDebugInfoEntryMinimal *DIE = nullptr); + /// @} + +private: + std::string OutputFilename; + bool Verbose; + BinaryHolder BinHolder; + + /// The units of the current debug map object. + std::vector Units; + + /// The debug map object curently under consideration. + DebugMapObject *CurrentDebugObject; +}; + +/// \brief Similar to DWARFUnitSection::getUnitForOffset(), but +/// returning our CompileUnit object instead. +CompileUnit *DwarfLinker::getUnitForOffset(unsigned Offset) { + auto CU = + std::upper_bound(Units.begin(), Units.end(), Offset, + [](uint32_t LHS, const CompileUnit &RHS) { + return LHS < RHS.getOrigUnit().getNextUnitOffset(); + }); + return CU != Units.end() ? &*CU : nullptr; +} + +/// \brief Resolve the DIE attribute reference that has been +/// extracted in \p RefValue. The resulting DIE migh be in another +/// CompileUnit which is stored into \p ReferencedCU. +/// \returns null if resolving fails for any reason. +const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference( + DWARFFormValue &RefValue, const DWARFUnit &Unit, + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) { + assert(RefValue.isFormClass(DWARFFormValue::FC_Reference)); + uint64_t RefOffset = *RefValue.getAsReference(&Unit); + + if ((RefCU = getUnitForOffset(RefOffset))) + if (const auto *RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset)) + return RefDie; + + reportWarning("could not find referenced DIE", &Unit, &DIE); + return nullptr; +} + +/// \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) { + if (CurrentDebugObject) + errs() << Twine("while processing ") + + CurrentDebugObject->getObjectFilename() + ":\n"; + errs() << Twine("warning: ") + Warning + "\n"; + + if (!Verbose || !DIE) + return; + + errs() << " in DIE:\n"; + DIE->dump(errs(), const_cast(Unit), 0 /* RecurseDepth */, + 6 /* Indent */); +} + +/// \brief Recursive helper to gather the child->parent relationships in the +/// original compile unit. +static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE, + unsigned ParentIdx, CompileUnit &CU) { + unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE); + CU.getInfo(MyIdx).ParentIdx = ParentIdx; + + if (DIE->hasChildren()) + for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL(); + Child = Child->getSibling()) + gatherDIEParents(Child, MyIdx, CU); +} + +static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) { + switch (Tag) { + default: + return false; + case dwarf::DW_TAG_subprogram: + case dwarf::DW_TAG_lexical_block: + case dwarf::DW_TAG_subroutine_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_union_type: + return true; + } + llvm_unreachable("Invalid Tag"); +} + +void DwarfLinker::startDebugObject(DWARFContext &Dwarf) { + Units.reserve(Dwarf.getNumCompileUnits()); + NextValidReloc = 0; +} + +void DwarfLinker::endDebugObject() { + Units.clear(); + ValidRelocs.clear(); +} + +/// \brief Iterate over the relocations of the given \p Section and +/// store the ones that correspond to debug map entries into the +/// ValidRelocs array. +void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section, + const object::MachOObjectFile &Obj, + const DebugMapObject &DMO) { + StringRef Contents; + Section.getContents(Contents); + DataExtractor Data(Contents, Obj.isLittleEndian(), 0); + + for (const object::RelocationRef &Reloc : Section.relocations()) { + object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl(); + MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef); + unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc); + uint64_t Offset64; + if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) { + reportWarning(" unsupported relocation in debug_info section."); + continue; + } + uint32_t Offset = Offset64; + // Mach-o uses REL relocations, the addend is at the relocation offset. + uint64_t Addend = Data.getUnsigned(&Offset, RelocSize); + + auto Sym = Reloc.getSymbol(); + if (Sym != Obj.symbol_end()) { + StringRef SymbolName; + if (Sym->getName(SymbolName)) { + reportWarning("error getting relocation symbol name."); + continue; + } + if (const auto *Mapping = DMO.lookupSymbol(SymbolName)) + ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping); + } else if (const auto *Mapping = DMO.lookupObjectAddress(Addend)) { + // Do not store the addend. The addend was the address of the + // symbol in the object file, the address in the binary that is + // stored in the debug map doesn't need to be offseted. + ValidRelocs.emplace_back(Offset64, RelocSize, 0, Mapping); + } + } +} + +/// \brief Dispatch the valid relocation finding logic to the +/// appropriate handler depending on the object file format. +bool DwarfLinker::findValidRelocs(const object::SectionRef &Section, + const object::ObjectFile &Obj, + const DebugMapObject &DMO) { + // Dispatch to the right handler depending on the file type. + if (auto *MachOObj = dyn_cast(&Obj)) + findValidRelocsMachO(Section, *MachOObj, DMO); + else + reportWarning(Twine("unsupported object file type: ") + Obj.getFileName()); + + if (ValidRelocs.empty()) + return false; + + // Sort the relocations by offset. We will walk the DIEs linearly in + // the file, this allows us to just keep an index in the relocation + // array that we advance during our walk, rather than resorting to + // some associative container. See DwarfLinker::NextValidReloc. + std::sort(ValidRelocs.begin(), ValidRelocs.end()); + return true; +} + +/// \brief Look for relocations in the debug_info section that match +/// entries in the debug map. These relocations will drive the Dwarf +/// link by indicating which DIEs refer to symbols present in the +/// linked binary. +/// \returns wether there are any valid relocations in the debug info. +bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj, + const DebugMapObject &DMO) { + // Find the debug_info section. + for (const object::SectionRef &Section : Obj.sections()) { + StringRef SectionName; + Section.getName(SectionName); + SectionName = SectionName.substr(SectionName.find_first_not_of("._")); + if (SectionName != "debug_info") + continue; + return findValidRelocs(Section, Obj, DMO); + } + return false; +} + +/// \brief Checks that there is a relocation against an actual debug +/// map entry between \p StartOffset and \p NextOffset. +/// +/// This function must be called with offsets in strictly ascending +/// order because it never looks back at relocations it already 'went past'. +/// \returns true and sets Info.InDebugMap if it is the case. +bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset, + CompileUnit::DIEInfo &Info) { + assert(NextValidReloc == 0 || + StartOffset > ValidRelocs[NextValidReloc - 1].Offset); + if (NextValidReloc >= ValidRelocs.size()) + return false; + + uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset; + + // We might need to skip some relocs that we didn't consider. For + // example the high_pc of a discarded DIE might contain a reloc that + // is in the list because it actually corresponds to the start of a + // function that is in the debug map. + while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1) + RelocOffset = ValidRelocs[++NextValidReloc].Offset; + + if (RelocOffset < StartOffset || RelocOffset >= EndOffset) + return false; + + const auto &ValidReloc = ValidRelocs[NextValidReloc++]; + if (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.InDebugMap = true; + return true; +} + +/// \brief Get the starting and ending (exclusive) offset for the +/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is +/// supposed to point to the position of the first attribute described +/// by \p Abbrev. +/// \return [StartOffset, EndOffset) as a pair. +static std::pair +getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx, + unsigned Offset, const DWARFUnit &Unit) { + DataExtractor Data = Unit.getDebugInfoExtractor(); + + for (unsigned i = 0; i < Idx; ++i) + DWARFFormValue::skipValue(Abbrev->getFormByIndex(i), Data, &Offset, &Unit); + + uint32_t End = Offset; + DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End, &Unit); + + return std::make_pair(Offset, End); +} + +/// \brief Check if a variable describing DIE should be kept. +/// \returns updated TraversalFlags. +unsigned DwarfLinker::shouldKeepVariableDIE( + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, unsigned Flags) { + const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); + + // Global variables with constant value can always be kept. + if (!(Flags & TF_InFunctionScope) && + Abbrev->findAttributeIndex(dwarf::DW_AT_const_value) != -1U) { + MyInfo.InDebugMap = true; + return Flags | TF_Keep; + } + + uint32_t LocationIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_location); + if (LocationIdx == -1U) + return Flags; + + uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); + const DWARFUnit &OrigUnit = Unit.getOrigUnit(); + uint32_t LocationOffset, LocationEndOffset; + std::tie(LocationOffset, LocationEndOffset) = + getAttributeOffsets(Abbrev, LocationIdx, Offset, OrigUnit); + + // See if there is a relocation to a valid debug map entry inside + // this variable's location. The order is important here. We want to + // always check in the variable has a valid relocation, so that the + // DIEInfo is filled. However, we don't want a static variable in a + // function to force us to keep the enclosing function. + if (!hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) || + (Flags & TF_InFunctionScope)) + return Flags; + + if (Verbose) + DIE.dump(outs(), const_cast(&OrigUnit), 0, 8 /* Indent */); + + return Flags | TF_Keep; +} + +/// \brief Check if a function describing DIE should be kept. +/// \returns updated TraversalFlags. +unsigned DwarfLinker::shouldKeepSubprogramDIE( + const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, unsigned Flags) { + const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); + + Flags |= TF_InFunctionScope; + + uint32_t LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc); + if (LowPcIdx == -1U) + return Flags; + + uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); + const DWARFUnit &OrigUnit = Unit.getOrigUnit(); + uint32_t LowPcOffset, LowPcEndOffset; + std::tie(LowPcOffset, LowPcEndOffset) = + getAttributeOffsets(Abbrev, LowPcIdx, Offset, OrigUnit); + + uint64_t LowPc = + DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL); + assert(LowPc != -1ULL && "low_pc attribute is not an address."); + if (LowPc == -1ULL || + !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo)) + return Flags; + + if (Verbose) + DIE.dump(outs(), const_cast(&OrigUnit), 0, 8 /* Indent */); + + return Flags | TF_Keep; +} + +/// \brief Check if a DIE should be kept. +/// \returns updated TraversalFlags. +unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit &Unit, + CompileUnit::DIEInfo &MyInfo, + unsigned Flags) { + switch (DIE.getTag()) { + case dwarf::DW_TAG_constant: + case dwarf::DW_TAG_variable: + return shouldKeepVariableDIE(DIE, Unit, MyInfo, Flags); + case dwarf::DW_TAG_subprogram: + return shouldKeepSubprogramDIE(DIE, Unit, MyInfo, Flags); + case dwarf::DW_TAG_module: + case dwarf::DW_TAG_imported_module: + case dwarf::DW_TAG_imported_declaration: + case dwarf::DW_TAG_imported_unit: + // We always want to keep these. + return Flags | TF_Keep; + } + + return Flags; +} + + +/// \brief Mark the passed DIE as well as all the ones it depends on +/// as kept. +/// +/// This function is called by lookForDIEsToKeep on DIEs that are +/// newly discovered to be needed in the link. It recursively calls +/// back to lookForDIEsToKeep while adding TF_DependencyWalk to the +/// TraversalFlags to inform it that it's not doing the primary DIE +/// tree walk. +void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE, + CompileUnit::DIEInfo &MyInfo, + const DebugMapObject &DMO, + CompileUnit &CU, unsigned Flags) { + const DWARFUnit &Unit = CU.getOrigUnit(); + MyInfo.Keep = true; + + // First mark all the parent chain as kept. + unsigned AncestorIdx = MyInfo.ParentIdx; + while (!CU.getInfo(AncestorIdx).Keep) { + lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU, + TF_ParentWalk | TF_Keep | TF_DependencyWalk); + AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx; + } + + // Then we need to mark all the DIEs referenced by this DIE's + // attributes as kept. + DataExtractor Data = Unit.getDebugInfoExtractor(); + const auto *Abbrev = DIE.getAbbreviationDeclarationPtr(); + uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode()); + + // Mark all DIEs referenced through atttributes as kept. + for (const auto &AttrSpec : Abbrev->attributes()) { + DWARFFormValue Val(AttrSpec.Form); + + if (!Val.isFormClass(DWARFFormValue::FC_Reference)) { + DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, &Unit); + continue; + } + + Val.extractValue(Data, &Offset, &Unit); + CompileUnit *ReferencedCU; + if (const auto *RefDIE = resolveDIEReference(Val, Unit, DIE, ReferencedCU)) + lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU, + TF_Keep | TF_DependencyWalk); + } +} + +/// \brief Recursively walk the \p DIE tree and look for DIEs to +/// keep. Store that information in \p CU's DIEInfo. +/// +/// This function is the entry point of the DIE selection +/// algorithm. It is expected to walk the DIE tree in file order and +/// (though the mediation of its helper) call hasValidRelocation() on +/// each DIE that might be a 'root DIE' (See DwarfLinker class +/// comment). +/// While walking the dependencies of root DIEs, this function is +/// also called, but during these dependency walks the file order is +/// not respected. The TF_DependencyWalk flag tells us which kind of +/// traversal we are currently doing. +void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE, + const DebugMapObject &DMO, CompileUnit &CU, + unsigned Flags) { + unsigned Idx = CU.getOrigUnit().getDIEIndex(&DIE); + CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx); + bool AlreadyKept = MyInfo.Keep; + + // If the Keep flag is set, we are marking a required DIE's + // dependencies. If our target is already marked as kept, we're all + // set. + if ((Flags & TF_DependencyWalk) && AlreadyKept) + return; + + // We must not call shouldKeepDIE while called from keepDIEAndDenpendencies, + // because it would screw up the relocation finding logic. + if (!(Flags & TF_DependencyWalk)) + Flags = shouldKeepDIE(DIE, CU, MyInfo, Flags); + + // If it is a newly kept DIE mark it as well as all its dependencies as kept. + if (!AlreadyKept && (Flags & TF_Keep)) + keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, Flags); + + // The TF_ParentWalk flag tells us that we are currently walking up + // the parent chain of a required DIE, and we don't want to mark all + // the children of the parents as kept (consider for example a + // DW_TAG_namespace node in the parent chain). There are however a + // set of DIE types for which we want to ignore that directive and still + // walk their children. + if (dieNeedsChildrenToBeMeaningful(DIE.getTag())) + Flags &= ~TF_ParentWalk; + + if (!DIE.hasChildren() || (Flags & TF_ParentWalk)) + return; + + for (auto *Child = DIE.getFirstChild(); Child && !Child->isNULL(); + Child = Child->getSibling()) + lookForDIEsToKeep(*Child, DMO, CU, Flags); +} + +bool DwarfLinker::link(const DebugMap &Map) { + + if (Map.begin() == Map.end()) { + errs() << "Empty debug map.\n"; + return false; + } + + for (const auto &Obj : Map.objects()) { + CurrentDebugObject = Obj.get(); + + if (Verbose) + outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; + auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename()); + if (std::error_code EC = ErrOrObj.getError()) { + reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message()); + continue; + } + + // Look for relocations that correspond to debug map entries. + if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { + if (Verbose) + outs() << "No valid relocations found. Skipping.\n"; + continue; + } + + // Setup access to the debug info. + DWARFContextInMemory DwarfContext(*ErrOrObj); + startDebugObject(DwarfContext); + + // 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) { + outs() << "Input compilation unit:"; + CUDie->dump(outs(), CU.get(), 0); + } + Units.emplace_back(*CU); + gatherDIEParents(CUDie, 0, Units.back()); + } + + // Then mark all the DIEs that need to be present in the linked + // output and collect some information about them. Note that this + // loop can not be merged with the previous one becaue cross-cu + // references require the ParentIdx to be setup for every CU in + // the object file before calling this. + for (auto &CurrentUnit : Units) + lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *Obj, + CurrentUnit, 0); + + // Clean-up before starting working on the next object. + endDebugObject(); + } + + return true; +} +} + +bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) { + DwarfLinker Linker(OutputFilename, Verbose); + return Linker.link(DM); +} +} +} diff --git a/tools/dsymutil/LLVMBuild.txt b/tools/dsymutil/LLVMBuild.txt new file mode 100644 index 0000000..c995291 --- /dev/null +++ b/tools/dsymutil/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/dsymutil/LLVMBuild.txt ---------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-dsymutil +parent = Tools +required_libraries = DebugInfoDWARF Object Support diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp new file mode 100644 index 0000000..7bb0011 --- /dev/null +++ b/tools/dsymutil/MachODebugMapParser.cpp @@ -0,0 +1,241 @@ +//===- tools/dsymutil/MachODebugMapParser.cpp - Parse STABS debug maps ----===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BinaryHolder.h" +#include "DebugMap.h" +#include "dsymutil.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +namespace { +using namespace llvm; +using namespace llvm::dsymutil; +using namespace llvm::object; + +class MachODebugMapParser { +public: + MachODebugMapParser(StringRef BinaryPath, StringRef PathPrefix = "", + bool Verbose = false) + : BinaryPath(BinaryPath), PathPrefix(PathPrefix), + MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose), + CurrentDebugMapObject(nullptr) {} + + /// \brief Parses and returns the DebugMap of the input binary. + /// \returns an error in case the provided BinaryPath doesn't exist + /// or isn't of a supported type. + ErrorOr> parse(); + +private: + std::string BinaryPath; + std::string PathPrefix; + + /// Owns the MemoryBuffer for the main binary. + BinaryHolder MainBinaryHolder; + /// Map of the binary symbol addresses. + StringMap MainBinarySymbolAddresses; + StringRef MainBinaryStrings; + /// The constructed DebugMap. + std::unique_ptr Result; + + /// Owns the MemoryBuffer for the currently handled object file. + BinaryHolder CurrentObjectHolder; + /// Map of the currently processed object file symbol addresses. + StringMap CurrentObjectAddresses; + /// Element of the debug map corresponfing to the current object file. + DebugMapObject *CurrentDebugMapObject; + + void switchToNewDebugMapObject(StringRef Filename); + void resetParserState(); + uint64_t getMainBinarySymbolAddress(StringRef Name); + void loadMainBinarySymbols(); + void loadCurrentObjectFileSymbols(); + void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, + uint8_t SectionIndex, uint16_t Flags, + uint64_t Value); + + template void handleStabDebugMapEntry(const STEType &STE) { + handleStabSymbolTableEntry(STE.n_strx, STE.n_type, STE.n_sect, STE.n_desc, + STE.n_value); + } +}; + +static void Warning(const Twine &Msg) { errs() << "warning: " + Msg + "\n"; } +} + +/// Reset the parser state coresponding to the current object +/// file. This is to be called after an object file is finished +/// processing. +void MachODebugMapParser::resetParserState() { + CurrentObjectAddresses.clear(); + CurrentDebugMapObject = nullptr; +} + +/// Create a new DebugMapObject. This function resets the state of the +/// parser that was referring to the last object file and sets +/// everything up to add symbols to the new one. +void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) { + resetParserState(); + + SmallString<80> Path(PathPrefix); + sys::path::append(Path, Filename); + + auto MachOOrError = CurrentObjectHolder.GetFileAs(Path); + if (auto Error = MachOOrError.getError()) { + Warning(Twine("cannot open debug object \"") + Path.str() + "\": " + + Error.message() + "\n"); + return; + } + + loadCurrentObjectFileSymbols(); + CurrentDebugMapObject = &Result->addDebugMapObject(Path); +} + +static Triple getTriple(const object::MachOObjectFile &Obj) { + Triple TheTriple("unknown-unknown-unknown"); + TheTriple.setArch(Triple::ArchType(Obj.getArch())); + TheTriple.setObjectFormat(Triple::MachO); + return TheTriple; +} + +/// This main parsing routine tries to open the main binary and if +/// successful iterates over the STAB entries. The real parsing is +/// done in handleStabSymbolTableEntry. +ErrorOr> MachODebugMapParser::parse() { + auto MainBinOrError = MainBinaryHolder.GetFileAs(BinaryPath); + if (auto Error = MainBinOrError.getError()) + return Error; + + const MachOObjectFile &MainBinary = *MainBinOrError; + loadMainBinarySymbols(); + Result = make_unique(getTriple(MainBinary)); + MainBinaryStrings = MainBinary.getStringTableData(); + for (const SymbolRef &Symbol : MainBinary.symbols()) { + const DataRefImpl &DRI = Symbol.getRawDataRefImpl(); + if (MainBinary.is64Bit()) + handleStabDebugMapEntry(MainBinary.getSymbol64TableEntry(DRI)); + else + handleStabDebugMapEntry(MainBinary.getSymbolTableEntry(DRI)); + } + + resetParserState(); + return std::move(Result); +} + +/// Interpret the STAB entries to fill the DebugMap. +void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, + uint8_t Type, + uint8_t SectionIndex, + uint16_t Flags, + uint64_t Value) { + if (!(Type & MachO::N_STAB)) + return; + + const char *Name = &MainBinaryStrings.data()[StringIndex]; + + // An N_OSO entry represents the start of a new object file description. + if (Type == MachO::N_OSO) + return switchToNewDebugMapObject(Name); + + // If the last N_OSO object file wasn't found, + // CurrentDebugMapObject will be null. Do not update anything + // until we find the next valid N_OSO entry. + if (!CurrentDebugMapObject) + return; + + switch (Type) { + case MachO::N_GSYM: + // This is a global variable. We need to query the main binary + // symbol table to find its address as it might not be in the + // debug map (for common symbols). + Value = getMainBinarySymbolAddress(Name); + if (Value == UnknownAddressOrSize) + 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') + return; + break; + case MachO::N_STSYM: + break; + default: + return; + } + + auto ObjectSymIt = CurrentObjectAddresses.find(Name); + if (ObjectSymIt == CurrentObjectAddresses.end()) + return Warning("could not find object file symbol for symbol " + + Twine(Name)); + if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value)) + return Warning(Twine("failed to insert symbol '") + Name + + "' in the debug map."); +} + +/// Load the current object file symbols into CurrentObjectAddresses. +void MachODebugMapParser::loadCurrentObjectFileSymbols() { + CurrentObjectAddresses.clear(); + + for (auto Sym : CurrentObjectHolder.Get().symbols()) { + StringRef Name; + uint64_t Addr; + if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize || + Sym.getName(Name)) + continue; + CurrentObjectAddresses[Name] = Addr; + } +} + +/// Lookup a symbol address in the main binary symbol table. The +/// parser only needs to query common symbols, thus not every symbol's +/// address is available through this function. +uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { + auto Sym = MainBinarySymbolAddresses.find(Name); + if (Sym == MainBinarySymbolAddresses.end()) + return UnknownAddressOrSize; + return Sym->second; +} + +/// Load the interesting main binary symbols' addresses into +/// MainBinarySymbolAddresses. +void MachODebugMapParser::loadMainBinarySymbols() { + const MachOObjectFile &MainBinary = MainBinaryHolder.GetAs(); + section_iterator Section = MainBinary.section_end(); + for (const auto &Sym : MainBinary.symbols()) { + SymbolRef::Type Type; + // Skip undefined and STAB entries. + if (Sym.getType(Type) || (Type & SymbolRef::ST_Debug) || + (Type & SymbolRef::ST_Unknown)) + continue; + StringRef Name; + uint64_t Addr; + // The only symbols of interest are the global variables. These + // are the only ones that need to be queried because the address + // of common data won't be described in the debug map. All other + // addresses should be fetched for the debug map. + if (Sym.getAddress(Addr) || Addr == UnknownAddressOrSize || + !(Sym.getFlags() & SymbolRef::SF_Global) || Sym.getSection(Section) || + Section->isText() || Sym.getName(Name) || Name.size() == 0 || + Name[0] == '\0') + continue; + MainBinarySymbolAddresses[Name] = Addr; + } +} + +namespace llvm { +namespace dsymutil { +llvm::ErrorOr> 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 new file mode 100644 index 0000000..e8dc569 --- /dev/null +++ b/tools/dsymutil/Makefile @@ -0,0 +1,17 @@ +##===- tools/dsymutil/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-dsymutil +LINK_COMPONENTS := DebugInfoDWARF Object Support + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp new file mode 100644 index 0000000..2b4fcfe --- /dev/null +++ b/tools/dsymutil/dsymutil.cpp @@ -0,0 +1,71 @@ +//===-- dsymutil.cpp - Debug info dumping utility for llvm ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that aims to be a dropin replacement for +// Darwin's dsymutil. +// +//===----------------------------------------------------------------------===// + +#include "DebugMap.h" +#include "dsymutil.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Options.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace llvm::dsymutil; + +namespace { +using namespace llvm::cl; + +static opt InputFile(Positional, desc(""), + init("a.out")); + +static opt OsoPrependPath("oso-prepend-path", + desc("Specify a directory to prepend " + "to the paths of object files."), + value_desc("path")); + +static opt Verbose("v", desc("Verbosity level"), init(false)); + +static opt + ParseOnly("parse-only", + desc("Only parse the debug map, do not actaully link " + "the DWARF."), + init(false)); +} + +int main(int argc, char **argv) { + llvm::sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram StackPrinter(argc, argv); + llvm::llvm_shutdown_obj Shutdown; + + llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n"); + auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose); + + if (auto EC = DebugMapPtrOrErr.getError()) { + llvm::errs() << "error: cannot parse the debug map for \"" << InputFile + << "\": " << EC.message() << '\n'; + return 1; + } + + if (Verbose) + (*DebugMapPtrOrErr)->print(llvm::outs()); + + if (ParseOnly) + return 0; + + std::string OutputBasename(InputFile); + if (OutputBasename == "-") + OutputBasename = "a.out"; + + return !linkDwarf(OutputBasename + ".dwarf", **DebugMapPtrOrErr, Verbose); +} diff --git a/tools/dsymutil/dsymutil.h b/tools/dsymutil/dsymutil.h new file mode 100644 index 0000000..9203bea --- /dev/null +++ b/tools/dsymutil/dsymutil.h @@ -0,0 +1,39 @@ +//===- tools/dsymutil/dsymutil.h - dsymutil high-level functionality ------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// +/// This file contains the class declaration for the code that parses STABS +/// debug maps that are embedded in the binaries symbol tables. +/// +//===----------------------------------------------------------------------===// +#ifndef LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H +#define LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H + +#include "DebugMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorOr.h" +#include + +namespace llvm { +namespace dsymutil { +/// \brief Extract the DebugMap from the given file. +/// The file has to be a MachO object file. +llvm::ErrorOr> +parseDebugMap(StringRef InputFile, StringRef PrependPath = "", + bool Verbose = false); + +/// \brief Link the Dwarf debuginfo as directed by the passed DebugMap +/// \p DM into a DwarfFile named \p OutputFilename. +/// \returns false if the link failed. +bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, + bool Verbose = false); +} +} +#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt index 3033010..1a6169d 100644 --- a/tools/gold/CMakeLists.txt +++ b/tools/gold/CMakeLists.txt @@ -1,13 +1,6 @@ -set(LLVM_BINUTILS_INCDIR "" CACHE PATH - "PATH to binutils/include containing plugin-api.h for gold plugin.") - set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/gold.exports) -if( NOT LLVM_BINUTILS_INCDIR ) - # Nothing to say. -elseif( NOT EXISTS "${LLVM_BINUTILS_INCDIR}/plugin-api.h" ) - message(STATUS "plugin-api.h not found. gold plugin excluded from the build.") -else() +if( LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR ) include_directories( ${LLVM_BINUTILS_INCDIR} ) # Because off_t is used in the public API, the largefile parts are required for diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index cfda6d2..e3a57b5 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -15,23 +15,28 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/Linker/Linker.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/IRObjectFile.h" -#include "llvm/PassManager.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/Utils/GlobalStatus.h" @@ -78,9 +83,14 @@ static std::vector Cleanup; static llvm::TargetOptions TargetOpts; namespace options { - enum generate_bc { BC_NO, BC_ONLY, BC_SAVE_TEMPS }; + enum OutputType { + OT_NORMAL, + OT_DISABLE, + OT_BC_ONLY, + OT_SAVE_TEMPS + }; static bool generate_api_file = false; - static generate_bc generate_bc_file = BC_NO; + static OutputType TheOutputType = OT_NORMAL; static std::string obj_path; static std::string extra_library_path; static std::string triple; @@ -109,9 +119,11 @@ namespace options { } else if (opt.startswith("obj-path=")) { obj_path = opt.substr(strlen("obj-path=")); } else if (opt == "emit-llvm") { - generate_bc_file = BC_ONLY; + TheOutputType = OT_BC_ONLY; } else if (opt == "save-temps") { - generate_bc_file = BC_SAVE_TEMPS; + TheOutputType = OT_SAVE_TEMPS; + } else if (opt == "disable-output") { + TheOutputType = OT_DISABLE; } else { // Save this option to pass to the code generator. // ParseCommandLineOptions() expects argv[0] to be program name. Lazily @@ -253,6 +265,44 @@ static const GlobalObject *getBaseObject(const GlobalValue &GV) { return cast(&GV); } +static bool shouldSkip(uint32_t Symflags) { + if (!(Symflags & object::BasicSymbolRef::SF_Global)) + return true; + if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) + return true; + return false; +} + +static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) { + if (const auto *BDI = dyn_cast(&DI)) { + std::error_code EC = BDI->getError(); + if (EC == BitcodeError::InvalidBitcodeSignature) + return; + } + + std::string ErrStorage; + { + raw_string_ostream OS(ErrStorage); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + } + ld_plugin_level Level; + switch (DI.getSeverity()) { + case DS_Error: + message(LDPL_FATAL, "LLVM gold plugin has failed to create LTO module: %s", + ErrStorage.c_str()); + llvm_unreachable("Fatal doesn't return."); + case DS_Warning: + Level = LDPL_WARNING; + break; + case DS_Remark: + case DS_Note: + Level = LDPL_INFO; + break; + } + message(Level, "LLVM gold plugin: %s", ErrStorage.c_str()); +} + /// Called by gold to see whether this file is one that our plugin can handle. /// We'll try to open it and register all the symbols with add_symbol if /// possible. @@ -286,11 +336,11 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, BufferRef = Buffer->getMemBufferRef(); } + Context.setDiagnosticHandler(diagnosticHandler); ErrorOr> ObjOrErr = - object::IRObjectFile::createIRObjectFile(BufferRef, Context); + object::IRObjectFile::create(BufferRef, Context); std::error_code EC = ObjOrErr.getError(); - if (EC == BitcodeError::InvalidBitcodeSignature || - EC == object::object_error::invalid_file_type || + if (EC == object::object_error::invalid_file_type || EC == object::object_error::bitcode_section_not_found) return LDPS_OK; @@ -310,10 +360,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, for (auto &Sym : Obj->symbols()) { uint32_t Symflags = Sym.getFlags(); - if (!(Symflags & object::BasicSymbolRef::SF_Global)) - continue; - - if (Symflags & object::BasicSymbolRef::SF_FormatSpecific) + if (shouldSkip(Symflags)) continue; cf.syms.push_back(ld_plugin_symbol()); @@ -467,51 +514,10 @@ static const char *getResolutionName(ld_plugin_symbol_resolution R) { llvm_unreachable("Unknown resolution"); } -static GlobalObject *makeInternalReplacement(GlobalObject *GO) { - Module *M = GO->getParent(); - GlobalObject *Ret; - if (auto *F = dyn_cast(GO)) { - if (F->materialize()) - message(LDPL_FATAL, "LLVM gold plugin has failed to read a function"); - - auto *NewF = Function::Create(F->getFunctionType(), F->getLinkage(), - F->getName(), M); - - ValueToValueMapTy VM; - Function::arg_iterator NewI = NewF->arg_begin(); - for (auto &Arg : F->args()) { - NewI->setName(Arg.getName()); - VM[&Arg] = NewI; - ++NewI; - } - - NewF->getBasicBlockList().splice(NewF->end(), F->getBasicBlockList()); - for (auto &BB : *NewF) { - for (auto &Inst : BB) - RemapInstruction(&Inst, VM, RF_IgnoreMissingEntries); - } - - Ret = NewF; - F->deleteBody(); - } else { - auto *Var = cast(GO); - Ret = new GlobalVariable( - *M, Var->getType()->getElementType(), Var->isConstant(), - Var->getLinkage(), Var->getInitializer(), Var->getName(), - nullptr, Var->getThreadLocalMode(), Var->getType()->getAddressSpace(), - Var->isExternallyInitialized()); - Var->setInitializer(nullptr); - } - Ret->copyAttributesFrom(GO); - Ret->setLinkage(GlobalValue::InternalLinkage); - Ret->setComdat(GO->getComdat()); - - return Ret; -} - namespace { class LocalValueMaterializer : public ValueMaterializer { DenseSet &Dropped; + DenseMap LocalVersions; public: LocalValueMaterializer(DenseSet &Dropped) : Dropped(Dropped) {} @@ -520,13 +526,39 @@ public: } Value *LocalValueMaterializer::materializeValueFor(Value *V) { - auto *GV = dyn_cast(V); - if (!GV) + auto *GO = dyn_cast(V); + if (!GO) return nullptr; - if (!Dropped.count(GV)) + + auto I = LocalVersions.find(GO); + if (I != LocalVersions.end()) + return I->second; + + if (!Dropped.count(GO)) return nullptr; - assert(!isa(GV) && "Found alias point to weak alias."); - return makeInternalReplacement(cast(GV)); + + Module &M = *GO->getParent(); + GlobalValue::LinkageTypes L = GO->getLinkage(); + GlobalObject *Declaration; + if (auto *F = dyn_cast(GO)) { + Declaration = Function::Create(F->getFunctionType(), L, "", &M); + } else { + auto *Var = cast(GO); + Declaration = new GlobalVariable(M, Var->getType()->getElementType(), + Var->isConstant(), L, + /*Initializer*/ nullptr); + } + Declaration->takeName(GO); + Declaration->copyAttributesFrom(GO); + + GO->setLinkage(GlobalValue::InternalLinkage); + GO->setName(Declaration->getName()); + Dropped.erase(GO); + GO->replaceAllUsesWith(Declaration); + + LocalVersions[Declaration] = GO; + + return GO; } static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM, @@ -534,12 +566,17 @@ static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM, return MapValue(C, VM, RF_IgnoreMissingEntries, nullptr, Materializer); } +static void freeSymName(ld_plugin_symbol &Sym) { + free(Sym.name); + free(Sym.comdat_key); + Sym.name = nullptr; + Sym.comdat_key = nullptr; +} + static std::unique_ptr -getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, +getModuleForFile(LLVMContext &Context, claimed_file &F, + ld_plugin_input_file &Info, raw_fd_ostream *ApiFile, StringSet<> &Internalize, StringSet<> &Maybe) { - ld_plugin_input_file File; - if (get_input_file(F.handle, &File) != LDPS_OK) - message(LDPL_FATAL, "Failed to get file information"); if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK) message(LDPL_FATAL, "Failed to get symbol information"); @@ -548,42 +585,45 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, if (get_view(F.handle, &View) != LDPS_OK) message(LDPL_FATAL, "Failed to get a view of file"); - llvm::ErrorOr MBOrErr = - object::IRObjectFile::findBitcodeInMemBuffer( - MemoryBufferRef(StringRef((const char *)View, File.filesize), "")); - if (std::error_code EC = MBOrErr.getError()) + MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize), + Info.name); + ErrorOr> ObjOrErr = + object::IRObjectFile::create(BufferRef, Context); + + if (std::error_code EC = ObjOrErr.getError()) message(LDPL_FATAL, "Could not read bitcode from file : %s", EC.message().c_str()); - std::unique_ptr Buffer = - MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false); - - if (release_input_file(F.handle) != LDPS_OK) - message(LDPL_FATAL, "Failed to release file information"); - - ErrorOr MOrErr = getLazyBitcodeModule(std::move(Buffer), Context); + object::IRObjectFile &Obj = **ObjOrErr; - if (std::error_code EC = MOrErr.getError()) - message(LDPL_FATAL, "Could not read bitcode from file : %s", - EC.message().c_str()); + Module &M = Obj.getModule(); - std::unique_ptr M(MOrErr.get()); + UpgradeDebugInfo(M); SmallPtrSet Used; - collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false); + collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); DenseSet Drop; std::vector KeptAliases; - for (ld_plugin_symbol &Sym : F.syms) { + + unsigned SymNum = 0; + for (auto &ObjSym : Obj.symbols()) { + if (shouldSkip(ObjSym.getFlags())) + continue; + ld_plugin_symbol &Sym = F.syms[SymNum]; + ++SymNum; + ld_plugin_symbol_resolution Resolution = (ld_plugin_symbol_resolution)Sym.resolution; if (options::generate_api_file) *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n'; - GlobalValue *GV = M->getNamedValue(Sym.name); - if (!GV) + GlobalValue *GV = Obj.getSymbolGV(ObjSym.getRawDataRefImpl()); + if (!GV) { + freeSymName(Sym); continue; // Asm symbol. + } if (Resolution != LDPR_PREVAILING_DEF_IRONLY && GV->hasCommonLinkage()) { // Common linkage is special. There is no single symbol that wins the @@ -591,6 +631,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // The IR linker does that for us if we just pass it every common GV. // We still have to keep track of LDPR_PREVAILING_DEF_IRONLY so we // internalize once the IR linker has done its job. + freeSymName(Sym); continue; } @@ -601,17 +642,23 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: - case LDPR_UNDEF: assert(GV->isDeclarationForLinker()); break; + case LDPR_UNDEF: + if (!GV->isDeclarationForLinker()) { + assert(GV->hasComdat()); + Drop.insert(GV); + } + break; + case LDPR_PREVAILING_DEF_IRONLY: { keepGlobalValue(*GV, KeptAliases); if (!Used.count(GV)) { // Since we use the regular lib/Linker, we cannot just internalize GV // now or it will not be copied to the merged module. Instead we force // it to be copied and then internalize it. - Internalize.insert(Sym.name); + Internalize.insert(GV->getName()); } break; } @@ -624,7 +671,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // Gold might have selected a linkonce_odr and preempted a weak_odr. // In that case we have to make sure we don't end up internalizing it. if (!GV->isDiscardableIfUnused()) - Maybe.erase(Sym.name); + Maybe.erase(GV->getName()); // fall-through case LDPR_PREEMPTED_REG: @@ -637,16 +684,13 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // and in that module the address might be significant, but that // copy will be LDPR_PREEMPTED_IR. if (GV->hasLinkOnceODRLinkage()) - Maybe.insert(Sym.name); + Maybe.insert(GV->getName()); keepGlobalValue(*GV, KeptAliases); break; } } - free(Sym.name); - free(Sym.comdat_key); - Sym.name = nullptr; - Sym.comdat_key = nullptr; + freeSymName(Sym); } ValueToValueMapTy VM; @@ -656,26 +700,31 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, raw_fd_ostream *ApiFile, // expression is being dropped. If that is the case, that GV must be copied. Constant *Aliasee = GA->getAliasee(); Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer); - if (Aliasee != Replacement) - GA->setAliasee(Replacement); + GA->setAliasee(Replacement); } for (auto *GV : Drop) drop(*GV); - return M; + return Obj.takeModule(); } static void runLTOPasses(Module &M, TargetMachine &TM) { - PassManager passes; + if (const DataLayout *DL = TM.getDataLayout()) + M.setDataLayout(DL); + + legacy::PassManager passes; + passes.add(new DataLayoutPass()); + passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis())); + PassManagerBuilder PMB; - PMB.LibraryInfo = new TargetLibraryInfo(Triple(TM.getTargetTriple())); + PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple())); PMB.Inliner = createFunctionInliningPass(); PMB.VerifyInput = true; PMB.VerifyOutput = true; PMB.LoopVectorize = true; PMB.SLPVectorize = true; - PMB.populateLTOPassManager(passes, &TM); + PMB.populateLTOPassManager(passes); passes.run(M); } @@ -711,10 +760,10 @@ static void codegen(Module &M) { runLTOPasses(M, *TM); - if (options::generate_bc_file == options::BC_SAVE_TEMPS) + if (options::TheOutputType == options::OT_SAVE_TEMPS) saveBCFile(output_name + ".opt.bc", M); - PassManager CodeGenPasses; + legacy::PassManager CodeGenPasses; CodeGenPasses.add(new DataLayoutPass()); SmallString<128> Filename; @@ -760,6 +809,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { return LDPS_OK; LLVMContext Context; + Context.setDiagnosticHandler(diagnosticHandler); + std::unique_ptr Combined(new Module("ld-temp.o", Context)); Linker L(Combined.get()); @@ -768,8 +819,11 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { StringSet<> Internalize; StringSet<> Maybe; for (claimed_file &F : Modules) { + ld_plugin_input_file File; + if (get_input_file(F.handle, &File) != LDPS_OK) + message(LDPL_FATAL, "Failed to get file information"); std::unique_ptr M = - getModuleForFile(Context, F, ApiFile, Internalize, Maybe); + getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe); if (!options::triple.empty()) M->setTargetTriple(options::triple.c_str()); else if (M->getTargetTriple().empty()) { @@ -778,6 +832,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { if (L.linkInModule(M.get())) message(LDPL_FATAL, "Failed to link module"); + if (release_input_file(F.handle) != LDPS_OK) + message(LDPL_FATAL, "Failed to release file information"); } for (const auto &Name : Internalize) { @@ -795,14 +851,17 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) { internalize(*GV); } - if (options::generate_bc_file != options::BC_NO) { + if (options::TheOutputType == options::OT_DISABLE) + return LDPS_OK; + + if (options::TheOutputType != options::OT_NORMAL) { std::string path; - if (options::generate_bc_file == options::BC_ONLY) + if (options::TheOutputType == options::OT_BC_ONLY) path = output_name; else path = output_name + ".bc"; saveBCFile(path, *L.getModule()); - if (options::generate_bc_file == options::BC_ONLY) + if (options::TheOutputType == options::OT_BC_ONLY) return LDPS_OK; } @@ -828,8 +887,16 @@ static ld_plugin_status all_symbols_read_hook(void) { Ret = allSymbolsReadHook(&ApiFile); } - if (options::generate_bc_file == options::BC_ONLY) + llvm_shutdown(); + + if (options::TheOutputType == options::OT_BC_ONLY || + options::TheOutputType == options::OT_DISABLE) { + if (options::TheOutputType == options::OT_DISABLE) + // Remove the output file here since ld.bfd creates the output file + // early. + sys::fs::remove(output_name); exit(0); + } return Ret; } diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index 393d64c..484ff40 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + Analysis AsmPrinter CodeGen Core @@ -8,7 +9,6 @@ set(LLVM_LINK_COMPONENTS ScalarOpts SelectionDAG Support - Target ) # Support plugins. diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index fe4d9ac..efa1422 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -15,17 +15,18 @@ #include "llvm/ADT/Triple.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Pass.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -39,7 +40,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetSubtargetInfo.h" #include @@ -95,9 +95,9 @@ static cl::opt AsmVerbose("asm-verbose", static int compileModule(char **, LLVMContext &); -static tool_output_file *GetOutputStream(const char *TargetName, - Triple::OSType OS, - const char *ProgName) { +static std::unique_ptr +GetOutputStream(const char *TargetName, Triple::OSType OS, + const char *ProgName) { // If we don't yet have an output filename, make one. if (OutputFilename.empty()) { if (InputFilename == "-") @@ -151,10 +151,10 @@ static tool_output_file *GetOutputStream(const char *TargetName, sys::fs::OpenFlags OpenFlags = sys::fs::F_None; if (!Binary) OpenFlags |= sys::fs::F_Text; - tool_output_file *FDOut = new tool_output_file(OutputFilename, EC, OpenFlags); + auto FDOut = llvm::make_unique(OutputFilename, EC, + OpenFlags); if (EC) { errs() << EC.message() << '\n'; - delete FDOut; return nullptr; } @@ -205,7 +205,6 @@ static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; std::unique_ptr M; - Module *mod = nullptr; Triple TheTriple; bool SkipModule = MCPU == "help" || @@ -220,16 +219,15 @@ static int compileModule(char **argv, LLVMContext &Context) { // If user just wants to list available options, skip module loading if (!SkipModule) { M = parseIRFile(InputFilename, Err, Context); - mod = M.get(); - if (mod == nullptr) { + if (!M) { Err.print(argv[0], errs()); return 1; } // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) - mod->setTargetTriple(Triple::normalize(TargetTriple)); - TheTriple = Triple(mod->getTargetTriple()); + M->setTargetTriple(Triple::normalize(TargetTriple)); + TheTriple = Triple(M->getTargetTriple()); } else { TheTriple = Triple(Triple::normalize(TargetTriple)); } @@ -273,10 +271,10 @@ static int compileModule(char **argv, LLVMContext &Context) { Options.MCOptions.MCUseDwarfDirectory = EnableDwarfDirectory; Options.MCOptions.AsmVerbose = AsmVerbose; - std::unique_ptr target( + std::unique_ptr Target( TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr, Options, RelocModel, CMModel, OLvl)); - assert(target.get() && "Could not allocate target machine!"); + assert(Target && "Could not allocate target machine!"); // If we don't have a module then just exit now. We do this down // here since the CPU/Feature help is underneath the target machine @@ -284,29 +282,30 @@ static int compileModule(char **argv, LLVMContext &Context) { if (SkipModule) return 0; - assert(mod && "Should have exited if we didn't have a module!"); - TargetMachine &Target = *target.get(); + assert(M && "Should have exited if we didn't have a module!"); if (GenerateSoftFloatCalls) FloatABIForCalls = FloatABI::Soft; // Figure out where we are going to send the output. - std::unique_ptr Out( - GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0])); + std::unique_ptr Out = + GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0]); if (!Out) return 1; // Build up all of the passes that we want to do to the module. - PassManager PM; + legacy::PassManager PM; // Add an appropriate TargetLibraryInfo pass for the module's triple. - TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple); + TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple())); + + // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) - TLI->disableAllFunctions(); - PM.add(TLI); + TLII.disableAllFunctions(); + PM.add(new TargetLibraryInfoWrapperPass(TLII)); // Add the target data from the target machine, if it exists, or the module. - if (const DataLayout *DL = Target.getSubtargetImpl()->getDataLayout()) - mod->setDataLayout(DL); + if (const DataLayout *DL = Target->getDataLayout()) + M->setDataLayout(DL); PM.add(new DataLayoutPass()); if (RelaxAll.getNumOccurrences() > 0 && @@ -338,8 +337,8 @@ static int compileModule(char **argv, LLVMContext &Context) { } // Ask the target to add backend passes as necessary. - if (Target.addPassesToEmitFile(PM, FOS, FileType, NoVerify, - StartAfterID, StopAfterID)) { + if (Target->addPassesToEmitFile(PM, FOS, FileType, NoVerify, + StartAfterID, StopAfterID)) { errs() << argv[0] << ": target does not support generation of this" << " file type!\n"; return 1; @@ -348,7 +347,7 @@ static int compileModule(char **argv, LLVMContext &Context) { // Before executing passes, print the final values of the LLVM options. cl::PrintOptionValues(); - PM.run(*mod); + PM.run(*M); } // Declare success. diff --git a/tools/lli/Android.mk b/tools/lli/Android.mk index 1b09102..d771e56 100644 --- a/tools/lli/Android.mk +++ b/tools/lli/Android.mk @@ -46,7 +46,6 @@ lli_STATIC_LIBRARIES := \ libLLVMSelectionDAG \ libLLVMCodeGen \ libLLVMInstrumentation \ - libLLVMExecutionEngine \ libLLVMLinker \ libLLVMInterpreter \ libLLVMScalarOpts \ @@ -55,6 +54,8 @@ lli_STATIC_LIBRARIES := \ libLLVMTarget \ libLLVMMC \ libLLVMMCJIT \ + libLLVMOrcJIT \ + libLLVMExecutionEngine \ libLLVMRuntimeDyld \ libLLVMMCParser \ libLLVMObject \ diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 3610d76..463c853 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -10,6 +10,8 @@ set(LLVM_LINK_COMPONENTS MC MCJIT Object + OrcJIT + RuntimeDyld SelectionDAG Support native @@ -25,7 +27,7 @@ endif( LLVM_USE_OPROFILE ) if( LLVM_USE_INTEL_JITEVENTS ) set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} - DebugInfo + DebugInfoDWARF IntelJITEvents Object ) diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp index 0d71b17..6c537d4 100644 --- a/tools/lli/ChildTarget/ChildTarget.cpp +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -97,15 +97,15 @@ void LLIChildTarget::handleMessage(LLIMessageType messageType) { // Incoming message handlers void LLIChildTarget::handleAllocateSpace() { // Read and verify the message data size. - uint32_t DataSize; + uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the message arguments. - uint32_t Alignment; - uint32_t AllocSize; + uint32_t Alignment = 0; + uint32_t AllocSize = 0; rc = ReadBytes(&Alignment, 4); assert(rc == 4); rc = ReadBytes(&AllocSize, 4); @@ -121,13 +121,13 @@ void LLIChildTarget::handleAllocateSpace() { void LLIChildTarget::handleLoadSection(bool IsCode) { // Read the message data size. - uint32_t DataSize; + uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); // Read the target load address. - uint64_t Addr; + uint64_t Addr = 0; rc = ReadBytes(&Addr, 8); assert(rc == 8); size_t BufferSize = DataSize - 8; @@ -150,14 +150,14 @@ void LLIChildTarget::handleLoadSection(bool IsCode) { void LLIChildTarget::handleExecute() { // Read the message data size. - uint32_t DataSize; + uint32_t DataSize = 0; int rc = ReadBytes(&DataSize, 4); (void)rc; assert(rc == 4); assert(DataSize == 8); // Read the target address. - uint64_t Addr; + uint64_t Addr = 0; rc = ReadBytes(&Addr, 8); assert(rc == 8); diff --git a/tools/lli/Makefile b/tools/lli/Makefile index 94d6f06..70d8c80 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -14,12 +14,12 @@ PARALLEL_DIRS := ChildTarget include $(LEVEL)/Makefile.config -LINK_COMPONENTS := mcjit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native +LINK_COMPONENTS := mcjit orcjit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native # If Intel JIT Events support is confiured, link against the LLVM Intel JIT # Events interface library ifeq ($(USE_INTEL_JITEVENTS), 1) - LINK_COMPONENTS += debuginfo inteljitevents object + LINK_COMPONENTS += debuginfodwarf inteljitevents object endif # If oprofile support is confiured, link against the LLVM oprofile interface diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp index 5a135ea..47da8fb 100644 --- a/tools/lli/RemoteMemoryManager.cpp +++ b/tools/lli/RemoteMemoryManager.cpp @@ -14,7 +14,6 @@ #include "RemoteMemoryManager.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" @@ -78,7 +77,7 @@ sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { } void RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, - const ObjectImage *Obj) { + const object::ObjectFile &Obj) { // The client should have called setRemoteTarget() before triggering any // code generation. assert(Target); diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h index 0bdb4e2..895bcda 100644 --- a/tools/lli/RemoteMemoryManager.h +++ b/tools/lli/RemoteMemoryManager.h @@ -80,7 +80,8 @@ public: // symbols from Modules it contains. uint64_t getSymbolAddress(const std::string &Name) override { return 0; } - void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj) override; + void notifyObjectLoaded(ExecutionEngine *EE, + const object::ObjectFile &Obj) override; bool finalizeMemory(std::string *ErrMsg) override; diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 276740b..9c2b781 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -25,6 +25,7 @@ #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/ObjectCache.h" +#include "llvm/ExecutionEngine/OrcMCJITReplacement.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" @@ -74,9 +75,12 @@ namespace { cl::desc("Force interpretation: disable JIT"), cl::init(false)); - cl::opt DebugIR( - "debug-ir", cl::desc("Generate debug information to allow debugging IR."), - cl::init(false)); + cl::opt UseOrcMCJITReplacement("use-orcmcjit", + cl::desc("Use the experimental " + "OrcMCJITReplacement as a " + "drop-in replacement for " + "MCJIT."), + cl::init(false)); // The MCJIT supports building for a target address space separate from // the JIT compilation process. Use a forked process and a copying @@ -414,11 +418,6 @@ int main(int argc, char **argv, char * const *envp) { } } - if (DebugIR) { - ModulePass *DebugIRPass = createDebugIRPass(); - DebugIRPass->runOnModule(*Mod); - } - std::string ErrorMsg; EngineBuilder builder(std::move(Owner)); builder.setMArch(MArch); @@ -430,6 +429,7 @@ int main(int argc, char **argv, char * const *envp) { builder.setEngineKind(ForceInterpreter ? EngineKind::Interpreter : EngineKind::JIT); + builder.setUseOrcMCJITReplacement(UseOrcMCJITReplacement); // If we are supposed to override the target triple, do so now. if (!TargetTriple.empty()) @@ -442,7 +442,11 @@ int main(int argc, char **argv, char * const *envp) { RTDyldMM = new RemoteMemoryManager(); else RTDyldMM = new SectionMemoryManager(); - builder.setMCJITMemoryManager(RTDyldMM); + + // Deliberately construct a temp std::unique_ptr to pass in. Do not null out + // RTDyldMM: We still use it below, even though we don't own it. + builder.setMCJITMemoryManager( + std::unique_ptr(RTDyldMM)); } else if (RemoteMCJIT) { errs() << "error: Remote process execution does not work with the " "interpreter.\n"; @@ -561,7 +565,7 @@ int main(int argc, char **argv, char * const *envp) { // If the user specifically requested an argv[0] to pass into the program, // do it now. if (!FakeArgv0.empty()) { - InputFile = FakeArgv0; + InputFile = static_cast(FakeArgv0); } else { // Otherwise, if there is a .bc suffix on the executable strip it off, it // might confuse the program. @@ -593,7 +597,7 @@ int main(int argc, char **argv, char * const *envp) { // function later on to make an explicit call, so get the function now. Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), Type::getInt32Ty(Context), - NULL); + nullptr); // Run static constructors. if (!ForceInterpreter) { diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 5193def..3782c87 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -9,9 +9,6 @@ add_llvm_tool(llvm-ar llvm-ar.cpp ) -# FIXME: this is duplicated from the clang CMakeLists.txt -# FIXME: bin/llvm-ranlib is not a valid build target with this setup (pr17024) - if(UNIX) set(LLVM_LINK_OR_COPY create_symlink) set(llvm_ar_binary "llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") @@ -21,10 +18,12 @@ else() endif() set(llvm_ranlib "${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX}") -add_custom_command(TARGET llvm-ar POST_BUILD - COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_ranlib}") -set_property(DIRECTORY APPEND - PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${llvm_ranlib}) +add_custom_command(OUTPUT ${llvm_ranlib} + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_ranlib}" + DEPENDS llvm-ar) + +add_custom_target(llvm-ranlib ALL DEPENDS ${llvm_ranlib}) +set_target_properties(llvm-ranlib PROPERTIES FOLDER Tools) -# TODO: Support check-local. +install(SCRIPT install_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\") diff --git a/tools/llvm-ar/install_symlink.cmake b/tools/llvm-ar/install_symlink.cmake new file mode 100644 index 0000000..e313897 --- /dev/null +++ b/tools/llvm-ar/install_symlink.cmake @@ -0,0 +1,25 @@ +# We need to execute this script at installation time because the +# DESTDIR environment variable may be unset at configuration time. +# See PR8397. + +if(UNIX) + set(LINK_OR_COPY create_symlink) + set(DESTDIR $ENV{DESTDIR}) +else() + set(LINK_OR_COPY copy) +endif() + +# CMAKE_EXECUTABLE_SUFFIX is undefined on cmake scripts. See PR9286. +if( WIN32 ) + set(EXECUTABLE_SUFFIX ".exe") +else() + set(EXECUTABLE_SUFFIX "") +endif() + +set(bindir "${DESTDIR}${CMAKE_INSTALL_PREFIX}/bin/") + +message("Creating llvm-ranlib") + +execute_process( + COMMAND "${CMAKE_COMMAND}" -E ${LINK_OR_COPY} "llvm-ar${EXECUTABLE_SUFFIX}" "llvm-ranlib${EXECUTABLE_SUFFIX}" + WORKING_DIRECTORY "${bindir}") diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 8ee66f6..2f1eb3b 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -92,7 +92,6 @@ static cl::extrahelp MoreHelp( " [a] - put file(s) after [relpos]\n" " [b] - put file(s) before [relpos] (same as [i])\n" " [i] - put file(s) before [relpos] (same as [b])\n" - " [N] - use instance [count] of name\n" " [o] - preserve original dates\n" " [s] - create an archive index (cf. ranlib)\n" " [S] - do not build a symbol table\n" @@ -413,8 +412,6 @@ class NewArchiveIterator { object::Archive::child_iterator OldI; StringRef NewFilename; - mutable int NewFD; - mutable sys::fs::file_status NewStatus; public: NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); @@ -426,7 +423,7 @@ public: object::Archive::child_iterator getOld() const; StringRef getNew() const; - int getFD() const; + int getFD(sys::fs::file_status &NewStatus) const; const sys::fs::file_status &getStatus() const; }; } @@ -438,7 +435,7 @@ NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, : IsNewMember(false), Name(Name), OldI(I) {} NewArchiveIterator::NewArchiveIterator(StringRef NewFilename, StringRef Name) - : IsNewMember(true), Name(Name), NewFilename(NewFilename), NewFD(-1) {} + : IsNewMember(true), Name(Name), NewFilename(NewFilename) {} StringRef NewArchiveIterator::getName() const { return Name; } @@ -454,10 +451,9 @@ StringRef NewArchiveIterator::getNew() const { return NewFilename; } -int NewArchiveIterator::getFD() const { +int NewArchiveIterator::getFD(sys::fs::file_status &NewStatus) const { assert(IsNewMember); - if (NewFD != -1) - return NewFD; + int NewFD; failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); assert(NewFD != -1); @@ -472,12 +468,6 @@ int NewArchiveIterator::getFD() const { return NewFD; } -const sys::fs::file_status &NewArchiveIterator::getStatus() const { - assert(IsNewMember); - assert(NewFD != -1 && "Must call getFD first"); - return NewStatus; -} - template void addMember(std::vector &Members, T I, StringRef Name, int Pos = -1) { @@ -694,10 +684,11 @@ static void writeStringTable(raw_fd_ostream &Out, Out.seek(Pos); } -static void -writeSymbolTable(raw_fd_ostream &Out, ArrayRef Members, - ArrayRef Buffers, - std::vector> &MemberOffsetRefs) { +// Returns the offset of the first reference to a member offset. +static unsigned writeSymbolTable(raw_fd_ostream &Out, + ArrayRef Members, + ArrayRef Buffers, + std::vector &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; @@ -732,14 +723,14 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef Members, failIfError(S.printName(NameOS)); NameOS << '\0'; ++NumSyms; - MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); + MemberOffsetRefs.push_back(MemberNum); print32BE(Out, 0); } } Out << NameOS.str(); if (StartOffset == 0) - return; + return 0; if (Out.tell() % 2) Out << '\0'; @@ -750,6 +741,7 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef Members, Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); + return StartOffset + 4; } static void @@ -764,10 +756,11 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, raw_fd_ostream &Out = Output.os(); Out << "!\n"; - std::vector > MemberOffsetRefs; + std::vector MemberOffsetRefs; std::vector> Buffers; std::vector Members; + std::vector NewMemberStatus; for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { NewArchiveIterator &Member = NewMembers[I]; @@ -775,11 +768,14 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, if (Member.isNewMember()) { StringRef Filename = Member.getNew(); - int FD = Member.getFD(); - const sys::fs::file_status &Status = Member.getStatus(); + NewMemberStatus.resize(NewMemberStatus.size() + 1); + sys::fs::file_status &Status = NewMemberStatus.back(); + int FD = Member.getFD(Status); ErrorOr> MemberBufferOrErr = MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); failIfError(MemberBufferOrErr.getError(), Filename); + if (close(FD) != 0) + fail("Could not close file"); Buffers.push_back(std::move(MemberBufferOrErr.get())); MemberRef = Buffers.back()->getMemBufferRef(); } else { @@ -792,35 +788,31 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, Members.push_back(MemberRef); } + unsigned MemberReferenceOffset = 0; if (Symtab) { - writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); + MemberReferenceOffset = + writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); } std::vector StringMapIndexes; writeStringTable(Out, NewMembers, StringMapIndexes); - std::vector >::iterator MemberRefsI = - MemberOffsetRefs.begin(); - unsigned MemberNum = 0; unsigned LongNameMemberNum = 0; + unsigned NewMemberNum = 0; + std::vector MemberOffset; for (std::vector::iterator I = NewMembers.begin(), E = NewMembers.end(); I != E; ++I, ++MemberNum) { unsigned Pos = Out.tell(); - while (MemberRefsI != MemberOffsetRefs.end() && - MemberRefsI->second == MemberNum) { - Out.seek(MemberRefsI->first); - print32BE(Out, Pos); - ++MemberRefsI; - } - Out.seek(Pos); + MemberOffset.push_back(Pos); MemoryBufferRef File = Members[MemberNum]; if (I->isNewMember()) { StringRef FileName = I->getNew(); - const sys::fs::file_status &Status = I->getStatus(); + const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum]; + NewMemberNum++; StringRef Name = sys::path::filename(FileName); if (Name.size() < 16) @@ -853,6 +845,12 @@ performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, Out << '\n'; } + if (MemberReferenceOffset) { + Out.seek(MemberReferenceOffset); + for (unsigned MemberNum : MemberOffsetRefs) + print32BE(Out, MemberOffset[MemberNum]); + } + Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index f95b272..8aa5697 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -28,10 +28,10 @@ //===----------------------------------------------------------------------===// #include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/ADT/Optional.h" #include "llvm/Bitcode/LLVMBitCodes.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Verifier.h" -#include "llvm/ADT/Optional.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" @@ -222,8 +222,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::FUNC_CODE_INST_BINOP: return "INST_BINOP"; case bitc::FUNC_CODE_INST_CAST: return "INST_CAST"; - case bitc::FUNC_CODE_INST_GEP: return "INST_GEP"; - case bitc::FUNC_CODE_INST_INBOUNDS_GEP: return "INST_INBOUNDS_GEP"; + case bitc::FUNC_CODE_INST_GEP_OLD: + return "INST_GEP_OLD"; + case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD: + return "INST_INBOUNDS_GEP_OLD"; case bitc::FUNC_CODE_INST_SELECT: return "INST_SELECT"; case bitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT"; case bitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT"; @@ -248,6 +250,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: return "DEBUG_LOC_AGAIN"; case bitc::FUNC_CODE_INST_CALL: return "INST_CALL"; case bitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC"; + case bitc::FUNC_CODE_INST_GEP: + return "INST_GEP"; } case bitc::VALUE_SYMTAB_BLOCK_ID: switch (CodeID) { @@ -267,7 +271,9 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::METADATA_NAME: return "METADATA_NAME"; case bitc::METADATA_KIND: return "METADATA_KIND"; case bitc::METADATA_NODE: return "METADATA_NODE"; - case bitc::METADATA_FN_NODE: return "METADATA_FN_NODE"; + case bitc::METADATA_VALUE: return "METADATA_VALUE"; + case bitc::METADATA_OLD_NODE: return "METADATA_OLD_NODE"; + case bitc::METADATA_OLD_FN_NODE: return "METADATA_OLD_FN_NODE"; case bitc::METADATA_NAMED_NODE: return "METADATA_NAMED_NODE"; } case bitc::USELIST_BLOCK_ID: diff --git a/tools/llvm-c-test/Android.mk b/tools/llvm-c-test/Android.mk index 3ab8830..6b978c0 100644 --- a/tools/llvm-c-test/Android.mk +++ b/tools/llvm-c-test/Android.mk @@ -13,6 +13,7 @@ llvm_c_test_SRC_FILES := \ helpers.c \ include-all.c \ main.c \ + metadata.c \ module.c \ object.c \ targets.c \ diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt index 989678b..f22dffb 100644 --- a/tools/llvm-c-test/CMakeLists.txt +++ b/tools/llvm-c-test/CMakeLists.txt @@ -7,7 +7,26 @@ set(LLVM_LINK_COMPONENTS Target ) -if(TARGET LLVM) +# We should only have llvm-c-test use libLLVM if libLLVM is built with the +# default list of components. Using libLLVM with custom components can result in +# build failures. + +set (USE_LLVM_DYLIB FALSE) + +if (TARGET LLVM) + set (USE_LLVM_DYLIB TRUE) + if (DEFINED LLVM_DYLIB_COMPONENTS) + foreach(c in ${LLVM_LINK_COMPONENTS}) + list(FIND LLVM_DYLIB_COMPONENTS ${c} C_IDX) + if (C_IDX EQUAL -1) + set(USE_LLVM_DYLIB FALSE) + break() + endif() + endforeach() + endif() +endif() + +if(USE_LLVM_DYLIB) set(LLVM_LINK_COMPONENTS) endif() @@ -22,11 +41,11 @@ add_llvm_tool(llvm-c-test include-all.c main.c module.c + metadata.c object.c targets.c ) -# Use libLLVM.so if it is available. -if(TARGET LLVM) +if(USE_LLVM_DYLIB) target_link_libraries(llvm-c-test LLVM) endif() diff --git a/tools/llvm-c-test/llvm-c-test.h b/tools/llvm-c-test/llvm-c-test.h index 0a25aa6..1b4976a 100644 --- a/tools/llvm-c-test/llvm-c-test.h +++ b/tools/llvm-c-test/llvm-c-test.h @@ -27,6 +27,10 @@ int calc(void); // disassemble.c int disassemble(void); +// metadata.c +int add_named_metadata_operand(void); +int set_metadata(void); + // object.c int object_list_sections(void); int object_list_symbols(void); diff --git a/tools/llvm-c-test/main.c b/tools/llvm-c-test/main.c index 72f8b04..59cc749 100644 --- a/tools/llvm-c-test/main.c +++ b/tools/llvm-c-test/main.c @@ -65,6 +65,10 @@ int main(int argc, char **argv) { return disassemble(); } else if (argc == 2 && !strcmp(argv[1], "--calc")) { return calc(); + } else if (argc == 2 && !strcmp(argv[1], "--add-named-metadata-operand")) { + return add_named_metadata_operand(); + } else if (argc == 2 && !strcmp(argv[1], "--set-metadata")) { + return set_metadata(); } else { print_usage(); } diff --git a/tools/llvm-c-test/metadata.c b/tools/llvm-c-test/metadata.c new file mode 100644 index 0000000..b64a696 --- /dev/null +++ b/tools/llvm-c-test/metadata.c @@ -0,0 +1,43 @@ +/*===-- object.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file implements the --add-named-metadata-operand and --set-metadata *| +|* commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Core.h" + +int add_named_metadata_operand(void) { + LLVMModuleRef m = LLVMModuleCreateWithName("Mod"); + LLVMValueRef values[] = { LLVMConstInt(LLVMInt32Type(), 0, 0) }; + + // This used to trigger an assertion + LLVMAddNamedMetadataOperand(m, "name", LLVMMDNode(values, 1)); + + LLVMDisposeModule(m); + + return 0; +} + +int set_metadata(void) { + LLVMBuilderRef b = LLVMCreateBuilder(); + LLVMValueRef values[] = { LLVMConstInt(LLVMInt32Type(), 0, 0) }; + + // This used to trigger an assertion + LLVMSetMetadata( + LLVMBuildRetVoid(b), + LLVMGetMDKindID("kind", 4), + LLVMMDNode(values, 1)); + + LLVMDisposeBuilder(b); + + return 0; +} diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in index 59b5835..f741663 100644 --- a/tools/llvm-config/BuildVariables.inc.in +++ b/tools/llvm-config/BuildVariables.inc.in @@ -23,5 +23,6 @@ #define LLVM_LDFLAGS "" #define LLVM_CXXFLAGS " -fPIC -fvisibility-inlines-hidden -Wall -W -Wno-unused-parameter -Wwrite-strings -Wmissing-field-initializers -pedantic -Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor -std=c++11 -fcolor-diagnostics -ffunction-sections -fdata-sections -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS" #define LLVM_BUILDMODE "" +#define LLVM_LIBDIR_SUFFIX "" #define LLVM_TARGETS_BUILT "X86 AArch64 ARM Mips" #define LLVM_SYSTEM_LIBS "-lrt -ldl -ltinfo -lpthread" diff --git a/tools/llvm-config/Makefile b/tools/llvm-config/Makefile index b78551e..1ff8b6f 100644 --- a/tools/llvm-config/Makefile +++ b/tools/llvm-config/Makefile @@ -59,6 +59,8 @@ $(ObjDir)/BuildVariables.inc: $(BUILDVARIABLES_SRCPATH) Makefile $(ObjDir)/.dir >> temp.sed $(Verb) $(ECHO) 's/@LLVM_BUILDMODE@/$(subst /,\/,$(BuildMode))/' \ >> temp.sed + $(Verb) $(ECHO) 's/@LLVM_LIBDIR_SUFFIX@//' \ + >> temp.sed $(Verb) $(ECHO) 's/@LLVM_SYSTEM_LIBS@/$(subst /,\/,$(LLVM_SYSTEM_LIBS))/' \ >> temp.sed $(Verb) $(ECHO) 's/@LLVM_TARGETS_BUILT@/$(subst /,\/,$(TARGETS_TO_BUILD))/' \ diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp index ed1c8c3..224035a 100644 --- a/tools/llvm-config/llvm-config.cpp +++ b/tools/llvm-config/llvm-config.cpp @@ -243,16 +243,18 @@ int main(int argc, char **argv) { case MakefileStyle: ActivePrefix = ActiveObjRoot; ActiveBinDir = ActiveObjRoot + "/" + build_mode + "/bin"; - ActiveLibDir = ActiveObjRoot + "/" + build_mode + "/lib"; + ActiveLibDir = + ActiveObjRoot + "/" + build_mode + "/lib" + LLVM_LIBDIR_SUFFIX; break; case CMakeStyle: ActiveBinDir = ActiveObjRoot + "/bin"; - ActiveLibDir = ActiveObjRoot + "/lib"; + ActiveLibDir = ActiveObjRoot + "/lib" + LLVM_LIBDIR_SUFFIX; break; case CMakeBuildModeStyle: ActivePrefix = ActiveObjRoot; ActiveBinDir = ActiveObjRoot + "/bin/" + build_mode; - ActiveLibDir = ActiveObjRoot + "/lib/" + build_mode; + ActiveLibDir = + ActiveObjRoot + "/lib" + LLVM_LIBDIR_SUFFIX + "/" + build_mode; break; } @@ -263,7 +265,7 @@ int main(int argc, char **argv) { ActivePrefix = CurrentExecPrefix; ActiveIncludeDir = ActivePrefix + "/include"; ActiveBinDir = ActivePrefix + "/bin"; - ActiveLibDir = ActivePrefix + "/lib"; + ActiveLibDir = ActivePrefix + "/lib" + LLVM_LIBDIR_SUFFIX; ActiveIncludeOption = "-I" + ActiveIncludeDir; } diff --git a/tools/llvm-cov/Android.mk b/tools/llvm-cov/Android.mk index d76c940..798e601 100644 --- a/tools/llvm-cov/Android.mk +++ b/tools/llvm-cov/Android.mk @@ -11,7 +11,6 @@ llvm_cov_SRC_FILES := \ CodeCoverage.cpp \ CoverageFilters.cpp \ CoverageReport.cpp \ - CoverageSummary.cpp \ CoverageSummaryInfo.cpp \ gcov.cpp \ llvm-cov.cpp \ diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt index b2d2b89..193218a 100644 --- a/tools/llvm-cov/CMakeLists.txt +++ b/tools/llvm-cov/CMakeLists.txt @@ -6,7 +6,6 @@ add_llvm_tool(llvm-cov CodeCoverage.cpp CoverageFilters.cpp CoverageReport.cpp - CoverageSummary.cpp CoverageSummaryInfo.cpp SourceCoverageView.cpp TestingSupport.cpp diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp index 093525e..cf8ab33 100644 --- a/tools/llvm-cov/CodeCoverage.cpp +++ b/tools/llvm-cov/CodeCoverage.cpp @@ -14,24 +14,21 @@ //===----------------------------------------------------------------------===// #include "RenderingSupport.h" -#include "CoverageViewOptions.h" #include "CoverageFilters.h" -#include "SourceCoverageView.h" -#include "CoverageSummary.h" #include "CoverageReport.h" -#include "llvm/ADT/StringRef.h" +#include "CoverageViewOptions.h" +#include "SourceCoverageView.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ProfileData/CoverageMapping.h" -#include "llvm/ProfileData/CoverageMappingReader.h" +#include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Path.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" #include #include @@ -327,10 +324,11 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) { for (const auto &File : InputSourceFiles) { SmallString<128> Path(File); - if (std::error_code EC = sys::fs::make_absolute(Path)) { - errs() << "error: " << File << ": " << EC.message(); - return 1; - } + if (!CompareFilenamesOnly) + if (std::error_code EC = sys::fs::make_absolute(Path)) { + errs() << "error: " << File << ": " << EC.message(); + return 1; + } SourceFiles.push_back(Path.str()); } return 0; @@ -461,15 +459,11 @@ int CodeCoverageTool::report(int argc, const char **argv, if (!Coverage) return 1; - CoverageSummary Summarizer; - Summarizer.createSummaries(*Coverage); - CoverageReport Report(ViewOpts, Summarizer); - if (SourceFiles.empty() && Filters.empty()) { + CoverageReport Report(ViewOpts, std::move(Coverage)); + if (SourceFiles.empty()) Report.renderFileReports(llvm::outs()); - return 0; - } - - Report.renderFunctionReports(llvm::outs()); + else + Report.renderFunctionReports(SourceFiles, llvm::outs()); return 0; } diff --git a/tools/llvm-cov/CoverageFilters.h b/tools/llvm-cov/CoverageFilters.h index e543005..dc5dc98 100644 --- a/tools/llvm-cov/CoverageFilters.h +++ b/tools/llvm-cov/CoverageFilters.h @@ -15,8 +15,8 @@ #define LLVM_COV_COVERAGEFILTERS_H #include "llvm/ProfileData/CoverageMapping.h" -#include #include +#include namespace llvm { diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp index 7ac9355..497c2f8 100644 --- a/tools/llvm-cov/CoverageReport.cpp +++ b/tools/llvm-cov/CoverageReport.cpp @@ -12,10 +12,9 @@ //===----------------------------------------------------------------------===// #include "CoverageReport.h" -#include "CoverageSummary.h" #include "RenderingSupport.h" -#include "llvm/Support/Format.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" using namespace llvm; namespace { @@ -156,14 +155,15 @@ void CoverageReport::render(const FunctionCoverageSummary &Function, OS << "\n"; } -void CoverageReport::renderFunctionReports(raw_ostream &OS) { +void CoverageReport::renderFunctionReports(ArrayRef Files, + raw_ostream &OS) { bool isFirst = true; - for (const auto &File : Summary.getFileSummaries()) { + for (StringRef Filename : Files) { if (isFirst) isFirst = false; else OS << "\n"; - OS << "File '" << File.Name << "':\n"; + OS << "File '" << Filename << "':\n"; OS << column("Name", FunctionReportColumns[0]) << column("Regions", FunctionReportColumns[1], Column::RightAlignment) << column("Miss", FunctionReportColumns[2], Column::RightAlignment) @@ -174,13 +174,19 @@ void CoverageReport::renderFunctionReports(raw_ostream &OS) { OS << "\n"; renderDivider(FunctionReportColumns, OS); OS << "\n"; - for (const auto &Function : File.FunctionSummaries) + FunctionCoverageSummary Totals("TOTAL"); + for (const auto &F : Coverage->getCoveredFunctions(Filename)) { + FunctionCoverageSummary Function = FunctionCoverageSummary::get(F); + ++Totals.ExecutionCount; + Totals.RegionCoverage += Function.RegionCoverage; + Totals.LineCoverage += Function.LineCoverage; render(Function, OS); - renderDivider(FunctionReportColumns, OS); - OS << "\n"; - render(FunctionCoverageSummary("TOTAL", /*ExecutionCount=*/0, - File.RegionCoverage, File.LineCoverage), - OS); + } + if (Totals.ExecutionCount) { + renderDivider(FunctionReportColumns, OS); + OS << "\n"; + render(Totals, OS); + } } } @@ -194,9 +200,17 @@ void CoverageReport::renderFileReports(raw_ostream &OS) { << "\n"; renderDivider(FileReportColumns, OS); OS << "\n"; - for (const auto &File : Summary.getFileSummaries()) - render(File, OS); + FileCoverageSummary Totals("TOTAL"); + for (StringRef Filename : Coverage->getUniqueSourceFiles()) { + FileCoverageSummary Summary(Filename); + for (const auto &F : Coverage->getCoveredFunctions(Filename)) { + FunctionCoverageSummary Function = FunctionCoverageSummary::get(F); + Summary.addFunction(Function); + Totals.addFunction(Function); + } + render(Summary, OS); + } renderDivider(FileReportColumns, OS); OS << "\n"; - render(Summary.getCombinedFileSummaries(), OS); + render(Totals, OS); } diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h index e8d34f2..7ec3df9 100644 --- a/tools/llvm-cov/CoverageReport.h +++ b/tools/llvm-cov/CoverageReport.h @@ -14,24 +14,25 @@ #ifndef LLVM_COV_COVERAGEREPORT_H #define LLVM_COV_COVERAGEREPORT_H +#include "CoverageSummaryInfo.h" #include "CoverageViewOptions.h" -#include "CoverageSummary.h" namespace llvm { /// \brief Displays the code coverage report. class CoverageReport { const CoverageViewOptions &Options; - CoverageSummary &Summary; + std::unique_ptr Coverage; void render(const FileCoverageSummary &File, raw_ostream &OS); void render(const FunctionCoverageSummary &Function, raw_ostream &OS); public: - CoverageReport(const CoverageViewOptions &Options, CoverageSummary &Summary) - : Options(Options), Summary(Summary) {} + CoverageReport(const CoverageViewOptions &Options, + std::unique_ptr Coverage) + : Options(Options), Coverage(std::move(Coverage)) {} - void renderFunctionReports(raw_ostream &OS); + void renderFunctionReports(ArrayRef Files, raw_ostream &OS); void renderFileReports(raw_ostream &OS); }; diff --git a/tools/llvm-cov/CoverageSummary.cpp b/tools/llvm-cov/CoverageSummary.cpp deleted file mode 100644 index 059c8c8..0000000 --- a/tools/llvm-cov/CoverageSummary.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===- CoverageSummary.cpp - Code coverage summary ------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class implements data management and rendering for the code coverage -// summaries of all files and functions. -// -//===----------------------------------------------------------------------===// - -#include "CoverageSummary.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Format.h" - -using namespace llvm; - -unsigned CoverageSummary::getFileID(StringRef Filename) { - for (unsigned I = 0, E = Filenames.size(); I < E; ++I) { - if (sys::fs::equivalent(Filenames[I], Filename)) - return I; - } - Filenames.push_back(Filename); - return Filenames.size() - 1; -} - -void -CoverageSummary::createSummaries(const coverage::CoverageMapping &Coverage) { - for (StringRef Filename : Coverage.getUniqueSourceFiles()) { - size_t PrevSize = FunctionSummaries.size(); - for (const auto &F : Coverage.getCoveredFunctions(Filename)) - FunctionSummaries.push_back(FunctionCoverageSummary::get(F)); - size_t Count = FunctionSummaries.size() - PrevSize; - if (Count == 0) - continue; - FileSummaries.push_back(FileCoverageSummary::get( - Filename, makeArrayRef(FunctionSummaries.data() + PrevSize, Count))); - } -} - -FileCoverageSummary CoverageSummary::getCombinedFileSummaries() { - size_t NumRegions = 0, CoveredRegions = 0; - size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0; - size_t NumFunctionsExecuted = 0, NumFunctions = 0; - for (const auto &File : FileSummaries) { - NumRegions += File.RegionCoverage.NumRegions; - CoveredRegions += File.RegionCoverage.Covered; - - NumLines += File.LineCoverage.NumLines; - NonCodeLines += File.LineCoverage.NonCodeLines; - CoveredLines += File.LineCoverage.Covered; - - NumFunctionsExecuted += File.FunctionCoverage.Executed; - NumFunctions += File.FunctionCoverage.NumFunctions; - } - return FileCoverageSummary( - "TOTAL", RegionCoverageInfo(CoveredRegions, NumRegions), - LineCoverageInfo(CoveredLines, NonCodeLines, NumLines), - FunctionCoverageInfo(NumFunctionsExecuted, NumFunctions), - None); -} diff --git a/tools/llvm-cov/CoverageSummary.h b/tools/llvm-cov/CoverageSummary.h deleted file mode 100644 index 9dbebde..0000000 --- a/tools/llvm-cov/CoverageSummary.h +++ /dev/null @@ -1,45 +0,0 @@ -//===- CoverageSummary.h - Code coverage summary --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This class implements data management and rendering for the code coverage -// summaries of all files and functions. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_COV_COVERAGESUMMARY_H -#define LLVM_COV_COVERAGESUMMARY_H - -#include "CoverageSummaryInfo.h" -#include - -namespace llvm { - -/// \brief Manager for the function and file code coverage summaries. -class CoverageSummary { - std::vector Filenames; - std::vector FunctionSummaries; - std::vector> FunctionSummariesFileIDs; - std::vector FileSummaries; - - unsigned getFileID(StringRef Filename); - -public: - void createSummaries(const coverage::CoverageMapping &Coverage); - - ArrayRef getFileSummaries() { return FileSummaries; } - - FileCoverageSummary getCombinedFileSummaries(); - - void render(const FunctionCoverageSummary &Summary, raw_ostream &OS); - - void render(raw_ostream &OS); -}; -} - -#endif // LLVM_COV_COVERAGESUMMARY_H diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp index dd78ace..de89750 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -69,28 +69,3 @@ FunctionCoverageSummary::get(const coverage::FunctionRecord &Function) { RegionCoverageInfo(CoveredRegions, NumCodeRegions), LineCoverageInfo(CoveredLines, 0, NumLines)); } - -FileCoverageSummary -FileCoverageSummary::get(StringRef Name, - ArrayRef FunctionSummaries) { - size_t NumRegions = 0, CoveredRegions = 0; - size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0; - size_t NumFunctionsExecuted = 0; - for (const auto &Func : FunctionSummaries) { - CoveredRegions += Func.RegionCoverage.Covered; - NumRegions += Func.RegionCoverage.NumRegions; - - CoveredLines += Func.LineCoverage.Covered; - NonCodeLines += Func.LineCoverage.NonCodeLines; - NumLines += Func.LineCoverage.NumLines; - - if (Func.ExecutionCount != 0) - ++NumFunctionsExecuted; - } - - return FileCoverageSummary( - Name, RegionCoverageInfo(CoveredRegions, NumRegions), - LineCoverageInfo(CoveredLines, NonCodeLines, NumLines), - FunctionCoverageInfo(NumFunctionsExecuted, FunctionSummaries.size()), - FunctionSummaries); -} diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h index 0036032..c393b00 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.h +++ b/tools/llvm-cov/CoverageSummaryInfo.h @@ -31,10 +31,19 @@ struct RegionCoverageInfo { /// \brief The total number of regions in a function/file. size_t NumRegions; + RegionCoverageInfo() : Covered(0), NotCovered(0), NumRegions(0) {} + RegionCoverageInfo(size_t Covered, size_t NumRegions) : Covered(Covered), NotCovered(NumRegions - Covered), NumRegions(NumRegions) {} + RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) { + Covered += RHS.Covered; + NotCovered += RHS.NotCovered; + NumRegions += RHS.NumRegions; + return *this; + } + bool isFullyCovered() const { return Covered == NumRegions; } double getPercentCovered() const { @@ -56,10 +65,21 @@ struct LineCoverageInfo { /// \brief The total number of lines in a function/file. size_t NumLines; + LineCoverageInfo() + : Covered(0), NotCovered(0), NonCodeLines(0), NumLines(0) {} + LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines) : Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered), NonCodeLines(NumNonCodeLines), NumLines(NumLines) {} + LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) { + Covered += RHS.Covered; + NotCovered += RHS.NotCovered; + NonCodeLines += RHS.NonCodeLines; + NumLines += RHS.NumLines; + return *this; + } + bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); } double getPercentCovered() const { @@ -75,9 +95,17 @@ struct FunctionCoverageInfo { /// \brief The total number of functions in this file. size_t NumFunctions; + FunctionCoverageInfo() : Executed(0), NumFunctions(0) {} + FunctionCoverageInfo(size_t Executed, size_t NumFunctions) : Executed(Executed), NumFunctions(NumFunctions) {} + void addFunction(bool Covered) { + if (Covered) + ++Executed; + ++NumFunctions; + } + bool isFullyCovered() const { return Executed == NumFunctions; } double getPercentCovered() const { @@ -92,6 +120,8 @@ struct FunctionCoverageSummary { RegionCoverageInfo RegionCoverage; LineCoverageInfo LineCoverage; + FunctionCoverageSummary(StringRef Name) : Name(Name), ExecutionCount(0) {} + FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount, const RegionCoverageInfo &RegionCoverage, const LineCoverageInfo &LineCoverage) @@ -111,21 +141,14 @@ struct FileCoverageSummary { RegionCoverageInfo RegionCoverage; LineCoverageInfo LineCoverage; FunctionCoverageInfo FunctionCoverage; - /// \brief The summary of every function - /// in this file. - ArrayRef FunctionSummaries; - - FileCoverageSummary(StringRef Name, const RegionCoverageInfo &RegionCoverage, - const LineCoverageInfo &LineCoverage, - const FunctionCoverageInfo &FunctionCoverage, - ArrayRef FunctionSummaries) - : Name(Name), RegionCoverage(RegionCoverage), LineCoverage(LineCoverage), - FunctionCoverage(FunctionCoverage), - FunctionSummaries(FunctionSummaries) {} - - /// \brief Compute the code coverage summary for a file. - static FileCoverageSummary - get(StringRef Name, ArrayRef FunctionSummaries); + + FileCoverageSummary(StringRef Name) : Name(Name) {} + + void addFunction(const FunctionCoverageSummary &Function) { + RegionCoverage += Function.RegionCoverage; + LineCoverage += Function.LineCoverage; + FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0); + } }; } // namespace llvm diff --git a/tools/llvm-cov/RenderingSupport.h b/tools/llvm-cov/RenderingSupport.h index 0271329..3ef155d 100644 --- a/tools/llvm-cov/RenderingSupport.h +++ b/tools/llvm-cov/RenderingSupport.h @@ -18,7 +18,7 @@ namespace llvm { /// \brief A helper class that resets the output stream's color if needed /// when destroyed. class ColoredRawOstream { - ColoredRawOstream(const ColoredRawOstream &OS) LLVM_DELETED_FUNCTION; + ColoredRawOstream(const ColoredRawOstream &OS) = delete; public: raw_ostream &OS; diff --git a/tools/llvm-cov/SourceCoverageView.h b/tools/llvm-cov/SourceCoverageView.h index d92a748..9e6fe5f 100644 --- a/tools/llvm-cov/SourceCoverageView.h +++ b/tools/llvm-cov/SourceCoverageView.h @@ -90,15 +90,14 @@ private: bool hasMultipleRegions() const { return RegionCount > 1; } void addRegionStartCount(uint64_t Count) { - Mapped = true; - ExecutionCount = Count; + // The max of all region starts is the most interesting value. + addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count); ++RegionCount; } void addRegionCount(uint64_t Count) { Mapped = true; - if (!RegionCount) - ExecutionCount = Count; + ExecutionCount = Count; } }; diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp index 537f133..6959897 100644 --- a/tools/llvm-cov/TestingSupport.cpp +++ b/tools/llvm-cov/TestingSupport.cpp @@ -8,15 +8,14 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/LEB128.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryObject.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/PrettyStackTrace.h" -#include +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include +#include using namespace llvm; using namespace object; diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp index 4c9195a..c0a48f8 100644 --- a/tools/llvm-cov/gcov.cpp +++ b/tools/llvm-cov/gcov.cpp @@ -17,7 +17,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/GCOV.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" @@ -81,7 +80,7 @@ void reportCoverage(StringRef SourceFile, StringRef ObjectDir, FileInfo FI(Options); GF.collectLineCounts(FI); - FI.print(SourceFile, GCNO, GCDA); + FI.print(llvm::outs(), SourceFile, GCNO, GCDA); } int gcovMain(int argc, const char *argv[]) { diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index a67859e..86ec26d 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -13,8 +13,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include using namespace llvm; diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index fb73717..1c3a9ce 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -20,6 +20,8 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" @@ -112,6 +114,24 @@ public: } // end anon namespace +static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) { + raw_ostream &OS = errs(); + OS << (char *)Context << ": "; + switch (DI.getSeverity()) { + case DS_Error: OS << "error: "; break; + case DS_Warning: OS << "warning: "; break; + case DS_Remark: OS << "remark: "; break; + case DS_Note: OS << "note: "; break; + } + + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + OS << '\n'; + + if (DI.getSeverity() == DS_Error) + exit(1); +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); @@ -120,6 +140,7 @@ int main(int argc, char **argv) { LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + Context.setDiagnosticHandler(diagnosticHandler, argv[0]); cl::ParseCommandLineOptions(argc, argv, "llvm .bc -> .ll disassembler\n"); @@ -127,30 +148,17 @@ int main(int argc, char **argv) { std::unique_ptr M; // Use the bitcode streaming interface - DataStreamer *streamer = getDataFileStreamer(InputFilename, &ErrorMessage); - if (streamer) { + DataStreamer *Streamer = getDataFileStreamer(InputFilename, &ErrorMessage); + if (Streamer) { std::string DisplayFilename; if (InputFilename == "-") DisplayFilename = ""; else DisplayFilename = InputFilename; - M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context, - &ErrorMessage)); - if(M.get()) { - if (std::error_code EC = M->materializeAllPermanently()) { - ErrorMessage = EC.message(); - M.reset(); - } - } - } - - if (!M.get()) { - errs() << argv[0] << ": "; - if (ErrorMessage.size()) - errs() << ErrorMessage << "\n"; - else - errs() << "bitcode didn't read correctly.\n"; - return 1; + ErrorOr> MOrErr = + getStreamedBitcodeModule(DisplayFilename, Streamer, Context); + M = std::move(*MOrErr); + M->materializeAllPermanently(); } // Just use stdout. We won't actually print anything on it. diff --git a/tools/llvm-dwarfdump/Android.mk b/tools/llvm-dwarfdump/Android.mk index 61049e8..225004a 100644 --- a/tools/llvm-dwarfdump/Android.mk +++ b/tools/llvm-dwarfdump/Android.mk @@ -11,7 +11,8 @@ llvm_dwarfdump_SRC_FILES := \ llvm-dwarfdump.cpp llvm_dwarfdump_STATIC_LIBRARIES := \ - libLLVMDebugInfo \ + libLLVMDebugInfoDWARF \ + libLLVMDebugInfoPDB \ libLLVMObject \ libLLVMBitReader \ libLLVMMC \ diff --git a/tools/llvm-dwarfdump/CMakeLists.txt b/tools/llvm-dwarfdump/CMakeLists.txt index 288b323..086b139 100644 --- a/tools/llvm-dwarfdump/CMakeLists.txt +++ b/tools/llvm-dwarfdump/CMakeLists.txt @@ -1,5 +1,5 @@ set(LLVM_LINK_COMPONENTS - DebugInfo + DebugInfoDWARF Object Support ) diff --git a/tools/llvm-dwarfdump/LLVMBuild.txt b/tools/llvm-dwarfdump/LLVMBuild.txt index 28b7c4c..a9dca3e 100644 --- a/tools/llvm-dwarfdump/LLVMBuild.txt +++ b/tools/llvm-dwarfdump/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-dwarfdump parent = Tools -required_libraries = DebugInfo Object +required_libraries = DebugInfoDWARF Object diff --git a/tools/llvm-dwarfdump/Makefile b/tools/llvm-dwarfdump/Makefile index 7ca1a8d..00b18c6 100644 --- a/tools/llvm-dwarfdump/Makefile +++ b/tools/llvm-dwarfdump/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-dwarfdump -LINK_COMPONENTS := DebugInfo Object +LINK_COMPONENTS := DebugInfoDWARF Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 1c540c9..a99f57f 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -13,7 +13,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Triple.h" -#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DIContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" #include "llvm/Support/CommandLine.h" @@ -21,7 +21,6 @@ #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 53b2f0d..8cbcdc5 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -20,7 +20,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -246,7 +246,7 @@ 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. - PassManager Passes; + legacy::PassManager Passes; Passes.add(new DataLayoutPass()); // Use correct DataLayout std::vector Gvs(GVs.begin(), GVs.end()); diff --git a/tools/llvm-go/llvm-go.go b/tools/llvm-go/llvm-go.go index 47f9481..c5c3fd2 100644 --- a/tools/llvm-go/llvm-go.go +++ b/tools/llvm-go/llvm-go.go @@ -30,6 +30,7 @@ type pkg struct { var packages = []pkg{ {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"}, + {"tools/llgo", "llvm.org/llgo"}, } type compilerFlags struct { @@ -45,7 +46,7 @@ var components = []string{ "bitwriter", "codegen", "core", - "debuginfo", + "debuginfodwarf", "executionengine", "instrumentation", "interpreter", @@ -136,7 +137,7 @@ type (run_build_sh int) `, flags.cpp, flags.cxx, flags.ld) } -func runGoWithLLVMEnv(args []string, cc, cxx, cppflags, cxxflags, ldflags string) { +func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string) { args = addTag(args, "byollvm") srcdir := llvmConfig("--src-root") @@ -159,6 +160,8 @@ func runGoWithLLVMEnv(args []string, cc, cxx, cppflags, cxxflags, ldflags string } } + newpath := os.Getenv("PATH") + newgopathlist := []string{tmpgopath} newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...) newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator)) @@ -172,24 +175,31 @@ func runGoWithLLVMEnv(args []string, cc, cxx, cppflags, cxxflags, ldflags string "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags, "CGO_LDFLAGS=" + flags.ld + " " + ldflags, "GOPATH=" + newgopath, + "PATH=" + newpath, + } + if llgo != "" { + newenv = append(newenv, "GCCGO=" + llgo) } + for _, v := range os.Environ() { if !strings.HasPrefix(v, "CC=") && !strings.HasPrefix(v, "CXX=") && !strings.HasPrefix(v, "CGO_CPPFLAGS=") && !strings.HasPrefix(v, "CGO_CXXFLAGS=") && !strings.HasPrefix(v, "CGO_LDFLAGS=") && - !strings.HasPrefix(v, "GOPATH=") { + !strings.HasPrefix(v, "GCCGO=") && + !strings.HasPrefix(v, "GOPATH=") && + !strings.HasPrefix(v, "PATH=") { newenv = append(newenv, v) } } - gocmdpath, err := exec.LookPath("go") + gocmdpath, err := exec.LookPath(gocmd) if err != nil { panic(err.Error()) } - proc, err := os.StartProcess(gocmdpath, append([]string{"go"}, args...), + proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...), &os.ProcAttr{ Env: newenv, Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, @@ -222,6 +232,8 @@ func main() { cppflags := os.Getenv("CGO_CPPFLAGS") cxxflags := os.Getenv("CGO_CXXFLAGS") ldflags := os.Getenv("CGO_LDFLAGS") + gocmd := "go" + llgo := "" args := os.Args[1:] DONE: for { @@ -234,6 +246,12 @@ func main() { case strings.HasPrefix(args[0], "cxx="): cxx = args[0][4:] args = args[1:] + case strings.HasPrefix(args[0], "go="): + gocmd = args[0][3:] + args = args[1:] + case strings.HasPrefix(args[0], "llgo="): + llgo = args[0][5:] + args = args[1:] case strings.HasPrefix(args[0], "cppflags="): cppflags = args[0][9:] args = args[1:] @@ -250,7 +268,7 @@ func main() { switch args[0] { case "build", "get", "install", "run", "test": - runGoWithLLVMEnv(args, cc, cxx, cppflags, cxxflags, ldflags) + runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags) case "print-components": printComponents() case "print-config": diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile index 6d72427..06132f9 100644 --- a/tools/llvm-jitlistener/Makefile +++ b/tools/llvm-jitlistener/Makefile @@ -18,7 +18,7 @@ LINK_COMPONENTS := mcjit interpreter nativecodegen bitreader asmparser irreader # Events interface library. If not, this tool will do nothing useful, but it # will build correctly. ifeq ($(USE_INTEL_JITEVENTS), 1) - LINK_COMPONENTS += debuginfo inteljitevents + LINK_COMPONENTS += debuginfodwarf inteljitevents endif # This tool has no plugins, optimize startup time. diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp index 0bb6e8b..c3091a5 100644 --- a/tools/llvm-jitlistener/llvm-jitlistener.cpp +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -17,12 +17,12 @@ #include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/Module.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" @@ -140,7 +140,7 @@ protected: TheJIT.reset(EngineBuilder(std::move(TheModule)) .setEngineKind(EngineKind::JIT) .setErrorStr(&Error) - .setMCJITMemoryManager(MemMgr) + .setMCJITMemoryManager(std::unique_ptr(MemMgr)) .create()); if (Error.empty() == false) errs() << Error; diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 3c950ba..32b3134 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -65,6 +65,14 @@ DSOSymbols("dso-symbol", cl::desc("Symbol to put in the symtab in the resulting dso"), cl::ZeroOrMore); +static cl::opt ListSymbolsOnly( + "list-symbols-only", cl::init(false), + cl::desc("Instead of running LTO, list the symbols in each IR file")); + +static cl::opt SetMergedModule( + "set-merged-module", cl::init(false), + cl::desc("Use the first input module as the merged module")); + namespace { struct ModuleInfo { std::vector CanBeHidden; @@ -90,6 +98,46 @@ void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity, errs() << Msg << "\n"; } +std::unique_ptr +getLocalLTOModule(StringRef Path, std::unique_ptr &Buffer, + const TargetOptions &Options, std::string &Error) { + ErrorOr> BufferOrErr = + MemoryBuffer::getFile(Path); + if (std::error_code EC = BufferOrErr.getError()) { + Error = EC.message(); + return nullptr; + } + Buffer = std::move(BufferOrErr.get()); + return std::unique_ptr(LTOModule::createInLocalContext( + Buffer->getBufferStart(), Buffer->getBufferSize(), Options, Error, Path)); +} + +/// \brief List symbols in each IR file. +/// +/// The main point here is to provide lit-testable coverage for the LTOModule +/// 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) { + for (auto &Filename : InputFilenames) { + std::string Error; + std::unique_ptr Buffer; + std::unique_ptr Module = + getLocalLTOModule(Filename, Buffer, Options, Error); + if (!Module) { + errs() << Command << ": error loading file '" << Filename + << "': " << Error << "\n"; + return 1; + } + + // List the symbols. + outs() << Filename << ":\n"; + for (int I = 0, E = Module->getSymbolCount(); I != E; ++I) + outs() << Module->getSymbolName(I) << "\n"; + } + return 0; +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); @@ -107,6 +155,9 @@ int main(int argc, char **argv) { // set up the TargetOptions for the machine TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); + if (ListSymbolsOnly) + return listSymbols(argv[0], Options); + unsigned BaseArg = 0; LTOCodeGenerator CodeGen; @@ -147,15 +198,22 @@ int main(int argc, char **argv) { return 1; } - if (!CodeGen.addModule(Module.get())) + LTOModule *LTOMod = Module.get(); + + // We use the first input module as the destination module when + // SetMergedModule is true. + if (SetMergedModule && i == BaseArg) { + // Transfer ownership to the code generator. + CodeGen.setModule(Module.release()); + } else if (!CodeGen.addModule(Module.get())) return 1; - unsigned NumSyms = Module->getSymbolCount(); + unsigned NumSyms = LTOMod->getSymbolCount(); for (unsigned I = 0; I < NumSyms; ++I) { - StringRef Name = Module->getSymbolName(I); + StringRef Name = LTOMod->getSymbolName(I); if (!DSOSymbolsSet.count(Name)) continue; - lto_symbol_attributes Attrs = Module->getSymbolAttributes(I); + lto_symbol_attributes Attrs = LTOMod->getSymbolAttributes(I); unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) KeptDSOSyms.push_back(Name); @@ -170,6 +228,9 @@ int main(int argc, char **argv) { for (unsigned i = 0; i < KeptDSOSyms.size(); ++i) CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str()); + // Set cpu and attrs strings for the default target/subtarget. + CodeGen.setCpu(MCPU.c_str()); + std::string attrs; for (unsigned i = 0; i < MAttrs.size(); ++i) { if (i > 0) diff --git a/tools/llvm-mc/Android.mk b/tools/llvm-mc/Android.mk index e6de9eb..ad83637 100644 --- a/tools/llvm-mc/Android.mk +++ b/tools/llvm-mc/Android.mk @@ -37,6 +37,7 @@ llvm_mc_STATIC_LIBRARIES := \ libLLVMX86CodeGen \ libLLVMAsmPrinter \ libLLVMCodeGen \ + libLLVMTransformUtils \ libLLVMAnalysis \ libLLVMTarget \ libLLVMMC \ diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 95d146a..5ffeffc 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -36,7 +36,6 @@ static bool PrintInsts(const MCDisassembler &DisAsm, SourceMgr &SM, raw_ostream &Out, MCStreamer &Streamer, bool InAtomicBlock, const MCSubtargetInfo &STI) { - // Wrap the vector in a MemoryObject. ArrayRef Data(Bytes.first.data(), Bytes.first.size()); // Disassemble it to strings. diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 5da9e86..91bacc0 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -204,16 +204,15 @@ static const Target *GetTarget(const char *ProgName) { return TheTarget; } -static tool_output_file *GetOutputStream() { +static std::unique_ptr GetOutputStream() { if (OutputFilename == "") OutputFilename = "-"; std::error_code EC; - tool_output_file *Out = - new tool_output_file(OutputFilename, EC, sys::fs::F_None); + auto Out = llvm::make_unique(OutputFilename, EC, + sys::fs::F_None); if (EC) { errs() << EC.message() << '\n'; - delete Out; return nullptr; } @@ -239,7 +238,7 @@ static void setDwarfDebugProducer(void) { } static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, - tool_output_file *Out) { + raw_ostream &OS) { AsmLexer Lexer(MAI); Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer()); @@ -258,60 +257,60 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, Error = true; // error already printed. break; case AsmToken::Identifier: - Out->os() << "identifier: " << Lexer.getTok().getString(); + OS << "identifier: " << Lexer.getTok().getString(); break; case AsmToken::Integer: - Out->os() << "int: " << Lexer.getTok().getString(); + OS << "int: " << Lexer.getTok().getString(); break; case AsmToken::Real: - Out->os() << "real: " << Lexer.getTok().getString(); + OS << "real: " << Lexer.getTok().getString(); break; case AsmToken::String: - Out->os() << "string: " << Lexer.getTok().getString(); + OS << "string: " << Lexer.getTok().getString(); break; - case AsmToken::Amp: Out->os() << "Amp"; break; - case AsmToken::AmpAmp: Out->os() << "AmpAmp"; break; - case AsmToken::At: Out->os() << "At"; break; - case AsmToken::Caret: Out->os() << "Caret"; break; - case AsmToken::Colon: Out->os() << "Colon"; break; - case AsmToken::Comma: Out->os() << "Comma"; break; - case AsmToken::Dollar: Out->os() << "Dollar"; break; - case AsmToken::Dot: Out->os() << "Dot"; break; - case AsmToken::EndOfStatement: Out->os() << "EndOfStatement"; break; - case AsmToken::Eof: Out->os() << "Eof"; break; - case AsmToken::Equal: Out->os() << "Equal"; break; - case AsmToken::EqualEqual: Out->os() << "EqualEqual"; break; - case AsmToken::Exclaim: Out->os() << "Exclaim"; break; - case AsmToken::ExclaimEqual: Out->os() << "ExclaimEqual"; break; - case AsmToken::Greater: Out->os() << "Greater"; break; - case AsmToken::GreaterEqual: Out->os() << "GreaterEqual"; break; - case AsmToken::GreaterGreater: Out->os() << "GreaterGreater"; break; - case AsmToken::Hash: Out->os() << "Hash"; break; - case AsmToken::LBrac: Out->os() << "LBrac"; break; - case AsmToken::LCurly: Out->os() << "LCurly"; break; - case AsmToken::LParen: Out->os() << "LParen"; break; - case AsmToken::Less: Out->os() << "Less"; break; - case AsmToken::LessEqual: Out->os() << "LessEqual"; break; - case AsmToken::LessGreater: Out->os() << "LessGreater"; break; - case AsmToken::LessLess: Out->os() << "LessLess"; break; - case AsmToken::Minus: Out->os() << "Minus"; break; - case AsmToken::Percent: Out->os() << "Percent"; break; - case AsmToken::Pipe: Out->os() << "Pipe"; break; - case AsmToken::PipePipe: Out->os() << "PipePipe"; break; - case AsmToken::Plus: Out->os() << "Plus"; break; - case AsmToken::RBrac: Out->os() << "RBrac"; break; - case AsmToken::RCurly: Out->os() << "RCurly"; break; - case AsmToken::RParen: Out->os() << "RParen"; break; - case AsmToken::Slash: Out->os() << "Slash"; break; - case AsmToken::Star: Out->os() << "Star"; break; - case AsmToken::Tilde: Out->os() << "Tilde"; break; + case AsmToken::Amp: OS << "Amp"; break; + case AsmToken::AmpAmp: OS << "AmpAmp"; break; + case AsmToken::At: OS << "At"; break; + case AsmToken::Caret: OS << "Caret"; break; + case AsmToken::Colon: OS << "Colon"; break; + case AsmToken::Comma: OS << "Comma"; break; + case AsmToken::Dollar: OS << "Dollar"; break; + case AsmToken::Dot: OS << "Dot"; break; + case AsmToken::EndOfStatement: OS << "EndOfStatement"; break; + case AsmToken::Eof: OS << "Eof"; break; + case AsmToken::Equal: OS << "Equal"; break; + case AsmToken::EqualEqual: OS << "EqualEqual"; break; + case AsmToken::Exclaim: OS << "Exclaim"; break; + case AsmToken::ExclaimEqual: OS << "ExclaimEqual"; break; + case AsmToken::Greater: OS << "Greater"; break; + case AsmToken::GreaterEqual: OS << "GreaterEqual"; break; + case AsmToken::GreaterGreater: OS << "GreaterGreater"; break; + case AsmToken::Hash: OS << "Hash"; break; + case AsmToken::LBrac: OS << "LBrac"; break; + case AsmToken::LCurly: OS << "LCurly"; break; + case AsmToken::LParen: OS << "LParen"; break; + case AsmToken::Less: OS << "Less"; break; + case AsmToken::LessEqual: OS << "LessEqual"; break; + case AsmToken::LessGreater: OS << "LessGreater"; break; + case AsmToken::LessLess: OS << "LessLess"; break; + case AsmToken::Minus: OS << "Minus"; break; + case AsmToken::Percent: OS << "Percent"; break; + case AsmToken::Pipe: OS << "Pipe"; break; + case AsmToken::PipePipe: OS << "PipePipe"; break; + case AsmToken::Plus: OS << "Plus"; break; + case AsmToken::RBrac: OS << "RBrac"; break; + case AsmToken::RCurly: OS << "RCurly"; break; + case AsmToken::RParen: OS << "RParen"; break; + case AsmToken::Slash: OS << "Slash"; break; + case AsmToken::Star: OS << "Star"; break; + case AsmToken::Tilde: OS << "Tilde"; break; } // Print the token string. - Out->os() << " (\""; - Out->os().write_escaped(Tok.getString()); - Out->os() << "\")\n"; + OS << " (\""; + OS.write_escaped(Tok.getString()); + OS << "\")\n"; } return Error; @@ -333,7 +332,7 @@ static int AssembleInput(const char *ProgName, const Target *TheTarget, } Parser->setShowParsedOperands(ShowInstOperands); - Parser->setTargetParser(*TAP.get()); + Parser->setTargetParser(*TAP); int Res = Parser->Run(NoInitialTextSection); @@ -435,7 +434,7 @@ int main(int argc, char **argv) { FeaturesStr = Features.getString(); } - std::unique_ptr Out(GetOutputStream()); + std::unique_ptr Out = GetOutputStream(); if (!Out) return 1; @@ -466,7 +465,7 @@ int main(int argc, char **argv) { MAB, ShowInst)); } else if (FileType == OFT_Null) { - Str.reset(createNullStreamer(Ctx)); + Str.reset(TheTarget->createNullStreamer(Ctx)); } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); @@ -481,7 +480,7 @@ int main(int argc, char **argv) { bool disassemble = false; switch (Action) { case AC_AsLex: - Res = AsLexInput(SrcMgr, *MAI, Out.get()); + Res = AsLexInput(SrcMgr, *MAI, Out->os()); break; case AC_Assemble: Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI, diff --git a/tools/llvm-nm/Android.mk b/tools/llvm-nm/Android.mk index a17ca4d..e3b66f0 100644 --- a/tools/llvm-nm/Android.mk +++ b/tools/llvm-nm/Android.mk @@ -38,6 +38,7 @@ llvm_nm_STATIC_LIBRARIES := \ libLLVMX86Utils \ libLLVMX86Disassembler \ libLLVMCodeGen \ + libLLVMTransformUtils \ libLLVMAnalysis \ libLLVMTarget \ libLLVMObject \ diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index be2c4fa..f911c72 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -36,8 +36,8 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -1069,7 +1069,6 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { ArchFound = true; ErrorOr> ObjOrErr = I->getAsObjectFile(); - std::unique_ptr A; std::string ArchiveName; std::string ArchitectureName; ArchiveName.clear(); @@ -1086,7 +1085,9 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); - } else if (!I->getAsArchive(A)) { + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { @@ -1133,13 +1134,14 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { I != E; ++I) { if (HostArchName == I->getArchTypeName()) { ErrorOr> ObjOrErr = I->getAsObjectFile(); - std::unique_ptr A; std::string ArchiveName; ArchiveName.clear(); if (ObjOrErr) { ObjectFile &Obj = *ObjOrErr.get(); dumpSymbolNamesFromObject(Obj, false); - } else if (!I->getAsArchive(A)) { + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { @@ -1170,7 +1172,6 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { E = UB->end_objects(); I != E; ++I) { ErrorOr> ObjOrErr = I->getAsObjectFile(); - std::unique_ptr A; std::string ArchiveName; std::string ArchitectureName; ArchiveName.clear(); @@ -1189,7 +1190,8 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { outs() << ":\n"; } dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName); - } else if (!I->getAsArchive(A)) { + } else if (ErrorOr> AOrErr = I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { ErrorOr> ChildOrErr = diff --git a/tools/llvm-objdump/Android.mk b/tools/llvm-objdump/Android.mk index 077e0ee..3b5eafd 100644 --- a/tools/llvm-objdump/Android.mk +++ b/tools/llvm-objdump/Android.mk @@ -14,7 +14,8 @@ llvm_objdump_SRC_FILES := \ MachODump.cpp \ llvm_objdump_STATIC_LIBRARIES := \ - libLLVMDebugInfo \ + libLLVMDebugInfoDWARF \ + libLLVMDebugInfoPDB \ libLLVMARMAsmParser \ libLLVMARMInfo \ libLLVMARMDesc \ @@ -40,6 +41,7 @@ llvm_objdump_STATIC_LIBRARIES := \ libLLVMX86Disassembler \ libLLVMAsmPrinter \ libLLVMCodeGen \ + libLLVMTransformUtils \ libLLVMAnalysis \ libLLVMTarget \ libLLVMObject \ diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 61bf3b3..d717653 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -1,6 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - DebugInfo + DebugInfoDWARF MC MCDisassembler Object diff --git a/tools/llvm-objdump/LLVMBuild.txt b/tools/llvm-objdump/LLVMBuild.txt index d16c501..4232873 100644 --- a/tools/llvm-objdump/LLVMBuild.txt +++ b/tools/llvm-objdump/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-objdump parent = Tools -required_libraries = DebugInfo MC MCDisassembler MCParser Object all-targets +required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Object all-targets diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 3a28703..cae4356 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -17,7 +17,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" #include "llvm/Config/config.h" -#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DIContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" @@ -28,15 +28,17 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" +#include "llvm/Support/FormattedStream.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/FormattedStream.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" @@ -65,6 +67,40 @@ static cl::opt PrintImmHex("print-imm-hex", cl::desc("Use hex format for immediate values")); +cl::opt llvm::UniversalHeaders("universal-headers", + cl::desc("Print Mach-O universal headers " + "(requires -macho)")); + +cl::opt + llvm::ArchiveHeaders("archive-headers", + cl::desc("Print archive headers for Mach-O archives " + "(requires -macho)")); + +cl::opt + llvm::IndirectSymbols("indirect-symbols", + cl::desc("Print indirect symbol table for Mach-O " + "objects (requires -macho)")); + +cl::opt + llvm::DataInCode("data-in-code", + cl::desc("Print the data in code table for Mach-O objects " + "(requires -macho)")); + +cl::opt + llvm::LinkOptHints("link-opt-hints", + cl::desc("Print the linker optimization hints for " + "Mach-O objects (requires -macho)")); + +cl::list + llvm::DumpSections("section", + cl::desc("Prints the specified segment,section for " + "Mach-O objects (requires -macho)")); + +static cl::list + ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; + static std::string ThumbTripleName; static const Target *GetTarget(const MachOObjectFile *MachOObj, @@ -205,8 +241,12 @@ static void getSectionsAndSymbols(const MachO::mach_header Header, std::vector &Symbols, SmallVectorImpl &FoundFns, uint64_t &BaseSegmentAddress) { - for (const SymbolRef &Symbol : MachOObj->symbols()) - Symbols.push_back(Symbol); + for (const SymbolRef &Symbol : MachOObj->symbols()) { + StringRef SymName; + Symbol.getName(SymName); + if (!SymName.startswith("ltmp")) + Symbols.push_back(Symbol); + } for (const SectionRef &Section : MachOObj->sections()) { StringRef SectName; @@ -214,52 +254,1325 @@ static void getSectionsAndSymbols(const MachO::mach_header Header, Sections.push_back(Section); } - MachOObjectFile::LoadCommandInfo Command = - MachOObj->getFirstLoadCommandInfo(); - bool BaseSegmentAddressSet = false; - for (unsigned i = 0;; ++i) { - if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { - // We found a function starts segment, parse the addresses for later - // consumption. - MachO::linkedit_data_command LLC = - MachOObj->getLinkeditDataLoadCommand(Command); + MachOObjectFile::LoadCommandInfo Command = + MachOObj->getFirstLoadCommandInfo(); + bool BaseSegmentAddressSet = false; + for (unsigned i = 0;; ++i) { + if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { + // We found a function starts segment, parse the addresses for later + // consumption. + MachO::linkedit_data_command LLC = + MachOObj->getLinkeditDataLoadCommand(Command); + + MachOObj->ReadULEB128s(LLC.dataoff, FoundFns); + } else if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command); + StringRef SegName = SLC.segname; + if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") { + BaseSegmentAddressSet = true; + BaseSegmentAddress = SLC.vmaddr; + } + } + + if (i == Header.ncmds - 1) + break; + else + Command = MachOObj->getNextLoadCommandInfo(Command); + } +} + +static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, + uint32_t n, uint32_t count, + uint32_t stride, uint64_t addr) { + MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand(); + uint32_t nindirectsyms = Dysymtab.nindirectsyms; + if (n > nindirectsyms) + outs() << " (entries start past the end of the indirect symbol " + "table) (reserved1 field greater than the table size)"; + else if (n + count > nindirectsyms) + outs() << " (entries extends past the end of the indirect symbol " + "table)"; + outs() << "\n"; + uint32_t cputype = O->getHeader().cputype; + if (cputype & MachO::CPU_ARCH_ABI64) + outs() << "address index"; + else + outs() << "address index"; + if (verbose) + outs() << " name\n"; + else + outs() << "\n"; + for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) { + if (cputype & MachO::CPU_ARCH_ABI64) + outs() << format("0x%016" PRIx64, addr + j * stride) << " "; + else + outs() << format("0x%08" PRIx32, addr + j * stride) << " "; + MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand(); + uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j); + if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) { + outs() << "LOCAL\n"; + continue; + } + if (indirect_symbol == + (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) { + outs() << "LOCAL ABSOLUTE\n"; + continue; + } + if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) { + outs() << "ABSOLUTE\n"; + 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() << "?"; + } + outs() << "\n"; + } +} + +static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) { + uint32_t LoadCommandCount = O->getHeader().ncmds; + MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo(); + for (unsigned I = 0;; ++I) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load); + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = O->getSection64(Load, J); + uint32_t section_type = Sec.flags & MachO::SECTION_TYPE; + if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS || + section_type == MachO::S_LAZY_SYMBOL_POINTERS || + section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS || + section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS || + section_type == MachO::S_SYMBOL_STUBS) { + uint32_t stride; + if (section_type == MachO::S_SYMBOL_STUBS) + stride = Sec.reserved2; + else + stride = 8; + if (stride == 0) { + outs() << "Can't print indirect symbols for (" << Sec.segname << "," + << Sec.sectname << ") " + << "(size of stubs in reserved2 field is zero)\n"; + continue; + } + uint32_t count = Sec.size / stride; + outs() << "Indirect symbols for (" << Sec.segname << "," + << Sec.sectname << ") " << count << " entries"; + uint32_t n = Sec.reserved1; + PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr); + } + } + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = O->getSegmentLoadCommand(Load); + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = O->getSection(Load, J); + uint32_t section_type = Sec.flags & MachO::SECTION_TYPE; + if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS || + section_type == MachO::S_LAZY_SYMBOL_POINTERS || + section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS || + section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS || + section_type == MachO::S_SYMBOL_STUBS) { + uint32_t stride; + if (section_type == MachO::S_SYMBOL_STUBS) + stride = Sec.reserved2; + else + stride = 4; + if (stride == 0) { + outs() << "Can't print indirect symbols for (" << Sec.segname << "," + << Sec.sectname << ") " + << "(size of stubs in reserved2 field is zero)\n"; + continue; + } + uint32_t count = Sec.size / stride; + outs() << "Indirect symbols for (" << Sec.segname << "," + << Sec.sectname << ") " << count << " entries"; + uint32_t n = Sec.reserved1; + PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr); + } + } + } + if (I == LoadCommandCount - 1) + break; + else + Load = O->getNextLoadCommandInfo(Load); + } +} + +static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) { + MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand(); + uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry); + outs() << "Data in code table (" << nentries << " entries)\n"; + outs() << "offset length kind\n"; + for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE; + ++DI) { + uint32_t Offset; + DI->getOffset(Offset); + outs() << format("0x%08" PRIx32, Offset) << " "; + uint16_t Length; + DI->getLength(Length); + outs() << format("%6u", Length) << " "; + uint16_t Kind; + DI->getKind(Kind); + if (verbose) { + switch (Kind) { + case MachO::DICE_KIND_DATA: + outs() << "DATA"; + break; + case MachO::DICE_KIND_JUMP_TABLE8: + outs() << "JUMP_TABLE8"; + break; + case MachO::DICE_KIND_JUMP_TABLE16: + outs() << "JUMP_TABLE16"; + break; + case MachO::DICE_KIND_JUMP_TABLE32: + outs() << "JUMP_TABLE32"; + break; + case MachO::DICE_KIND_ABS_JUMP_TABLE32: + outs() << "ABS_JUMP_TABLE32"; + break; + default: + outs() << format("0x%04" PRIx32, Kind); + break; + } + } else + outs() << format("0x%04" PRIx32, Kind); + outs() << "\n"; + } +} + +static void PrintLinkOptHints(MachOObjectFile *O) { + MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand(); + const char *loh = O->getData().substr(LohLC.dataoff, 1).data(); + uint32_t nloh = LohLC.datasize; + outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n"; + for (uint32_t i = 0; i < nloh;) { + unsigned n; + uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n); + i += n; + outs() << " identifier " << identifier << " "; + if (i >= nloh) + return; + switch (identifier) { + case 1: + outs() << "AdrpAdrp\n"; + break; + case 2: + outs() << "AdrpLdr\n"; + break; + case 3: + outs() << "AdrpAddLdr\n"; + break; + case 4: + outs() << "AdrpLdrGotLdr\n"; + break; + case 5: + outs() << "AdrpAddStr\n"; + break; + case 6: + outs() << "AdrpLdrGotStr\n"; + break; + case 7: + outs() << "AdrpAdd\n"; + break; + case 8: + outs() << "AdrpLdrGot\n"; + break; + default: + outs() << "Unknown identifier value\n"; + break; + } + uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n); + i += n; + outs() << " narguments " << narguments << "\n"; + if (i >= nloh) + return; + + for (uint32_t j = 0; j < narguments; j++) { + uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n); + i += n; + outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n"; + if (i >= nloh) + return; + } + } +} + +typedef DenseMap SymbolAddressMap; + +static void CreateSymbolAddressMap(MachOObjectFile *O, + SymbolAddressMap *AddrMap) { + // Create a map of symbol addresses to symbol names. + for (const SymbolRef &Symbol : O->symbols()) { + SymbolRef::Type ST; + Symbol.getType(ST); + if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data || + ST == SymbolRef::ST_Other) { + uint64_t Address; + Symbol.getAddress(Address); + StringRef SymName; + Symbol.getName(SymName); + (*AddrMap)[Address] = SymName; + } + } +} + +// GuessSymbolName is passed the address of what might be a symbol and a +// pointer to the SymbolAddressMap. It returns the name of a symbol +// with that address or nullptr if no symbol is found with that address. +static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) { + const char *SymbolName = nullptr; + // A DenseMap can't lookup up some values. + if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) { + StringRef name = AddrMap->lookup(value); + if (!name.empty()) + SymbolName = name.data(); + } + return SymbolName; +} + +static void DumpCstringChar(const char c) { + char p[2]; + p[0] = c; + p[1] = '\0'; + outs().write_escaped(p); +} + +static void DumpCstringSection(MachOObjectFile *O, const char *sect, + uint32_t sect_size, uint64_t sect_addr, + bool print_addresses) { + for (uint32_t i = 0; i < sect_size; i++) { + if (print_addresses) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, sect_addr + i) << " "; + else + outs() << format("%08" PRIx64, sect_addr + i) << " "; + } + for (; i < sect_size && sect[i] != '\0'; i++) + DumpCstringChar(sect[i]); + if (i < sect_size && sect[i] == '\0') + outs() << "\n"; + } +} + +static void DumpLiteral4(uint32_t l, float f) { + outs() << format("0x%08" PRIx32, l); + if ((l & 0x7f800000) != 0x7f800000) + outs() << format(" (%.16e)\n", f); + else { + if (l == 0x7f800000) + outs() << " (+Infinity)\n"; + else if (l == 0xff800000) + outs() << " (-Infinity)\n"; + else if ((l & 0x00400000) == 0x00400000) + outs() << " (non-signaling Not-a-Number)\n"; + else + outs() << " (signaling Not-a-Number)\n"; + } +} + +static void DumpLiteral4Section(MachOObjectFile *O, const char *sect, + uint32_t sect_size, uint64_t sect_addr, + bool print_addresses) { + for (uint32_t i = 0; i < sect_size; i += sizeof(float)) { + if (print_addresses) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, sect_addr + i) << " "; + else + outs() << format("%08" PRIx64, sect_addr + i) << " "; + } + float f; + memcpy(&f, sect + i, sizeof(float)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(f); + uint32_t l; + memcpy(&l, sect + i, sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(l); + DumpLiteral4(l, f); + } +} + +static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1, + double d) { + outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1); + uint32_t Hi, Lo; + if (O->isLittleEndian()) { + Hi = l1; + Lo = l0; + } else { + Hi = l0; + Lo = l1; + } + // Hi is the high word, so this is equivalent to if(isfinite(d)) + if ((Hi & 0x7ff00000) != 0x7ff00000) + outs() << format(" (%.16e)\n", d); + else { + if (Hi == 0x7ff00000 && Lo == 0) + outs() << " (+Infinity)\n"; + else if (Hi == 0xfff00000 && Lo == 0) + outs() << " (-Infinity)\n"; + else if ((Hi & 0x00080000) == 0x00080000) + outs() << " (non-signaling Not-a-Number)\n"; + else + outs() << " (signaling Not-a-Number)\n"; + } +} + +static void DumpLiteral8Section(MachOObjectFile *O, const char *sect, + uint32_t sect_size, uint64_t sect_addr, + bool print_addresses) { + for (uint32_t i = 0; i < sect_size; i += sizeof(double)) { + if (print_addresses) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, sect_addr + i) << " "; + else + outs() << format("%08" PRIx64, sect_addr + i) << " "; + } + double d; + memcpy(&d, sect + i, sizeof(double)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(d); + uint32_t l0, l1; + memcpy(&l0, sect + i, sizeof(uint32_t)); + memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) { + sys::swapByteOrder(l0); + sys::swapByteOrder(l1); + } + DumpLiteral8(O, l0, l1, d); + } +} + +static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) { + outs() << format("0x%08" PRIx32, l0) << " "; + outs() << format("0x%08" PRIx32, l1) << " "; + outs() << format("0x%08" PRIx32, l2) << " "; + outs() << format("0x%08" PRIx32, l3) << "\n"; +} + +static void DumpLiteral16Section(MachOObjectFile *O, const char *sect, + uint32_t sect_size, uint64_t sect_addr, + bool print_addresses) { + for (uint32_t i = 0; i < sect_size; i += 16) { + if (print_addresses) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, sect_addr + i) << " "; + else + outs() << format("%08" PRIx64, sect_addr + i) << " "; + } + uint32_t l0, l1, l2, l3; + memcpy(&l0, sect + i, sizeof(uint32_t)); + memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t)); + memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t)); + memcpy(&l3, sect + i + 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); + } +} + +static void DumpLiteralPointerSection(MachOObjectFile *O, + const SectionRef &Section, + const char *sect, uint32_t sect_size, + uint64_t sect_addr, + bool print_addresses) { + // Collect the literal sections in this Mach-O file. + std::vector LiteralSections; + for (const SectionRef &Section : O->sections()) { + DataRefImpl Ref = Section.getRawDataRefImpl(); + 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; + } + if (section_type == MachO::S_CSTRING_LITERALS || + section_type == MachO::S_4BYTE_LITERALS || + section_type == MachO::S_8BYTE_LITERALS || + section_type == MachO::S_16BYTE_LITERALS) + LiteralSections.push_back(Section); + } + + // Set the size of the literal pointer. + uint32_t lp_size = O->is64Bit() ? 8 : 4; + + // Collect the external relocation symbols for the the literal pointers. + std::vector> Relocs; + for (const RelocationRef &Reloc : Section.relocations()) { + DataRefImpl Rel; + MachO::any_relocation_info RE; + bool isExtern = false; + Rel = Reloc.getRawDataRefImpl(); + RE = O->getRelocation(Rel); + isExtern = O->getPlainRelocationExternal(RE); + if (isExtern) { + uint64_t RelocOffset; + Reloc.getOffset(RelocOffset); + symbol_iterator RelocSym = Reloc.getSymbol(); + Relocs.push_back(std::make_pair(RelocOffset, *RelocSym)); + } + } + array_pod_sort(Relocs.begin(), Relocs.end()); + + // Dump each literal pointer. + for (uint32_t i = 0; i < sect_size; i += lp_size) { + if (print_addresses) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, sect_addr + i) << " "; + else + outs() << format("%08" PRIx64, sect_addr + i) << " "; + } + uint64_t lp; + if (O->is64Bit()) { + memcpy(&lp, sect + i, sizeof(uint64_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(lp); + } else { + uint32_t li; + memcpy(&li, sect + i, sizeof(uint32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(li); + lp = li; + } + + // 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) + 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; + } + + StringRef BytesStr; + LiteralSections[SectIdx].getContents(BytesStr); + const char *Contents = reinterpret_cast(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"; + } +} + +static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect, + uint32_t sect_size, uint64_t sect_addr, + SymbolAddressMap *AddrMap, + bool verbose) { + uint32_t stride; + if (O->is64Bit()) + stride = sizeof(uint64_t); + else + stride = sizeof(uint32_t); + for (uint32_t i = 0; i < sect_size; i += stride) { + const char *SymbolName = nullptr; + if (O->is64Bit()) { + outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " "; + uint64_t pointer_value; + memcpy(&pointer_value, sect + i, stride); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(pointer_value); + outs() << format("0x%016" PRIx64, pointer_value); + if (verbose) + SymbolName = GuessSymbolName(pointer_value, AddrMap); + } else { + outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " "; + uint32_t pointer_value; + memcpy(&pointer_value, sect + i, stride); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(pointer_value); + outs() << format("0x%08" PRIx32, pointer_value); + if (verbose) + SymbolName = GuessSymbolName(pointer_value, AddrMap); + } + if (SymbolName) + outs() << " " << SymbolName; + outs() << "\n"; + } +} + +static void DumpRawSectionContents(MachOObjectFile *O, const char *sect, + uint32_t size, uint64_t addr) { + uint32_t cputype = O->getHeader().cputype; + if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) { + uint32_t j; + for (uint32_t i = 0; i < size; i += j, addr += j) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, addr) << "\t"; + else + outs() << format("%08" PRIx64, sect) << "\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) << " "; + } + outs() << "\n"; + } + } else { + uint32_t j; + for (uint32_t i = 0; i < size; i += j, addr += j) { + if (O->is64Bit()) + outs() << format("%016" PRIx64, addr) << "\t"; + else + outs() << format("%08" PRIx64, sect) << "\t"; + for (j = 0; j < 4 * sizeof(int32_t) && i + j < size; + j += sizeof(int32_t)) { + if (i + j + sizeof(int32_t) < size) { + uint32_t long_word; + memcpy(&long_word, sect + i + j, sizeof(int32_t)); + if (O->isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(long_word); + outs() << format("%08" PRIx32, long_word) << " "; + } else { + for (uint32_t k = 0; i + j + k < size; k++) { + uint8_t byte_word = *(sect + i + j); + outs() << format("%02" PRIx32, (uint32_t)byte_word) << " "; + } + } + } + outs() << "\n"; + } + } +} + +static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, + StringRef DisSegName, StringRef DisSectName); + +static void DumpSectionContents(StringRef Filename, MachOObjectFile *O, + bool verbose) { + SymbolAddressMap AddrMap; + if (verbose) + CreateSymbolAddressMap(O, &AddrMap); + + for (unsigned i = 0; i < DumpSections.size(); ++i) { + StringRef DumpSection = DumpSections[i]; + std::pair DumpSegSectName; + DumpSegSectName = DumpSection.split(','); + StringRef DumpSegName, DumpSectName; + if (DumpSegSectName.second.size()) { + DumpSegName = DumpSegSectName.first; + DumpSectName = DumpSegSectName.second; + } else { + DumpSegName = ""; + DumpSectName = DumpSegSectName.first; + } + for (const SectionRef &Section : O->sections()) { + StringRef SectName; + Section.getName(SectName); + DataRefImpl Ref = Section.getRawDataRefImpl(); + StringRef SegName = O->getSectionFinalSegmentName(Ref); + if ((DumpSegName.empty() || SegName == DumpSegName) && + (SectName == DumpSectName)) { + outs() << "Contents of (" << SegName << "," << SectName + << ") section\n"; + uint32_t section_flags; + if (O->is64Bit()) { + const MachO::section_64 Sec = O->getSection64(Ref); + section_flags = Sec.flags; + + } else { + const MachO::section Sec = O->getSection(Ref); + section_flags = Sec.flags; + } + uint32_t section_type = section_flags & MachO::SECTION_TYPE; + + StringRef BytesStr; + Section.getContents(BytesStr); + const char *sect = reinterpret_cast(BytesStr.data()); + uint32_t sect_size = BytesStr.size(); + uint64_t sect_addr = Section.getAddress(); + + if (verbose) { + if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) || + (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) { + DisassembleMachO(Filename, O, SegName, SectName); + continue; + } + switch (section_type) { + case MachO::S_REGULAR: + DumpRawSectionContents(O, sect, sect_size, sect_addr); + break; + case MachO::S_ZEROFILL: + 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); + break; + case MachO::S_4BYTE_LITERALS: + DumpLiteral4Section(O, sect, sect_size, sect_addr, verbose); + break; + case MachO::S_8BYTE_LITERALS: + DumpLiteral8Section(O, sect, sect_size, sect_addr, verbose); + break; + case MachO::S_16BYTE_LITERALS: + DumpLiteral16Section(O, sect, sect_size, sect_addr, verbose); + break; + case MachO::S_LITERAL_POINTERS: + DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr, + verbose); + break; + case MachO::S_MOD_INIT_FUNC_POINTERS: + case MachO::S_MOD_TERM_FUNC_POINTERS: + DumpInitTermPointerSection(O, sect, sect_size, sect_addr, &AddrMap, + verbose); + break; + default: + outs() << "Unknown section type (" + << format("0x%08" PRIx32, section_type) << ")\n"; + DumpRawSectionContents(O, sect, sect_size, sect_addr); + break; + } + } else { + if (section_type == MachO::S_ZEROFILL) + outs() << "zerofill section and has no contents in the file\n"; + else + DumpRawSectionContents(O, sect, sect_size, sect_addr); + } + } + } + } +} + +// 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 +// architectures were specified. If not then an error is generated and this +// routine returns false. Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { + if (isa(O) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast(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) { + errs() << "llvm-objdump: file: " + Filename + " does not contain " + << "architecture: " + ArchFlags[i] + "\n"; + return false; + } + } + return true; +} + +// ProcessMachO() is passed a single opened Mach-O file, which may be an +// archive member and or in a slice of a universal file. It prints the +// the file name and header info and then processes it according to the +// command line options. +static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, + StringRef ArchiveMemberName = StringRef(), + StringRef ArchitectureName = StringRef()) { + // If we are doing some processing here on the Mach-O file print the header + // info. And don't print it otherwise like in the case of printing the + // UniversalHeaders or ArchiveHeaders. + if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind || + LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints || + DumpSections.size() != 0) { + outs() << Filename; + if (!ArchiveMemberName.empty()) + outs() << '(' << ArchiveMemberName << ')'; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << ":\n"; + } + + if (Disassemble) + DisassembleMachO(Filename, MachOOF, "__TEXT", "__text"); + if (IndirectSymbols) + PrintIndirectSymbols(MachOOF, true); + if (DataInCode) + PrintDataInCodeTable(MachOOF, true); + if (LinkOptHints) + PrintLinkOptHints(MachOOF); + if (Relocations) + PrintRelocations(MachOOF); + if (SectionHeaders) + PrintSectionHeaders(MachOOF); + if (SectionContents) + PrintSectionContents(MachOOF); + if (DumpSections.size() != 0) + DumpSectionContents(Filename, MachOOF, true); + if (SymbolTable) + PrintSymbolTable(MachOOF); + if (UnwindInfo) + printMachOUnwindInfo(MachOOF); + if (PrivateHeaders) + printMachOFileHeader(MachOOF); + if (ExportsTrie) + printExportsTrie(MachOOF); + if (Rebase) + printRebaseTable(MachOOF); + if (Bind) + printBindTable(MachOOF); + if (LazyBind) + printLazyBindTable(MachOOF); + if (WeakBind) + printWeakBindTable(MachOOF); +} + +// printUnknownCPUType() helps print_fat_headers for unknown CPU's. +static void printUnknownCPUType(uint32_t cputype, uint32_t cpusubtype) { + outs() << " cputype (" << cputype << ")\n"; + outs() << " cpusubtype (" << cpusubtype << ")\n"; +} + +// printCPUType() helps print_fat_headers by printing the cputype and +// pusubtype (symbolically for the one's it knows about). +static void printCPUType(uint32_t cputype, uint32_t cpusubtype) { + switch (cputype) { + case MachO::CPU_TYPE_I386: + switch (cpusubtype) { + case MachO::CPU_SUBTYPE_I386_ALL: + outs() << " cputype CPU_TYPE_I386\n"; + outs() << " cpusubtype CPU_SUBTYPE_I386_ALL\n"; + break; + default: + printUnknownCPUType(cputype, cpusubtype); + break; + } + break; + case MachO::CPU_TYPE_X86_64: + switch (cpusubtype) { + case MachO::CPU_SUBTYPE_X86_64_ALL: + outs() << " cputype CPU_TYPE_X86_64\n"; + outs() << " cpusubtype CPU_SUBTYPE_X86_64_ALL\n"; + break; + case MachO::CPU_SUBTYPE_X86_64_H: + outs() << " cputype CPU_TYPE_X86_64\n"; + outs() << " cpusubtype CPU_SUBTYPE_X86_64_H\n"; + break; + default: + printUnknownCPUType(cputype, cpusubtype); + break; + } + break; + case MachO::CPU_TYPE_ARM: + switch (cpusubtype) { + case MachO::CPU_SUBTYPE_ARM_ALL: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_ALL\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V4T: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V4T\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V5TEJ: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V5TEJ\n"; + break; + case MachO::CPU_SUBTYPE_ARM_XSCALE: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_XSCALE\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V6: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V6\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V6M: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V6M\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V7: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V7\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V7EM: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V7EM\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V7K: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V7K\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V7M: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V7M\n"; + break; + case MachO::CPU_SUBTYPE_ARM_V7S: + outs() << " cputype CPU_TYPE_ARM\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM_V7S\n"; + break; + default: + printUnknownCPUType(cputype, cpusubtype); + break; + } + break; + case MachO::CPU_TYPE_ARM64: + switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM64_ALL: + outs() << " cputype CPU_TYPE_ARM64\n"; + outs() << " cpusubtype CPU_SUBTYPE_ARM64_ALL\n"; + break; + default: + printUnknownCPUType(cputype, cpusubtype); + break; + } + break; + default: + printUnknownCPUType(cputype, cpusubtype); + break; + } +} + +static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB, + bool verbose) { + outs() << "Fat headers\n"; + if (verbose) + outs() << "fat_magic FAT_MAGIC\n"; + else + outs() << "fat_magic " << format("0x%" PRIx32, MachO::FAT_MAGIC) << "\n"; + + uint32_t nfat_arch = UB->getNumberOfObjects(); + StringRef Buf = UB->getData(); + uint64_t size = Buf.size(); + uint64_t big_size = sizeof(struct MachO::fat_header) + + nfat_arch * sizeof(struct MachO::fat_arch); + outs() << "nfat_arch " << UB->getNumberOfObjects(); + if (nfat_arch == 0) + outs() << " (malformed, contains zero architecture types)\n"; + else if (big_size > size) + outs() << " (malformed, architectures past end of file)\n"; + else + outs() << "\n"; + + for (uint32_t i = 0; i < nfat_arch; ++i) { + MachOUniversalBinary::ObjectForArch OFA(UB, i); + uint32_t cputype = OFA.getCPUType(); + uint32_t cpusubtype = OFA.getCPUSubType(); + outs() << "architecture "; + for (uint32_t j = 0; i != 0 && j <= i - 1; j++) { + MachOUniversalBinary::ObjectForArch other_OFA(UB, j); + uint32_t other_cputype = other_OFA.getCPUType(); + uint32_t other_cpusubtype = other_OFA.getCPUSubType(); + if (cputype != 0 && cpusubtype != 0 && cputype == other_cputype && + (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) == + (other_cpusubtype & ~MachO::CPU_SUBTYPE_MASK)) { + outs() << "(illegal duplicate architecture) "; + break; + } + } + if (verbose) { + outs() << OFA.getArchTypeName() << "\n"; + printCPUType(cputype, cpusubtype & ~MachO::CPU_SUBTYPE_MASK); + } else { + outs() << i << "\n"; + outs() << " cputype " << cputype << "\n"; + outs() << " cpusubtype " << (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) + << "\n"; + } + if (verbose && + (cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) + outs() << " capabilities CPU_SUBTYPE_LIB64\n"; + else + outs() << " capabilities " + << format("0x%" PRIx32, + (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24) << "\n"; + outs() << " offset " << OFA.getOffset(); + if (OFA.getOffset() > size) + outs() << " (past end of file)"; + if (OFA.getOffset() % (1 << OFA.getAlign()) != 0) + outs() << " (not aligned on it's alignment (2^" << OFA.getAlign() << ")"; + outs() << "\n"; + outs() << " size " << OFA.getSize(); + big_size = OFA.getOffset() + OFA.getSize(); + if (big_size > size) + outs() << " (past end of file)"; + outs() << "\n"; + outs() << " align 2^" << OFA.getAlign() << " (" << (1 << OFA.getAlign()) + << ")\n"; + } +} + +static void printArchiveChild(Archive::Child &C, bool verbose, + bool print_offset) { + if (print_offset) + outs() << C.getChildOffset() << "\t"; + sys::fs::perms Mode = C.getAccessMode(); + if (verbose) { + // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG. + // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG. + outs() << "-"; + if (Mode & sys::fs::owner_read) + outs() << "r"; + else + outs() << "-"; + if (Mode & sys::fs::owner_write) + outs() << "w"; + else + outs() << "-"; + if (Mode & sys::fs::owner_exe) + outs() << "x"; + else + outs() << "-"; + if (Mode & sys::fs::group_read) + outs() << "r"; + else + outs() << "-"; + if (Mode & sys::fs::group_write) + outs() << "w"; + else + outs() << "-"; + if (Mode & sys::fs::group_exe) + outs() << "x"; + else + outs() << "-"; + if (Mode & sys::fs::others_read) + outs() << "r"; + else + outs() << "-"; + if (Mode & sys::fs::others_write) + outs() << "w"; + else + outs() << "-"; + if (Mode & sys::fs::others_exe) + outs() << "x"; + else + outs() << "-"; + } else { + outs() << format("0%o ", Mode); + } + + unsigned UID = C.getUID(); + outs() << format("%3d/", UID); + unsigned GID = C.getGID(); + outs() << format("%-3d ", GID); + uint64_t Size = C.getRawSize(); + outs() << format("%5" PRId64, Size) << " "; - MachOObj->ReadULEB128s(LLC.dataoff, FoundFns); - } else if (Command.C.cmd == MachO::LC_SEGMENT) { - MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command); - StringRef SegName = SLC.segname; - if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") { - BaseSegmentAddressSet = true; - BaseSegmentAddress = SLC.vmaddr; - } + StringRef RawLastModified = C.getRawLastModified(); + if (verbose) { + unsigned Seconds; + if (RawLastModified.getAsInteger(10, Seconds)) + outs() << "(date: \"%s\" contains non-decimal chars) " << RawLastModified; + else { + // Since cime(3) returns a 26 character string of the form: + // "Sun Sep 16 01:03:52 1973\n\0" + // just print 24 characters. + time_t t = Seconds; + outs() << format("%.24s ", ctime(&t)); } + } else { + outs() << RawLastModified << " "; + } - if (i == Header.ncmds - 1) - break; - else - Command = MachOObj->getNextLoadCommandInfo(Command); + if (verbose) { + ErrorOr NameOrErr = C.getName(); + if (NameOrErr.getError()) { + StringRef RawName = C.getRawName(); + outs() << RawName << "\n"; + } else { + StringRef Name = NameOrErr.get(); + outs() << Name << "\n"; + } + } else { + StringRef RawName = C.getRawName(); + outs() << RawName << "\n"; } } -static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFile *MachOOF); - -void llvm::DisassembleInputMachO(StringRef Filename) { - ErrorOr> BuffOrErr = - MemoryBuffer::getFileOrSTDIN(Filename); - if (std::error_code EC = BuffOrErr.getError()) { - errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n"; - return; +static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) { + if (A->hasSymbolTable()) { + Archive::child_iterator S = A->getSymbolTableChild(); + Archive::Child C = *S; + printArchiveChild(C, verbose, print_offset); + } + for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; + ++I) { + Archive::Child C = *I; + printArchiveChild(C, verbose, print_offset); } - std::unique_ptr Buff = std::move(BuffOrErr.get()); +} - std::unique_ptr MachOOF = std::move( - ObjectFile::createMachOObjectFile(Buff.get()->getMemBufferRef()).get()); +// ParseInputMachO() parses the named Mach-O file in Filename and handles the +// -arch flags selecting just those slices as specified by them and also parses +// archive files. Then for each individual Mach-O file ProcessMachO() is +// called to process the file based on the command line options. +void llvm::ParseInputMachO(StringRef Filename) { + // Check for -arch all and verifiy the -arch flags are valid. + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == "all") { + ArchAll = true; + } else { + if (!MachOObjectFile::isValidArch(ArchFlags[i])) { + errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] + + "'for the -arch option\n"; + return; + } + } + } - DisassembleInputMachO2(Filename, MachOOF.get()); + // Attempt to open the binary. + ErrorOr> BinaryOrErr = createBinary(Filename); + if (std::error_code EC = BinaryOrErr.getError()) { + errs() << "llvm-objdump: '" << Filename << "': " << EC.message() << ".\n"; + return; + } + Binary &Bin = *BinaryOrErr.get().getBinary(); + + if (Archive *A = dyn_cast(&Bin)) { + outs() << "Archive : " << Filename << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(A, true, false); + for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); + I != E; ++I) { + ErrorOr> ChildOrErr = I->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + ProcessMachO(Filename, O, O->getFileName()); + } + } + return; + } + if (UniversalHeaders) { + if (MachOUniversalBinary *UB = dyn_cast(&Bin)) + printMachOUniversalHeaders(UB, true); + } + if (MachOUniversalBinary *UB = dyn_cast(&Bin)) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchTypeName()) { + ArchFound = true; + ErrorOr> ObjOrErr = + I->getAsObjectFile(); + std::string ArchitectureName = ""; + if (ArchFlags.size() > 1) + ArchitectureName = I->getArchTypeName(); + if (ObjOrErr) { + ObjectFile &O = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&O)) + ProcessMachO(Filename, MachOOF, "", ArchitectureName); + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(A.get(), true, false); + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) + ProcessMachO(Filename, O, O->getFileName(), ArchitectureName); + } + } + } + } + if (!ArchFound) { + errs() << "llvm-objdump: file: " + Filename + " does not contain " + << "architecture: " + ArchFlags[i] + "\n"; + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (MachOObjectFile::getHostArch().getArchName() == + I->getArchTypeName()) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::string ArchiveName; + ArchiveName.clear(); + if (ObjOrErr) { + ObjectFile &O = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&O)) + ProcessMachO(Filename, MachOOF); + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; + outs() << "Archive : " << Filename << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(A.get(), true, false); + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) + ProcessMachO(Filename, O, O->getFileName()); + } + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool moreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::string ArchitectureName = ""; + if (moreThanOneArch) + ArchitectureName = I->getArchTypeName(); + if (ObjOrErr) { + ObjectFile &Obj = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&Obj)) + ProcessMachO(Filename, MachOOF, "", ArchitectureName); + } else if (ErrorOr> AOrErr = I->getAsArchive()) { + std::unique_ptr &A = *AOrErr; + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; + if (ArchiveHeaders) + printArchiveHeaders(A.get(), true, false); + for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) { + if (MachOObjectFile *MachOOF = dyn_cast(O)) + ProcessMachO(Filename, MachOOF, MachOOF->getFileName(), + ArchitectureName); + } + } + } + } + return; + } + if (ObjectFile *O = dyn_cast(&Bin)) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + if (MachOObjectFile *MachOOF = dyn_cast(&*O)) { + ProcessMachO(Filename, MachOOF); + } else + errs() << "llvm-objdump: '" << Filename << "': " + << "Object is not a Mach-O file type.\n"; + } else + errs() << "llvm-objdump: '" << Filename << "': " + << "Unrecognized file type.\n"; } -typedef DenseMap SymbolAddressMap; typedef std::pair BindInfoEntry; typedef std::vector BindTable; typedef BindTable::iterator bind_table_iterator; @@ -280,21 +1593,6 @@ struct DisassembleInfo { BindTable *bindtable; }; -// GuessSymbolName is passed the address of what might be a symbol and a -// pointer to the DisassembleInfo struct. It returns the name of a symbol -// with that address or nullptr if no symbol is found with that address. -static const char *GuessSymbolName(uint64_t value, - struct DisassembleInfo *info) { - const char *SymbolName = nullptr; - // A DenseMap can't lookup up some values. - if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) { - StringRef name = info->AddrMap->lookup(value); - if (!name.empty()) - SymbolName = name.data(); - } - return SymbolName; -} - // SymbolizerGetOpInfo() is the operand information call back function. // This is called to get the symbolic information for operand(s) of an // instruction when it is being done. This routine does this from @@ -385,8 +1683,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, } if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF || r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) { - const char *add = GuessSymbolName(r_value, info); - const char *sub = GuessSymbolName(pair_r_value, info); + const char *add = GuessSymbolName(r_value, info->AddrMap); + const char *sub = GuessSymbolName(pair_r_value, info->AddrMap); uint32_t offset = value - (r_value - pair_r_value); op_info->AddSymbol.Present = 1; if (add != nullptr) @@ -527,34 +1825,18 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, const char *name = SymName.data(); op_info->AddSymbol.Present = 1; op_info->AddSymbol.Name = name; - if (value != 0) { - switch (r_type) { - case MachO::ARM_RELOC_HALF: - if ((r_length & 0x1) == 1) { - op_info->Value = value << 16 | other_half; - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; - } else { - op_info->Value = other_half << 16 | value; - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; - } - break; - default: - break; - } - } else { - switch (r_type) { - case MachO::ARM_RELOC_HALF: - if ((r_length & 0x1) == 1) { - op_info->Value = value << 16 | other_half; - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; - } else { - op_info->Value = other_half << 16 | value; - op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; - } - break; - default: - break; + switch (r_type) { + case MachO::ARM_RELOC_HALF: + if ((r_length & 0x1) == 1) { + op_info->Value = value << 16 | other_half; + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; + } else { + op_info->Value = other_half << 16 | value; + op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; } + break; + default: + break; } return 1; } @@ -587,8 +1869,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16; else op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; - const char *add = GuessSymbolName(r_value, info); - const char *sub = GuessSymbolName(pair_r_value, info); + const char *add = GuessSymbolName(r_value, info->AddrMap); + const char *sub = GuessSymbolName(pair_r_value, info->AddrMap); int32_t offset = value - (r_value - pair_r_value); op_info->AddSymbol.Present = 1; if (add != nullptr) @@ -617,7 +1899,7 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset, op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16; } } - const char *add = GuessSymbolName(value, info); + const char *add = GuessSymbolName(value, info->AddrMap); if (add != nullptr) { op_info->AddSymbol.Name = add; return 1; @@ -1078,7 +2360,7 @@ const char *get_symbol_64(uint32_t sect_offset, SectionRef S, // // NOTE: need add passing the ReferenceValue to this routine. Then that code // would simply be this: - // SymbolName = GuessSymbolName(ReferenceValue, info); + // SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap); return SymbolName; } @@ -1421,7 +2703,7 @@ const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue, return nullptr; } - const char *SymbolName = GuessSymbolName(ReferenceValue, info); + const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap); if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) { *ReferenceName = GuessIndirectSymbol(ReferenceValue, info); @@ -1585,8 +2867,8 @@ static void emitComments(raw_svector_ostream &CommentStream, CommentStream.resync(); } -static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFile *MachOOF) { +static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, + StringRef DisSegName, StringRef DisSectName) { const char *McpuDefault = nullptr; const Target *ThumbTarget = nullptr; const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget); @@ -1628,7 +2910,7 @@ static void DisassembleInputMachO2(StringRef Filename, if (RelInfo) { Symbolizer.reset(TheTarget->createMCSymbolizer( TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp, - &SymbolizerInfo, &Ctx, RelInfo.release())); + &SymbolizerInfo, &Ctx, std::move(RelInfo))); DisAsm->setSymbolizer(std::move(Symbolizer)); } int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); @@ -1639,6 +2921,12 @@ static void DisassembleInputMachO2(StringRef Filename, // Comment stream and backing vector. SmallString<128> CommentsToEmit; raw_svector_ostream CommentStream(CommentsToEmit); + // FIXME: Setting the CommentStream in the InstPrinter is problematic in that + // if it is done then arm64 comments for string literals don't get printed + // and some constant get printed instead and not setting it causes intel + // (32-bit and 64-bit) comments printed with different spacing before the + // comment causing different diffs with the 'C' disassembler library API. + // IP->setCommentStream(CommentStream); if (!AsmInfo || !STI || !DisAsm || !IP) { errs() << "error: couldn't initialize disassembler for target " @@ -1670,7 +2958,7 @@ static void DisassembleInputMachO2(StringRef Filename, if (ThumbRelInfo) { ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer( ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp, - &ThumbSymbolizerInfo, PtrThumbCtx, ThumbRelInfo.release())); + &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo))); ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer)); } int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect(); @@ -1687,8 +2975,6 @@ static void DisassembleInputMachO2(StringRef Filename, return; } - outs() << '\n' << Filename << ":\n\n"; - MachO::mach_header Header = MachOOF->getHeader(); // FIXME: Using the -cfg command line option, this code used to be able to @@ -1750,20 +3036,18 @@ static void DisassembleInputMachO2(StringRef Filename, diContext.reset(DIContext::getDWARFContext(*DbgObj)); } - for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { - - bool SectIsText = Sections[SectIdx].isText(); - if (SectIsText == false) - continue; + if (DumpSections.size() == 0) + outs() << "(" << DisSegName << "," << DisSectName << ") section\n"; + for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { StringRef SectName; - if (Sections[SectIdx].getName(SectName) || SectName != "__text") - continue; // Skip non-text sections + if (Sections[SectIdx].getName(SectName) || SectName != DisSectName) + continue; DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR); - if (SegmentName != "__TEXT") + if (SegmentName != DisSegName) continue; StringRef BytesStr; @@ -2013,6 +3297,11 @@ static void DisassembleInputMachO2(StringRef Filename, } } } + // The TripleName's need to be reset if we are called again for a different + // archtecture. + TripleName = ""; + ThumbTripleName = ""; + if (SymbolizerInfo.method != nullptr) free(SymbolizerInfo.method); if (SymbolizerInfo.demangled_name != nullptr) @@ -2504,12 +3793,17 @@ static void PrintMachHeader(uint32_t magic, uint32_t cputype, break; case MachO::CPU_TYPE_X86_64: outs() << " X86_64"; - case MachO::CPU_SUBTYPE_X86_64_ALL: - outs() << " ALL"; - break; - case MachO::CPU_SUBTYPE_X86_64_H: - outs() << " Haswell"; - outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK); + switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_X86_64_ALL: + outs() << " ALL"; + break; + case MachO::CPU_SUBTYPE_X86_64_H: + outs() << " Haswell"; + break; + default: + outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK); + break; + } break; case MachO::CPU_TYPE_ARM: outs() << " ARM"; @@ -2774,8 +4068,8 @@ static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize, outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n"; outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n"; } else { - outs() << " vmaddr " << format("0x%08" PRIx32, vmaddr) << "\n"; - outs() << " vmsize " << format("0x%08" PRIx32, vmsize) << "\n"; + outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n"; + outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n"; } outs() << " fileoff " << fileoff; if (fileoff > object_size) @@ -2878,8 +4172,8 @@ static void PrintSection(const char *sectname, const char *segname, outs() << " addr " << format("0x%016" PRIx64, addr) << "\n"; outs() << " size " << format("0x%016" PRIx64, size); } else { - outs() << " addr " << format("0x%08" PRIx32, addr) << "\n"; - outs() << " size " << format("0x%08" PRIx32, size); + outs() << " addr " << format("0x%08" PRIx64, addr) << "\n"; + outs() << " size " << format("0x%08" PRIx64, size); } if ((flags & MachO::S_ZEROFILL) != 0 && offset + size > object_size) outs() << " (past end of file)\n"; @@ -3299,6 +4593,21 @@ static void PrintUuidLoadCommand(MachO::uuid_command uuid) { outs() << "\n"; } +static void PrintRpathLoadCommand(MachO::rpath_command rpath, const char *Ptr) { + outs() << " cmd LC_RPATH\n"; + outs() << " cmdsize " << rpath.cmdsize; + if (rpath.cmdsize < sizeof(struct MachO::rpath_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + if (rpath.path >= rpath.cmdsize) + outs() << " path ?(bad offset " << rpath.path << ")\n"; + else { + const char *P = (const char *)(Ptr) + rpath.path; + outs() << " path " << P << " (offset " << rpath.path << ")\n"; + } +} + static void PrintVersionMinLoadCommand(MachO::version_min_command vd) { if (vd.cmd == MachO::LC_VERSION_MIN_MACOSX) outs() << " cmd LC_VERSION_MIN_MACOSX\n"; @@ -3317,7 +4626,7 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) { outs() << "." << (vd.version & 0xff); outs() << "\n"; if (vd.sdk == 0) - outs() << " sdk n/a\n"; + outs() << " sdk n/a"; else { outs() << " sdk " << ((vd.sdk >> 16) & 0xffff) << "." << ((vd.sdk >> 8) & 0xff); @@ -3360,6 +4669,525 @@ static void PrintEntryPointCommand(MachO::entry_point_command ep) { outs() << " stacksize " << ep.stacksize << "\n"; } +static void PrintEncryptionInfoCommand(MachO::encryption_info_command ec, + uint32_t object_size) { + outs() << " cmd LC_ENCRYPTION_INFO\n"; + outs() << " cmdsize " << ec.cmdsize; + if (ec.cmdsize != sizeof(struct MachO::encryption_info_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " cryptoff " << ec.cryptoff; + if (ec.cryptoff > object_size) + outs() << " (past end of file)\n"; + else + outs() << "\n"; + outs() << " cryptsize " << ec.cryptsize; + if (ec.cryptsize > object_size) + outs() << " (past end of file)\n"; + else + outs() << "\n"; + outs() << " cryptid " << ec.cryptid << "\n"; +} + +static void PrintEncryptionInfoCommand64(MachO::encryption_info_command_64 ec, + uint32_t object_size) { + outs() << " cmd LC_ENCRYPTION_INFO_64\n"; + outs() << " cmdsize " << ec.cmdsize; + if (ec.cmdsize != sizeof(struct MachO::encryption_info_command_64)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " cryptoff " << ec.cryptoff; + if (ec.cryptoff > object_size) + outs() << " (past end of file)\n"; + else + outs() << "\n"; + outs() << " cryptsize " << ec.cryptsize; + if (ec.cryptsize > object_size) + outs() << " (past end of file)\n"; + else + outs() << "\n"; + outs() << " cryptid " << ec.cryptid << "\n"; + outs() << " pad " << ec.pad << "\n"; +} + +static void PrintLinkerOptionCommand(MachO::linker_option_command lo, + const char *Ptr) { + outs() << " cmd LC_LINKER_OPTION\n"; + outs() << " cmdsize " << lo.cmdsize; + if (lo.cmdsize < sizeof(struct MachO::linker_option_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " count " << lo.count << "\n"; + const char *string = Ptr + sizeof(struct MachO::linker_option_command); + uint32_t left = lo.cmdsize - sizeof(struct MachO::linker_option_command); + uint32_t i = 0; + while (left > 0) { + while (*string == '\0' && left > 0) { + string++; + left--; + } + if (left > 0) { + i++; + outs() << " string #" << i << " " << format("%.*s\n", left, string); + uint32_t NullPos = StringRef(string, left).find('\0'); + uint32_t len = std::min(NullPos, left) + 1; + string += len; + left -= len; + } + } + if (lo.count != i) + outs() << " count " << lo.count << " does not match number of strings " + << i << "\n"; +} + +static void PrintSubFrameworkCommand(MachO::sub_framework_command sub, + const char *Ptr) { + outs() << " cmd LC_SUB_FRAMEWORK\n"; + outs() << " cmdsize " << sub.cmdsize; + if (sub.cmdsize < sizeof(struct MachO::sub_framework_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + if (sub.umbrella < sub.cmdsize) { + const char *P = Ptr + sub.umbrella; + outs() << " umbrella " << P << " (offset " << sub.umbrella << ")\n"; + } else { + outs() << " umbrella ?(bad offset " << sub.umbrella << ")\n"; + } +} + +static void PrintSubUmbrellaCommand(MachO::sub_umbrella_command sub, + const char *Ptr) { + outs() << " cmd LC_SUB_UMBRELLA\n"; + outs() << " cmdsize " << sub.cmdsize; + if (sub.cmdsize < sizeof(struct MachO::sub_umbrella_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + if (sub.sub_umbrella < sub.cmdsize) { + const char *P = Ptr + sub.sub_umbrella; + outs() << " sub_umbrella " << P << " (offset " << sub.sub_umbrella << ")\n"; + } else { + outs() << " sub_umbrella ?(bad offset " << sub.sub_umbrella << ")\n"; + } +} + +static void PrintSubLibraryCommand(MachO::sub_library_command sub, + const char *Ptr) { + outs() << " cmd LC_SUB_LIBRARY\n"; + outs() << " cmdsize " << sub.cmdsize; + if (sub.cmdsize < sizeof(struct MachO::sub_library_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + if (sub.sub_library < sub.cmdsize) { + const char *P = Ptr + sub.sub_library; + outs() << " sub_library " << P << " (offset " << sub.sub_library << ")\n"; + } else { + outs() << " sub_library ?(bad offset " << sub.sub_library << ")\n"; + } +} + +static void PrintSubClientCommand(MachO::sub_client_command sub, + const char *Ptr) { + outs() << " cmd LC_SUB_CLIENT\n"; + outs() << " cmdsize " << sub.cmdsize; + if (sub.cmdsize < sizeof(struct MachO::sub_client_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + if (sub.client < sub.cmdsize) { + const char *P = Ptr + sub.client; + outs() << " client " << P << " (offset " << sub.client << ")\n"; + } else { + outs() << " client ?(bad offset " << sub.client << ")\n"; + } +} + +static void PrintRoutinesCommand(MachO::routines_command r) { + outs() << " cmd LC_ROUTINES\n"; + outs() << " cmdsize " << r.cmdsize; + if (r.cmdsize != sizeof(struct MachO::routines_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " init_address " << format("0x%08" PRIx32, r.init_address) << "\n"; + outs() << " init_module " << r.init_module << "\n"; + outs() << " reserved1 " << r.reserved1 << "\n"; + outs() << " reserved2 " << r.reserved2 << "\n"; + outs() << " reserved3 " << r.reserved3 << "\n"; + outs() << " reserved4 " << r.reserved4 << "\n"; + outs() << " reserved5 " << r.reserved5 << "\n"; + outs() << " reserved6 " << r.reserved6 << "\n"; +} + +static void PrintRoutinesCommand64(MachO::routines_command_64 r) { + outs() << " cmd LC_ROUTINES_64\n"; + outs() << " cmdsize " << r.cmdsize; + if (r.cmdsize != sizeof(struct MachO::routines_command_64)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " init_address " << format("0x%016" PRIx64, r.init_address) << "\n"; + outs() << " init_module " << r.init_module << "\n"; + outs() << " reserved1 " << r.reserved1 << "\n"; + outs() << " reserved2 " << r.reserved2 << "\n"; + outs() << " reserved3 " << r.reserved3 << "\n"; + outs() << " reserved4 " << r.reserved4 << "\n"; + outs() << " reserved5 " << r.reserved5 << "\n"; + outs() << " reserved6 " << r.reserved6 << "\n"; +} + +static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) { + outs() << " rax " << format("0x%016" PRIx64, cpu64.rax); + outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx); + outs() << " rcx " << format("0x%016" PRIx64, cpu64.rcx) << "\n"; + outs() << " rdx " << format("0x%016" PRIx64, cpu64.rdx); + outs() << " rdi " << format("0x%016" PRIx64, cpu64.rdi); + outs() << " rsi " << format("0x%016" PRIx64, cpu64.rsi) << "\n"; + outs() << " rbp " << format("0x%016" PRIx64, cpu64.rbp); + outs() << " rsp " << format("0x%016" PRIx64, cpu64.rsp); + outs() << " r8 " << format("0x%016" PRIx64, cpu64.r8) << "\n"; + outs() << " r9 " << format("0x%016" PRIx64, cpu64.r9); + outs() << " r10 " << format("0x%016" PRIx64, cpu64.r10); + outs() << " r11 " << format("0x%016" PRIx64, cpu64.r11) << "\n"; + outs() << " r12 " << format("0x%016" PRIx64, cpu64.r12); + outs() << " r13 " << format("0x%016" PRIx64, cpu64.r13); + outs() << " r14 " << format("0x%016" PRIx64, cpu64.r14) << "\n"; + outs() << " r15 " << format("0x%016" PRIx64, cpu64.r15); + outs() << " rip " << format("0x%016" PRIx64, cpu64.rip) << "\n"; + outs() << "rflags " << format("0x%016" PRIx64, cpu64.rflags); + outs() << " cs " << format("0x%016" PRIx64, cpu64.cs); + outs() << " fs " << format("0x%016" PRIx64, cpu64.fs) << "\n"; + outs() << " gs " << format("0x%016" PRIx64, cpu64.gs) << "\n"; +} + +static void Print_mmst_reg(MachO::mmst_reg_t &r) { + uint32_t f; + outs() << "\t mmst_reg "; + for (f = 0; f < 10; f++) + outs() << format("%02" PRIx32, (r.mmst_reg[f] & 0xff)) << " "; + outs() << "\n"; + outs() << "\t mmst_rsrv "; + for (f = 0; f < 6; f++) + outs() << format("%02" PRIx32, (r.mmst_rsrv[f] & 0xff)) << " "; + outs() << "\n"; +} + +static void Print_xmm_reg(MachO::xmm_reg_t &r) { + uint32_t f; + outs() << "\t xmm_reg "; + for (f = 0; f < 16; f++) + outs() << format("%02" PRIx32, (r.xmm_reg[f] & 0xff)) << " "; + outs() << "\n"; +} + +static void Print_x86_float_state_t(MachO::x86_float_state64_t &fpu) { + outs() << "\t fpu_reserved[0] " << fpu.fpu_reserved[0]; + outs() << " fpu_reserved[1] " << fpu.fpu_reserved[1] << "\n"; + outs() << "\t control: invalid " << fpu.fpu_fcw.invalid; + outs() << " denorm " << fpu.fpu_fcw.denorm; + outs() << " zdiv " << fpu.fpu_fcw.zdiv; + outs() << " ovrfl " << fpu.fpu_fcw.ovrfl; + outs() << " undfl " << fpu.fpu_fcw.undfl; + outs() << " precis " << fpu.fpu_fcw.precis << "\n"; + outs() << "\t\t pc "; + if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_24B) + outs() << "FP_PREC_24B "; + else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_53B) + outs() << "FP_PREC_53B "; + else if (fpu.fpu_fcw.pc == MachO::x86_FP_PREC_64B) + outs() << "FP_PREC_64B "; + else + outs() << fpu.fpu_fcw.pc << " "; + outs() << "rc "; + if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_NEAR) + outs() << "FP_RND_NEAR "; + else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_DOWN) + outs() << "FP_RND_DOWN "; + else if (fpu.fpu_fcw.rc == MachO::x86_FP_RND_UP) + outs() << "FP_RND_UP "; + else if (fpu.fpu_fcw.rc == MachO::x86_FP_CHOP) + outs() << "FP_CHOP "; + outs() << "\n"; + outs() << "\t status: invalid " << fpu.fpu_fsw.invalid; + outs() << " denorm " << fpu.fpu_fsw.denorm; + outs() << " zdiv " << fpu.fpu_fsw.zdiv; + outs() << " ovrfl " << fpu.fpu_fsw.ovrfl; + outs() << " undfl " << fpu.fpu_fsw.undfl; + outs() << " precis " << fpu.fpu_fsw.precis; + outs() << " stkflt " << fpu.fpu_fsw.stkflt << "\n"; + outs() << "\t errsumm " << fpu.fpu_fsw.errsumm; + outs() << " c0 " << fpu.fpu_fsw.c0; + outs() << " c1 " << fpu.fpu_fsw.c1; + outs() << " c2 " << fpu.fpu_fsw.c2; + outs() << " tos " << fpu.fpu_fsw.tos; + outs() << " c3 " << fpu.fpu_fsw.c3; + outs() << " busy " << fpu.fpu_fsw.busy << "\n"; + outs() << "\t fpu_ftw " << format("0x%02" PRIx32, fpu.fpu_ftw); + outs() << " fpu_rsrv1 " << format("0x%02" PRIx32, fpu.fpu_rsrv1); + outs() << " fpu_fop " << format("0x%04" PRIx32, fpu.fpu_fop); + outs() << " fpu_ip " << format("0x%08" PRIx32, fpu.fpu_ip) << "\n"; + outs() << "\t fpu_cs " << format("0x%04" PRIx32, fpu.fpu_cs); + outs() << " fpu_rsrv2 " << format("0x%04" PRIx32, fpu.fpu_rsrv2); + outs() << " fpu_dp " << format("0x%08" PRIx32, fpu.fpu_dp); + outs() << " fpu_ds " << format("0x%04" PRIx32, fpu.fpu_ds) << "\n"; + outs() << "\t fpu_rsrv3 " << format("0x%04" PRIx32, fpu.fpu_rsrv3); + outs() << " fpu_mxcsr " << format("0x%08" PRIx32, fpu.fpu_mxcsr); + outs() << " fpu_mxcsrmask " << format("0x%08" PRIx32, fpu.fpu_mxcsrmask); + outs() << "\n"; + outs() << "\t fpu_stmm0:\n"; + Print_mmst_reg(fpu.fpu_stmm0); + outs() << "\t fpu_stmm1:\n"; + Print_mmst_reg(fpu.fpu_stmm1); + outs() << "\t fpu_stmm2:\n"; + Print_mmst_reg(fpu.fpu_stmm2); + outs() << "\t fpu_stmm3:\n"; + Print_mmst_reg(fpu.fpu_stmm3); + outs() << "\t fpu_stmm4:\n"; + Print_mmst_reg(fpu.fpu_stmm4); + outs() << "\t fpu_stmm5:\n"; + Print_mmst_reg(fpu.fpu_stmm5); + outs() << "\t fpu_stmm6:\n"; + Print_mmst_reg(fpu.fpu_stmm6); + outs() << "\t fpu_stmm7:\n"; + Print_mmst_reg(fpu.fpu_stmm7); + outs() << "\t fpu_xmm0:\n"; + Print_xmm_reg(fpu.fpu_xmm0); + outs() << "\t fpu_xmm1:\n"; + Print_xmm_reg(fpu.fpu_xmm1); + outs() << "\t fpu_xmm2:\n"; + Print_xmm_reg(fpu.fpu_xmm2); + outs() << "\t fpu_xmm3:\n"; + Print_xmm_reg(fpu.fpu_xmm3); + outs() << "\t fpu_xmm4:\n"; + Print_xmm_reg(fpu.fpu_xmm4); + outs() << "\t fpu_xmm5:\n"; + Print_xmm_reg(fpu.fpu_xmm5); + outs() << "\t fpu_xmm6:\n"; + Print_xmm_reg(fpu.fpu_xmm6); + outs() << "\t fpu_xmm7:\n"; + Print_xmm_reg(fpu.fpu_xmm7); + outs() << "\t fpu_xmm8:\n"; + Print_xmm_reg(fpu.fpu_xmm8); + outs() << "\t fpu_xmm9:\n"; + Print_xmm_reg(fpu.fpu_xmm9); + outs() << "\t fpu_xmm10:\n"; + Print_xmm_reg(fpu.fpu_xmm10); + outs() << "\t fpu_xmm11:\n"; + Print_xmm_reg(fpu.fpu_xmm11); + outs() << "\t fpu_xmm12:\n"; + Print_xmm_reg(fpu.fpu_xmm12); + outs() << "\t fpu_xmm13:\n"; + Print_xmm_reg(fpu.fpu_xmm13); + outs() << "\t fpu_xmm14:\n"; + Print_xmm_reg(fpu.fpu_xmm14); + outs() << "\t fpu_xmm15:\n"; + Print_xmm_reg(fpu.fpu_xmm15); + outs() << "\t fpu_rsrv4:\n"; + for (uint32_t f = 0; f < 6; f++) { + outs() << "\t "; + for (uint32_t g = 0; g < 16; g++) + outs() << format("%02" PRIx32, fpu.fpu_rsrv4[f * g]) << " "; + outs() << "\n"; + } + outs() << "\t fpu_reserved1 " << format("0x%08" PRIx32, fpu.fpu_reserved1); + outs() << "\n"; +} + +static void Print_x86_exception_state_t(MachO::x86_exception_state64_t &exc64) { + outs() << "\t trapno " << format("0x%08" PRIx32, exc64.trapno); + outs() << " err " << format("0x%08" PRIx32, exc64.err); + outs() << " faultvaddr " << format("0x%016" PRIx64, exc64.faultvaddr) << "\n"; +} + +static void PrintThreadCommand(MachO::thread_command t, const char *Ptr, + bool isLittleEndian, uint32_t cputype) { + if (t.cmd == MachO::LC_THREAD) + outs() << " cmd LC_THREAD\n"; + else if (t.cmd == MachO::LC_UNIXTHREAD) + outs() << " cmd LC_UNIXTHREAD\n"; + else + outs() << " cmd " << t.cmd << " (unknown)\n"; + outs() << " cmdsize " << t.cmdsize; + if (t.cmdsize < sizeof(struct MachO::thread_command) + 2 * sizeof(uint32_t)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + + const char *begin = Ptr + sizeof(struct MachO::thread_command); + const char *end = Ptr + t.cmdsize; + uint32_t flavor, count, left; + if (cputype == MachO::CPU_TYPE_X86_64) { + while (begin < end) { + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&flavor, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + flavor = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(flavor); + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&count, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + count = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(count); + if (flavor == MachO::x86_THREAD_STATE64) { + outs() << " flavor x86_THREAD_STATE64\n"; + if (count == MachO::x86_THREAD_STATE64_COUNT) + outs() << " count x86_THREAD_STATE64_COUNT\n"; + else + outs() << " count " << count + << " (not x86_THREAD_STATE64_COUNT)\n"; + MachO::x86_thread_state64_t cpu64; + left = end - begin; + if (left >= sizeof(MachO::x86_thread_state64_t)) { + memcpy(&cpu64, begin, sizeof(MachO::x86_thread_state64_t)); + begin += sizeof(MachO::x86_thread_state64_t); + } else { + memset(&cpu64, '\0', sizeof(MachO::x86_thread_state64_t)); + memcpy(&cpu64, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(cpu64); + Print_x86_thread_state64_t(cpu64); + } else if (flavor == MachO::x86_THREAD_STATE) { + outs() << " flavor x86_THREAD_STATE\n"; + if (count == MachO::x86_THREAD_STATE_COUNT) + outs() << " count x86_THREAD_STATE_COUNT\n"; + else + outs() << " count " << count + << " (not x86_THREAD_STATE_COUNT)\n"; + struct MachO::x86_thread_state_t ts; + left = end - begin; + if (left >= sizeof(MachO::x86_thread_state_t)) { + memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t)); + begin += sizeof(MachO::x86_thread_state_t); + } else { + memset(&ts, '\0', sizeof(MachO::x86_thread_state_t)); + memcpy(&ts, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(ts); + if (ts.tsh.flavor == MachO::x86_THREAD_STATE64) { + outs() << "\t tsh.flavor x86_THREAD_STATE64 "; + if (ts.tsh.count == MachO::x86_THREAD_STATE64_COUNT) + outs() << "tsh.count x86_THREAD_STATE64_COUNT\n"; + else + outs() << "tsh.count " << ts.tsh.count + << " (not x86_THREAD_STATE64_COUNT\n"; + Print_x86_thread_state64_t(ts.uts.ts64); + } else { + outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count " + << ts.tsh.count << "\n"; + } + } else if (flavor == MachO::x86_FLOAT_STATE) { + outs() << " flavor x86_FLOAT_STATE\n"; + if (count == MachO::x86_FLOAT_STATE_COUNT) + outs() << " count x86_FLOAT_STATE_COUNT\n"; + else + outs() << " count " << count << " (not x86_FLOAT_STATE_COUNT)\n"; + struct MachO::x86_float_state_t fs; + left = end - begin; + if (left >= sizeof(MachO::x86_float_state_t)) { + memcpy(&fs, begin, sizeof(MachO::x86_float_state_t)); + begin += sizeof(MachO::x86_float_state_t); + } else { + memset(&fs, '\0', sizeof(MachO::x86_float_state_t)); + memcpy(&fs, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(fs); + if (fs.fsh.flavor == MachO::x86_FLOAT_STATE64) { + outs() << "\t fsh.flavor x86_FLOAT_STATE64 "; + if (fs.fsh.count == MachO::x86_FLOAT_STATE64_COUNT) + outs() << "fsh.count x86_FLOAT_STATE64_COUNT\n"; + else + outs() << "fsh.count " << fs.fsh.count + << " (not x86_FLOAT_STATE64_COUNT\n"; + Print_x86_float_state_t(fs.ufs.fs64); + } else { + outs() << "\t fsh.flavor " << fs.fsh.flavor << " fsh.count " + << fs.fsh.count << "\n"; + } + } else if (flavor == MachO::x86_EXCEPTION_STATE) { + outs() << " flavor x86_EXCEPTION_STATE\n"; + if (count == MachO::x86_EXCEPTION_STATE_COUNT) + outs() << " count x86_EXCEPTION_STATE_COUNT\n"; + else + outs() << " count " << count + << " (not x86_EXCEPTION_STATE_COUNT)\n"; + struct MachO::x86_exception_state_t es; + left = end - begin; + if (left >= sizeof(MachO::x86_exception_state_t)) { + memcpy(&es, begin, sizeof(MachO::x86_exception_state_t)); + begin += sizeof(MachO::x86_exception_state_t); + } else { + memset(&es, '\0', sizeof(MachO::x86_exception_state_t)); + memcpy(&es, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(es); + if (es.esh.flavor == MachO::x86_EXCEPTION_STATE64) { + outs() << "\t esh.flavor x86_EXCEPTION_STATE64\n"; + if (es.esh.count == MachO::x86_EXCEPTION_STATE64_COUNT) + outs() << "\t esh.count x86_EXCEPTION_STATE64_COUNT\n"; + else + outs() << "\t esh.count " << es.esh.count + << " (not x86_EXCEPTION_STATE64_COUNT\n"; + Print_x86_exception_state_t(es.ues.es64); + } else { + outs() << "\t esh.flavor " << es.esh.flavor << " esh.count " + << es.esh.count << "\n"; + } + } else { + outs() << " flavor " << flavor << " (unknown)\n"; + outs() << " count " << count << "\n"; + outs() << " state (unknown)\n"; + begin += count * sizeof(uint32_t); + } + } + } else { + while (begin < end) { + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&flavor, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + flavor = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(flavor); + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&count, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + count = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(count); + outs() << " flavor " << flavor << "\n"; + outs() << " count " << count << "\n"; + outs() << " state (Unknown cputype/cpusubtype)\n"; + begin += count * sizeof(uint32_t); + } + } +} + static void PrintDylibCommand(MachO::dylib_command dl, const char *Ptr) { if (dl.cmd == MachO::LC_ID_DYLIB) outs() << " cmd LC_ID_DYLIB\n"; @@ -3443,6 +5271,8 @@ static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld, static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds, uint32_t filetype, uint32_t cputype, bool verbose) { + if (ncmds == 0) + return; StringRef Buf = Obj->getData(); MachOObjectFile::LoadCommandInfo Command = Obj->getFirstLoadCommandInfo(); for (unsigned i = 0;; ++i) { @@ -3455,7 +5285,7 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds, SLC.initprot, SLC.nsects, SLC.flags, Buf.size(), verbose); for (unsigned j = 0; j < SLC.nsects; j++) { - MachO::section_64 S = Obj->getSection64(Command, j); + MachO::section S = Obj->getSection(Command, j); PrintSection(S.sectname, S.segname, S.addr, S.size, S.offset, S.align, S.reloff, S.nreloc, S.flags, S.reserved1, S.reserved2, SLC.cmd, sg_segname, filetype, Buf.size(), verbose); @@ -3494,7 +5324,11 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds, } else if (Command.C.cmd == MachO::LC_UUID) { MachO::uuid_command Uuid = Obj->getUuidCommand(Command); PrintUuidLoadCommand(Uuid); - } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX) { + } else if (Command.C.cmd == MachO::LC_RPATH) { + MachO::rpath_command Rpath = Obj->getRpathCommand(Command); + PrintRpathLoadCommand(Rpath, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_VERSION_MIN_MACOSX || + Command.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) { MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command); PrintVersionMinLoadCommand(Vd); } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) { @@ -3503,6 +5337,40 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t ncmds, } else if (Command.C.cmd == MachO::LC_MAIN) { MachO::entry_point_command Ep = Obj->getEntryPointCommand(Command); PrintEntryPointCommand(Ep); + } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO) { + MachO::encryption_info_command Ei = + Obj->getEncryptionInfoCommand(Command); + PrintEncryptionInfoCommand(Ei, Buf.size()); + } else if (Command.C.cmd == MachO::LC_ENCRYPTION_INFO_64) { + MachO::encryption_info_command_64 Ei = + Obj->getEncryptionInfoCommand64(Command); + PrintEncryptionInfoCommand64(Ei, Buf.size()); + } else if (Command.C.cmd == MachO::LC_LINKER_OPTION) { + MachO::linker_option_command Lo = + Obj->getLinkerOptionLoadCommand(Command); + PrintLinkerOptionCommand(Lo, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_SUB_FRAMEWORK) { + MachO::sub_framework_command Sf = Obj->getSubFrameworkCommand(Command); + PrintSubFrameworkCommand(Sf, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_SUB_UMBRELLA) { + MachO::sub_umbrella_command Sf = Obj->getSubUmbrellaCommand(Command); + PrintSubUmbrellaCommand(Sf, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_SUB_LIBRARY) { + MachO::sub_library_command Sl = Obj->getSubLibraryCommand(Command); + PrintSubLibraryCommand(Sl, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_SUB_CLIENT) { + MachO::sub_client_command Sc = Obj->getSubClientCommand(Command); + PrintSubClientCommand(Sc, Command.Ptr); + } else if (Command.C.cmd == MachO::LC_ROUTINES) { + MachO::routines_command Rc = Obj->getRoutinesCommand(Command); + PrintRoutinesCommand(Rc); + } else if (Command.C.cmd == MachO::LC_ROUTINES_64) { + MachO::routines_command_64 Rc = Obj->getRoutinesCommand64(Command); + PrintRoutinesCommand64(Rc); + } else if (Command.C.cmd == MachO::LC_THREAD || + Command.C.cmd == MachO::LC_UNIXTHREAD) { + MachO::thread_command Tc = Obj->getThreadCommand(Command); + PrintThreadCommand(Tc, Command.Ptr, Obj->isLittleEndian(), cputype); } else if (Command.C.cmd == MachO::LC_LOAD_DYLIB || Command.C.cmd == MachO::LC_ID_DYLIB || Command.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile index 4616b78..7c16523 100644 --- a/tools/llvm-objdump/Makefile +++ b/tools/llvm-objdump/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-objdump -LINK_COMPONENTS := all-targets DebugInfo MC MCParser MCDisassembler Object +LINK_COMPONENTS := all-targets DebugInfoDWARF MC MCParser MCDisassembler Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 8903bff..6e62aaa 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -44,7 +44,6 @@ #include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/MemoryObject.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" @@ -62,36 +61,36 @@ using namespace object; static cl::list InputFilenames(cl::Positional, cl::desc(""),cl::ZeroOrMore); -static cl::opt -Disassemble("disassemble", +cl::opt +llvm::Disassemble("disassemble", cl::desc("Display assembler mnemonics for the machine instructions")); static cl::alias Disassembled("d", cl::desc("Alias for --disassemble"), cl::aliasopt(Disassemble)); -static cl::opt -Relocations("r", cl::desc("Display the relocation entries in the file")); +cl::opt +llvm::Relocations("r", cl::desc("Display the relocation entries in the file")); -static cl::opt -SectionContents("s", cl::desc("Display the content of each section")); +cl::opt +llvm::SectionContents("s", cl::desc("Display the content of each section")); -static cl::opt -SymbolTable("t", cl::desc("Display the symbol table")); +cl::opt +llvm::SymbolTable("t", cl::desc("Display the symbol table")); -static cl::opt -ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols")); +cl::opt +llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols")); -static cl::opt -Rebase("rebase", cl::desc("Display mach-o rebasing info")); +cl::opt +llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info")); -static cl::opt -Bind("bind", cl::desc("Display mach-o binding info")); +cl::opt +llvm::Bind("bind", cl::desc("Display mach-o binding info")); -static cl::opt -LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info")); +cl::opt +llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info")); -static cl::opt -WeakBind("weak-bind", cl::desc("Display mach-o weak binding info")); +cl::opt +llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info")); static cl::opt MachOOpt("macho", cl::desc("Use MachO specific object file parser")); @@ -109,12 +108,12 @@ llvm::MCPU("mcpu", cl::init("")); cl::opt -llvm::ArchName("arch", cl::desc("Target arch to disassemble for, " +llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, " "see -version for available targets")); -static cl::opt -SectionHeaders("section-headers", cl::desc("Display summaries of the headers " - "for each section.")); +cl::opt +llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the " + "headers for each section.")); static cl::alias SectionHeadersShort("headers", cl::desc("Alias for --section-headers"), cl::aliasopt(SectionHeaders)); @@ -133,22 +132,23 @@ llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling " "instructions, do not print " "the instruction bytes.")); -static cl::opt -UnwindInfo("unwind-info", cl::desc("Display unwind information")); +cl::opt +llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information")); static cl::alias UnwindInfoShort("u", cl::desc("Alias for --unwind-info"), cl::aliasopt(UnwindInfo)); -static cl::opt -PrivateHeaders("private-headers", - cl::desc("Display format specific file headers")); +cl::opt +llvm::PrivateHeaders("private-headers", + cl::desc("Display format specific file headers")); static cl::alias PrivateHeadersShort("p", cl::desc("Alias for --private-headers"), cl::aliasopt(PrivateHeaders)); static StringRef ToolName; +static int ReturnValue = EXIT_SUCCESS; bool llvm::error(std::error_code EC) { if (!EC) @@ -156,6 +156,7 @@ bool llvm::error(std::error_code EC) { outs() << ToolName << ": error reading file: " << EC.message() << ".\n"; outs().flush(); + ReturnValue = EXIT_FAILURE; return true; } @@ -452,7 +453,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } } -static void PrintRelocations(const ObjectFile *Obj) { +void llvm::PrintRelocations(const ObjectFile *Obj) { StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 : "%08" PRIx64; // Regular objdump doesn't print relocations in non-relocatable object @@ -489,7 +490,7 @@ static void PrintRelocations(const ObjectFile *Obj) { } } -static void PrintSectionHeaders(const ObjectFile *Obj) { +void llvm::PrintSectionHeaders(const ObjectFile *Obj) { outs() << "Sections:\n" "Idx Name Size Address Type\n"; unsigned i = 0; @@ -510,7 +511,7 @@ static void PrintSectionHeaders(const ObjectFile *Obj) { } } -static void PrintSectionContents(const ObjectFile *Obj) { +void llvm::PrintSectionContents(const ObjectFile *Obj) { std::error_code EC; for (const SectionRef &Section : Obj->sections()) { StringRef Name; @@ -613,7 +614,7 @@ static void PrintCOFFSymbolTable(const COFFObjectFile *coff) { } } -static void PrintSymbolTable(const ObjectFile *o) { +void llvm::PrintSymbolTable(const ObjectFile *o) { outs() << "SYMBOL TABLE:\n"; if (const COFFObjectFile *coff = dyn_cast(o)) { @@ -641,7 +642,15 @@ static void PrintSymbolTable(const ObjectFile *o) { bool Global = Flags & SymbolRef::SF_Global; bool Weak = Flags & SymbolRef::SF_Weak; bool Absolute = Flags & SymbolRef::SF_Absolute; - + bool Common = Flags & SymbolRef::SF_Common; + + if (Common) { + uint32_t Alignment; + if (error(Symbol.getAlignment(Alignment))) + Alignment = 0; + Address = Size; + Size = Alignment; + } if (Address == UnknownAddressOrSize) Address = 0; if (Size == UnknownAddressOrSize) @@ -671,6 +680,8 @@ static void PrintSymbolTable(const ObjectFile *o) { << ' '; if (Absolute) { outs() << "*ABS*"; + } else if (Common) { + outs() << "*COM*"; } else if (Section == o->section_end()) { outs() << "*UND*"; } else { @@ -707,7 +718,7 @@ static void PrintUnwindInfo(const ObjectFile *o) { } } -static void printExportsTrie(const ObjectFile *o) { +void llvm::printExportsTrie(const ObjectFile *o) { outs() << "Exports trie:\n"; if (const MachOObjectFile *MachO = dyn_cast(o)) printMachOExportsTrie(MachO); @@ -718,7 +729,7 @@ static void printExportsTrie(const ObjectFile *o) { } } -static void printRebaseTable(const ObjectFile *o) { +void llvm::printRebaseTable(const ObjectFile *o) { outs() << "Rebase table:\n"; if (const MachOObjectFile *MachO = dyn_cast(o)) printMachORebaseTable(MachO); @@ -729,7 +740,7 @@ static void printRebaseTable(const ObjectFile *o) { } } -static void printBindTable(const ObjectFile *o) { +void llvm::printBindTable(const ObjectFile *o) { outs() << "Bind table:\n"; if (const MachOObjectFile *MachO = dyn_cast(o)) printMachOBindTable(MachO); @@ -740,7 +751,7 @@ static void printBindTable(const ObjectFile *o) { } } -static void printLazyBindTable(const ObjectFile *o) { +void llvm::printLazyBindTable(const ObjectFile *o) { outs() << "Lazy bind table:\n"; if (const MachOObjectFile *MachO = dyn_cast(o)) printMachOLazyBindTable(MachO); @@ -751,7 +762,7 @@ static void printLazyBindTable(const ObjectFile *o) { } } -static void printWeakBindTable(const ObjectFile *o) { +void llvm::printWeakBindTable(const ObjectFile *o) { outs() << "Weak bind table:\n"; if (const MachOObjectFile *MachO = dyn_cast(o)) printMachOWeakBindTable(MachO); @@ -831,8 +842,11 @@ static void DumpInput(StringRef file) { return; } - if (MachOOpt && Disassemble) { - DisassembleInputMachO(file); + // If we are using the Mach-O specific object file parser, then let it parse + // the file and process the command line options. So the -arch flags can + // be used to select specific slices, etc. + if (MachOOpt) { + ParseInputMachO(file); return; } @@ -887,7 +901,13 @@ int main(int argc, char **argv) { && !Rebase && !Bind && !LazyBind - && !WeakBind) { + && !WeakBind + && !(UniversalHeaders && MachOOpt) + && !(ArchiveHeaders && MachOOpt) + && !(IndirectSymbols && MachOOpt) + && !(DataInCode && MachOOpt) + && !(LinkOptHints && MachOOpt) + && !(DumpSections.size() != 0 && MachOOpt)) { cl::PrintHelpMessage(); return 2; } @@ -895,5 +915,5 @@ int main(int argc, char **argv) { std::for_each(InputFilenames.begin(), InputFilenames.end(), DumpInput); - return 0; + return ReturnValue; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index ef1509f..19f842f 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -26,13 +26,31 @@ extern cl::opt TripleName; extern cl::opt ArchName; extern cl::opt MCPU; extern cl::list MAttrs; +extern cl::list DumpSections; +extern cl::opt Disassemble; extern cl::opt NoShowRawInsn; +extern cl::opt PrivateHeaders; +extern cl::opt ExportsTrie; +extern cl::opt Rebase; +extern cl::opt Bind; +extern cl::opt LazyBind; +extern cl::opt WeakBind; +extern cl::opt UniversalHeaders; +extern cl::opt ArchiveHeaders; +extern cl::opt IndirectSymbols; +extern cl::opt DataInCode; +extern cl::opt LinkOptHints; +extern cl::opt Relocations; +extern cl::opt SectionHeaders; +extern cl::opt SectionContents; +extern cl::opt SymbolTable; +extern cl::opt UnwindInfo; // Various helper functions. bool error(std::error_code ec); bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void DumpBytes(StringRef bytes); -void DisassembleInputMachO(StringRef Filename); +void ParseInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printMachOUnwindInfo(const object::MachOObjectFile* o); void printMachOExportsTrie(const object::MachOObjectFile* o); @@ -43,6 +61,15 @@ void printMachOWeakBindTable(const object::MachOObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); void printCOFFFileHeader(const object::ObjectFile *o); void printMachOFileHeader(const object::ObjectFile *o); +void printExportsTrie(const object::ObjectFile *o); +void printRebaseTable(const object::ObjectFile *o); +void printBindTable(const object::ObjectFile *o); +void printLazyBindTable(const object::ObjectFile *o); +void printWeakBindTable(const object::ObjectFile *o); +void PrintRelocations(const object::ObjectFile *o); +void PrintSectionHeaders(const object::ObjectFile *o); +void PrintSectionContents(const object::ObjectFile *o); +void PrintSymbolTable(const object::ObjectFile *o); } // end namespace llvm diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt new file mode 100644 index 0000000..0519bf0 --- /dev/null +++ b/tools/llvm-pdbdump/CMakeLists.txt @@ -0,0 +1,14 @@ +set(LLVM_LINK_COMPONENTS + Support + DebugInfoPDB + ) + +add_llvm_tool(llvm-pdbdump + llvm-pdbdump.cpp + ClassDefinitionDumper.cpp + CompilandDumper.cpp + FunctionDumper.cpp + TypeDumper.cpp + TypedefDumper.cpp + VariableDumper.cpp + ) diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp new file mode 100644 index 0000000..edf6eb4 --- /dev/null +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp @@ -0,0 +1,152 @@ +//===- ClassDefinitionDumper.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ClassDefinitionDumper.h" +#include "FunctionDumper.h" +#include "llvm-pdbdump.h" +#include "TypedefDumper.h" +#include "VariableDumper.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +ClassDefinitionDumper::ClassDefinitionDumper() : PDBSymDumper(true) {} + +void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class, + raw_ostream &OS, int Indent) { + OS << "class " << Class.getName() << " {"; + auto Children = Class.findAllChildren(); + if (Children->getChildCount() == 0) { + OS << "}"; + return; + } + + // Try to dump symbols organized by member access level. Public members + // first, then protected, then private. This might be slow, so it's worth + // reconsidering the value of this if performance of large PDBs is a problem. + // NOTE: Access level of nested types is not recorded in the PDB, so we have + // a special case for them. + SymbolGroupByAccess Groups; + Groups.insert(std::make_pair(0, SymbolGroup())); + Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup())); + Groups.insert( + std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup())); + Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup())); + + while (auto Child = Children->getNext()) { + PDB_MemberAccess Access = Child->getRawSymbol().getAccess(); + if (isa(*Child)) + continue; + + auto &AccessGroup = Groups.find((int)Access)->second; + + if (auto Func = dyn_cast(Child.get())) { + if (Func->isCompilerGenerated()) + continue; + if (Func->getLength() == 0 && !Func->isPureVirtual()) + continue; + Child.release(); + AccessGroup.Functions.push_back(std::unique_ptr(Func)); + } else if (auto Data = dyn_cast(Child.get())) { + Child.release(); + AccessGroup.Data.push_back(std::unique_ptr(Data)); + } else { + AccessGroup.Unknown.push_back(std::move(Child)); + } + } + + int Count = 0; + Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0], OS, Indent); + Count += dumpAccessGroup(PDB_MemberAccess::Public, + Groups[(int)PDB_MemberAccess::Public], OS, Indent); + Count += + dumpAccessGroup(PDB_MemberAccess::Protected, + Groups[(int)PDB_MemberAccess::Protected], OS, Indent); + Count += dumpAccessGroup(PDB_MemberAccess::Private, + Groups[(int)PDB_MemberAccess::Private], OS, Indent); + + if (Count > 0) + OS << newline(Indent); + OS << "}"; +} + +int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access, + const SymbolGroup &Group, + raw_ostream &OS, int Indent) { + 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:"; + for (auto iter = Group.Functions.begin(), end = Group.Functions.end(); + iter != end; ++iter) { + ++Count; + (*iter)->dump(OS, Indent + 2, *this); + } + for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end; + ++iter) { + ++Count; + (*iter)->dump(OS, Indent + 2, *this); + } + for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end(); + iter != end; ++iter) { + ++Count; + (*iter)->dump(OS, Indent + 2, *this); + } + return Count; +} + +void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol, + raw_ostream &OS, int Indent) {} + +void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS, + int Indent) { + VariableDumper Dumper; + Dumper.start(Symbol, OS, Indent); +} + +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 PDBSymbolTypeVTable &Symbol, + raw_ostream &OS, int Indent) {} + +void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol, + raw_ostream &OS, int Indent) { + OS << newline(Indent) << "enum " << Symbol.getName(); +} + +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 PDBSymbolTypeUDT &Symbol, + raw_ostream &OS, int Indent) {} diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.h b/tools/llvm-pdbdump/ClassDefinitionDumper.h new file mode 100644 index 0000000..aaf0376 --- /dev/null +++ b/tools/llvm-pdbdump/ClassDefinitionDumper.h @@ -0,0 +1,64 @@ +//===- ClassDefinitionDumper.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_CLASSDEFINITIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_CLASSDEFINITIONDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" + +#include +#include +#include + +namespace llvm { + +class ClassDefinitionDumper : public PDBSymDumper { +public: + ClassDefinitionDumper(); + + void start(const PDBSymbolTypeUDT &Exe, raw_ostream &OS, int Indent); + + 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; + +private: + struct SymbolGroup { + SymbolGroup() {} + SymbolGroup(SymbolGroup &&Other) { + Functions = std::move(Other.Functions); + Data = std::move(Other.Data); + Unknown = std::move(Other.Unknown); + } + + std::list> Functions; + std::list> Data; + std::list> Unknown; + SymbolGroup(const SymbolGroup &other) = delete; + SymbolGroup &operator=(const SymbolGroup &other) = delete; + }; + typedef std::unordered_map SymbolGroupByAccess; + + int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group, + raw_ostream &OS, int Indent); +}; +} + +#endif diff --git a/tools/llvm-pdbdump/CompilandDumper.cpp b/tools/llvm-pdbdump/CompilandDumper.cpp new file mode 100644 index 0000000..852ddfa --- /dev/null +++ b/tools/llvm-pdbdump/CompilandDumper.cpp @@ -0,0 +1,117 @@ +//===- CompilandDumper.cpp - llvm-pdbdump compiland symbol dumper *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CompilandDumper.h" +#include "llvm-pdbdump.h" + +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBExtras.h" +#include "llvm/DebugInfo/PDB/PDBSymbol.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h" +#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h" +#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +#include "FunctionDumper.h" + +#include +#include + +using namespace llvm; + +CompilandDumper::CompilandDumper() : PDBSymDumper(true) {} + +void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol, + raw_ostream &OS, int Indent) {} + +void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol, raw_ostream &OS, + int Indent) {} + +void CompilandDumper::start(const PDBSymbolCompiland &Symbol, raw_ostream &OS, + int Indent, bool Children) { + std::string FullName = Symbol.getName(); + OS << newline(Indent) << FullName; + if (!Children) + return; + + auto ChildrenEnum = Symbol.findAllChildren(); + while (auto Child = ChildrenEnum->getNext()) + Child->dump(OS, Indent + 2, *this); +} + +void CompilandDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS, + int Indent) { + OS << newline(Indent); + switch (auto LocType = Symbol.getLocationType()) { + case PDB_LocType::Static: + OS << "data: ["; + OS << format_hex(Symbol.getRelativeVirtualAddress(), 10); + OS << "]"; + break; + case PDB_LocType::Constant: + OS << "constant: [" << Symbol.getValue() << "]"; + break; + default: + OS << "data(unexpected type=" << LocType << ")"; + } + + OS << " " << Symbol.getName(); +} + +void CompilandDumper::dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, + int Indent) { + if (Symbol.getLength() == 0) + return; + + FunctionDumper Dumper; + Dumper.start(Symbol, FunctionDumper::PointerType::None, OS, Indent); +} + +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 PDBSymbolThunk &Symbol, raw_ostream &OS, + int Indent) { + OS << newline(Indent) << "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); + } else { + OS << "[" << format_hex(RVA, 10); + OS << " - " << format_hex(RVA + Symbol.getLength(), 10) << "]"; + } + OS << " (" << Ordinal << ") "; + std::string Name = Symbol.getName(); + if (!Name.empty()) + OS << Name; +} + +void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, + int Indent) {} + +void CompilandDumper::dump(const PDBSymbolUnknown &Symbol, raw_ostream &OS, + int Indent) { + OS << newline(Indent); + OS << "unknown (" << Symbol.getSymTag() << ")"; +} diff --git a/tools/llvm-pdbdump/CompilandDumper.h b/tools/llvm-pdbdump/CompilandDumper.h new file mode 100644 index 0000000..abcebc2 --- /dev/null +++ b/tools/llvm-pdbdump/CompilandDumper.h @@ -0,0 +1,39 @@ +//===- CompilandDumper.h - llvm-pdbdump compiland symbol dumper *- 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_COMPILANDDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_COMPILANDDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +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; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/FunctionDumper.cpp b/tools/llvm-pdbdump/FunctionDumper.cpp new file mode 100644 index 0000000..e659830 --- /dev/null +++ b/tools/llvm-pdbdump/FunctionDumper.cpp @@ -0,0 +1,243 @@ +//===- FunctionDumper.cpp ------------------------------------ *- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "FunctionDumper.h" +#include "llvm-pdbdump.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolData.h" +#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h" +#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" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +namespace { +template +void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS, + llvm::FunctionDumper &Dumper) { + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().template getConcreteSymbolById( + ClassParentId); + if (!ClassParent) + return; + + OS << ClassParent->getName() << "::"; +} +} + +FunctionDumper::FunctionDumper() : PDBSymDumper(true) {} + +void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol, + PointerType Pointer, raw_ostream &OS) { + auto ReturnType = Symbol.getReturnType(); + ReturnType->dump(OS, 0, *this); + OS << " "; + uint32_t ClassParentId = Symbol.getClassParentId(); + auto ClassParent = + Symbol.getSession().getConcreteSymbolById( + ClassParentId); + + PDB_CallingConv CC = Symbol.getCallingConvention(); + bool ShouldDumpCallingConvention = true; + if ((ClassParent && CC == PDB_CallingConv::Thiscall) || + (!ClassParent && CC == PDB_CallingConv::NearStdcall)) { + ShouldDumpCallingConvention = false; + } + + if (Pointer == PointerType::None) { + if (ShouldDumpCallingConvention) + OS << CC << " "; + if (ClassParent) + OS << "(" << ClassParent->getName() << "::)"; + } else { + OS << "("; + if (ShouldDumpCallingConvention) + OS << CC << " "; + OS << Symbol.getCallingConvention() << " "; + if (ClassParent) + OS << ClassParent->getName() << "::"; + if (Pointer == PointerType::Reference) + OS << "&"; + else + OS << "*"; + OS << ")"; + } + + OS << "("; + if (auto ChildEnum = Symbol.getArguments()) { + uint32_t Index = 0; + while (auto Arg = ChildEnum->getNext()) { + Arg->dump(OS, 0, *this); + if (++Index < ChildEnum->getChildCount()) + OS << ", "; + } + } + OS << ")"; + + if (Symbol.isConstType()) + OS << " const"; + if (Symbol.isVolatileType()) + OS << " volatile"; +} + +void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer, + raw_ostream &OS, int Indent) { + 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()) + OS << "+" << DebugStart->getRelativeVirtualAddress() - FuncStart; + OS << " - " << format_hex(FuncEnd, 8); + if (auto DebugEnd = Symbol.findOneChild()) + OS << "-" << FuncEnd - DebugEnd->getRelativeVirtualAddress(); + OS << "] "; + + if (Symbol.hasFramePointer()) + OS << "(" << Symbol.getLocalBasePointerRegisterId() << ")"; + else + OS << "(FPO)"; + + OS << " "; + if (Symbol.isVirtual() || Symbol.isPureVirtual()) + OS << "virtual "; + + auto Signature = Symbol.getSignature(); + if (!Signature) { + OS << Symbol.getName(); + if (Pointer == PointerType::Pointer) + OS << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + OS << "&"; + return; + } + + auto ReturnType = Signature->getReturnType(); + ReturnType->dump(OS, 0, *this); + OS << " "; + + auto ClassParent = Symbol.getClassParent(); + PDB_CallingConv CC = Signature->getCallingConvention(); + if (Pointer != FunctionDumper::PointerType::None) + OS << "("; + + if ((ClassParent && CC != PDB_CallingConv::Thiscall) || + (!ClassParent && CC != PDB_CallingConv::NearStdcall)) + OS << Signature->getCallingConvention() << " "; + OS << Symbol.getName(); + if (Pointer != FunctionDumper::PointerType::None) { + if (Pointer == PointerType::Pointer) + OS << "*"; + else if (Pointer == FunctionDumper::PointerType::Reference) + OS << "&"; + OS << ")"; + } + + OS << "("; + 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(); + if (++Index < Arguments->getChildCount()) + OS << ", "; + } + } + OS << ")"; + if (Symbol.isConstType()) + OS << " const"; + if (Symbol.isVolatileType()) + OS << " volatile"; + if (Symbol.isPureVirtual()) + OS << " = 0"; +} + +void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, + int Indent) { + uint32_t ElementTypeId = Symbol.getTypeId(); + auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId); + if (!ElementType) + return; + + ElementType->dump(OS, 0, *this); + OS << "[" << Symbol.getLength() << "]"; +} + +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 PDBSymbolTypeEnum &Symbol, raw_ostream &OS, + int Indent) { + dumpClassParentWithScopeOperator(Symbol, OS, *this); + OS << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol, + raw_ostream &OS, int Indent) { + // 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); +} + +void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, + int Indent) { + dumpClassParentWithScopeOperator(Symbol, OS, *this); + OS << Symbol.getName(); +} + +void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, + int Indent) { + uint32_t PointeeId = Symbol.getTypeId(); + auto PointeeType = Symbol.getSession().getSymbolById(PointeeId); + if (!PointeeType) + return; + + if (auto FuncSig = dyn_cast(PointeeType.get())) { + FunctionDumper NestedDumper; + PointerType Pointer = + Symbol.isReference() ? PointerType::Reference : PointerType::Pointer; + NestedDumper.start(*FuncSig, Pointer, OS); + } else { + if (Symbol.isConstType()) + OS << "const "; + if (Symbol.isVolatileType()) + OS << "volatile "; + PointeeType->dump(OS, Indent, *this); + OS << (Symbol.isReference() ? "&" : "*"); + } +} + +void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, + int Indent) { + OS << Symbol.getName(); +} diff --git a/tools/llvm-pdbdump/FunctionDumper.h b/tools/llvm-pdbdump/FunctionDumper.h new file mode 100644 index 0000000..f9338cb --- /dev/null +++ b/tools/llvm-pdbdump/FunctionDumper.h @@ -0,0 +1,45 @@ +//===- FunctionDumper.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_FUNCTIONDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_FUNCTIONDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class FunctionDumper : public PDBSymDumper { +public: + FunctionDumper(); + + 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; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/LLVMBuild.txt b/tools/llvm-pdbdump/LLVMBuild.txt new file mode 100644 index 0000000..4877689 --- /dev/null +++ b/tools/llvm-pdbdump/LLVMBuild.txt @@ -0,0 +1,23 @@ +;===- ./tools/llvm-pdbdump/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-pdbdump +parent = Tools +required_libraries = DebugInfoPDB + diff --git a/tools/llvm-pdbdump/Makefile b/tools/llvm-pdbdump/Makefile new file mode 100644 index 0000000..18aafc4 --- /dev/null +++ b/tools/llvm-pdbdump/Makefile @@ -0,0 +1,17 @@ +##===- tools/llvm-pdbdump/Makefile -------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-pdbdump +LINK_COMPONENTS := DebugInfoPDB Object + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-pdbdump/TypeDumper.cpp b/tools/llvm-pdbdump/TypeDumper.cpp new file mode 100644 index 0000000..3131e9f --- /dev/null +++ b/tools/llvm-pdbdump/TypeDumper.cpp @@ -0,0 +1,96 @@ +//===- TypeDumper.cpp - PDBSymDumper implementation for types *----- C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TypeDumper.h" + +#include "ClassDefinitionDumper.h" +#include "FunctionDumper.h" +#include "llvm-pdbdump.h" +#include "TypedefDumper.h" + +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.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) {} + +void TypeDumper::start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent) { + auto Enums = Exe.findAllChildren(); + OS << newline(Indent) << "Enums: (" << Enums->getChildCount() << " items)"; + while (auto Enum = Enums->getNext()) + Enum->dump(OS, Indent + 2, *this); + + auto FuncSigs = Exe.findAllChildren(); + OS << newline(Indent); + OS << "Function Signatures: (" << FuncSigs->getChildCount() << " items)"; + while (auto Sig = FuncSigs->getNext()) + Sig->dump(OS, Indent + 2, *this); + + auto Typedefs = Exe.findAllChildren(); + OS << newline(Indent) << "Typedefs: (" << Typedefs->getChildCount() + << " items)"; + while (auto Typedef = Typedefs->getNext()) + Typedef->dump(OS, Indent + 2, *this); + + auto Classes = Exe.findAllChildren(); + OS << newline(Indent) << "Classes: (" << Classes->getChildCount() + << " items)"; + while (auto Class = Classes->getNext()) + Class->dump(OS, Indent + 2, *this); +} + +void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, + int Indent) { + if (Symbol.getUnmodifiedTypeId() != 0) + 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); +} + +void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, + int Indent) { + if (!InlineDump) + OS << newline(Indent); + + TypedefDumper Dumper; + Dumper.start(Symbol, OS, Indent); +} + +void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, + int Indent) { + if (Symbol.getUnmodifiedTypeId() != 0) + return; + if (!InlineDump) + OS << newline(Indent); + + if (FullClassDefs) { + ClassDefinitionDumper Dumper; + Dumper.start(Symbol, OS, Indent); + } else { + OS << "class " << Symbol.getName(); + } +} diff --git a/tools/llvm-pdbdump/TypeDumper.h b/tools/llvm-pdbdump/TypeDumper.h new file mode 100644 index 0000000..d96c24c --- /dev/null +++ b/tools/llvm-pdbdump/TypeDumper.h @@ -0,0 +1,38 @@ +//===- TypeDumper.h - PDBSymDumper implementation for types *- 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_TYPEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +class TypeDumper : public PDBSymDumper { +public: + TypeDumper(bool Inline, bool ClassDefs); + + void start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent); + + 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; + +private: + bool InlineDump; + bool FullClassDefs; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/TypedefDumper.cpp b/tools/llvm-pdbdump/TypedefDumper.cpp new file mode 100644 index 0000000..6eea6b6 --- /dev/null +++ b/tools/llvm-pdbdump/TypedefDumper.cpp @@ -0,0 +1,84 @@ +//===- TypedefDumper.cpp - PDBSymDumper impl for typedefs -------- * C++ *-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TypedefDumper.h" + +#include "FunctionDumper.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" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +using namespace llvm; + +TypedefDumper::TypedefDumper() : PDBSymDumper(true) {} + +void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, + int Indent) { + OS << "typedef "; + uint32_t TargetId = Symbol.getTypeId(); + if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId)) + TypeSymbol->dump(OS, 0, *this); + OS << " " << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS, + int Indent) {} + +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 PDBSymbolTypeEnum &Symbol, raw_ostream &OS, + int Indent) { + OS << "enum " << Symbol.getName(); +} + +void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, + int Indent) { + if (Symbol.isConstType()) + OS << "const "; + if (Symbol.isVolatileType()) + OS << "volatile "; + uint32_t PointeeId = Symbol.getTypeId(); + auto PointeeType = Symbol.getSession().getSymbolById(PointeeId); + if (!PointeeType) + return; + if (auto FuncSig = dyn_cast(PointeeType.get())) { + FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer; + if (Symbol.isReference()) + Pointer = FunctionDumper::PointerType::Reference; + FunctionDumper NestedDumper; + NestedDumper.start(*FuncSig, Pointer, OS); + } else { + PointeeType->dump(OS, Indent, *this); + OS << ((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 PDBSymbolTypeUDT &Symbol, raw_ostream &OS, + int Indent) { + OS << "class " << Symbol.getName(); +} diff --git a/tools/llvm-pdbdump/TypedefDumper.h b/tools/llvm-pdbdump/TypedefDumper.h new file mode 100644 index 0000000..e6211a8 --- /dev/null +++ b/tools/llvm-pdbdump/TypedefDumper.h @@ -0,0 +1,38 @@ +//===- TypedefDumper.h - llvm-pdbdump typedef dumper ---------*- 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_TYPEDEFDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDEFDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" + +namespace llvm { + +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; +}; +} + +#endif diff --git a/tools/llvm-pdbdump/VariableDumper.cpp b/tools/llvm-pdbdump/VariableDumper.cpp new file mode 100644 index 0000000..913cfee --- /dev/null +++ b/tools/llvm-pdbdump/VariableDumper.cpp @@ -0,0 +1,120 @@ +//===- VariableDumper.cpp - -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "VariableDumper.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/PDBSymbolTypePointer.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" + +#include "llvm/Support/Format.h" + +using namespace llvm; + +VariableDumper::VariableDumper() : PDBSymDumper(true) {} + +void VariableDumper::start(const PDBSymbolData &Var, raw_ostream &OS, + int Indent) { + OS << newline(Indent); + OS << "data "; + + 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); + break; + case PDB_LocType::Constant: + OS << "const "; + dumpSymbolTypeAndName(*VarType, Var.getName(), OS); + OS << "[" << Var.getValue() << "]"; + break; + case PDB_LocType::ThisRel: + OS << "+" << format_hex(Var.getOffset(), 4) << " "; + dumpSymbolTypeAndName(*VarType, Var.getName(), OS); + break; + default: + break; + OS << "unknown(" << LocType << ") " << Var.getName(); + } +} + +void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS, + int Indent) { + OS << Symbol.getBuiltinType(); +} + +void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS, + int Indent) { + OS << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol, + raw_ostream &OS, int Indent) {} + +void VariableDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS, + int Indent) { + auto PointeeType = Symbol.getPointeeType(); + if (!PointeeType) + return; + + if (auto Func = dyn_cast(PointeeType.get())) { + FunctionDumper NestedDumper; + FunctionDumper::PointerType Pointer = + Symbol.isReference() ? FunctionDumper::PointerType::Reference + : FunctionDumper::PointerType::Pointer; + NestedDumper.start(*Func, Pointer, OS, Indent); + } else { + if (Symbol.isConstType()) + OS << "const "; + if (Symbol.isVolatileType()) + OS << "volatile "; + PointeeType->dump(OS, Indent, *this); + OS << (Symbol.isReference() ? "&" : "*"); + } +} + +void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, + int Indent) { + OS << "typedef " << Symbol.getName(); +} + +void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS, + int Indent) { + OS << Symbol.getName(); +} + +void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type, + StringRef Name, raw_ostream &OS) { + if (auto *ArrayType = dyn_cast(&Type)) { + std::string IndexSpec; + raw_string_ostream IndexStream(IndexSpec); + std::unique_ptr ElementType = ArrayType->getElementType(); + while (auto NestedArray = dyn_cast(ElementType.get())) { + IndexStream << "[" << NestedArray->getCount() << "]"; + ElementType = NestedArray->getElementType(); + } + IndexStream << "[" << ArrayType->getCount() << "]"; + ElementType->dump(OS, 0, *this); + OS << " " << Name << IndexStream.str(); + } else { + Type.dump(OS, 0, *this); + OS << " " << Name; + } +} diff --git a/tools/llvm-pdbdump/VariableDumper.h b/tools/llvm-pdbdump/VariableDumper.h new file mode 100644 index 0000000..e6e71fa --- /dev/null +++ b/tools/llvm-pdbdump/VariableDumper.h @@ -0,0 +1,43 @@ +//===- VariableDumper.h - PDBSymDumper implementation for types -*- 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_VARIABLEDUMPER_H +#define LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H + +#include "llvm/DebugInfo/PDB/PDBSymDumper.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +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; + +private: + void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name, + raw_ostream &OS); +}; +} + +#endif diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp new file mode 100644 index 0000000..e33e715 --- /dev/null +++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp @@ -0,0 +1,134 @@ +//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Dumps debug information present in PDB files. This utility makes use of +// the Microsoft Windows SDK, so will not compile or run on non-Windows +// platforms. +// +//===----------------------------------------------------------------------===// + +#include "llvm-pdbdump.h" +#include "CompilandDumper.h" +#include "TypeDumper.h" + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Config/config.h" +#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h" +#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h" +#include "llvm/DebugInfo/PDB/IPDBSession.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h" +#include "llvm/DebugInfo/PDB/PDBSymbolExe.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Signals.h" + +#if defined(HAVE_DIA_SDK) +#include +#endif + +using namespace llvm; + +namespace opts { + +enum class PDB_DumpType { ByType, ByObjFile, Both }; + +cl::list InputFilenames(cl::Positional, + cl::desc(""), + cl::OneOrMore); + +cl::opt DumpCompilands("compilands", cl::desc("Display compilands")); +cl::opt DumpSymbols("symbols", + cl::desc("Display symbols (implies --compilands")); +cl::opt DumpTypes("types", cl::desc("Display types")); +cl::opt DumpClassDefs("class-definitions", + cl::desc("Display full class definitions")); +} + +static void dumpInput(StringRef Path) { + std::unique_ptr 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."; + return; + } + + auto GlobalScope(Session->getGlobalScope()); + std::string FileName(GlobalScope->getSymbolsFileName()); + + outs() << "Summary for " << FileName; + 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: "; + if (GlobalScope->hasCTypes()) + outs() << "HasCTypes "; + if (GlobalScope->hasPrivateSymbols()) + outs() << "HasPrivateSymbols "; + + if (opts::DumpTypes) { + outs() << "\nDumping types"; + TypeDumper Dumper(false, opts::DumpClassDefs); + Dumper.start(*GlobalScope, outs(), 2); + } + + if (opts::DumpSymbols || opts::DumpCompilands) { + outs() << "\nDumping compilands"; + auto Compilands = GlobalScope->findAllChildren(); + CompilandDumper Dumper; + while (auto Compiland = Compilands->getNext()) + Dumper.start(*Compiland, outs(), 2, opts::DumpSymbols); + } + outs().flush(); +} + +int main(int argc_, const char *argv_[]) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc_, argv_); + + SmallVector argv; + llvm::SpecificBumpPtrAllocator ArgAllocator; + std::error_code EC = llvm::sys::Process::GetArgumentVector( + argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator); + if (EC) { + llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n'; + return 1; + } + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n"); + +#if defined(HAVE_DIA_SDK) + CoInitializeEx(nullptr, COINIT_MULTITHREADED); +#endif + + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); + +#if defined(HAVE_DIA_SDK) + CoUninitialize(); +#endif + + return 0; +} diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h new file mode 100644 index 0000000..74a1718 --- /dev/null +++ b/tools/llvm-pdbdump/llvm-pdbdump.h @@ -0,0 +1,28 @@ +//===- llvm-pdbdump.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_LLVMPDBDUMP_H +#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H + +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +struct newline { + newline(int IndentWidth) : Width(IndentWidth) {} + int Width; +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const newline &Indent) { + OS << "\n"; + OS.indent(Indent.Width); + return OS; +} +} + +#endif \ No newline at end of file diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index e977799..0137e35 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -12,11 +12,11 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/ProfileData/InstrProfWriter.h" #include "llvm/ProfileData/SampleProfReader.h" #include "llvm/ProfileData/SampleProfWriter.h" -#include "llvm/IR/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" @@ -38,7 +38,8 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") { enum ProfileKinds { instr, sample }; -void mergeInstrProfile(cl::list Inputs, StringRef OutputFilename) { +void mergeInstrProfile(const cl::list &Inputs, + StringRef OutputFilename) { if (OutputFilename.compare("-") == 0) exitWithError("Cannot write indexed profdata format to stdout."); @@ -64,7 +65,8 @@ void mergeInstrProfile(cl::list Inputs, StringRef OutputFilename) { Writer.write(Output); } -void mergeSampleProfile(cl::list Inputs, StringRef OutputFilename, +void mergeSampleProfile(const cl::list &Inputs, + StringRef OutputFilename, sampleprof::SampleProfileFormat OutputFormat) { using namespace sampleprof; auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat); diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp index d35cd14..e2d7191 100644 --- a/tools/llvm-readobj/ARMAttributeParser.cpp +++ b/tools/llvm-readobj/ARMAttributeParser.cpp @@ -141,7 +141,7 @@ void ARMAttributeParser::CPU_arch_profile(AttrType Tag, const uint8_t *Data, case 'R': Profile = "Real-time"; break; case 'M': Profile = "Microcontroller"; break; case 'S': Profile = "Classic"; break; - case '0': Profile = "None"; break; + case 0: Profile = "None"; break; } PrintAttribute(Tag, Encoded, Profile); diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp index ede36d1..62252fc 100644 --- a/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -64,8 +64,8 @@ #include "ARMWinEHPrinter.h" #include "Error.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/ARMWinEH.h" #include "llvm/Support/Format.h" diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 5276428..1412111 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -57,6 +57,7 @@ public: void printDynamicSymbols() override; void printUnwindInfo() override; void printCOFFImports() override; + void printCOFFExports() override; void printCOFFDirectives() override; void printCOFFBaseReloc() override; @@ -70,7 +71,7 @@ private: void printBaseOfDataField(const pe32_header *Hdr); void printBaseOfDataField(const pe32plus_header *Hdr); - void printCodeViewLineTables(const SectionRef &Section); + void printCodeViewDebugInfo(const SectionRef &Section); void printCodeViewSymbolsSubsection(StringRef Subsection, const SectionRef &Section, @@ -468,7 +469,7 @@ void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { void COFFDumper::printBaseOfDataField(const pe32plus_header *) {} -void COFFDumper::printCodeViewLineTables(const SectionRef &Section) { +void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) { StringRef Data; if (error(Section.getContents(Data))) return; @@ -476,7 +477,7 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) { SmallVector FunctionNames; StringMap FunctionLineTables; - ListScope D(W, "CodeViewLineTables"); + ListScope D(W, "CodeViewDebugInfo"); { // FIXME: Add more offset correctness checks. DataExtractor DE(Data, true, 4); @@ -502,14 +503,17 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) { return; } - // Print the raw contents to simplify debugging if anything goes wrong - // afterwards. StringRef Contents = Data.substr(Offset, PayloadSize); - W.printBinaryBlock("Contents", Contents); + if (opts::CodeViewSubsectionBytes) { + // Print the raw contents to simplify debugging if anything goes wrong + // afterwards. + W.printBinaryBlock("Contents", Contents); + } switch (SubSectionType) { case COFF::DEBUG_SYMBOL_SUBSECTION: - printCodeViewSymbolsSubsection(Contents, Section, Offset); + if (opts::SectionSymbols) + printCodeViewSymbolsSubsection(Contents, Section, Offset); break; case COFF::DEBUG_LINE_TABLE_SUBSECTION: { // Holds a PC to file:line table. Some data to parse this subsection is @@ -694,10 +698,20 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection, InFunctionScope = false; break; } - default: + default: { + if (opts::CodeViewSubsectionBytes) { + ListScope S(W, "Record"); + W.printHex("Size", Size); + W.printHex("Type", Type); + + StringRef Contents = DE.getData().substr(Offset, Size); + W.printBinaryBlock("Contents", Contents); + } + Offset += Size; break; } + } } if (InFunctionScope) @@ -746,8 +760,8 @@ void COFFDumper::printSections() { } } - if (Name == ".debug$S" && opts::CodeViewLineTables) - printCodeViewLineTables(Sec); + if (Name == ".debug$S" && opts::CodeView) + printCodeViewDebugInfo(Sec); if (opts::SectionData && !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) { @@ -1062,6 +1076,26 @@ void COFFDumper::printCOFFImports() { } } +void COFFDumper::printCOFFExports() { + for (const ExportDirectoryEntryRef &E : Obj->export_directories()) { + DictScope Export(W, "Export"); + + StringRef Name; + uint32_t Ordinal, RVA; + + if (error(E.getSymbolName(Name))) + continue; + if (error(E.getOrdinal(Ordinal))) + continue; + if (error(E.getExportRVA(RVA))) + continue; + + W.printNumber("Ordinal", Ordinal); + W.printString("Name", Name); + W.printHex("RVA", RVA); + } +} + void COFFDumper::printCOFFDirectives() { for (const SectionRef &Section : Obj->sections()) { StringRef Contents; @@ -1086,6 +1120,7 @@ static StringRef getBaseRelocTypeName(uint8_t Type) { case COFF::IMAGE_REL_BASED_LOW: return "LOW"; case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW"; case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ"; + case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)"; case COFF::IMAGE_REL_BASED_DIR64: return "DIR64"; default: return "unknown (" + llvm::utostr(Type) + ")"; } diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index d68c786..e4b7601 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -372,9 +372,10 @@ static const EnumEntry ElfMachineType[] = { }; static const EnumEntry ElfSymbolBindings[] = { - { "Local", ELF::STB_LOCAL }, - { "Global", ELF::STB_GLOBAL }, - { "Weak", ELF::STB_WEAK } + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK }, + { "Unique", ELF::STB_GNU_UNIQUE } }; static const EnumEntry ElfSymbolTypes[] = { diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index a34e091..27e658f 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -45,6 +45,7 @@ public: // Only implemented for PE/COFF. virtual void printCOFFImports() { } + virtual void printCOFFExports() { } virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index d08f186..f8f3086 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -127,9 +127,14 @@ namespace opts { cl::opt ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); - // -codeview-linetables - cl::opt CodeViewLineTables("codeview-linetables", - cl::desc("Display CodeView line table information")); + // -codeview + cl::opt CodeView("codeview", + cl::desc("Display CodeView debug information")); + + // -codeview-subsection-bytes + cl::opt CodeViewSubsectionBytes( + "codeview-subsection-bytes", + cl::desc("Dump raw contents of codeview debug sections and records")); // -arm-attributes, -a cl::opt ARMAttributes("arm-attributes", @@ -146,6 +151,10 @@ namespace opts { cl::opt COFFImports("coff-imports", cl::desc("Display the PE/COFF import table")); + // -coff-exports + cl::opt + COFFExports("coff-exports", cl::desc("Display the PE/COFF export table")); + // -coff-directives cl::opt COFFDirectives("coff-directives", @@ -282,6 +291,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printMipsPLTGOT(); if (opts::COFFImports) Dumper->printCOFFImports(); + if (opts::COFFExports) + Dumper->printCOFFExports(); if (opts::COFFDirectives) Dumper->printCOFFDirectives(); if (opts::COFFBaseRelocs) diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index 1c33417..74b9a60 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -36,7 +36,8 @@ namespace opts { extern llvm::cl::opt DynamicSymbols; extern llvm::cl::opt UnwindInfo; extern llvm::cl::opt ExpandRelocs; - extern llvm::cl::opt CodeViewLineTables; + extern llvm::cl::opt CodeView; + extern llvm::cl::opt CodeViewSubsectionBytes; extern llvm::cl::opt ARMAttributes; extern llvm::cl::opt MipsPLTGOT; } // namespace opts diff --git a/tools/llvm-rtdyld/Android.mk b/tools/llvm-rtdyld/Android.mk index 4f4fb4c..853c71a 100644 --- a/tools/llvm-rtdyld/Android.mk +++ b/tools/llvm-rtdyld/Android.mk @@ -37,7 +37,8 @@ llvm_rtdyld_STATIC_LIBRARIES := \ libLLVMX86AsmParser \ libLLVMX86Utils \ libLLVMX86Disassembler \ - libLLVMDebugInfo \ + libLLVMDebugInfoDWARF \ + libLLVMDebugInfoPDB \ libLLVMExecutionEngine \ libLLVMCodeGen \ libLLVMObject \ diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt index feb2134..c1acbe5 100644 --- a/tools/llvm-rtdyld/CMakeLists.txt +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -1,8 +1,9 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - DebugInfo + DebugInfoDWARF ExecutionEngine MC + Object RuntimeDyld Support ) diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile index 9de753e..3e868b9 100644 --- a/tools/llvm-rtdyld/Makefile +++ b/tools/llvm-rtdyld/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-rtdyld -LINK_COMPONENTS := all-targets support MC object RuntimeDyld MCJIT debuginfo +LINK_COMPONENTS := all-targets support MC object RuntimeDyld MCJIT DebugInfoDWARF # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 87d381e..58bf206 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -12,16 +12,14 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/StringMap.h" -#include "llvm/DebugInfo/DIContext.h" -#include "llvm/ExecutionEngine/ObjectBuffer.h" -#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/DebugInfo/DWARF/DIContext.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/ExecutionEngine/RuntimeDyldChecker.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" -#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" @@ -30,10 +28,10 @@ #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -207,23 +205,32 @@ static int printLineInfoForInput() { if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); - std::unique_ptr LoadedObject; + ErrorOr> MaybeObj( + ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); + + if (std::error_code EC = MaybeObj.getError()) + return Error("unable to create object file: '" + EC.message() + "'"); + + ObjectFile &Obj = **MaybeObj; + // Load the object file - LoadedObject = Dyld.loadObject( - llvm::make_unique(std::move(*InputBuffer))); - if (!LoadedObject) { + std::unique_ptr LoadedObjInfo = + Dyld.loadObject(Obj); + + if (Dyld.hasError()) return Error(Dyld.getErrorString()); - } // Resolve all the relocations we can. Dyld.resolveRelocations(); + OwningBinary DebugObj = LoadedObjInfo->getObjectForDebug(Obj); + std::unique_ptr Context( - DIContext::getDWARFContext(*LoadedObject->getObjectFile())); + DIContext::getDWARFContext(*DebugObj.getBinary())); // Use symbol info to iterate functions in the object. - for (object::symbol_iterator I = LoadedObject->begin_symbols(), - E = LoadedObject->end_symbols(); + for (object::symbol_iterator I = DebugObj.getBinary()->symbol_begin(), + E = DebugObj.getBinary()->symbol_end(); I != E; ++I) { object::SymbolRef::Type SymType; if (I->getType(SymType)) continue; @@ -268,11 +275,17 @@ static int executeInput() { MemoryBuffer::getFileOrSTDIN(InputFileList[i]); if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); - std::unique_ptr LoadedObject; + ErrorOr> MaybeObj( + ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); + + if (std::error_code EC = MaybeObj.getError()) + return Error("unable to create object file: '" + EC.message() + "'"); + + ObjectFile &Obj = **MaybeObj; + // Load the object file - LoadedObject = Dyld.loadObject( - llvm::make_unique(std::move(*InputBuffer))); - if (!LoadedObject) { + Dyld.loadObject(Obj); + if (Dyld.hasError()) { return Error(Dyld.getErrorString()); } } @@ -512,14 +525,21 @@ static int linkAndVerify() { // Load the input memory buffer. ErrorOr> InputBuffer = MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + if (std::error_code EC = InputBuffer.getError()) return Error("unable to read input: '" + EC.message() + "'"); - std::unique_ptr LoadedObject; + ErrorOr> MaybeObj( + ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef())); + + if (std::error_code EC = MaybeObj.getError()) + return Error("unable to create object file: '" + EC.message() + "'"); + + ObjectFile &Obj = **MaybeObj; + // Load the object file - LoadedObject = Dyld.loadObject( - llvm::make_unique(std::move(*InputBuffer))); - if (!LoadedObject) { + Dyld.loadObject(Obj); + if (Dyld.hasError()) { return Error(Dyld.getErrorString()); } } diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt index 100c184..9a8cd4a 100644 --- a/tools/llvm-shlib/CMakeLists.txt +++ b/tools/llvm-shlib/CMakeLists.txt @@ -57,7 +57,7 @@ if(NOT DEFINED LLVM_EXPORTED_SYMBOL_FILE) foreach (lib ${LIB_NAMES}) - set(LIB_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib) + set(LIB_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) set(LIB_NAME ${LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}) set(LIB_PATH ${LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}) set(LIB_EXPORTS_PATH ${LIB_NAME}.exports) @@ -78,6 +78,8 @@ if(NOT DEFINED LLVM_EXPORTED_SYMBOL_FILE) DEPENDS ${LLVM_DYLIB_REQUIRED_EXPORTS} COMMENT "Generating combined export list...") + add_custom_target(libLLVMExports DEPENDS ${LLVM_EXPORTED_SYMBOL_FILE}) + endif() add_llvm_library(LLVM SHARED ${SOURCES}) @@ -90,7 +92,7 @@ endif() target_link_libraries(LLVM ${cmake_2_8_12_PRIVATE} ${LIB_NAMES}) -add_dependencies(LLVM ${LLVM_EXPORTED_SYMBOL_FILE}) +add_dependencies(LLVM libLLVMExports) if (APPLE) set_property(TARGET LLVM APPEND_STRING PROPERTY diff --git a/tools/llvm-shlib/libllvm.cpp b/tools/llvm-shlib/libllvm.cpp index 40b4f66..8424d66 100644 --- a/tools/llvm-shlib/libllvm.cpp +++ b/tools/llvm-shlib/libllvm.cpp @@ -11,3 +11,10 @@ // you can't define a target with no sources. // //===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#if defined(DISABLE_LLVM_DYLIB_ATEXIT) +extern "C" int __cxa_atexit(); +extern "C" int __cxa_atexit() { return 0; } +#endif diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index 59a5f20..0e0dd59 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -15,9 +15,9 @@ #include "llvm/ADT/APInt.h" #include "llvm/Object/Archive.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -484,7 +484,6 @@ static void PrintFileSectionSizes(StringRef file) { if (ArchFlags[i] == I->getArchTypeName()) { ArchFound = true; ErrorOr> UO = I->getAsObjectFile(); - std::unique_ptr UA; if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -503,7 +502,9 @@ static void PrintFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (!I->getAsArchive(UA)) { + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its // sizes. for (object::Archive::child_iterator i = UA->child_begin(), @@ -560,7 +561,6 @@ static void PrintFileSectionSizes(StringRef file) { I != E; ++I) { if (HostArchName == I->getArchTypeName()) { ErrorOr> UO = I->getAsObjectFile(); - std::unique_ptr UA; if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -579,7 +579,9 @@ static void PrintFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (!I->getAsArchive(UA)) { + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its // sizes. for (object::Archive::child_iterator i = UA->child_begin(), @@ -623,7 +625,6 @@ static void PrintFileSectionSizes(StringRef file) { E = UB->end_objects(); I != E; ++I) { ErrorOr> UO = I->getAsObjectFile(); - std::unique_ptr UA; if (UO) { if (ObjectFile *o = dyn_cast(&*UO.get())) { MachOObjectFile *MachO = dyn_cast(o); @@ -643,7 +644,9 @@ static void PrintFileSectionSizes(StringRef file) { outs() << "\n"; } } - } else if (!I->getAsArchive(UA)) { + } else if (ErrorOr> AOrErr = + I->getAsArchive()) { + std::unique_ptr &UA = *AOrErr; // This is an archive. Iterate over each member and display its sizes. for (object::Archive::child_iterator i = UA->child_begin(), e = UA->child_end(); @@ -706,7 +709,7 @@ int main(int argc, char **argv) { ToolName = argv[0]; if (OutputFormatShort.getNumOccurrences()) - OutputFormat = OutputFormatShort; + OutputFormat = static_cast(OutputFormatShort); if (RadixShort.getNumOccurrences()) Radix = RadixShort; diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index 21a79e3..05ceeb5 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -20,7 +20,7 @@ #include "llvm/IR/LegacyPassNameParser.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -711,7 +711,7 @@ int main(int argc, char **argv) { return 1; } - PassManager Passes; + legacy::PassManager Passes; Passes.add(createVerifierPass()); Passes.add(createDebugInfoVerifierPass()); Passes.add(createPrintModulePass(Out->os())); diff --git a/tools/llvm-symbolizer/Android.mk b/tools/llvm-symbolizer/Android.mk index 6a2d1d0..9f376c2 100644 --- a/tools/llvm-symbolizer/Android.mk +++ b/tools/llvm-symbolizer/Android.mk @@ -16,7 +16,8 @@ LOCAL_SRC_FILES := $(llvm_symbolizer_SRC_FILES) LOCAL_LDLIBS += -lpthread -lm -ldl LOCAL_STATIC_LIBRARIES := \ - libLLVMDebugInfo \ + libLLVMDebugInfoDWARF \ + libLLVMDebugInfoPDB \ libLLVMObject \ libLLVMBitReader \ libLLVMMC \ diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt index 9e76248..6968f1c 100644 --- a/tools/llvm-symbolizer/CMakeLists.txt +++ b/tools/llvm-symbolizer/CMakeLists.txt @@ -4,7 +4,7 @@ # targets as well. Currently, there is no support for such a build strategy. set(LLVM_LINK_COMPONENTS - DebugInfo + DebugInfoDWARF Object Support ) diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index ff848fc..c109221 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -14,7 +14,7 @@ #define LLVM_TOOLS_LLVM_SYMBOLIZER_LLVMSYMBOLIZE_H #include "llvm/ADT/SmallVector.h" -#include "llvm/DebugInfo/DIContext.h" +#include "llvm/DebugInfo/DWARF/DIContext.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/DataExtractor.h" diff --git a/tools/llvm-symbolizer/Makefile b/tools/llvm-symbolizer/Makefile index 5ac83a5..c5d2cf7 100644 --- a/tools/llvm-symbolizer/Makefile +++ b/tools/llvm-symbolizer/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-symbolizer -LINK_COMPONENTS := DebugInfo Object +LINK_COMPONENTS := DebugInfoDWARF Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 559b22b..87f42e8 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} + Core LTO MC MCDisassembler diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index ef37c90..714b8e0 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -14,9 +14,11 @@ #include "llvm-c/lto.h" #include "llvm/CodeGen/CommandFlags.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/LTO/LTOModule.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/TargetSelect.h" // extra command-line flags needed for LTOCodeGenerator @@ -50,6 +52,12 @@ static bool parsedOptions = false; // Initialize the configured targets if they have not been initialized. static void lto_initialize() { if (!initialized) { +#ifdef LLVM_ON_WIN32 + // Dialog box on crash disabling doesn't work across DLL boundaries, so do + // it here. + llvm::sys::DisableSystemDialogsOnCrash(); +#endif + InitializeAllTargetInfos(); InitializeAllTargets(); InitializeAllTargetMCs(); @@ -213,23 +221,37 @@ void lto_codegen_set_diagnostic_handler(lto_code_gen_t cg, unwrap(cg)->setDiagnosticHandler(diag_handler, ctxt); } -lto_code_gen_t lto_codegen_create(void) { +static lto_code_gen_t createCodeGen(bool InLocalContext) { lto_initialize(); TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - LTOCodeGenerator *CodeGen = new LTOCodeGenerator(); + LTOCodeGenerator *CodeGen = + InLocalContext ? new LTOCodeGenerator(make_unique()) + : new LTOCodeGenerator(); if (CodeGen) CodeGen->setTargetOptions(Options); return wrap(CodeGen); } +lto_code_gen_t lto_codegen_create(void) { + return createCodeGen(/* InLocalContext */ false); +} + +lto_code_gen_t lto_codegen_create_in_local_context(void) { + return createCodeGen(/* InLocalContext */ true); +} + void lto_codegen_dispose(lto_code_gen_t cg) { delete unwrap(cg); } bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) { return !unwrap(cg)->addModule(unwrap(mod)); } +void lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod) { + unwrap(cg)->setModule(unwrap(mod)); +} + bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) { unwrap(cg)->setDebugInfo(debug); return false; @@ -278,6 +300,26 @@ const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { 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, + 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; + } + 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(); @@ -292,3 +334,5 @@ bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) { void lto_codegen_debug_options(lto_code_gen_t cg, const char *opt) { unwrap(cg)->setCodeGenDebugOptions(opt); } + +unsigned int lto_api_version() { return LTO_API_VERSION; } diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index b10ab1a..8729050 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -6,6 +6,8 @@ lto_module_create_from_fd lto_module_create_from_fd_at_offset lto_module_create_from_memory lto_module_create_from_memory_with_path +lto_module_create_in_local_context +lto_module_create_in_codegen_context lto_module_get_deplib lto_module_get_linkeropt lto_module_get_num_deplibs @@ -20,11 +22,14 @@ lto_module_is_object_file_for_target lto_module_is_object_file_in_memory lto_module_is_object_file_in_memory_for_target lto_module_dispose +lto_api_version lto_codegen_set_diagnostic_handler lto_codegen_add_module +lto_codegen_set_module lto_codegen_add_must_preserve_symbol lto_codegen_compile lto_codegen_create +lto_codegen_create_in_local_context lto_codegen_dispose lto_codegen_set_debug_model lto_codegen_set_pic_model @@ -34,6 +39,8 @@ lto_codegen_set_assembler_args lto_codegen_set_assembler_path lto_codegen_set_cpu lto_codegen_compile_to_file +lto_codegen_optimize +lto_codegen_compile_optimized LLVMCreateDisasm LLVMCreateDisasmCPU LLVMDisasmDispose diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index aac720d..604f93a 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -300,12 +300,12 @@ DumpDataInCodeDataCommand(const MachOObjectFile &Obj, static int DumpLinkerOptionsCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - MachO::linker_options_command LOLC = Obj.getLinkerOptionsLoadCommand(LCI); + MachO::linker_option_command LOLC = Obj.getLinkerOptionLoadCommand(LCI); outs() << " ('count', " << LOLC.count << ")\n" << " ('_strings', [\n"; - uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_options_command); - const char *P = LCI.Ptr + sizeof(MachO::linker_options_command); + uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_option_command); + const char *P = LCI.Ptr + sizeof(MachO::linker_option_command); StringRef Data(P, DataSize); for (unsigned i = 0; i != LOLC.count; ++i) { std::pair Split = Data.split('\0'); @@ -356,7 +356,7 @@ static int DumpLoadCommand(const MachOObjectFile &Obj, return DumpLinkeditDataCommand(Obj, LCI); case MachO::LC_DATA_IN_CODE: return DumpDataInCodeDataCommand(Obj, LCI); - case MachO::LC_LINKER_OPTIONS: + case MachO::LC_LINKER_OPTION: return DumpLinkerOptionsCommand(Obj, LCI); case MachO::LC_VERSION_MIN_IPHONEOS: case MachO::LC_VERSION_MIN_MACOSX: diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp index d770ce1..e606df2 100644 --- a/tools/obj2yaml/elf2yaml.cpp +++ b/tools/obj2yaml/elf2yaml.cpp @@ -21,8 +21,10 @@ namespace { template class ELFDumper { + typedef object::Elf_Sym_Impl Elf_Sym; typedef typename object::ELFFile::Elf_Shdr Elf_Shdr; typedef typename object::ELFFile::Elf_Sym_Iter Elf_Sym_Iter; + typedef typename object::ELFFile::Elf_Word Elf_Word; const object::ELFFile &Obj; @@ -38,6 +40,7 @@ class ELFDumper { ErrorOr dumpRelaSection(const Elf_Shdr *Shdr); ErrorOr dumpContentSection(const Elf_Shdr *Shdr); + ErrorOr dumpGroup(const Elf_Shdr *Shdr); public: ELFDumper(const object::ELFFile &O); @@ -86,7 +89,13 @@ ErrorOr ELFDumper::dump() { Y->Sections.push_back(std::unique_ptr(S.get())); break; } - // FIXME: Support SHT_GROUP section format. + case ELF::SHT_GROUP: { + ErrorOr G = dumpGroup(&Sec); + if (std::error_code EC = G.getError()) + return EC; + Y->Sections.push_back(std::unique_ptr(G.get())); + break; + } default: { ErrorOr S = dumpContentSection(&Sec); if (std::error_code EC = S.getError()) @@ -275,6 +284,41 @@ ELFDumper::dumpContentSection(const Elf_Shdr *Shdr) { } template +ErrorOr ELFDumper::dumpGroup(const Elf_Shdr *Shdr) { + auto S = make_unique(); + + if (std::error_code EC = dumpCommonSection(Shdr, *S)) + return EC; + // Get sh_info which is the signature. + const Elf_Sym *symbol = Obj.getSymbol(Shdr->sh_info); + const Elf_Shdr *symtab = Obj.getSection(Shdr->sh_link); + auto sectionContents = Obj.getSectionContents(Shdr); + if (std::error_code ec = sectionContents.getError()) + return ec; + ErrorOr symbolName = Obj.getSymbolName(symtab, symbol); + if (std::error_code EC = symbolName.getError()) + return EC; + S->Info = *symbolName; + const Elf_Word *groupMembers = + reinterpret_cast(sectionContents->data()); + const long count = (Shdr->sh_size) / sizeof(Elf_Word); + ELFYAML::SectionOrType s; + for (int i = 0; i < count; i++) { + if (groupMembers[i] == llvm::ELF::GRP_COMDAT) { + s.sectionNameOrType = "GRP_COMDAT"; + } else { + const Elf_Shdr *sHdr = Obj.getSection(groupMembers[i]); + ErrorOr sectionName = Obj.getSectionName(sHdr); + if (std::error_code ec = sectionName.getError()) + return ec; + s.sectionNameOrType = *sectionName; + } + S->Members.push_back(s); + } + return S.release(); +} + +template static std::error_code elf2yaml(raw_ostream &Out, const object::ELFFile &Obj) { ELFDumper Dumper(Obj); diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp index 8076ff4..a73750d 100644 --- a/tools/opt/NewPMDriver.cpp +++ b/tools/opt/NewPMDriver.cpp @@ -17,8 +17,8 @@ #include "Passes.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/CGSCCPassManager.h" -#include "llvm/Analysis/LazyCallGraph.h" #include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" @@ -27,28 +27,29 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetMachine.h" using namespace llvm; using namespace opt_tool; -bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, - tool_output_file *Out, StringRef PassPipeline, - OutputKind OK, VerifierKind VK) { - FunctionAnalysisManager FAM; - CGSCCAnalysisManager CGAM; - ModuleAnalysisManager MAM; +static cl::opt + DebugPM("debug-pass-manager", cl::Hidden, + cl::desc("Print pass management debugging information")); -#define MODULE_ANALYSIS(NAME, CREATE_PASS) \ - MAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" +bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, + TargetMachine *TM, tool_output_file *Out, + StringRef PassPipeline, OutputKind OK, + VerifierKind VK) { + Passes P(TM); -#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \ - CGAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" + FunctionAnalysisManager FAM(DebugPM); + CGSCCAnalysisManager CGAM(DebugPM); + ModuleAnalysisManager MAM(DebugPM); -#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \ - FAM.registerPass(CREATE_PASS); -#include "PassRegistry.def" + // Register all the basic analyses with the managers. + P.registerModuleAnalyses(MAM); + P.registerCGSCCAnalyses(CGAM); + P.registerFunctionAnalyses(FAM); // Cross register the analysis managers through their proxies. MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM)); @@ -58,11 +59,12 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, FAM.registerPass(CGSCCAnalysisManagerFunctionProxy(CGAM)); FAM.registerPass(ModuleAnalysisManagerFunctionProxy(MAM)); - ModulePassManager MPM; + ModulePassManager MPM(DebugPM); if (VK > VK_NoVerifier) MPM.addPass(VerifierPass()); - if (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass)) { + if (!P.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, + DebugPM)) { errs() << Arg0 << ": unable to parse pass pipeline description.\n"; return false; } @@ -86,7 +88,7 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, cl::PrintOptionValues(); // Now that we have all of the passes ready, run them. - MPM.run(&M, &MAM); + MPM.run(M, &MAM); // Declare success. if (OK != OK_NoOutput) diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h index f977bac..5384fe2 100644 --- a/tools/opt/NewPMDriver.h +++ b/tools/opt/NewPMDriver.h @@ -26,6 +26,7 @@ namespace llvm { class LLVMContext; class Module; +class TargetMachine; class tool_output_file; namespace opt_tool { @@ -48,8 +49,9 @@ enum VerifierKind { /// file. It's interface is consequentially somewhat ad-hoc, but will go away /// when the transition finishes. bool runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M, - tool_output_file *Out, StringRef PassPipeline, - opt_tool::OutputKind OK, opt_tool::VerifierKind VK); + TargetMachine *TM, tool_output_file *Out, + StringRef PassPipeline, opt_tool::OutputKind OK, + opt_tool::VerifierKind VK); } #endif diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def index e1e4900..d768a3a 100644 --- a/tools/opt/PassRegistry.def +++ b/tools/opt/PassRegistry.def @@ -20,32 +20,58 @@ #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", 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", 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", InvalidateAllAnalysesPass()) +FUNCTION_PASS("no-op-function", NoOpFunctionPass()) +FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass()) FUNCTION_PASS("print", PrintFunctionPass(dbgs())) +FUNCTION_PASS("print", AssumptionPrinterPass(dbgs())) +FUNCTION_PASS("print", DominatorTreePrinterPass(dbgs())) +FUNCTION_PASS("print", LoopPrinterPass(dbgs())) +FUNCTION_PASS("simplify-cfg", SimplifyCFGPass()) +FUNCTION_PASS("verify", VerifierPass()) +FUNCTION_PASS("verify", DominatorTreeVerifierPass()) #undef FUNCTION_PASS diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp index a171f42..e5ad5c0 100644 --- a/tools/opt/Passes.cpp +++ b/tools/opt/Passes.cpp @@ -15,12 +15,22 @@ //===----------------------------------------------------------------------===// #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; @@ -28,112 +38,184 @@ namespace { /// \brief No-op module pass which does nothing. struct NoOpModulePass { - PreservedAnalyses run(Module *M) { return PreservedAnalyses::all(); } + 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) { + 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(); } + 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. -static bool isModulePassName(StringRef Name) { - if (Name == "no-op-module") return true; +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) { - if (Name == "no-op-cgscc") return true; - #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) { - if (Name == "no-op-function") return true; - #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; } -static bool parseModulePassName(ModulePassManager &MPM, StringRef Name) { - if (Name == "no-op-module") { - MPM.addPass(NoOpModulePass()); - return true; - } - +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()); \ + return true; \ + } \ + if (Name == "invalidate<" NAME ">") { \ + MPM.addPass(InvalidateAnalysisPass()); \ + return true; \ + } #include "PassRegistry.def" return false; } -static bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name) { - if (Name == "no-op-cgscc") { - CGPM.addPass(NoOpCGSCCPass()); - return true; - } - +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()); \ + return true; \ + } \ + if (Name == "invalidate<" NAME ">") { \ + CGPM.addPass(InvalidateAnalysisPass()); \ + return true; \ + } #include "PassRegistry.def" return false; } -static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) { - if (Name == "no-op-function") { - FPM.addPass(NoOpFunctionPass()); - return true; - } - +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()); \ + return true; \ + } \ + if (Name == "invalidate<" NAME ">") { \ + FPM.addPass(InvalidateAnalysisPass()); \ + return true; \ + } #include "PassRegistry.def" return false; } -static bool parseFunctionPassPipeline(FunctionPassManager &FPM, - StringRef &PipelineText, - bool VerifyEachPass) { +bool Passes::parseFunctionPassPipeline(FunctionPassManager &FPM, + StringRef &PipelineText, + bool VerifyEachPass, bool DebugLogging) { for (;;) { // Parse nested pass managers by recursing. if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM; + FunctionPassManager NestedFPM(DebugLogging); // Parse the inner pipeline inte the nested manager. PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || + if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -160,17 +242,18 @@ static bool parseFunctionPassPipeline(FunctionPassManager &FPM, } } -static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, - StringRef &PipelineText, - bool VerifyEachPass) { +bool Passes::parseCGSCCPassPipeline(CGSCCPassManager &CGPM, + StringRef &PipelineText, + bool VerifyEachPass, bool DebugLogging) { for (;;) { // Parse nested pass managers by recursing. if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM; + CGSCCPassManager NestedCGPM(DebugLogging); // Parse the inner pipeline into the nested manager. PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass) || + if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -179,11 +262,12 @@ static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, // Add the nested pass manager with the appropriate adaptor. CGPM.addPass(std::move(NestedCGPM)); } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM; + FunctionPassManager NestedFPM(DebugLogging); // Parse the inner pipeline inte the nested manager. PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || + if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -209,17 +293,18 @@ static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, } } -static bool parseModulePassPipeline(ModulePassManager &MPM, - StringRef &PipelineText, - bool VerifyEachPass) { +bool Passes::parseModulePassPipeline(ModulePassManager &MPM, + StringRef &PipelineText, + bool VerifyEachPass, bool DebugLogging) { for (;;) { // Parse nested pass managers by recursing. if (PipelineText.startswith("module(")) { - ModulePassManager NestedMPM; + ModulePassManager NestedMPM(DebugLogging); // Parse the inner pipeline into the nested manager. PipelineText = PipelineText.substr(strlen("module(")); - if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass) || + if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -228,11 +313,12 @@ static bool parseModulePassPipeline(ModulePassManager &MPM, // Now add the nested manager as a module pass. MPM.addPass(std::move(NestedMPM)); } else if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager NestedCGPM; + CGSCCPassManager NestedCGPM(DebugLogging); // Parse the inner pipeline inte the nested manager. PipelineText = PipelineText.substr(strlen("cgscc(")); - if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass) || + if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -242,11 +328,12 @@ static bool parseModulePassPipeline(ModulePassManager &MPM, MPM.addPass( createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM))); } else if (PipelineText.startswith("function(")) { - FunctionPassManager NestedFPM; + FunctionPassManager NestedFPM(DebugLogging); // Parse the inner pipeline inte the nested manager. PipelineText = PipelineText.substr(strlen("function(")); - if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass) || + if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass, + DebugLogging) || PipelineText.empty()) return false; assert(PipelineText[0] == ')'); @@ -276,48 +363,39 @@ static bool parseModulePassPipeline(ModulePassManager &MPM, // 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 llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText, - bool VerifyEachPass) { - // Look at the first entry to figure out which layer to start parsing at. - if (PipelineText.startswith("module(")) - return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) && - PipelineText.empty(); - if (PipelineText.startswith("cgscc(")) { - CGSCCPassManager CGPM; - if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass) || - !PipelineText.empty()) - return false; - MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM))); - return true; - } - if (PipelineText.startswith("function(")) { - FunctionPassManager FPM; - if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) || - !PipelineText.empty()) - return false; - MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); - return true; - } - - // This isn't a direct pass manager name, look for the end of a pass name. +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(",)")); - if (isModulePassName(FirstName)) - return parseModulePassPipeline(MPM, PipelineText, VerifyEachPass) && - PipelineText.empty(); + 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; - if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass) || + 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; - if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass) || + FunctionPassManager FPM(DebugLogging); + if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass, + DebugLogging) || !PipelineText.empty()) return false; MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM))); diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h index 3bd6752..d3cb628 100644 --- a/tools/opt/Passes.h +++ b/tools/opt/Passes.h @@ -1,4 +1,4 @@ -//===- Passes.h - Parsing, selection, and running of passes -----*- C++ -*-===// +//===- Passes.h - Utilities for manipulating all passes ---------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// /// \file /// -/// Interfaces for producing common pass manager configurations and parsing -/// textual pass specifications. +/// Interfaces for registering passes, producing common pass manager +/// configurations, and parsing of pass pipelines. /// //===----------------------------------------------------------------------===// @@ -17,40 +17,88 @@ #define LLVM_TOOLS_OPT_PASSES_H #include "llvm/ADT/StringRef.h" +#include "llvm/Analysis/CGSCCPassManager.h" +#include "llvm/IR/PassManager.h" namespace llvm { -class ModulePassManager; +class TargetMachine; -/// \brief Parse a textual pass pipeline description into a \c ModulePassManager. +/// \brief This class provides access to all of LLVM's passes. /// -/// 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); +/// 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); +}; } diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index cdd22e4..d952525 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -20,6 +20,8 @@ #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/RegionPass.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/DataLayout.h" @@ -33,7 +35,7 @@ #include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/ManagedStatic.h" @@ -45,7 +47,6 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include @@ -179,7 +180,7 @@ DefaultDataLayout("default-data-layout", -static inline void addPass(PassManagerBase &PM, Pass *P) { +static inline void addPass(legacy::PassManagerBase &PM, Pass *P) { // Add the pass to the pass manager... PM.add(P); @@ -194,7 +195,8 @@ static inline void addPass(PassManagerBase &PM, Pass *P) { /// OptLevel. /// /// OptLevel - Optimization Level -static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, +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 @@ -229,7 +231,7 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, Builder.populateModulePassManager(MPM); } -static void AddStandardLinkPasses(PassManagerBase &PM) { +static void AddStandardLinkPasses(legacy::PassManagerBase &PM) { PassManagerBuilder Builder; Builder.VerifyInput = true; Builder.StripDebug = StripDebug; @@ -307,7 +309,6 @@ int main(int argc, char **argv) { // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); - initializeDebugIRPass(Registry); initializeScalarOpts(Registry); initializeObjCARCOpts(Registry); initializeVectorization(Registry); @@ -323,6 +324,8 @@ int main(int argc, char **argv) { initializeCodeGenPreparePass(Registry); initializeAtomicExpandPass(Registry); initializeRewriteSymbolsPass(Registry); + initializeWinEHPreparePass(Registry); + initializeDwarfEHPreparePass(Registry); #ifdef LINK_POLLY_INTO_TOOLS polly::initializePollyPasses(Registry); @@ -341,7 +344,7 @@ int main(int argc, char **argv) { // Load the input module... std::unique_ptr M = parseIRFile(InputFilename, Err, Context); - if (!M.get()) { + if (!M) { Err.print(argv[0], errs()); return 1; } @@ -369,6 +372,12 @@ int main(int argc, char **argv) { } } + Triple ModuleTriple(M->getTargetTriple()); + TargetMachine *Machine = nullptr; + if (ModuleTriple.getArch()) + Machine = GetTargetMachine(ModuleTriple); + std::unique_ptr TM(Machine); + // If the output is set to be emitted to standard out, and standard out is a // console, print out a warning message and refuse to do it. We don't // impress anyone by spewing tons of binary goo to a terminal. @@ -390,8 +399,8 @@ int main(int argc, char **argv) { // The user has asked to use the new pass manager and provided a pipeline // string. Hand off the rest of the functionality to the new code for that // layer. - return runPassPipeline(argv[0], Context, *M.get(), Out.get(), PassPipeline, - OK, VK) + return runPassPipeline(argv[0], Context, *M, TM.get(), Out.get(), + PassPipeline, OK, VK) ? 0 : 1; } @@ -399,44 +408,37 @@ int main(int argc, char **argv) { // Create a PassManager to hold and optimize the collection of passes we are // about to build. // - PassManager Passes; + legacy::PassManager Passes; // Add an appropriate TargetLibraryInfo pass for the module's triple. - TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple())); + TargetLibraryInfoImpl TLII(ModuleTriple); // The -disable-simplify-libcalls flag actually disables all builtin optzns. if (DisableSimplifyLibCalls) - TLI->disableAllFunctions(); - Passes.add(TLI); + TLII.disableAllFunctions(); + Passes.add(new TargetLibraryInfoWrapperPass(TLII)); // Add an appropriate DataLayout instance for this module. - const DataLayout *DL = M.get()->getDataLayout(); + const DataLayout *DL = M->getDataLayout(); if (!DL && !DefaultDataLayout.empty()) { M->setDataLayout(DefaultDataLayout); - DL = M.get()->getDataLayout(); + DL = M->getDataLayout(); } if (DL) Passes.add(new DataLayoutPass()); - Triple ModuleTriple(M->getTargetTriple()); - TargetMachine *Machine = nullptr; - if (ModuleTriple.getArch()) - Machine = GetTargetMachine(Triple(ModuleTriple)); - std::unique_ptr TM(Machine); - // Add internal analysis passes from the target machine. - if (TM.get()) - TM->addAnalysisPasses(Passes); + Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis() + : TargetIRAnalysis())); - std::unique_ptr FPasses; + std::unique_ptr FPasses; if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { - FPasses.reset(new FunctionPassManager(M.get())); + FPasses.reset(new legacy::FunctionPassManager(M.get())); if (DL) FPasses->add(new DataLayoutPass()); - if (TM.get()) - TM->addAnalysisPasses(*FPasses); - + FPasses->add(createTargetTransformInfoWrapperPass( + TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())); } if (PrintBreakpoints) { @@ -446,7 +448,8 @@ int main(int argc, char **argv) { OutputFilename = "-"; std::error_code EC; - Out.reset(new tool_output_file(OutputFilename, EC, sys::fs::F_None)); + Out = llvm::make_unique(OutputFilename, EC, + sys::fs::F_None); if (EC) { errs() << EC.message() << '\n'; return 1; @@ -556,8 +559,8 @@ int main(int argc, char **argv) { if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { FPasses->doInitialization(); - for (Module::iterator F = M->begin(), E = M->end(); F != E; ++F) - FPasses->run(*F); + for (Function &F : *M) + FPasses->run(F); FPasses->doFinalization(); } @@ -579,7 +582,7 @@ int main(int argc, char **argv) { cl::PrintOptionValues(); // Now that we have all of the passes ready, run them. - Passes.run(*M.get()); + Passes.run(*M); // Declare success. if (!NoOutput || PrintBreakpoints) diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp index 992a5b0..a653608 100644 --- a/tools/verify-uselistorder/verify-uselistorder.cpp +++ b/tools/verify-uselistorder/verify-uselistorder.cpp @@ -197,9 +197,12 @@ ValueMapping::ValueMapping(const Module &M) { map(G.getInitializer()); for (const GlobalAlias &A : M.aliases()) map(A.getAliasee()); - for (const Function &F : M) + for (const Function &F : M) { if (F.hasPrefixData()) map(F.getPrefixData()); + if (F.hasPrologueData()) + map(F.getPrologueData()); + } // Function bodies. for (const Function &F : M) { @@ -463,9 +466,12 @@ static void changeUseLists(Module &M, Changer changeValueUseList) { changeValueUseList(G.getInitializer()); for (GlobalAlias &A : M.aliases()) changeValueUseList(A.getAliasee()); - for (Function &F : M) + for (Function &F : M) { if (F.hasPrefixData()) changeValueUseList(F.getPrefixData()); + if (F.hasPrologueData()) + changeValueUseList(F.getPrologueData()); + } // Function bodies. for (Function &F : M) { diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index 6983e9d..8322b2f 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -13,13 +13,13 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Object/COFFYAML.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/COFFYAML.h" #include "llvm/Support/Endian.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 44c8c12..5d4c263 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -131,6 +131,8 @@ class ELFState { bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::RelocationSection &Section, ContiguousBlobAccumulator &CBA); + bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group, + ContiguousBlobAccumulator &CBA); // - SHT_NULL entry (placed first, i.e. 0'th entry) // - symbol table (.symtab) (placed third to last) @@ -223,6 +225,16 @@ bool ELFState::initSectionHeaders(std::vector &SHeaders, if (!writeSectionContent(SHeader, *S, CBA)) return false; + } else if (auto S = dyn_cast(Sec.get())) { + unsigned SymIdx; + if (SymN2I.lookup(S->Info, SymIdx)) { + errs() << "error: Unknown symbol referenced: '" << S->Info + << "' at YAML section '" << S->Name << "'.\n"; + return false; + } + SHeader.sh_info = SymIdx; + if (!writeSectionContent(SHeader, *S, CBA)) + return false; } else llvm_unreachable("Unknown section type"); @@ -321,6 +333,12 @@ ELFState::writeSectionContent(Elf_Shdr &SHeader, SHeader.sh_size = Section.Size; } +static bool isMips64EL(const ELFYAML::Object &Doc) { + return Doc.Header.Machine == ELFYAML::ELF_EM(llvm::ELF::EM_MIPS) && + Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64) && + Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); +} + template bool ELFState::writeSectionContent(Elf_Shdr &SHeader, @@ -351,19 +369,51 @@ ELFState::writeSectionContent(Elf_Shdr &SHeader, zero(REntry); REntry.r_offset = Rel.Offset; REntry.r_addend = Rel.Addend; - REntry.setSymbolAndType(SymIdx, Rel.Type); + REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); OS.write((const char *)&REntry, sizeof(REntry)); } else { Elf_Rel REntry; zero(REntry); REntry.r_offset = Rel.Offset; - REntry.setSymbolAndType(SymIdx, Rel.Type); + REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc)); OS.write((const char *)&REntry, sizeof(REntry)); } } return true; } +template +bool ELFState::writeSectionContent(Elf_Shdr &SHeader, + const ELFYAML::Group &Section, + ContiguousBlobAccumulator &CBA) { + typedef typename object::ELFFile::Elf_Word Elf_Word; + if (Section.Type != llvm::ELF::SHT_GROUP) { + errs() << "error: Invalid section type.\n"; + return false; + } + + SHeader.sh_entsize = sizeof(Elf_Word); + SHeader.sh_size = SHeader.sh_entsize * Section.Members.size(); + + auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset); + + for (auto member : Section.Members) { + Elf_Word SIdx; + unsigned int sectionIndex = 0; + if (member.sectionNameOrType == "GRP_COMDAT") + sectionIndex = llvm::ELF::GRP_COMDAT; + else if (SN2I.lookup(member.sectionNameOrType, sectionIndex)) { + errs() << "error: Unknown section referenced: '" + << member.sectionNameOrType << "' at YAML section' " + << Section.Name << "\n"; + return false; + } + SIdx = sectionIndex; + OS.write((const char *)&SIdx, sizeof(SIdx)); + } + return true; +} + template bool ELFState::buildSectionIndex() { SN2I.addName(".symtab", getDotSymTabSecNo()); SN2I.addName(".strtab", getDotStrTabSecNo()); -- cgit v1.1