aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2015-03-23 12:10:34 -0700
committerStephen Hines <srhines@google.com>2015-03-23 12:10:34 -0700
commitebe69fe11e48d322045d5949c83283927a0d790b (patch)
treec92f1907a6b8006628a4b01615f38264d29834ea /tools
parentb7d2e72b02a4cb8034f32f8247a2558d2434e121 (diff)
downloadexternal_llvm-ebe69fe11e48d322045d5949c83283927a0d790b.zip
external_llvm-ebe69fe11e48d322045d5949c83283927a0d790b.tar.gz
external_llvm-ebe69fe11e48d322045d5949c83283927a0d790b.tar.bz2
Update aosp/master LLVM for rebase to r230699.
Change-Id: I2b5be30509658cb8266be782de0ab24f9099f9b9
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt16
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile2
-rw-r--r--tools/bugpoint/CrashDebugger.cpp4
-rw-r--r--tools/bugpoint/ExtractFunction.cpp6
-rw-r--r--tools/bugpoint/OptimizerDriver.cpp2
-rw-r--r--tools/bugpoint/bugpoint.cpp4
-rw-r--r--tools/dsymutil/BinaryHolder.cpp111
-rw-r--r--tools/dsymutil/BinaryHolder.h104
-rw-r--r--tools/dsymutil/CMakeLists.txt14
-rw-r--r--tools/dsymutil/DebugMap.cpp92
-rw-r--r--tools/dsymutil/DebugMap.h142
-rw-r--r--tools/dsymutil/DwarfLinker.cpp667
-rw-r--r--tools/dsymutil/LLVMBuild.txt22
-rw-r--r--tools/dsymutil/MachODebugMapParser.cpp241
-rw-r--r--tools/dsymutil/Makefile17
-rw-r--r--tools/dsymutil/dsymutil.cpp71
-rw-r--r--tools/dsymutil/dsymutil.h39
-rw-r--r--tools/gold/CMakeLists.txt9
-rw-r--r--tools/gold/gold-plugin.cpp275
-rw-r--r--tools/llc/CMakeLists.txt2
-rw-r--r--tools/llc/llc.cpp53
-rw-r--r--tools/lli/Android.mk3
-rw-r--r--tools/lli/CMakeLists.txt4
-rw-r--r--tools/lli/ChildTarget/ChildTarget.cpp14
-rw-r--r--tools/lli/Makefile4
-rw-r--r--tools/lli/RemoteMemoryManager.cpp3
-rw-r--r--tools/lli/RemoteMemoryManager.h3
-rw-r--r--tools/lli/lli.cpp26
-rw-r--r--tools/llvm-ar/CMakeLists.txt15
-rw-r--r--tools/llvm-ar/install_symlink.cmake25
-rw-r--r--tools/llvm-ar/llvm-ar.cpp68
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp14
-rw-r--r--tools/llvm-c-test/Android.mk1
-rw-r--r--tools/llvm-c-test/CMakeLists.txt25
-rw-r--r--tools/llvm-c-test/llvm-c-test.h4
-rw-r--r--tools/llvm-c-test/main.c4
-rw-r--r--tools/llvm-c-test/metadata.c43
-rw-r--r--tools/llvm-config/BuildVariables.inc.in1
-rw-r--r--tools/llvm-config/Makefile2
-rw-r--r--tools/llvm-config/llvm-config.cpp10
-rw-r--r--tools/llvm-cov/Android.mk1
-rw-r--r--tools/llvm-cov/CMakeLists.txt1
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp36
-rw-r--r--tools/llvm-cov/CoverageFilters.h2
-rw-r--r--tools/llvm-cov/CoverageReport.cpp42
-rw-r--r--tools/llvm-cov/CoverageReport.h11
-rw-r--r--tools/llvm-cov/CoverageSummary.cpp64
-rw-r--r--tools/llvm-cov/CoverageSummary.h45
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.cpp25
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h53
-rw-r--r--tools/llvm-cov/RenderingSupport.h2
-rw-r--r--tools/llvm-cov/SourceCoverageView.h7
-rw-r--r--tools/llvm-cov/TestingSupport.cpp9
-rw-r--r--tools/llvm-cov/gcov.cpp3
-rw-r--r--tools/llvm-cov/llvm-cov.cpp2
-rw-r--r--tools/llvm-dis/llvm-dis.cpp46
-rw-r--r--tools/llvm-dwarfdump/Android.mk3
-rw-r--r--tools/llvm-dwarfdump/CMakeLists.txt2
-rw-r--r--tools/llvm-dwarfdump/LLVMBuild.txt2
-rw-r--r--tools/llvm-dwarfdump/Makefile2
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp3
-rw-r--r--tools/llvm-extract/llvm-extract.cpp4
-rw-r--r--tools/llvm-go/llvm-go.go30
-rw-r--r--tools/llvm-jitlistener/Makefile2
-rw-r--r--tools/llvm-jitlistener/llvm-jitlistener.cpp6
-rw-r--r--tools/llvm-lto/llvm-lto.cpp69
-rw-r--r--tools/llvm-mc/Android.mk1
-rw-r--r--tools/llvm-mc/Disassembler.cpp1
-rw-r--r--tools/llvm-mc/llvm-mc.cpp103
-rw-r--r--tools/llvm-nm/Android.mk1
-rw-r--r--tools/llvm-nm/llvm-nm.cpp16
-rw-r--r--tools/llvm-objdump/Android.mk4
-rw-r--r--tools/llvm-objdump/CMakeLists.txt2
-rw-r--r--tools/llvm-objdump/LLVMBuild.txt2
-rw-r--r--tools/llvm-objdump/MachODump.cpp2052
-rw-r--r--tools/llvm-objdump/Makefile2
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp104
-rw-r--r--tools/llvm-objdump/llvm-objdump.h29
-rw-r--r--tools/llvm-pdbdump/CMakeLists.txt14
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.cpp152
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.h64
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.cpp117
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.h39
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.cpp243
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.h45
-rw-r--r--tools/llvm-pdbdump/LLVMBuild.txt23
-rw-r--r--tools/llvm-pdbdump/Makefile17
-rw-r--r--tools/llvm-pdbdump/TypeDumper.cpp96
-rw-r--r--tools/llvm-pdbdump/TypeDumper.h38
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.cpp84
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.h38
-rw-r--r--tools/llvm-pdbdump/VariableDumper.cpp120
-rw-r--r--tools/llvm-pdbdump/VariableDumper.h43
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.cpp134
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.h28
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp8
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.cpp2
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp2
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp55
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp7
-rw-r--r--tools/llvm-readobj/ObjDumper.h1
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp17
-rw-r--r--tools/llvm-readobj/llvm-readobj.h3
-rw-r--r--tools/llvm-rtdyld/Android.mk3
-rw-r--r--tools/llvm-rtdyld/CMakeLists.txt3
-rw-r--r--tools/llvm-rtdyld/Makefile2
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp62
-rw-r--r--tools/llvm-shlib/CMakeLists.txt6
-rw-r--r--tools/llvm-shlib/libllvm.cpp7
-rw-r--r--tools/llvm-size/llvm-size.cpp19
-rw-r--r--tools/llvm-stress/llvm-stress.cpp4
-rw-r--r--tools/llvm-symbolizer/Android.mk3
-rw-r--r--tools/llvm-symbolizer/CMakeLists.txt2
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.h2
-rw-r--r--tools/llvm-symbolizer/Makefile2
-rw-r--r--tools/lto/CMakeLists.txt1
-rw-r--r--tools/lto/lto.cpp48
-rw-r--r--tools/lto/lto.exports7
-rw-r--r--tools/macho-dump/macho-dump.cpp8
-rw-r--r--tools/obj2yaml/elf2yaml.cpp46
-rw-r--r--tools/opt/NewPMDriver.cpp40
-rw-r--r--tools/opt/NewPMDriver.h6
-rw-r--r--tools/opt/PassRegistry.def26
-rw-r--r--tools/opt/Passes.cpp236
-rw-r--r--tools/opt/Passes.h114
-rw-r--r--tools/opt/opt.cpp67
-rw-r--r--tools/verify-uselistorder/verify-uselistorder.cpp10
-rw-r--r--tools/yaml2obj/yaml2coff.cpp4
-rw-r--r--tools/yaml2obj/yaml2elf.cpp54
130 files changed, 6200 insertions, 925 deletions
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<const Instruction*>
}
// 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<std::pair<Function*, int> > &TorList) {
assert(!TorList.empty() && "Don't create empty tor list!");
std::vector<Constant*> 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<MemoryBufferRef>
+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<MemoryBufferRef>
+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<MemoryBufferRef>
+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<const object::ObjectFile &>
+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<object::Archive> CurrentArchive;
+ std::unique_ptr<MemoryBuffer> CurrentMemoryBuffer;
+ std::unique_ptr<object::ObjectFile> 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<MemoryBufferRef> 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<MemoryBufferRef> 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<MemoryBufferRef> 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<const object::ObjectFile &> GetObjectFile(StringRef Filename);
+
+ /// \brief Wraps GetObjectFile() to return a derived ObjectFile type.
+ template <typename ObjectFileType>
+ ErrorOr<const ObjectFileType &> GetFileAs(StringRef Filename) {
+ auto ErrOrObjFile = GetObjectFile(Filename);
+ if (auto Err = ErrOrObjFile.getError())
+ return Err;
+ if (const auto *Derived = dyn_cast<ObjectFileType>(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 <typename ObjectFileType> const ObjectFileType &GetAs() {
+ return cast<ObjectFileType>(*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 <algorithm>
+
+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<StringRef, SymbolMapping> Entry;
+ std::vector<Entry> 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<SymbolMapping>::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 <vector>
+
+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<std::unique_ptr<DebugMapObject>> ObjectContainer;
+ ObjectContainer Objects;
+
+public:
+ DebugMap(const Triple &BinaryTriple) : BinaryTriple(BinaryTriple) {}
+
+ typedef ObjectContainer::const_iterator const_iterator;
+
+ iterator_range<const_iterator> 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<SymbolMapping> 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<SymbolMapping> Symbols;
+ DenseMap<uint64_t, DebugMapEntry *> 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 <string>
+
+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<DIEInfo> 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<ValidReloc> 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<CompileUnit> 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<DWARFUnit *>(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<object::MachOObjectFile>(&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<uint32_t, uint32_t>
+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<DWARFUnit *>(&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<DWARFUnit *>(&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<std::unique_ptr<DebugMap>> parse();
+
+private:
+ std::string BinaryPath;
+ std::string PathPrefix;
+
+ /// Owns the MemoryBuffer for the main binary.
+ BinaryHolder MainBinaryHolder;
+ /// Map of the binary symbol addresses.
+ StringMap<uint64_t> MainBinarySymbolAddresses;
+ StringRef MainBinaryStrings;
+ /// The constructed DebugMap.
+ std::unique_ptr<DebugMap> Result;
+
+ /// Owns the MemoryBuffer for the currently handled object file.
+ BinaryHolder CurrentObjectHolder;
+ /// Map of the currently processed object file symbol addresses.
+ StringMap<uint64_t> 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 <typename STEType> 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<MachOObjectFile>(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<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
+ auto MainBinOrError = MainBinaryHolder.GetFileAs<MachOObjectFile>(BinaryPath);
+ if (auto Error = MainBinOrError.getError())
+ return Error;
+
+ const MachOObjectFile &MainBinary = *MainBinOrError;
+ loadMainBinarySymbols();
+ Result = make_unique<DebugMap>(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<MachOObjectFile>();
+ 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<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile,
+ StringRef PrependPath,
+ bool Verbose) {
+ MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
+ return Parser.parse();
+}
+}
+}
diff --git a/tools/dsymutil/Makefile b/tools/dsymutil/Makefile
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 <string>
+
+using namespace llvm::dsymutil;
+
+namespace {
+using namespace llvm::cl;
+
+static opt<std::string> InputFile(Positional, desc("<input file>"),
+ init("a.out"));
+
+static opt<std::string> OsoPrependPath("oso-prepend-path",
+ desc("Specify a directory to prepend "
+ "to the paths of object files."),
+ value_desc("path"));
+
+static opt<bool> Verbose("v", desc("Verbosity level"), init(false));
+
+static opt<bool>
+ 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 <memory>
+
+namespace llvm {
+namespace dsymutil {
+/// \brief Extract the DebugMap from the given file.
+/// The file has to be a MachO object file.
+llvm::ErrorOr<std::unique_ptr<DebugMap>>
+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<std::string> 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<GlobalObject>(&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<BitcodeDiagnosticInfo>(&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<std::unique_ptr<object::IRObjectFile>> 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<Function>(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<GlobalVariable>(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<GlobalValue *> &Dropped;
+ DenseMap<GlobalObject *, GlobalObject *> LocalVersions;
public:
LocalValueMaterializer(DenseSet<GlobalValue *> &Dropped) : Dropped(Dropped) {}
@@ -520,13 +526,39 @@ public:
}
Value *LocalValueMaterializer::materializeValueFor(Value *V) {
- auto *GV = dyn_cast<GlobalValue>(V);
- if (!GV)
+ auto *GO = dyn_cast<GlobalObject>(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<GlobalAlias>(GV) && "Found alias point to weak alias.");
- return makeInternalReplacement(cast<GlobalObject>(GV));
+
+ Module &M = *GO->getParent();
+ GlobalValue::LinkageTypes L = GO->getLinkage();
+ GlobalObject *Declaration;
+ if (auto *F = dyn_cast<Function>(GO)) {
+ Declaration = Function::Create(F->getFunctionType(), L, "", &M);
+ } else {
+ auto *Var = cast<GlobalVariable>(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<Module>
-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<MemoryBufferRef> 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<std::unique_ptr<object::IRObjectFile>> 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<MemoryBuffer> Buffer =
- MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false);
-
- if (release_input_file(F.handle) != LDPS_OK)
- message(LDPL_FATAL, "Failed to release file information");
-
- ErrorOr<Module *> 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<Module> M(MOrErr.get());
+ UpgradeDebugInfo(M);
SmallPtrSet<GlobalValue *, 8> Used;
- collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
+ collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
DenseSet<GlobalValue *> Drop;
std::vector<GlobalAlias *> 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<Module> 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<Module> 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 <memory>
@@ -95,9 +95,9 @@ static cl::opt<bool> 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<tool_output_file>
+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<tool_output_file>(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<Module> 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<TargetMachine> target(
+ std::unique_ptr<TargetMachine> 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<tool_output_file> Out(
- GetOutputStream(TheTarget->getName(), TheTriple.getOS(), argv[0]));
+ std::unique_ptr<tool_output_file> 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<bool> DebugIR(
- "debug-ir", cl::desc("Generate debug information to allow debugging IR."),
- cl::init(false));
+ cl::opt<bool> UseOrcMCJITReplacement("use-orcmcjit",
+ cl::desc("Use the experimental "
+ "OrcMCJITReplacement as a "
+ "drop-in replacement for "
+ "MCJIT."),
+ cl::init(false));
// 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<RTDyldMemoryManager>(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<std::string>(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 <typename T>
void addMember(std::vector<NewArchiveIterator> &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<NewArchiveIterator> Members,
- ArrayRef<MemoryBufferRef> Buffers,
- std::vector<std::pair<unsigned, unsigned>> &MemberOffsetRefs) {
+// Returns the offset of the first reference to a member offset.
+static unsigned writeSymbolTable(raw_fd_ostream &Out,
+ ArrayRef<NewArchiveIterator> Members,
+ ArrayRef<MemoryBufferRef> Buffers,
+ std::vector<unsigned> &MemberOffsetRefs) {
unsigned StartOffset = 0;
unsigned MemberNum = 0;
std::string NameBuf;
@@ -732,14 +723,14 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> 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<NewArchiveIterator> 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 << "!<arch>\n";
- std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs;
+ std::vector<unsigned> MemberOffsetRefs;
std::vector<std::unique_ptr<MemoryBuffer>> Buffers;
std::vector<MemoryBufferRef> Members;
+ std::vector<sys::fs::file_status> 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<std::unique_ptr<MemoryBuffer>> 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<unsigned> StringMapIndexes;
writeStringTable(Out, NewMembers, StringMapIndexes);
- std::vector<std::pair<unsigned, unsigned> >::iterator MemberRefsI =
- MemberOffsetRefs.begin();
-
unsigned MemberNum = 0;
unsigned LongNameMemberNum = 0;
+ unsigned NewMemberNum = 0;
+ std::vector<unsigned> MemberOffset;
for (std::vector<NewArchiveIterator>::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 <functional>
#include <system_error>
@@ -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 <vector>
#include <memory>
+#include <vector>
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<std::string> 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::CoverageMapping> 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::CoverageMapping> Coverage)
+ : Options(Options), Coverage(std::move(Coverage)) {}
- void renderFunctionReports(raw_ostream &OS);
+ void renderFunctionReports(ArrayRef<std::string> 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 <vector>
-
-namespace llvm {
-
-/// \brief Manager for the function and file code coverage summaries.
-class CoverageSummary {
- std::vector<StringRef> Filenames;
- std::vector<FunctionCoverageSummary> FunctionSummaries;
- std::vector<std::pair<unsigned, unsigned>> FunctionSummariesFileIDs;
- std::vector<FileCoverageSummary> FileSummaries;
-
- unsigned getFileID(StringRef Filename);
-
-public:
- void createSummaries(const coverage::CoverageMapping &Coverage);
-
- ArrayRef<FileCoverageSummary> 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<FunctionCoverageSummary> 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<FunctionCoverageSummary> FunctionSummaries;
-
- FileCoverageSummary(StringRef Name, const RegionCoverageInfo &RegionCoverage,
- const LineCoverageInfo &LineCoverage,
- const FunctionCoverageInfo &FunctionCoverage,
- ArrayRef<FunctionCoverageSummary> 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<FunctionCoverageSummary> 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 <system_error>
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
#include <functional>
+#include <system_error>
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 <string>
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<Module> 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 = "<stdin>";
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<std::unique_ptr<Module>> 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<GlobalValue*> 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<RTDyldMemoryManager>(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<bool> ListSymbolsOnly(
+ "list-symbols-only", cl::init(false),
+ cl::desc("Instead of running LTO, list the symbols in each IR file"));
+
+static cl::opt<bool> SetMergedModule(
+ "set-merged-module", cl::init(false),
+ cl::desc("Use the first input module as the merged module"));
+
namespace {
struct ModuleInfo {
std::vector<bool> CanBeHidden;
@@ -90,6 +98,46 @@ void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
errs() << Msg << "\n";
}
+std::unique_ptr<LTOModule>
+getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
+ const TargetOptions &Options, std::string &Error) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> 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>(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<MemoryBuffer> Buffer;
+ std::unique_ptr<LTOModule> 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<uint8_t> 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<tool_output_file> 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<tool_output_file>(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<tool_output_file> Out(GetOutputStream());
+ std::unique_ptr<tool_output_file> 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 <algorithm>
#include <cctype>
#include <cerrno>
@@ -1069,7 +1069,6 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
ArchFound = true;
ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
I->getAsObjectFile();
- std::unique_ptr<Archive> 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<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
- std::unique_ptr<Archive> A;
std::string ArchiveName;
ArchiveName.clear();
if (ObjOrErr) {
ObjectFile &Obj = *ObjOrErr.get();
dumpSymbolNamesFromObject(Obj, false);
- } else if (!I->getAsArchive(A)) {
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
- std::unique_ptr<Archive> 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<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
+ std::unique_ptr<Archive> &A = *AOrErr;
for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
AI != AE; ++AI) {
ErrorOr<std::unique_ptr<Binary>> 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<bool>
PrintImmHex("print-imm-hex",
cl::desc("Use hex format for immediate values"));
+cl::opt<bool> llvm::UniversalHeaders("universal-headers",
+ cl::desc("Print Mach-O universal headers "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::ArchiveHeaders("archive-headers",
+ cl::desc("Print archive headers for Mach-O archives "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::IndirectSymbols("indirect-symbols",
+ cl::desc("Print indirect symbol table for Mach-O "
+ "objects (requires -macho)"));
+
+cl::opt<bool>
+ llvm::DataInCode("data-in-code",
+ cl::desc("Print the data in code table for Mach-O objects "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::LinkOptHints("link-opt-hints",
+ cl::desc("Print the linker optimization hints for "
+ "Mach-O objects (requires -macho)"));
+
+cl::list<std::string>
+ llvm::DumpSections("section",
+ cl::desc("Prints the specified segment,section for "
+ "Mach-O objects (requires -macho)"));
+
+static cl::list<std::string>
+ 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<SymbolRef> &Symbols,
SmallVectorImpl<uint64_t> &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;
@@ -241,25 +281,1298 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
}
}
-static void DisassembleInputMachO2(StringRef Filename,
- MachOObjectFile *MachOOF);
+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";
+ }
+}
-void llvm::DisassembleInputMachO(StringRef Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = BuffOrErr.getError()) {
- errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n";
- return;
+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);
}
- std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
+}
- std::unique_ptr<MachOObjectFile> MachOOF = std::move(
- ObjectFile::createMachOObjectFile(Buff.get()->getMemBufferRef()).get());
+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;
- DisassembleInputMachO2(Filename, MachOOF.get());
+ 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<uint64_t, StringRef> 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<SectionRef> 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<std::pair<uint64_t, SymbolRef>> 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<const char *>(BytesStr.data());
+
+ switch (section_type) {
+ case MachO::S_CSTRING_LITERALS:
+ for (uint64_t i = lp - SectAddress;
+ i < SectSize && Contents[i] != '\0'; i++) {
+ DumpCstringChar(Contents[i]);
+ }
+ outs() << "\n";
+ break;
+ case MachO::S_4BYTE_LITERALS:
+ float f;
+ memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
+ uint32_t l;
+ memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l);
+ }
+ DumpLiteral4(l, f);
+ break;
+ case MachO::S_8BYTE_LITERALS: {
+ double d;
+ memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
+ uint32_t l0, l1;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ }
+ DumpLiteral8(O, l0, l1, d);
+ break;
+ }
+ case MachO::S_16BYTE_LITERALS: {
+ uint32_t l0, l1, l2, l3;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ sys::swapByteOrder(l2);
+ sys::swapByteOrder(l3);
+ }
+ DumpLiteral16(l0, l1, l2, l3);
+ break;
+ }
+ }
+ }
+ }
+ if (found == false)
+ outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
+ }
+}
+
+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<StringRef, StringRef> 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<const char *>(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<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) {
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
+ bool ArchFound = false;
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ Triple T;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
+ }
+ unsigned i;
+ for (i = 0; i < ArchFlags.size(); ++i) {
+ if (ArchFlags[i] == T.getArchName())
+ ArchFound = true;
+ break;
+ }
+ if (!ArchFound) {
+ 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) << " ";
+
+ 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 (verbose) {
+ ErrorOr<StringRef> 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 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);
+ }
+}
+
+// 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;
+ }
+ }
+ }
+
+ // Attempt to open the binary.
+ ErrorOr<OwningBinary<Binary>> 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<Archive>(&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<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O = dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ ProcessMachO(Filename, O, O->getFileName());
+ }
+ }
+ return;
+ }
+ if (UniversalHeaders) {
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
+ printMachOUniversalHeaders(UB, true);
+ }
+ if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&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<std::unique_ptr<ObjectFile>> ObjOrErr =
+ I->getAsObjectFile();
+ std::string ArchitectureName = "";
+ if (ArchFlags.size() > 1)
+ ArchitectureName = I->getArchTypeName();
+ if (ObjOrErr) {
+ ObjectFile &O = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
+ ProcessMachO(Filename, MachOOF, "", ArchitectureName);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*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<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ std::string ArchiveName;
+ ArchiveName.clear();
+ if (ObjOrErr) {
+ ObjectFile &O = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&O))
+ ProcessMachO(Filename, MachOOF);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*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<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile();
+ std::string ArchitectureName = "";
+ if (moreThanOneArch)
+ ArchitectureName = I->getArchTypeName();
+ if (ObjOrErr) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&Obj))
+ ProcessMachO(Filename, MachOOF, "", ArchitectureName);
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
+ if (ChildOrErr.getError())
+ continue;
+ if (MachOObjectFile *O =
+ dyn_cast<MachOObjectFile>(&*ChildOrErr.get())) {
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(O))
+ ProcessMachO(Filename, MachOOF, MachOOF->getFileName(),
+ ArchitectureName);
+ }
+ }
+ }
+ }
+ return;
+ }
+ if (ObjectFile *O = dyn_cast<ObjectFile>(&Bin)) {
+ if (!checkMachOAndArchFlags(O, Filename))
+ return;
+ if (MachOObjectFile *MachOOF = dyn_cast<MachOObjectFile>(&*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 std::pair<uint64_t, const char *> BindInfoEntry;
typedef std::vector<BindInfoEntry> 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<std::string>
InputFilenames(cl::Positional, cl::desc("<input object files>"),cl::ZeroOrMore);
-static cl::opt<bool>
-Disassemble("disassemble",
+cl::opt<bool>
+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<bool>
-Relocations("r", cl::desc("Display the relocation entries in the file"));
+cl::opt<bool>
+llvm::Relocations("r", cl::desc("Display the relocation entries in the file"));
-static cl::opt<bool>
-SectionContents("s", cl::desc("Display the content of each section"));
+cl::opt<bool>
+llvm::SectionContents("s", cl::desc("Display the content of each section"));
-static cl::opt<bool>
-SymbolTable("t", cl::desc("Display the symbol table"));
+cl::opt<bool>
+llvm::SymbolTable("t", cl::desc("Display the symbol table"));
-static cl::opt<bool>
-ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
+cl::opt<bool>
+llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
-static cl::opt<bool>
-Rebase("rebase", cl::desc("Display mach-o rebasing info"));
+cl::opt<bool>
+llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
-static cl::opt<bool>
-Bind("bind", cl::desc("Display mach-o binding info"));
+cl::opt<bool>
+llvm::Bind("bind", cl::desc("Display mach-o binding info"));
-static cl::opt<bool>
-LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
+cl::opt<bool>
+llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
-static cl::opt<bool>
-WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
+cl::opt<bool>
+llvm::WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
static cl::opt<bool>
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
@@ -109,12 +108,12 @@ llvm::MCPU("mcpu",
cl::init(""));
cl::opt<std::string>
-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<bool>
-SectionHeaders("section-headers", cl::desc("Display summaries of the headers "
- "for each section."));
+cl::opt<bool>
+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<bool>
-UnwindInfo("unwind-info", cl::desc("Display unwind information"));
+cl::opt<bool>
+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<bool>
-PrivateHeaders("private-headers",
- cl::desc("Display format specific file headers"));
+cl::opt<bool>
+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<const COFFObjectFile>(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<MachOObjectFile>(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<MachOObjectFile>(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<MachOObjectFile>(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<MachOObjectFile>(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<MachOObjectFile>(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<std::string> TripleName;
extern cl::opt<std::string> ArchName;
extern cl::opt<std::string> MCPU;
extern cl::list<std::string> MAttrs;
+extern cl::list<std::string> DumpSections;
+extern cl::opt<bool> Disassemble;
extern cl::opt<bool> NoShowRawInsn;
+extern cl::opt<bool> PrivateHeaders;
+extern cl::opt<bool> ExportsTrie;
+extern cl::opt<bool> Rebase;
+extern cl::opt<bool> Bind;
+extern cl::opt<bool> LazyBind;
+extern cl::opt<bool> WeakBind;
+extern cl::opt<bool> UniversalHeaders;
+extern cl::opt<bool> ArchiveHeaders;
+extern cl::opt<bool> IndirectSymbols;
+extern cl::opt<bool> DataInCode;
+extern cl::opt<bool> LinkOptHints;
+extern cl::opt<bool> Relocations;
+extern cl::opt<bool> SectionHeaders;
+extern cl::opt<bool> SectionContents;
+extern cl::opt<bool> SymbolTable;
+extern cl::opt<bool> UnwindInfo;
// Various helper functions.
bool error(std::error_code ec);
bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b);
void DumpBytes(StringRef bytes);
-void 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<PDBSymbolTypeBaseClass>(*Child))
+ continue;
+
+ auto &AccessGroup = Groups.find((int)Access)->second;
+
+ if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
+ if (Func->isCompilerGenerated())
+ continue;
+ if (Func->getLength() == 0 && !Func->isPureVirtual())
+ continue;
+ Child.release();
+ AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
+ } else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
+ Child.release();
+ AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(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 <list>
+#include <memory>
+#include <unordered_map>
+
+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<std::unique_ptr<PDBSymbolFunc>> Functions;
+ std::list<std::unique_ptr<PDBSymbolData>> Data;
+ std::list<std::unique_ptr<PDBSymbol>> Unknown;
+ SymbolGroup(const SymbolGroup &other) = delete;
+ SymbolGroup &operator=(const SymbolGroup &other) = delete;
+ };
+ typedef std::unordered_map<int, SymbolGroup> 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 <utility>
+#include <vector>
+
+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 <class T>
+void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS,
+ llvm::FunctionDumper &Dumper) {
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>(
+ 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<PDBSymbolTypeUDT>(
+ 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<PDBSymbolFuncDebugStart>())
+ OS << "+" << DebugStart->getRelativeVirtualAddress() - FuncStart;
+ OS << " - " << format_hex(FuncEnd, 8);
+ if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>())
+ 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<PDBSymbolTypeFunctionSig>(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<PDBSymbolTypeEnum>();
+ OS << newline(Indent) << "Enums: (" << Enums->getChildCount() << " items)";
+ while (auto Enum = Enums->getNext())
+ Enum->dump(OS, Indent + 2, *this);
+
+ auto FuncSigs = Exe.findAllChildren<PDBSymbolTypeFunctionSig>();
+ OS << newline(Indent);
+ OS << "Function Signatures: (" << FuncSigs->getChildCount() << " items)";
+ while (auto Sig = FuncSigs->getNext())
+ Sig->dump(OS, Indent + 2, *this);
+
+ auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
+ OS << newline(Indent) << "Typedefs: (" << Typedefs->getChildCount()
+ << " items)";
+ while (auto Typedef = Typedefs->getNext())
+ Typedef->dump(OS, Indent + 2, *this);
+
+ auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
+ 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<PDBSymbolTypeFunctionSig>(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<PDBSymbolFunc>(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<PDBSymbolTypeArray>(&Type)) {
+ std::string IndexSpec;
+ raw_string_ostream IndexStream(IndexSpec);
+ std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
+ while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
+ IndexStream << "[" << NestedArray->getCount() << "]";
+ 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 <Windows.h>
+#endif
+
+using namespace llvm;
+
+namespace opts {
+
+enum class PDB_DumpType { ByType, ByObjFile, Both };
+
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore);
+
+cl::opt<bool> DumpCompilands("compilands", cl::desc("Display compilands"));
+cl::opt<bool> DumpSymbols("symbols",
+ cl::desc("Display symbols (implies --compilands"));
+cl::opt<bool> DumpTypes("types", cl::desc("Display types"));
+cl::opt<bool> DumpClassDefs("class-definitions",
+ cl::desc("Display full class definitions"));
+}
+
+static void dumpInput(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session(
+ llvm::createPDBReader(PDB_ReaderType::DIA, Path));
+ if (!Session) {
+ outs() << "Unable to create PDB reader. Check that a valid implementation";
+ outs() << " is available for your platform.";
+ 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<PDBSymbolCompiland>();
+ 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<const char *, 256> argv;
+ llvm::SpecificBumpPtrAllocator<char> 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<std::string> Inputs, StringRef OutputFilename) {
+void mergeInstrProfile(const cl::list<std::string> &Inputs,
+ StringRef OutputFilename) {
if (OutputFilename.compare("-") == 0)
exitWithError("Cannot write indexed profdata format to stdout.");
@@ -64,7 +65,8 @@ void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
Writer.write(Output);
}
-void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
+void mergeSampleProfile(const cl::list<std::string> &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<StringRef, 10> FunctionNames;
StringMap<StringRef> 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<unsigned> ElfMachineType[] = {
};
static const EnumEntry<unsigned> 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<unsigned> 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<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
- // -codeview-linetables
- cl::opt<bool> CodeViewLineTables("codeview-linetables",
- cl::desc("Display CodeView line table information"));
+ // -codeview
+ cl::opt<bool> CodeView("codeview",
+ cl::desc("Display CodeView debug information"));
+
+ // -codeview-subsection-bytes
+ cl::opt<bool> CodeViewSubsectionBytes(
+ "codeview-subsection-bytes",
+ cl::desc("Dump raw contents of codeview debug sections and records"));
// -arm-attributes, -a
cl::opt<bool> ARMAttributes("arm-attributes",
@@ -146,6 +151,10 @@ namespace opts {
cl::opt<bool>
COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
+ // -coff-exports
+ cl::opt<bool>
+ COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
+
// -coff-directives
cl::opt<bool>
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<bool> DynamicSymbols;
extern llvm::cl::opt<bool> UnwindInfo;
extern llvm::cl::opt<bool> ExpandRelocs;
- extern llvm::cl::opt<bool> CodeViewLineTables;
+ extern llvm::cl::opt<bool> CodeView;
+ extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
extern llvm::cl::opt<bool> ARMAttributes;
extern llvm::cl::opt<bool> 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 <list>
#include <system_error>
@@ -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<ObjectImage> LoadedObject;
+ ErrorOr<std::unique_ptr<ObjectFile>> 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<ObjectBuffer>(std::move(*InputBuffer)));
- if (!LoadedObject) {
+ std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo =
+ Dyld.loadObject(Obj);
+
+ if (Dyld.hasError())
return Error(Dyld.getErrorString());
- }
// Resolve all the relocations we can.
Dyld.resolveRelocations();
+ OwningBinary<ObjectFile> DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
+
std::unique_ptr<DIContext> 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<ObjectImage> LoadedObject;
+ ErrorOr<std::unique_ptr<ObjectFile>> 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<ObjectBuffer>(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<std::unique_ptr<MemoryBuffer>> InputBuffer =
MemoryBuffer::getFileOrSTDIN(InputFileList[i]);
+
if (std::error_code EC = InputBuffer.getError())
return Error("unable to read input: '" + EC.message() + "'");
- std::unique_ptr<ObjectImage> LoadedObject;
+ ErrorOr<std::unique_ptr<ObjectFile>> 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<ObjectBuffer>(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<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
- std::unique_ptr<Archive> UA;
if (UO) {
if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
@@ -503,7 +502,9 @@ static void PrintFileSectionSizes(StringRef file) {
outs() << "\n";
}
}
- } else if (!I->getAsArchive(UA)) {
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
- std::unique_ptr<Archive> UA;
if (UO) {
if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
@@ -579,7 +579,9 @@ static void PrintFileSectionSizes(StringRef file) {
outs() << "\n";
}
}
- } else if (!I->getAsArchive(UA)) {
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile();
- std::unique_ptr<Archive> UA;
if (UO) {
if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) {
MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o);
@@ -643,7 +644,9 @@ static void PrintFileSectionSizes(StringRef file) {
outs() << "\n";
}
}
- } else if (!I->getAsArchive(UA)) {
+ } else if (ErrorOr<std::unique_ptr<Archive>> AOrErr =
+ I->getAsArchive()) {
+ std::unique_ptr<Archive> &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<OutputFormatTy>(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<LLVMContext>())
+ : 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<StringRef,StringRef> 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 ELFT>
class ELFDumper {
+ typedef object::Elf_Sym_Impl<ELFT> Elf_Sym;
typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter;
+ typedef typename object::ELFFile<ELFT>::Elf_Word Elf_Word;
const object::ELFFile<ELFT> &Obj;
@@ -38,6 +40,7 @@ class ELFDumper {
ErrorOr<ELFYAML::RelocationSection *> dumpRelaSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::RawContentSection *>
dumpContentSection(const Elf_Shdr *Shdr);
+ ErrorOr<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
public:
ELFDumper(const object::ELFFile<ELFT> &O);
@@ -86,7 +89,13 @@ ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
break;
}
- // FIXME: Support SHT_GROUP section format.
+ case ELF::SHT_GROUP: {
+ ErrorOr<ELFYAML::Group *> G = dumpGroup(&Sec);
+ if (std::error_code EC = G.getError())
+ return EC;
+ Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(G.get()));
+ break;
+ }
default: {
ErrorOr<ELFYAML::RawContentSection *> S = dumpContentSection(&Sec);
if (std::error_code EC = S.getError())
@@ -275,6 +284,41 @@ ELFDumper<ELFT>::dumpContentSection(const Elf_Shdr *Shdr) {
}
template <class ELFT>
+ErrorOr<ELFYAML::Group *> ELFDumper<ELFT>::dumpGroup(const Elf_Shdr *Shdr) {
+ auto S = make_unique<ELFYAML::Group>();
+
+ 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<StringRef> symbolName = Obj.getSymbolName(symtab, symbol);
+ if (std::error_code EC = symbolName.getError())
+ return EC;
+ S->Info = *symbolName;
+ const Elf_Word *groupMembers =
+ reinterpret_cast<const Elf_Word *>(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<StringRef> 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 <class ELFT>
static std::error_code elf2yaml(raw_ostream &Out,
const object::ELFFile<ELFT> &Obj) {
ELFDumper<ELFT> 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<bool>
+ 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<all>", InvalidateAllAnalysesPass())
+MODULE_PASS("no-op-module", NoOpModulePass())
MODULE_PASS("print", PrintModulePass(dbgs()))
MODULE_PASS("print-cg", LazyCallGraphPrinterPass(dbgs()))
+MODULE_PASS("verify", VerifierPass())
#undef MODULE_PASS
#ifndef CGSCC_ANALYSIS
#define CGSCC_ANALYSIS(NAME, CREATE_PASS)
#endif
+CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
#undef CGSCC_ANALYSIS
#ifndef CGSCC_PASS
#define CGSCC_PASS(NAME, CREATE_PASS)
#endif
+CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass())
+CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
#undef CGSCC_PASS
#ifndef FUNCTION_ANALYSIS
#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
#endif
+FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis())
+FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis())
+FUNCTION_ANALYSIS("loops", LoopAnalysis())
+FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis())
+FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
+FUNCTION_ANALYSIS("targetir",
+ TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
#undef FUNCTION_ANALYSIS
#ifndef FUNCTION_PASS
#define FUNCTION_PASS(NAME, CREATE_PASS)
#endif
+FUNCTION_PASS("early-cse", EarlyCSEPass())
+FUNCTION_PASS("instcombine", InstCombinePass())
+FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
+FUNCTION_PASS("no-op-function", NoOpFunctionPass())
+FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass())
FUNCTION_PASS("print", PrintFunctionPass(dbgs()))
+FUNCTION_PASS("print<assumptions>", AssumptionPrinterPass(dbgs()))
+FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs()))
+FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs()))
+FUNCTION_PASS("simplify-cfg", SimplifyCFGPass())
+FUNCTION_PASS("verify", VerifierPass())
+FUNCTION_PASS("verify<domtree>", DominatorTreeVerifierPass())
#undef FUNCTION_PASS
diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp
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<decltype(CREATE_PASS)>()); \
+ return true; \
+ } \
+ if (Name == "invalidate<" NAME ">") { \
+ MPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
+ 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<decltype(CREATE_PASS)>()); \
+ return true; \
+ } \
+ if (Name == "invalidate<" NAME ">") { \
+ CGPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
+ 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<decltype(CREATE_PASS)>()); \
+ return true; \
+ } \
+ if (Name == "invalidate<" NAME ">") { \
+ FPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
+ 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 <algorithm>
@@ -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<Module> 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<TargetMachine> 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<TargetMachine> 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<FunctionPassManager> FPasses;
+ std::unique_ptr<legacy::FunctionPassManager> 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<tool_output_file>(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<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
if (!writeSectionContent(SHeader, *S, CBA))
return false;
+ } else if (auto S = dyn_cast<ELFYAML::Group>(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<ELFT>::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 <class ELFT>
bool
ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
@@ -351,19 +369,51 @@ ELFState<ELFT>::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 <class ELFT>
+bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::Group &Section,
+ ContiguousBlobAccumulator &CBA) {
+ typedef typename object::ELFFile<ELFT>::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 <class ELFT> bool ELFState<ELFT>::buildSectionIndex() {
SN2I.addName(".symtab", getDotSymTabSecNo());
SN2I.addName(".strtab", getDotStrTabSecNo());