aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-01-18 16:17:27 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-01-18 16:17:27 +0000
commit67c32a98315f785a9ec9d531c1f571a0196c7463 (patch)
tree4abb9cbeecc7901726dd0b4a37369596c852e9ef /tools
parent9f61947910e6ab40de38e6b4034751ef1513200f (diff)
downloadsrc-67c32a98315f785a9ec9d531c1f571a0196c7463.tar.gz
src-67c32a98315f785a9ec9d531c1f571a0196c7463.zip
Vendor import of llvm RELEASE_360/rc1 tag r226102 (effectively, 3.6.0 RC1):vendor/llvm/llvm-release_360-r226102
Notes
Notes: svn path=/vendor/llvm/dist/; revision=277323 svn path=/vendor/llvm/llvm-release_360-r226102/; revision=277324; tag=vendor/llvm/llvm-release_360-r226102
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt25
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile10
-rw-r--r--tools/bugpoint/BugDriver.cpp21
-rw-r--r--tools/bugpoint/BugDriver.h81
-rw-r--r--tools/bugpoint/CrashDebugger.cpp31
-rw-r--r--tools/bugpoint/ExtractFunction.cpp45
-rw-r--r--tools/bugpoint/ListReducer.h4
-rw-r--r--tools/bugpoint/Miscompilation.cpp57
-rw-r--r--tools/bugpoint/OptimizerDriver.cpp50
-rw-r--r--tools/bugpoint/ToolRunner.cpp39
-rw-r--r--tools/bugpoint/ToolRunner.h4
-rw-r--r--tools/bugpoint/bugpoint.cpp14
-rw-r--r--tools/dsymutil/BinaryHolder.cpp111
-rw-r--r--tools/dsymutil/BinaryHolder.h104
-rw-r--r--tools/dsymutil/CMakeLists.txt13
-rw-r--r--tools/dsymutil/DebugMap.cpp80
-rw-r--r--tools/dsymutil/DebugMap.h128
-rw-r--r--tools/dsymutil/DwarfLinker.cpp20
-rw-r--r--tools/dsymutil/LLVMBuild.txt22
-rw-r--r--tools/dsymutil/MachODebugMapParser.cpp234
-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.txt10
-rw-r--r--tools/gold/Makefile2
-rw-r--r--tools/gold/gold-plugin.cpp820
-rw-r--r--tools/llc/llc.cpp75
-rw-r--r--tools/lli/CMakeLists.txt1
-rw-r--r--tools/lli/ChildTarget/ChildTarget.cpp14
-rw-r--r--tools/lli/LLVMBuild.txt2
-rw-r--r--tools/lli/Makefile2
-rw-r--r--tools/lli/RPCChannel.h6
-rw-r--r--tools/lli/RemoteMemoryManager.cpp36
-rw-r--r--tools/lli/RemoteMemoryManager.h27
-rw-r--r--tools/lli/RemoteTarget.h4
-rw-r--r--tools/lli/RemoteTargetExternal.h6
-rw-r--r--tools/lli/RemoteTargetMessage.h4
-rw-r--r--tools/lli/lli.cpp121
-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.cpp399
-rw-r--r--tools/llvm-as/llvm-as.cpp10
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp110
-rw-r--r--tools/llvm-c-test/CMakeLists.txt27
-rw-r--r--tools/llvm-c-test/disassemble.c20
-rw-r--r--tools/llvm-config/BuildVariables.inc.in1
-rw-r--r--tools/llvm-config/CMakeLists.txt15
-rw-r--r--tools/llvm-config/Makefile2
-rw-r--r--tools/llvm-config/llvm-config.cpp10
-rw-r--r--tools/llvm-cov/CMakeLists.txt10
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp483
-rw-r--r--tools/llvm-cov/CoverageFilters.cpp59
-rw-r--r--tools/llvm-cov/CoverageFilters.h127
-rw-r--r--tools/llvm-cov/CoverageReport.cpp202
-rw-r--r--tools/llvm-cov/CoverageReport.h40
-rw-r--r--tools/llvm-cov/CoverageSummary.cpp64
-rw-r--r--tools/llvm-cov/CoverageSummary.h45
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.cpp96
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h133
-rw-r--r--tools/llvm-cov/CoverageViewOptions.h36
-rw-r--r--tools/llvm-cov/LLVMBuild.txt2
-rw-r--r--tools/llvm-cov/Makefile2
-rw-r--r--tools/llvm-cov/RenderingSupport.h60
-rw-r--r--tools/llvm-cov/SourceCoverageView.cpp260
-rw-r--r--tools/llvm-cov/SourceCoverageView.h162
-rw-r--r--tools/llvm-cov/TestingSupport.cpp90
-rw-r--r--tools/llvm-cov/gcov.cpp152
-rw-r--r--tools/llvm-cov/llvm-cov.cpp178
-rw-r--r--tools/llvm-diff/DiffConsumer.h4
-rw-r--r--tools/llvm-diff/DiffLog.h4
-rw-r--r--tools/llvm-diff/DifferenceEngine.h4
-rw-r--r--tools/llvm-diff/llvm-diff.cpp22
-rw-r--r--tools/llvm-dis/llvm-dis.cpp47
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp21
-rw-r--r--tools/llvm-extract/llvm-extract.cpp38
-rw-r--r--tools/llvm-go/CMakeLists.txt9
-rw-r--r--tools/llvm-go/Makefile16
-rw-r--r--tools/llvm-go/llvm-go.go290
-rw-r--r--tools/llvm-jitlistener/CMakeLists.txt43
-rw-r--r--tools/llvm-jitlistener/LLVMBuild.txt2
-rw-r--r--tools/llvm-jitlistener/Makefile2
-rw-r--r--tools/llvm-jitlistener/llvm-jitlistener.cpp23
-rw-r--r--tools/llvm-link/llvm-link.cpp69
-rw-r--r--tools/llvm-lto/llvm-lto.cpp99
-rw-r--r--tools/llvm-mc/Disassembler.cpp71
-rw-r--r--tools/llvm-mc/Disassembler.h4
-rw-r--r--tools/llvm-mc/llvm-mc.cpp118
-rw-r--r--tools/llvm-mcmarkup/llvm-mcmarkup.cpp7
-rw-r--r--tools/llvm-nm/llvm-nm.cpp274
-rw-r--r--tools/llvm-objdump/CMakeLists.txt2
-rw-r--r--tools/llvm-objdump/COFFDump.cpp13
-rw-r--r--tools/llvm-objdump/LLVMBuild.txt2
-rw-r--r--tools/llvm-objdump/MachODump.cpp4694
-rw-r--r--tools/llvm-objdump/Makefile2
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp391
-rw-r--r--tools/llvm-objdump/llvm-objdump.h31
-rw-r--r--tools/llvm-profdata/CMakeLists.txt6
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp180
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.cpp2
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.h4
-rw-r--r--tools/llvm-readobj/ARMEHABIPrinter.h4
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp63
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.h52
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp428
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp5
-rw-r--r--tools/llvm-readobj/Error.cpp2
-rw-r--r--tools/llvm-readobj/Error.h4
-rw-r--r--tools/llvm-readobj/MachODumper.cpp202
-rw-r--r--tools/llvm-readobj/ObjDumper.h10
-rw-r--r--tools/llvm-readobj/StreamWriter.h20
-rw-r--r--tools/llvm-readobj/Win64EHDumper.h4
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp52
-rw-r--r--tools/llvm-readobj/llvm-readobj.h4
-rw-r--r--tools/llvm-rtdyld/CMakeLists.txt1
-rw-r--r--tools/llvm-rtdyld/LLVMBuild.txt2
-rw-r--r--tools/llvm-rtdyld/Makefile2
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp234
-rw-r--r--tools/llvm-shlib/CMakeLists.txt100
-rw-r--r--tools/llvm-shlib/libllvm.cpp20
-rw-r--r--tools/llvm-size/llvm-size.cpp65
-rw-r--r--tools/llvm-stress/llvm-stress.cpp9
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.cpp190
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.h56
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp14
-rw-r--r--tools/llvm-vtabledump/CMakeLists.txt10
-rw-r--r--tools/llvm-vtabledump/Error.cpp43
-rw-r--r--tools/llvm-vtabledump/Error.h39
-rw-r--r--tools/llvm-vtabledump/LLVMBuild.txt22
-rw-r--r--tools/llvm-vtabledump/Makefile18
-rw-r--r--tools/llvm-vtabledump/llvm-vtabledump.cpp464
-rw-r--r--tools/llvm-vtabledump/llvm-vtabledump.h23
-rw-r--r--tools/lto/CMakeLists.txt2
-rw-r--r--tools/lto/Makefile4
-rw-r--r--tools/lto/lto.cpp47
-rw-r--r--tools/lto/lto.exports3
-rw-r--r--tools/macho-dump/macho-dump.cpp16
-rw-r--r--tools/msbuild/CMakeLists.txt11
-rw-r--r--tools/msbuild/install.bat40
-rw-r--r--tools/msbuild/toolset-vs2014.targets3
-rw-r--r--tools/msbuild/toolset-vs2014_xp.targets21
-rw-r--r--tools/msbuild/uninstall.bat23
-rw-r--r--tools/obj2yaml/CMakeLists.txt2
-rw-r--r--tools/obj2yaml/Error.cpp4
-rw-r--r--tools/obj2yaml/Error.h4
-rw-r--r--tools/obj2yaml/Makefile3
-rw-r--r--tools/obj2yaml/coff2yaml.cpp161
-rw-r--r--tools/obj2yaml/elf2yaml.cpp2
-rw-r--r--tools/obj2yaml/obj2yaml.cpp6
-rw-r--r--tools/obj2yaml/obj2yaml.h4
-rw-r--r--tools/opt/BreakpointPrinter.cpp2
-rw-r--r--tools/opt/NewPMDriver.cpp33
-rw-r--r--tools/opt/NewPMDriver.h4
-rw-r--r--tools/opt/PassRegistry.def14
-rw-r--r--tools/opt/Passes.cpp209
-rw-r--r--tools/opt/Passes.h27
-rw-r--r--tools/opt/opt.cpp121
-rw-r--r--tools/verify-uselistorder/CMakeLists.txt12
-rw-r--r--tools/verify-uselistorder/LLVMBuild.txt22
-rw-r--r--tools/verify-uselistorder/Makefile17
-rw-r--r--tools/verify-uselistorder/verify-uselistorder.cpp568
-rw-r--r--tools/yaml2obj/CMakeLists.txt2
-rw-r--r--tools/yaml2obj/Makefile3
-rw-r--r--tools/yaml2obj/yaml2coff.cpp311
-rw-r--r--tools/yaml2obj/yaml2elf.cpp12
-rw-r--r--tools/yaml2obj/yaml2obj.cpp8
-rw-r--r--tools/yaml2obj/yaml2obj.h4
167 files changed, 13126 insertions, 2442 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 846ad1e25d62..7e9938119f5d 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -8,6 +8,12 @@ else(WITH_POLLY)
list(APPEND LLVM_IMPLICIT_PROJECT_IGNORE "${LLVM_MAIN_SRC_DIR}/tools/polly")
endif(WITH_POLLY)
+if( LLVM_BUILD_LLVM_DYLIB )
+ add_llvm_tool_subdirectory(llvm-shlib)
+else()
+ ignore_llvm_tool_subdirectory(llvm-shlib)
+endif()
+
add_llvm_tool_subdirectory(opt)
add_llvm_tool_subdirectory(llvm-as)
add_llvm_tool_subdirectory(llvm-dis)
@@ -30,6 +36,8 @@ 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)
else()
@@ -42,6 +50,8 @@ add_llvm_tool_subdirectory(llvm-bcanalyzer)
add_llvm_tool_subdirectory(llvm-stress)
add_llvm_tool_subdirectory(llvm-mcmarkup)
+add_llvm_tool_subdirectory(verify-uselistorder)
+
add_llvm_tool_subdirectory(llvm-symbolizer)
add_llvm_tool_subdirectory(llvm-c-test)
@@ -49,6 +59,8 @@ add_llvm_tool_subdirectory(llvm-c-test)
add_llvm_tool_subdirectory(obj2yaml)
add_llvm_tool_subdirectory(yaml2obj)
+add_llvm_tool_subdirectory(llvm-go)
+
if(NOT CYGWIN AND LLVM_ENABLE_PIC)
add_llvm_tool_subdirectory(lto)
add_llvm_tool_subdirectory(llvm-lto)
@@ -57,19 +69,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 1b537a372da3..53d4ffc28dc1 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
+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 dsymutil
[component_0]
type = Group
diff --git a/tools/Makefile b/tools/Makefile
index 97ad99a9d1a2..b559edacd52d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -21,7 +21,8 @@ endif
# Build LLD and LLDB if present. Note LLDB must be built last as it depends on
# the wider LLVM infrastructure (including Clang).
-OPTIONAL_DIRS := lld lldb
+OPTIONAL_PARALLEL_DIRS += lld
+OPTIONAL_DIRS := lldb
# NOTE: The tools are organized into five groups of four consisting of one
# large and three small executables. This is done to minimize memory load
@@ -31,7 +32,8 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \
lli llvm-extract llvm-mc bugpoint llvm-bcanalyzer llvm-diff \
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-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
+ llvm-vtabledump verify-uselistorder dsymutil
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
@@ -72,4 +74,8 @@ ifneq ($(ENABLE_SHARED),1)
endif
endif
+ifneq (,$(filter go,$(BINDINGS_TO_BUILD)))
+ PARALLEL_DIRS += llvm-go
+endif
+
include $(LEVEL)/Makefile.common
diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp
index cecccbe0f0ef..b8be17e44dd2 100644
--- a/tools/bugpoint/BugDriver.cpp
+++ b/tools/bugpoint/BugDriver.cpp
@@ -82,14 +82,10 @@ BugDriver::~BugDriver() {
delete gcc;
}
-
-/// ParseInputFile - Given a bitcode or assembly input filename, parse and
-/// return it, or return null if not possible.
-///
-Module *llvm::ParseInputFile(const std::string &Filename,
- LLVMContext& Ctxt) {
+std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename,
+ LLVMContext &Ctxt) {
SMDiagnostic Err;
- Module *Result = ParseIRFile(Filename, Err, Ctxt);
+ std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
if (!Result)
Err.print("bugpoint", errs());
@@ -120,23 +116,18 @@ bool BugDriver::addSources(const std::vector<std::string> &Filenames) {
assert(!Filenames.empty() && "Must specify at least on input filename!");
// Load the first input file.
- Program = ParseInputFile(Filenames[0], Context);
+ Program = parseInputFile(Filenames[0], Context).release();
if (!Program) return true;
outs() << "Read input file : '" << Filenames[0] << "'\n";
for (unsigned i = 1, e = Filenames.size(); i != e; ++i) {
- std::unique_ptr<Module> M(ParseInputFile(Filenames[i], Context));
+ std::unique_ptr<Module> M = parseInputFile(Filenames[i], Context);
if (!M.get()) return true;
outs() << "Linking in input file: '" << Filenames[i] << "'\n";
- std::string ErrorMessage;
- if (Linker::LinkModules(Program, M.get(), Linker::DestroySource,
- &ErrorMessage)) {
- errs() << ToolName << ": error linking in '" << Filenames[i] << "': "
- << ErrorMessage << '\n';
+ if (Linker::LinkModules(Program, M.get()))
return true;
- }
}
outs() << "*** All input ok\n";
diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h
index 3169d293da02..579781246c54 100644
--- a/tools/bugpoint/BugDriver.h
+++ b/tools/bugpoint/BugDriver.h
@@ -13,11 +13,12 @@
//
//===----------------------------------------------------------------------===//
-#ifndef BUGDRIVER_H
-#define BUGDRIVER_H
+#ifndef LLVM_TOOLS_BUGPOINT_BUGDRIVER_H
+#define LLVM_TOOLS_BUGPOINT_BUGDRIVER_H
#include "llvm/IR/ValueMap.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
+#include <memory>
#include <string>
#include <vector>
@@ -210,41 +211,46 @@ public:
void EmitProgressBitcode(const Module *M, const std::string &ID,
bool NoFlyer = false) const;
- /// deleteInstructionFromProgram - This method clones the current Program and
- /// deletes the specified instruction from the cloned module. It then runs a
- /// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code
- /// which depends on the value. The modified module is then returned.
+ /// This method clones the current Program and deletes the specified
+ /// instruction from the cloned module. It then runs a series of cleanup
+ /// passes (ADCE and SimplifyCFG) to eliminate any code which depends on the
+ /// value. The modified module is then returned.
///
- Module *deleteInstructionFromProgram(const Instruction *I, unsigned Simp);
+ std::unique_ptr<Module> deleteInstructionFromProgram(const Instruction *I,
+ unsigned Simp);
- /// performFinalCleanups - This method clones the current Program and performs
- /// a series of cleanups intended to get rid of extra cruft on the module. If
- /// the MayModifySemantics argument is true, then the cleanups is allowed to
+ /// This method clones the current Program and performs a series of cleanups
+ /// intended to get rid of extra cruft on the module. If the
+ /// MayModifySemantics argument is true, then the cleanups is allowed to
/// modify how the code behaves.
///
- Module *performFinalCleanups(Module *M, bool MayModifySemantics = false);
-
- /// ExtractLoop - Given a module, extract up to one loop from it into a new
- /// function. This returns null if there are no extractable loops in the
- /// program or if the loop extractor crashes.
- Module *ExtractLoop(Module *M);
-
- /// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
- /// into their own functions. The only detail is that M is actually a module
- /// cloned from the one the BBs are in, so some mapping needs to be performed.
- /// If this operation fails for some reason (ie the implementation is buggy),
- /// this function should return null, otherwise it returns a new Module.
- Module *ExtractMappedBlocksFromModule(const std::vector<BasicBlock*> &BBs,
- Module *M);
-
- /// runPassesOn - Carefully run the specified set of pass on the specified
- /// module, returning the transformed module on success, or a null pointer on
- /// failure. If AutoDebugCrashes is set to true, then bugpoint will
- /// automatically attempt to track down a crashing pass if one exists, and
- /// this method will never return null.
- Module *runPassesOn(Module *M, const std::vector<std::string> &Passes,
- bool AutoDebugCrashes = false, unsigned NumExtraArgs = 0,
- const char * const *ExtraArgs = nullptr);
+ std::unique_ptr<Module> performFinalCleanups(Module *M,
+ bool MayModifySemantics = false);
+
+ /// Given a module, extract up to one loop from it into a new function. This
+ /// returns null if there are no extractable loops in the program or if the
+ /// loop extractor crashes.
+ std::unique_ptr<Module> extractLoop(Module *M);
+
+ /// Extract all but the specified basic blocks into their own functions. The
+ /// only detail is that M is actually a module cloned from the one the BBs are
+ /// in, so some mapping needs to be performed. If this operation fails for
+ /// some reason (ie the implementation is buggy), this function should return
+ /// null, otherwise it returns a new Module.
+ std::unique_ptr<Module>
+ extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
+ Module *M);
+
+ /// Carefully run the specified set of pass on the specified/ module,
+ /// returning the transformed module on success, or a null pointer on failure.
+ /// If AutoDebugCrashes is set to true, then bugpoint will automatically
+ /// attempt to track down a crashing pass if one exists, and this method will
+ /// never return null.
+ std::unique_ptr<Module> runPassesOn(Module *M,
+ const std::vector<std::string> &Passes,
+ bool AutoDebugCrashes = false,
+ unsigned NumExtraArgs = 0,
+ const char *const *ExtraArgs = nullptr);
/// runPasses - Run the specified passes on Program, outputting a bitcode
/// file and writting the filename into OutputFile if successful. If the
@@ -296,12 +302,11 @@ private:
bool initializeExecutionEnvironment();
};
-/// ParseInputFile - Given a bitcode or assembly input filename, parse and
-/// return it, or return null if not possible.
+/// Given a bitcode or assembly input filename, parse and return it, or return
+/// null if not possible.
///
-Module *ParseInputFile(const std::string &InputFilename,
- LLVMContext& ctxt);
-
+std::unique_ptr<Module> parseInputFile(StringRef InputFilename,
+ LLVMContext &ctxt);
/// getPassesString - Turn a list of passes into a string which indicates the
/// command line options that must be passed to add the passes.
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp
index 8bd61b3c0964..bac948aaf3ab 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -72,7 +72,7 @@ ReducePassList::doTest(std::vector<std::string> &Prefix,
OrigProgram = BD.Program;
- BD.Program = ParseInputFile(PrefixOutput, BD.getContext());
+ BD.Program = parseInputFile(PrefixOutput, BD.getContext()).release();
if (BD.Program == nullptr) {
errs() << BD.getToolName() << ": Error reading bitcode file '"
<< PrefixOutput << "'!\n";
@@ -312,22 +312,21 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
// have to take.
std::vector<std::pair<std::string, std::string> > BlockInfo;
- for (SmallPtrSet<BasicBlock*, 8>::iterator I = Blocks.begin(),
- E = Blocks.end(); I != E; ++I)
- BlockInfo.push_back(std::make_pair((*I)->getParent()->getName(),
- (*I)->getName()));
+ for (BasicBlock *BB : Blocks)
+ BlockInfo.push_back(std::make_pair(BB->getParent()->getName(),
+ BB->getName()));
// Now run the CFG simplify pass on the function...
std::vector<std::string> Passes;
Passes.push_back("simplifycfg");
Passes.push_back("verify");
- Module *New = BD.runPassesOn(M, Passes);
+ std::unique_ptr<Module> New = BD.runPassesOn(M, Passes);
delete M;
if (!New) {
errs() << "simplifycfg failed!\n";
exit(1);
}
- M = New;
+ M = New.release();
// Try running on the hacked up program...
if (TestFn(BD, M)) {
@@ -420,9 +419,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
// Make sure to use instruction pointers that point into the now-current
// module, and that they don't include any deleted blocks.
Insts.clear();
- for (SmallPtrSet<Instruction*, 64>::const_iterator I = Instructions.begin(),
- E = Instructions.end(); I != E; ++I)
- Insts.push_back(*I);
+ for (Instruction *Inst : Instructions)
+ Insts.push_back(Inst);
return true;
}
delete M; // It didn't crash, try something else.
@@ -578,20 +576,17 @@ static bool DebugACrash(BugDriver &BD,
continue;
outs() << "Checking instruction: " << *I;
- Module *M = BD.deleteInstructionFromProgram(I, Simplification);
+ std::unique_ptr<Module> M =
+ BD.deleteInstructionFromProgram(I, Simplification);
// Find out if the pass still crashes on this pass...
- if (TestFn(BD, M)) {
+ if (TestFn(BD, M.get())) {
// Yup, it does, we delete the old module, and continue trying
// to reduce the testcase...
- BD.setNewProgram(M);
+ BD.setNewProgram(M.release());
InstructionsToSkipBeforeDeleting = CurInstructionNum;
goto TryAgain; // I wish I had a multi-level break here!
}
-
- // This pass didn't crash without this instruction, try the next
- // one.
- delete M;
}
}
@@ -607,7 +602,7 @@ ExitLoops:
if (!BugpointIsInterrupted) {
outs() << "\n*** Attempting to perform final cleanups: ";
Module *M = CloneModule(BD.getProgram());
- M = BD.performFinalCleanups(M, true);
+ M = BD.performFinalCleanups(M, true).release();
// Find out if the pass still crashes on the cleaned up program...
if (TestFn(BD, M)) {
diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp
index 4fb68566ac62..34fe53c08112 100644
--- a/tools/bugpoint/ExtractFunction.cpp
+++ b/tools/bugpoint/ExtractFunction.cpp
@@ -82,13 +82,9 @@ namespace {
}
} // end anonymous namespace
-/// deleteInstructionFromProgram - This method clones the current Program and
-/// deletes the specified instruction from the cloned module. It then runs a
-/// series of cleanup passes (ADCE and SimplifyCFG) to eliminate any code which
-/// depends on the value. The modified module is then returned.
-///
-Module *BugDriver::deleteInstructionFromProgram(const Instruction *I,
- unsigned Simplification) {
+std::unique_ptr<Module>
+BugDriver::deleteInstructionFromProgram(const Instruction *I,
+ unsigned Simplification) {
// FIXME, use vmap?
Module *Clone = CloneModule(Program);
@@ -123,7 +119,7 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I,
Passes.push_back("simplifycfg"); // Delete dead control flow
Passes.push_back("verify");
- Module *New = runPassesOn(Clone, Passes);
+ std::unique_ptr<Module> New = runPassesOn(Clone, Passes);
delete Clone;
if (!New) {
errs() << "Instruction removal failed. Sorry. :( Please report a bug!\n";
@@ -132,11 +128,8 @@ Module *BugDriver::deleteInstructionFromProgram(const Instruction *I,
return New;
}
-/// performFinalCleanups - This method clones the current Program and performs
-/// a series of cleanups intended to get rid of extra cruft on the module
-/// before handing it to the user.
-///
-Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) {
+std::unique_ptr<Module>
+BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) {
// Make all functions external, so GlobalDCE doesn't delete them...
for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
I->setLinkage(GlobalValue::ExternalLinkage);
@@ -149,24 +142,20 @@ Module *BugDriver::performFinalCleanups(Module *M, bool MayModifySemantics) {
else
CleanupPasses.push_back("deadargelim");
- Module *New = runPassesOn(M, CleanupPasses);
+ std::unique_ptr<Module> New = runPassesOn(M, CleanupPasses);
if (!New) {
errs() << "Final cleanups failed. Sorry. :( Please report a bug!\n";
- return M;
+ return nullptr;
}
delete M;
return New;
}
-
-/// ExtractLoop - Given a module, extract up to one loop from it into a new
-/// function. This returns null if there are no extractable loops in the
-/// program or if the loop extractor crashes.
-Module *BugDriver::ExtractLoop(Module *M) {
+std::unique_ptr<Module> BugDriver::extractLoop(Module *M) {
std::vector<std::string> LoopExtractPasses;
LoopExtractPasses.push_back("loop-extract-single");
- Module *NewM = runPassesOn(M, LoopExtractPasses);
+ std::unique_ptr<Module> NewM = runPassesOn(M, LoopExtractPasses);
if (!NewM) {
outs() << "*** Loop extraction failed: ";
EmitProgressBitcode(M, "loopextraction", true);
@@ -179,7 +168,6 @@ Module *BugDriver::ExtractLoop(Module *M) {
// to avoid taking forever.
static unsigned NumExtracted = 32;
if (M->size() == NewM->size() || --NumExtracted == 0) {
- delete NewM;
return nullptr;
} else {
assert(M->size() < NewM->size() && "Loop extract removed functions?");
@@ -356,14 +344,9 @@ llvm::SplitFunctionsOutOfModule(Module *M,
// Basic Block Extraction Code
//===----------------------------------------------------------------------===//
-/// ExtractMappedBlocksFromModule - Extract all but the specified basic blocks
-/// into their own functions. The only detail is that M is actually a module
-/// cloned from the one the BBs are in, so some mapping needs to be performed.
-/// If this operation fails for some reason (ie the implementation is buggy),
-/// this function should return null, otherwise it returns a new Module.
-Module *BugDriver::ExtractMappedBlocksFromModule(const
- std::vector<BasicBlock*> &BBs,
- Module *M) {
+std::unique_ptr<Module>
+BugDriver::extractMappedBlocksFromModule(const std::vector<BasicBlock *> &BBs,
+ Module *M) {
SmallString<128> Filename;
int FD;
std::error_code EC = sys::fs::createUniqueFile(
@@ -401,7 +384,7 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const
std::vector<std::string> PI;
PI.push_back("extract-blocks");
- Module *Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
+ std::unique_ptr<Module> Ret = runPassesOn(M, PI, false, 1, &ExtraArg);
sys::fs::remove(Filename.c_str());
diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h
index 8083e2d65fb1..a0bb570a5cb2 100644
--- a/tools/bugpoint/ListReducer.h
+++ b/tools/bugpoint/ListReducer.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef BUGPOINT_LIST_REDUCER_H
-#define BUGPOINT_LIST_REDUCER_H
+#ifndef LLVM_TOOLS_BUGPOINT_LISTREDUCER_H
+#define LLVM_TOOLS_BUGPOINT_LISTREDUCER_H
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index 3f1f84ef6244..8cb45838773a 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -128,8 +128,8 @@ ReduceMiscompilingPasses::doTest(std::vector<std::string> &Prefix,
// Ok, so now we know that the prefix passes work, try running the suffix
// passes on the result of the prefix passes.
//
- std::unique_ptr<Module> PrefixOutput(
- ParseInputFile(BitcodeResult, BD.getContext()));
+ std::unique_ptr<Module> PrefixOutput =
+ parseInputFile(BitcodeResult, BD.getContext());
if (!PrefixOutput) {
errs() << BD.getToolName() << ": Error reading bitcode file '"
<< BitcodeResult << "'!\n";
@@ -218,16 +218,12 @@ static Module *TestMergedProgram(const BugDriver &BD, Module *M1, Module *M2,
bool DeleteInputs, std::string &Error,
bool &Broken) {
// Link the two portions of the program back to together.
- std::string ErrorMsg;
if (!DeleteInputs) {
M1 = CloneModule(M1);
M2 = CloneModule(M2);
}
- if (Linker::LinkModules(M1, M2, Linker::DestroySource, &ErrorMsg)) {
- errs() << BD.getToolName() << ": Error linking modules together:"
- << ErrorMsg << '\n';
+ if (Linker::LinkModules(M1, M2))
exit(1);
- }
delete M2; // We are done with this module.
// Execute the program.
@@ -316,7 +312,7 @@ static bool ExtractLoops(BugDriver &BD,
Module *ToOptimize = SplitFunctionsOutOfModule(ToNotOptimize,
MiscompiledFunctions,
VMap);
- Module *ToOptimizeLoopExtracted = BD.ExtractLoop(ToOptimize);
+ Module *ToOptimizeLoopExtracted = BD.extractLoop(ToOptimize).release();
if (!ToOptimizeLoopExtracted) {
// If the loop extractor crashed or if there were no extractible loops,
// then this chapter of our odyssey is over with.
@@ -334,8 +330,8 @@ static bool ExtractLoops(BugDriver &BD,
// extraction.
AbstractInterpreter *AI = BD.switchToSafeInterpreter();
bool Failure;
- Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted, ToNotOptimize,
- false, Error, Failure);
+ Module *New = TestMergedProgram(BD, ToOptimizeLoopExtracted,
+ ToNotOptimize, false, Error, Failure);
if (!New)
return false;
@@ -364,7 +360,6 @@ static bool ExtractLoops(BugDriver &BD,
<< OutputPrefix << "-loop-extract-fail-*.bc files.\n";
delete ToOptimize;
delete ToNotOptimize;
- delete ToOptimizeLoopExtracted;
return MadeChange;
}
delete ToOptimize;
@@ -397,13 +392,8 @@ static bool ExtractLoops(BugDriver &BD,
F->getFunctionType()));
}
- std::string ErrorMsg;
- if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted,
- Linker::DestroySource, &ErrorMsg)){
- errs() << BD.getToolName() << ": Error linking modules together:"
- << ErrorMsg << '\n';
+ if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted))
exit(1);
- }
MiscompiledFunctions.clear();
for (unsigned i = 0, e = MisCompFunctions.size(); i != e; ++i) {
@@ -431,13 +421,9 @@ static bool ExtractLoops(BugDriver &BD,
// extraction both didn't break the program, and didn't mask the problem.
// Replace the current program with the loop extracted version, and try to
// extract another loop.
- std::string ErrorMsg;
- if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted,
- Linker::DestroySource, &ErrorMsg)){
- errs() << BD.getToolName() << ": Error linking modules together:"
- << ErrorMsg << '\n';
+ if (Linker::LinkModules(ToNotOptimize, ToOptimizeLoopExtracted))
exit(1);
- }
+
delete ToOptimizeLoopExtracted;
// All of the Function*'s in the MiscompiledFunctions list are in the old
@@ -533,11 +519,12 @@ bool ReduceMiscompiledBlocks::TestFuncs(const std::vector<BasicBlock*> &BBs,
// Try the extraction. If it doesn't work, then the block extractor crashed
// or something, in which case bugpoint can't chase down this possibility.
- if (Module *New = BD.ExtractMappedBlocksFromModule(BBsOnClone, ToOptimize)) {
+ if (std::unique_ptr<Module> New =
+ BD.extractMappedBlocksFromModule(BBsOnClone, ToOptimize)) {
delete ToOptimize;
// Run the predicate,
// note that the predicate will delete both input modules.
- bool Ret = TestFn(BD, New, ToNotOptimize, Error);
+ bool Ret = TestFn(BD, New.get(), ToNotOptimize, Error);
delete BD.swapProgramIn(Orig);
return Ret;
}
@@ -591,7 +578,8 @@ static bool ExtractBlocks(BugDriver &BD,
Module *ToExtract = SplitFunctionsOutOfModule(ProgClone,
MiscompiledFunctions,
VMap);
- Module *Extracted = BD.ExtractMappedBlocksFromModule(Blocks, ToExtract);
+ std::unique_ptr<Module> Extracted =
+ BD.extractMappedBlocksFromModule(Blocks, ToExtract);
if (!Extracted) {
// Weird, extraction should have worked.
errs() << "Nondeterministic problem extracting blocks??\n";
@@ -611,14 +599,8 @@ static bool ExtractBlocks(BugDriver &BD,
MisCompFunctions.push_back(std::make_pair(I->getName(),
I->getFunctionType()));
- std::string ErrorMsg;
- if (Linker::LinkModules(ProgClone, Extracted, Linker::DestroySource,
- &ErrorMsg)) {
- errs() << BD.getToolName() << ": Error linking modules together:"
- << ErrorMsg << '\n';
+ if (Linker::LinkModules(ProgClone, Extracted.get()))
exit(1);
- }
- delete Extracted;
// Set the new program and delete the old one.
BD.setNewProgram(ProgClone);
@@ -730,14 +712,15 @@ static bool TestOptimizer(BugDriver &BD, Module *Test, Module *Safe,
// Run the optimization passes on ToOptimize, producing a transformed version
// of the functions being tested.
outs() << " Optimizing functions being tested: ";
- Module *Optimized = BD.runPassesOn(Test, BD.getPassesToRun(),
- /*AutoDebugCrashes*/true);
+ std::unique_ptr<Module> Optimized = BD.runPassesOn(Test, BD.getPassesToRun(),
+ /*AutoDebugCrashes*/ true);
outs() << "done.\n";
delete Test;
outs() << " Checking to see if the merged program executes correctly: ";
bool Broken;
- Module *New = TestMergedProgram(BD, Optimized, Safe, true, Error, Broken);
+ Module *New =
+ TestMergedProgram(BD, Optimized.get(), Safe, true, Error, Broken);
if (New) {
outs() << (Broken ? " nope.\n" : " yup.\n");
// Delete the original and set the new program.
@@ -796,7 +779,7 @@ void BugDriver::debugMiscompilation(std::string *Error) {
static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
Module *Safe) {
// Clean up the modules, removing extra cruft that we don't need anymore...
- Test = BD.performFinalCleanups(Test);
+ Test = BD.performFinalCleanups(Test).release();
// If we are executing the JIT, we have several nasty issues to take care of.
if (!BD.isExecutingJIT()) return;
diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp
index d452fd94c06a..f197cc53926a 100644
--- a/tools/bugpoint/OptimizerDriver.cpp
+++ b/tools/bugpoint/OptimizerDriver.cpp
@@ -66,15 +66,15 @@ static bool writeProgramToFileAux(tool_output_file &Out, const Module *M) {
bool BugDriver::writeProgramToFile(const std::string &Filename, int FD,
const Module *M) const {
- tool_output_file Out(Filename.c_str(), FD);
+ tool_output_file Out(Filename, FD);
return writeProgramToFileAux(Out, M);
}
bool BugDriver::writeProgramToFile(const std::string &Filename,
const Module *M) const {
- std::string ErrInfo;
- tool_output_file Out(Filename.c_str(), ErrInfo, sys::fs::F_None);
- if (ErrInfo.empty())
+ std::error_code EC;
+ tool_output_file Out(Filename, EC, sys::fs::F_None);
+ if (!EC)
return writeProgramToFileAux(Out, M);
return true;
}
@@ -149,7 +149,7 @@ bool BugDriver::runPasses(Module *Program,
return 1;
}
- tool_output_file InFile(InputFilename.c_str(), InputFD);
+ tool_output_file InFile(InputFilename, InputFD);
WriteBitcodeToFile(Program, InFile.os());
InFile.os().close();
@@ -159,12 +159,31 @@ bool BugDriver::runPasses(Module *Program,
return 1;
}
- std::string tool = OptCmd.empty()? sys::FindProgramByName("opt") : OptCmd;
+ std::string tool = OptCmd;
+ if (OptCmd.empty()) {
+ if (ErrorOr<std::string> Path = sys::findProgramByName("opt"))
+ tool = *Path;
+ else
+ errs() << Path.getError().message() << "\n";
+ }
if (tool.empty()) {
errs() << "Cannot find `opt' in PATH!\n";
return 1;
}
+ std::string Prog;
+ if (UseValgrind) {
+ if (ErrorOr<std::string> Path = sys::findProgramByName("valgrind"))
+ Prog = *Path;
+ else
+ errs() << Path.getError().message() << "\n";
+ } else
+ Prog = tool;
+ if (Prog.empty()) {
+ errs() << "Cannot find `valgrind' in PATH!\n";
+ return 1;
+ }
+
// Ok, everything that could go wrong before running opt is done.
InFile.keep();
@@ -204,12 +223,6 @@ bool BugDriver::runPasses(Module *Program,
errs() << "\n";
);
- std::string Prog;
- if (UseValgrind)
- Prog = sys::FindProgramByName("valgrind");
- else
- Prog = tool;
-
// Redirect stdout and stderr to nowhere if SilencePasses is given
StringRef Nowhere;
const StringRef *Redirects[3] = {nullptr, &Nowhere, &Nowhere};
@@ -247,13 +260,10 @@ bool BugDriver::runPasses(Module *Program,
}
-/// runPassesOn - Carefully run the specified set of pass on the specified
-/// module, returning the transformed module on success, or a null pointer on
-/// failure.
-Module *BugDriver::runPassesOn(Module *M,
- const std::vector<std::string> &Passes,
- bool AutoDebugCrashes, unsigned NumExtraArgs,
- const char * const *ExtraArgs) {
+std::unique_ptr<Module>
+BugDriver::runPassesOn(Module *M, const std::vector<std::string> &Passes,
+ bool AutoDebugCrashes, unsigned NumExtraArgs,
+ const char *const *ExtraArgs) {
std::string BitcodeResult;
if (runPasses(M, Passes, BitcodeResult, false/*delete*/, true/*quiet*/,
NumExtraArgs, ExtraArgs)) {
@@ -267,7 +277,7 @@ Module *BugDriver::runPassesOn(Module *M,
return nullptr;
}
- Module *Ret = ParseInputFile(BitcodeResult, Context);
+ std::unique_ptr<Module> Ret = parseInputFile(BitcodeResult, Context);
if (!Ret) {
errs() << getToolName() << ": Error reading bitcode file '"
<< BitcodeResult << "'!\n";
diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp
index a28b2856f1e9..51091e297d7d 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -141,21 +141,13 @@ static std::string ProcessFailure(StringRef ProgPath, const char** Args,
// Rerun the compiler, capturing any error messages to print them.
SmallString<128> ErrorFilename;
- int ErrorFD;
std::error_code EC = sys::fs::createTemporaryFile(
- "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename);
+ "bugpoint.program_error_messages", "", ErrorFilename);
if (EC) {
errs() << "Error making unique filename: " << EC.message() << "\n";
exit(1);
}
-#ifdef _WIN32
- // Close ErrorFD immediately, or it couldn't be reopened on Win32.
- // FIXME: We may have an option in openFileForWrite(), not to use ResultFD
- // but to close it.
- delete new raw_fd_ostream(ErrorFD, true);
-#endif
-
RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),
ErrorFilename.str(), Timeout, MemoryLimit);
// FIXME: check return code ?
@@ -435,13 +427,14 @@ static void lexCommand(std::string &Message, const std::string &CommandLine,
pos = CommandLine.find_first_of(delimiters, lastPos);
}
- CmdPath = sys::FindProgramByName(Command);
- if (CmdPath.empty()) {
+ auto Path = sys::findProgramByName(Command);
+ if (!Path) {
Message =
std::string("Cannot find '") + Command +
- "' in PATH!\n";
+ "' in PATH: " + Path.getError().message() + "\n";
return;
}
+ CmdPath = *Path;
Message = "Found command in: " + CmdPath + "\n";
}
@@ -915,16 +908,24 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType,
GCC *GCC::create(std::string &Message,
const std::string &GCCBinary,
const std::vector<std::string> *Args) {
- std::string GCCPath = sys::FindProgramByName(GCCBinary);
- if (GCCPath.empty()) {
- Message = "Cannot find `"+ GCCBinary +"' in PATH!\n";
+ auto GCCPath = sys::findProgramByName(GCCBinary);
+ if (!GCCPath) {
+ Message = "Cannot find `" + GCCBinary + "' in PATH: " +
+ GCCPath.getError().message() + "\n";
return nullptr;
}
std::string RemoteClientPath;
- if (!RemoteClient.empty())
- RemoteClientPath = sys::FindProgramByName(RemoteClient);
+ if (!RemoteClient.empty()) {
+ auto Path = sys::findProgramByName(RemoteClient);
+ if (!Path) {
+ Message = "Cannot find `" + RemoteClient + "' in PATH: " +
+ Path.getError().message() + "\n";
+ return nullptr;
+ }
+ RemoteClientPath = *Path;
+ }
- Message = "Found gcc: " + GCCPath + "\n";
- return new GCC(GCCPath, RemoteClientPath, Args);
+ Message = "Found gcc: " + *GCCPath + "\n";
+ return new GCC(*GCCPath, RemoteClientPath, Args);
}
diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h
index 6e7b95c7847b..454724ace5ce 100644
--- a/tools/bugpoint/ToolRunner.h
+++ b/tools/bugpoint/ToolRunner.h
@@ -14,8 +14,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef BUGPOINT_TOOLRUNNER_H
-#define BUGPOINT_TOOLRUNNER_H
+#ifndef LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H
+#define LLVM_TOOLS_BUGPOINT_TOOLRUNNER_H
#include "llvm/ADT/Triple.h"
#include "llvm/Support/CommandLine.h"
diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp
index c7dae0f45b66..d0bade507d2a 100644
--- a/tools/bugpoint/bugpoint.cpp
+++ b/tools/bugpoint/bugpoint.cpp
@@ -63,10 +63,6 @@ static cl::list<const PassInfo*, bool, PassNameParser>
PassList(cl::desc("Passes available:"), cl::ZeroOrMore);
static cl::opt<bool>
-StandardCompileOpts("std-compile-opts",
- cl::desc("Include the standard compile time optimizations"));
-
-static cl::opt<bool>
StandardLinkOpts("std-link-opts",
cl::desc("Include the standard link time optimizations"));
@@ -170,17 +166,11 @@ int main(int argc, char **argv) {
if (D.addSources(InputFilenames)) return 1;
AddToDriver PM(D);
- if (StandardCompileOpts) {
- PassManagerBuilder Builder;
- Builder.OptLevel = 3;
- Builder.Inliner = createFunctionInliningPass();
- Builder.populateModulePassManager(PM);
- }
if (StandardLinkOpts) {
PassManagerBuilder Builder;
- Builder.populateLTOPassManager(PM, /*Internalize=*/true,
- /*RunInliner=*/true);
+ Builder.Inliner = createFunctionInliningPass();
+ Builder.populateLTOPassManager(PM);
}
if (OptLevelO1 || OptLevelO2 || OptLevelO3) {
diff --git a/tools/dsymutil/BinaryHolder.cpp b/tools/dsymutil/BinaryHolder.cpp
new file mode 100644
index 000000000000..ad66105bc249
--- /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 000000000000..04871b5d5855
--- /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 000000000000..bfe7c706391a
--- /dev/null
+++ b/tools/dsymutil/CMakeLists.txt
@@ -0,0 +1,13 @@
+set(LLVM_LINK_COMPONENTS
+ 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 000000000000..7898160ae6b9
--- /dev/null
+++ b/tools/dsymutil/DebugMap.cpp
@@ -0,0 +1,80 @@
+//===- 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)));
+ 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::SymbolMapping *
+DebugMapObject::lookupSymbol(StringRef SymbolName) const {
+ StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
+ if (Sym == Symbols.end())
+ return nullptr;
+ return &Sym->getValue();
+}
+
+void DebugMap::print(raw_ostream &OS) const {
+ OS << "DEBUG MAP: object 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 000000000000..54bff3272080
--- /dev/null
+++ b/tools/dsymutil/DebugMap.h
@@ -0,0 +1,128 @@
+//===- 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/StringMap.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 {
+ typedef std::vector<std::unique_ptr<DebugMapObject>> ObjectContainer;
+ ObjectContainer Objects;
+
+public:
+ 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);
+
+ 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) {}
+ };
+
+ /// \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 SymbolMapping *lookupSymbol(StringRef SymbolName) 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;
+};
+}
+}
+
+#endif // LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
new file mode 100644
index 000000000000..ad471055bd9c
--- /dev/null
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -0,0 +1,20 @@
+//===- 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 "dsymutil.h"
+
+namespace llvm {
+namespace dsymutil {
+
+bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) {
+ // Do nothing for now.
+ return true;
+}
+}
+}
diff --git a/tools/dsymutil/LLVMBuild.txt b/tools/dsymutil/LLVMBuild.txt
new file mode 100644
index 000000000000..24b9033c78c6
--- /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 = Object Support
diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp
new file mode 100644
index 000000000000..6b244fc369e9
--- /dev/null
+++ b/tools/dsymutil/MachODebugMapParser.cpp
@@ -0,0 +1,234 @@
+//===- 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);
+}
+
+/// 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>();
+ 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 000000000000..9eda7dcabc0a
--- /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 := 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 000000000000..2b4fcfe07008
--- /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 000000000000..9203beaf6774
--- /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 3864e154548c..a70905c84bf0 100644
--- a/tools/gold/CMakeLists.txt
+++ b/tools/gold/CMakeLists.txt
@@ -3,11 +3,7 @@ set(LLVM_BINUTILS_INCDIR "" CACHE PATH
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
@@ -16,7 +12,9 @@ else()
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
- LTO
+ Linker
+ BitWriter
+ IPO
)
add_llvm_loadable_module(LLVMgold
diff --git a/tools/gold/Makefile b/tools/gold/Makefile
index 593d8eab2932..aa006b0048fc 100644
--- a/tools/gold/Makefile
+++ b/tools/gold/Makefile
@@ -20,7 +20,7 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/gold.exports
# early so we can set up LINK_COMPONENTS before including Makefile.rules
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := $(TARGETS_TO_BUILD) LTO
+LINK_COMPONENTS := $(TARGETS_TO_BUILD) Linker BitWriter IPO
# Because off_t is used in the public API, the largefile parts are required for
# ABI compatibility.
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index b90851019fea..bcc91e9d0612 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -13,33 +13,38 @@
//===----------------------------------------------------------------------===//
#include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
-#include "llvm-c/lto.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/CommandFlags.h"
-#include "llvm/LTO/LTOCodeGenerator.h"
-#include "llvm/LTO/LTOModule.h"
-#include "llvm/Support/Errno.h"
-#include "llvm/Support/FileSystem.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/LLVMContext.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/Path.h"
-#include "llvm/Support/Program.h"
+#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include <cerrno>
-#include <cstdlib>
-#include <cstring>
+#include "llvm/Target/TargetLibraryInfo.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/GlobalStatus.h"
+#include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Transforms/Utils/ValueMapper.h"
#include <list>
#include <plugin-api.h>
#include <system_error>
#include <vector>
-// Support Windows/MinGW crazyness.
-#ifdef _WIN32
-# include <io.h>
-# define lseek _lseek
-# define read _read
-#endif
-
#ifndef LDPO_PIE
// FIXME: remove this declaration when we stop maintaining Ubuntu Quantal and
// Precise and Debian Wheezy (binutils 2.23 is required)
@@ -61,25 +66,29 @@ static ld_plugin_status discard_message(int level, const char *format, ...) {
abort();
}
-static ld_plugin_add_symbols add_symbols = NULL;
-static ld_plugin_get_symbols get_symbols = NULL;
-static ld_plugin_add_input_file add_input_file = NULL;
-static ld_plugin_set_extra_library_path set_extra_library_path = NULL;
-static ld_plugin_get_view get_view = NULL;
+static ld_plugin_get_input_file get_input_file = nullptr;
+static ld_plugin_release_input_file release_input_file = nullptr;
+static ld_plugin_add_symbols add_symbols = nullptr;
+static ld_plugin_get_symbols get_symbols = nullptr;
+static ld_plugin_add_input_file add_input_file = nullptr;
+static ld_plugin_set_extra_library_path set_extra_library_path = nullptr;
+static ld_plugin_get_view get_view = nullptr;
static ld_plugin_message message = discard_message;
-static lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
+static Reloc::Model RelocationModel = Reloc::Default;
static std::string output_name = "";
static std::list<claimed_file> Modules;
static std::vector<std::string> Cleanup;
-static LTOCodeGenerator *CodeGen = nullptr;
-static StringSet<> CannotBeHidden;
static llvm::TargetOptions TargetOpts;
namespace options {
- enum generate_bc { BC_NO, BC_ALSO, BC_ONLY };
+ 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 std::string bc_path;
+ static OutputType TheOutputType = OT_NORMAL;
static std::string obj_path;
static std::string extra_library_path;
static std::string triple;
@@ -89,11 +98,11 @@ namespace options {
// as plugin exclusive to pass to the code generator.
// For example, "generate-api-file" and "as"options are for the plugin
// use only and will not be passed.
- static std::vector<std::string> extra;
+ static std::vector<const char *> extra;
static void process_plugin_option(const char* opt_)
{
- if (opt_ == NULL)
+ if (opt_ == nullptr)
return;
llvm::StringRef opt = opt_;
@@ -108,21 +117,19 @@ 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;
- } else if (opt == "also-emit-llvm") {
- generate_bc_file = BC_ALSO;
- } else if (opt.startswith("also-emit-llvm=")) {
- llvm::StringRef path = opt.substr(strlen("also-emit-llvm="));
- generate_bc_file = BC_ALSO;
- if (!bc_path.empty()) {
- (*message)(LDPL_WARNING, "Path to the output IL file specified twice. "
- "Discarding %s", opt_);
- } else {
- bc_path = path;
- }
+ TheOutputType = OT_BC_ONLY;
+ } else if (opt == "save-temps") {
+ TheOutputType = OT_SAVE_TEMPS;
+ } else if (opt == "disable-output") {
+ TheOutputType = OT_DISABLE;
} else {
// Save this option to pass to the code generator.
- extra.push_back(opt);
+ // ParseCommandLineOptions() expects argv[0] to be program name. Lazily
+ // add that.
+ if (extra.empty())
+ extra.push_back("LLVMgold");
+
+ extra.push_back(opt_);
}
}
}
@@ -159,14 +166,13 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
case LDPO_REL: // .o
case LDPO_DYN: // .so
case LDPO_PIE: // position independent executable
- output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+ RelocationModel = Reloc::PIC_;
break;
case LDPO_EXEC: // .exe
- output_type = LTO_CODEGEN_PIC_MODEL_STATIC;
+ RelocationModel = Reloc::Static;
break;
default:
- (*message)(LDPL_ERROR, "Unknown output file type %d",
- tv->tv_u.tv_val);
+ message(LDPL_ERROR, "Unknown output file type %d", tv->tv_u.tv_val);
return LDPS_ERR;
}
break;
@@ -177,7 +183,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
ld_plugin_register_claim_file callback;
callback = tv->tv_u.tv_register_claim_file;
- if ((*callback)(claim_file_hook) != LDPS_OK)
+ if (callback(claim_file_hook) != LDPS_OK)
return LDPS_ERR;
registeredClaimFile = true;
@@ -186,7 +192,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
ld_plugin_register_all_symbols_read callback;
callback = tv->tv_u.tv_register_all_symbols_read;
- if ((*callback)(all_symbols_read_hook) != LDPS_OK)
+ if (callback(all_symbols_read_hook) != LDPS_OK)
return LDPS_ERR;
RegisteredAllSymbolsRead = true;
@@ -195,9 +201,15 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
ld_plugin_register_cleanup callback;
callback = tv->tv_u.tv_register_cleanup;
- if ((*callback)(cleanup_hook) != LDPS_OK)
+ if (callback(cleanup_hook) != LDPS_OK)
return LDPS_ERR;
} break;
+ case LDPT_GET_INPUT_FILE:
+ get_input_file = tv->tv_u.tv_get_input_file;
+ break;
+ case LDPT_RELEASE_INPUT_FILE:
+ release_input_file = tv->tv_u.tv_release_input_file;
+ break;
case LDPT_ADD_SYMBOLS:
add_symbols = tv->tv_u.tv_add_symbols;
break;
@@ -222,56 +234,75 @@ ld_plugin_status onload(ld_plugin_tv *tv) {
}
if (!registeredClaimFile) {
- (*message)(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
+ message(LDPL_ERROR, "register_claim_file not passed to LLVMgold.");
return LDPS_ERR;
}
if (!add_symbols) {
- (*message)(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
+ message(LDPL_ERROR, "add_symbols not passed to LLVMgold.");
return LDPS_ERR;
}
if (!RegisteredAllSymbolsRead)
return LDPS_OK;
- CodeGen = new LTOCodeGenerator();
-
- // Pass through extra options to the code generator.
- if (!options::extra.empty()) {
- for (std::vector<std::string>::iterator it = options::extra.begin();
- it != options::extra.end(); ++it) {
- CodeGen->setCodeGenDebugOptions((*it).c_str());
- }
+ if (!get_input_file) {
+ message(LDPL_ERROR, "get_input_file not passed to LLVMgold.");
+ return LDPS_ERR;
}
-
- CodeGen->parseCodeGenDebugOptions();
- if (MAttrs.size()) {
- std::string Attrs;
- for (unsigned I = 0; I < MAttrs.size(); ++I) {
- if (I > 0)
- Attrs.append(",");
- Attrs.append(MAttrs[I]);
- }
- CodeGen->setAttr(Attrs.c_str());
+ if (!release_input_file) {
+ message(LDPL_ERROR, "relesase_input_file not passed to LLVMgold.");
+ return LDPS_ERR;
}
- TargetOpts = InitTargetOptionsFromCodeGenFlags();
- CodeGen->setTargetOptions(TargetOpts);
-
return LDPS_OK;
}
+static const GlobalObject *getBaseObject(const GlobalValue &GV) {
+ if (auto *GA = dyn_cast<GlobalAlias>(&GV))
+ return GA->getBaseObject();
+ 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) {
+ assert(DI.getSeverity() == DS_Error && "Only expecting errors");
+ const auto &BDI = 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);
+ }
+ message(LDPL_FATAL, "LLVM gold plugin has failed to create LTO module: %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.
static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
int *claimed) {
- const void *view;
- std::unique_ptr<MemoryBuffer> buffer;
+ LLVMContext Context;
+ MemoryBufferRef BufferRef;
+ std::unique_ptr<MemoryBuffer> Buffer;
if (get_view) {
+ const void *view;
if (get_view(file->handle, &view) != LDPS_OK) {
- (*message)(LDPL_ERROR, "Failed to get a view of %s", file->name);
+ message(LDPL_ERROR, "Failed to get a view of %s", file->name);
return LDPS_ERR;
}
+ BufferRef = MemoryBufferRef(StringRef((const char *)view, file->filesize), "");
} else {
int64_t offset = 0;
// Gold has found what might be IR part-way inside of a file, such as
@@ -283,225 +314,566 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file,
MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize,
offset);
if (std::error_code EC = BufferOrErr.getError()) {
- (*message)(LDPL_ERROR, EC.message().c_str());
+ message(LDPL_ERROR, EC.message().c_str());
return LDPS_ERR;
}
- buffer = std::move(BufferOrErr.get());
- view = buffer->getBufferStart();
+ Buffer = std::move(BufferOrErr.get());
+ BufferRef = Buffer->getMemBufferRef();
}
- if (!LTOModule::isBitcodeFile(view, file->filesize))
+ Context.setDiagnosticHandler(diagnosticHandler);
+ ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
+ object::IRObjectFile::create(BufferRef, Context);
+ std::error_code EC = ObjOrErr.getError();
+ if (EC == object::object_error::invalid_file_type ||
+ EC == object::object_error::bitcode_section_not_found)
return LDPS_OK;
- std::string Error;
- LTOModule *M =
- LTOModule::createFromBuffer(view, file->filesize, TargetOpts, Error);
- if (!M) {
- (*message)(LDPL_ERROR,
- "LLVM gold plugin has failed to create LTO module: %s",
- Error.c_str());
- return LDPS_OK;
+ *claimed = 1;
+
+ if (EC) {
+ message(LDPL_ERROR, "LLVM gold plugin has failed to create LTO module: %s",
+ EC.message().c_str());
+ return LDPS_ERR;
}
+ std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr);
- *claimed = 1;
Modules.resize(Modules.size() + 1);
claimed_file &cf = Modules.back();
- if (!options::triple.empty())
- M->setTargetTriple(options::triple.c_str());
-
cf.handle = file->handle;
- unsigned sym_count = M->getSymbolCount();
- cf.syms.reserve(sym_count);
- for (unsigned i = 0; i != sym_count; ++i) {
- lto_symbol_attributes attrs = M->getSymbolAttributes(i);
- if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL)
+ for (auto &Sym : Obj->symbols()) {
+ uint32_t Symflags = Sym.getFlags();
+ if (shouldSkip(Symflags))
continue;
cf.syms.push_back(ld_plugin_symbol());
ld_plugin_symbol &sym = cf.syms.back();
- sym.name = strdup(M->getSymbolName(i));
- sym.version = NULL;
-
- int scope = attrs & LTO_SYMBOL_SCOPE_MASK;
- bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN;
- if (!CanBeHidden)
- CannotBeHidden.insert(sym.name);
- switch (scope) {
- case LTO_SYMBOL_SCOPE_HIDDEN:
+ sym.version = nullptr;
+
+ SmallString<64> Name;
+ {
+ raw_svector_ostream OS(Name);
+ Sym.printName(OS);
+ }
+ sym.name = strdup(Name.c_str());
+
+ const GlobalValue *GV = Obj->getSymbolGV(Sym.getRawDataRefImpl());
+
+ sym.visibility = LDPV_DEFAULT;
+ if (GV) {
+ switch (GV->getVisibility()) {
+ case GlobalValue::DefaultVisibility:
+ sym.visibility = LDPV_DEFAULT;
+ break;
+ case GlobalValue::HiddenVisibility:
sym.visibility = LDPV_HIDDEN;
break;
- case LTO_SYMBOL_SCOPE_PROTECTED:
+ case GlobalValue::ProtectedVisibility:
sym.visibility = LDPV_PROTECTED;
break;
- case 0: // extern
- case LTO_SYMBOL_SCOPE_DEFAULT:
- case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN:
- sym.visibility = LDPV_DEFAULT;
- break;
- default:
- (*message)(LDPL_ERROR, "Unknown scope attribute: %d", scope);
- return LDPS_ERR;
+ }
}
- int definition = attrs & LTO_SYMBOL_DEFINITION_MASK;
- sym.comdat_key = NULL;
- switch (definition) {
- case LTO_SYMBOL_DEFINITION_REGULAR:
- sym.def = LDPK_DEF;
- break;
- case LTO_SYMBOL_DEFINITION_UNDEFINED:
- sym.def = LDPK_UNDEF;
- break;
- case LTO_SYMBOL_DEFINITION_TENTATIVE:
- sym.def = LDPK_COMMON;
- break;
- case LTO_SYMBOL_DEFINITION_WEAK:
- sym.comdat_key = sym.name;
- sym.def = LDPK_WEAKDEF;
- break;
- case LTO_SYMBOL_DEFINITION_WEAKUNDEF:
+ if (Symflags & object::BasicSymbolRef::SF_Undefined) {
+ sym.def = LDPK_UNDEF;
+ if (GV && GV->hasExternalWeakLinkage())
sym.def = LDPK_WEAKUNDEF;
- break;
- default:
- (*message)(LDPL_ERROR, "Unknown definition attribute: %d", definition);
- return LDPS_ERR;
+ } else {
+ sym.def = LDPK_DEF;
+ if (GV) {
+ assert(!GV->hasExternalWeakLinkage() &&
+ !GV->hasAvailableExternallyLinkage() && "Not a declaration!");
+ if (GV->hasCommonLinkage())
+ sym.def = LDPK_COMMON;
+ else if (GV->isWeakForLinker())
+ sym.def = LDPK_WEAKDEF;
+ }
}
sym.size = 0;
+ sym.comdat_key = nullptr;
+ if (GV) {
+ const GlobalObject *Base = getBaseObject(*GV);
+ if (!Base)
+ message(LDPL_FATAL, "Unable to determine comdat of alias!");
+ const Comdat *C = Base->getComdat();
+ if (C)
+ sym.comdat_key = strdup(C->getName().str().c_str());
+ else if (Base->hasWeakLinkage() || Base->hasLinkOnceLinkage())
+ sym.comdat_key = strdup(sym.name);
+ }
sym.resolution = LDPR_UNKNOWN;
}
- cf.syms.reserve(cf.syms.size());
-
if (!cf.syms.empty()) {
- if ((*add_symbols)(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
- (*message)(LDPL_ERROR, "Unable to add symbols!");
+ if (add_symbols(cf.handle, cf.syms.size(), &cf.syms[0]) != LDPS_OK) {
+ message(LDPL_ERROR, "Unable to add symbols!");
return LDPS_ERR;
}
}
- if (CodeGen) {
- std::string Error;
- if (!CodeGen->addModule(M, Error)) {
- (*message)(LDPL_ERROR, "Error linking module: %s", Error.c_str());
- return LDPS_ERR;
- }
+ return LDPS_OK;
+}
+
+static void keepGlobalValue(GlobalValue &GV,
+ std::vector<GlobalAlias *> &KeptAliases) {
+ assert(!GV.hasLocalLinkage());
+
+ if (auto *GA = dyn_cast<GlobalAlias>(&GV))
+ KeptAliases.push_back(GA);
+
+ switch (GV.getLinkage()) {
+ default:
+ break;
+ case GlobalValue::LinkOnceAnyLinkage:
+ GV.setLinkage(GlobalValue::WeakAnyLinkage);
+ break;
+ case GlobalValue::LinkOnceODRLinkage:
+ GV.setLinkage(GlobalValue::WeakODRLinkage);
+ break;
}
- delete M;
+ assert(!GV.isDiscardableIfUnused());
+}
- return LDPS_OK;
+static void internalize(GlobalValue &GV) {
+ if (GV.isDeclarationForLinker())
+ return; // We get here if there is a matching asm definition.
+ if (!GV.hasLocalLinkage())
+ GV.setLinkage(GlobalValue::InternalLinkage);
}
-static bool mustPreserve(const claimed_file &F, int i) {
- if (F.syms[i].resolution == LDPR_PREVAILING_DEF)
- return true;
- if (F.syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
- return CannotBeHidden.count(F.syms[i].name);
- return false;
+static void drop(GlobalValue &GV) {
+ if (auto *F = dyn_cast<Function>(&GV)) {
+ F->deleteBody();
+ F->setComdat(nullptr); // Should deleteBody do this?
+ return;
+ }
+
+ if (auto *Var = dyn_cast<GlobalVariable>(&GV)) {
+ Var->setInitializer(nullptr);
+ Var->setLinkage(
+ GlobalValue::ExternalLinkage); // Should setInitializer do this?
+ Var->setComdat(nullptr); // and this?
+ return;
+ }
+
+ auto &Alias = cast<GlobalAlias>(GV);
+ Module &M = *Alias.getParent();
+ PointerType &Ty = *cast<PointerType>(Alias.getType());
+ GlobalValue::LinkageTypes L = Alias.getLinkage();
+ auto *Var =
+ new GlobalVariable(M, Ty.getElementType(), /*isConstant*/ false, L,
+ /*Initializer*/ nullptr);
+ Var->takeName(&Alias);
+ Alias.replaceAllUsesWith(Var);
+ Alias.eraseFromParent();
}
-/// all_symbols_read_hook - gold informs us that all symbols have been read.
-/// At this point, we use get_symbols to see if any of our definitions have
-/// been overridden by a native object file. Then, perform optimization and
-/// codegen.
-static ld_plugin_status all_symbols_read_hook(void) {
- // FIXME: raw_fd_ostream should be able to represent an unopened file.
- std::unique_ptr<raw_fd_ostream> api_file;
+static const char *getResolutionName(ld_plugin_symbol_resolution R) {
+ switch (R) {
+ case LDPR_UNKNOWN:
+ return "UNKNOWN";
+ case LDPR_UNDEF:
+ return "UNDEF";
+ case LDPR_PREVAILING_DEF:
+ return "PREVAILING_DEF";
+ case LDPR_PREVAILING_DEF_IRONLY:
+ return "PREVAILING_DEF_IRONLY";
+ case LDPR_PREEMPTED_REG:
+ return "PREEMPTED_REG";
+ case LDPR_PREEMPTED_IR:
+ return "PREEMPTED_IR";
+ case LDPR_RESOLVED_IR:
+ return "RESOLVED_IR";
+ case LDPR_RESOLVED_EXEC:
+ return "RESOLVED_EXEC";
+ case LDPR_RESOLVED_DYN:
+ return "RESOLVED_DYN";
+ case LDPR_PREVAILING_DEF_IRONLY_EXP:
+ return "PREVAILING_DEF_IRONLY_EXP";
+ }
+ llvm_unreachable("Unknown resolution");
+}
+
+namespace {
+class LocalValueMaterializer : public ValueMaterializer {
+ DenseSet<GlobalValue *> &Dropped;
+ DenseMap<GlobalObject *, GlobalObject *> LocalVersions;
+
+public:
+ LocalValueMaterializer(DenseSet<GlobalValue *> &Dropped) : Dropped(Dropped) {}
+ Value *materializeValueFor(Value *V) override;
+};
+}
+
+Value *LocalValueMaterializer::materializeValueFor(Value *V) {
+ auto *GO = dyn_cast<GlobalObject>(V);
+ if (!GO)
+ return nullptr;
- assert(CodeGen);
+ auto I = LocalVersions.find(GO);
+ if (I != LocalVersions.end())
+ return I->second;
- if (options::generate_api_file) {
- std::string Error;
- api_file.reset(new raw_fd_ostream("apifile.txt", Error, sys::fs::F_None));
- if (!Error.empty())
- (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing: %s",
- Error.c_str());
+ if (!Dropped.count(GO))
+ return nullptr;
+
+ 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,
+ LocalValueMaterializer *Materializer) {
+ 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,
+ 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");
+
+ const void *View;
+ if (get_view(F.handle, &View) != LDPS_OK)
+ message(LDPL_FATAL, "Failed to get a view of file");
+
+ MemoryBufferRef BufferRef(StringRef((const char *)View, File.filesize), "");
+ 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());
+
+ if (release_input_file(F.handle) != LDPS_OK)
+ message(LDPL_FATAL, "Failed to release file information");
+
+ object::IRObjectFile &Obj = **ObjOrErr;
- for (std::list<claimed_file>::iterator I = Modules.begin(),
- E = Modules.end(); I != E; ++I) {
- if (I->syms.empty())
+ Module &M = Obj.getModule();
+
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+ DenseSet<GlobalValue *> Drop;
+ std::vector<GlobalAlias *> KeptAliases;
+
+ 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 = 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
+ // resolution. Instead we have to collect the maximum alignment and size.
+ // 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;
- (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]);
- for (unsigned i = 0, e = I->syms.size(); i != e; i++) {
- if (mustPreserve(*I, i)) {
- CodeGen->addMustPreserveSymbol(I->syms[i].name);
+ }
- if (options::generate_api_file)
- (*api_file) << I->syms[i].name << "\n";
+ switch (Resolution) {
+ case LDPR_UNKNOWN:
+ llvm_unreachable("Unexpected resolution");
+
+ case LDPR_RESOLVED_IR:
+ case LDPR_RESOLVED_EXEC:
+ case LDPR_RESOLVED_DYN:
+ assert(GV->isDeclarationForLinker());
+ break;
+
+ case LDPR_UNDEF:
+ 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(GV->getName());
}
+ break;
}
+
+ case LDPR_PREVAILING_DEF:
+ keepGlobalValue(*GV, KeptAliases);
+ break;
+
+ case LDPR_PREEMPTED_IR:
+ // 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(GV->getName());
+
+ // fall-through
+ case LDPR_PREEMPTED_REG:
+ Drop.insert(GV);
+ break;
+
+ case LDPR_PREVAILING_DEF_IRONLY_EXP: {
+ // We can only check for address uses after we merge the modules. The
+ // reason is that this GV might have a copy in another module
+ // and in that module the address might be significant, but that
+ // copy will be LDPR_PREEMPTED_IR.
+ if (GV->hasLinkOnceODRLinkage())
+ Maybe.insert(GV->getName());
+ keepGlobalValue(*GV, KeptAliases);
+ break;
+ }
+ }
+
+ freeSymName(Sym);
}
- CodeGen->setCodePICModel(output_type);
- CodeGen->setDebugInfo(LTO_DEBUG_MODEL_DWARF);
- if (!options::mcpu.empty())
- CodeGen->setCpu(options::mcpu.c_str());
+ ValueToValueMapTy VM;
+ LocalValueMaterializer Materializer(Drop);
+ for (GlobalAlias *GA : KeptAliases) {
+ // Gold told us to keep GA. It is possible that a GV usied in the aliasee
+ // expression is being dropped. If that is the case, that GV must be copied.
+ Constant *Aliasee = GA->getAliasee();
+ Constant *Replacement = mapConstantToLocalCopy(Aliasee, VM, &Materializer);
+ GA->setAliasee(Replacement);
+ }
- if (options::generate_bc_file != options::BC_NO) {
- std::string path;
- if (options::generate_bc_file == options::BC_ONLY)
- path = output_name;
- else if (!options::bc_path.empty())
- path = options::bc_path;
- else
- path = output_name + ".bc";
- std::string Error;
- if (!CodeGen->writeMergedModules(path.c_str(), Error))
- (*message)(LDPL_FATAL, "Failed to write the output file.");
- if (options::generate_bc_file == options::BC_ONLY) {
- delete CodeGen;
- exit(0);
- }
+ for (auto *GV : Drop)
+ drop(*GV);
+
+ return Obj.takeModule();
+}
+
+static void runLTOPasses(Module &M, TargetMachine &TM) {
+ PassManager passes;
+ PassManagerBuilder PMB;
+ PMB.LibraryInfo = new TargetLibraryInfo(Triple(TM.getTargetTriple()));
+ PMB.Inliner = createFunctionInliningPass();
+ PMB.VerifyInput = true;
+ PMB.VerifyOutput = true;
+ PMB.LoopVectorize = true;
+ PMB.SLPVectorize = true;
+ PMB.populateLTOPassManager(passes, &TM);
+ passes.run(M);
+}
+
+static void saveBCFile(StringRef Path, Module &M) {
+ std::error_code EC;
+ raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ message(LDPL_FATAL, "Failed to write the output file.");
+ WriteBitcodeToFile(&M, OS);
+}
+
+static void codegen(Module &M) {
+ const std::string &TripleStr = M.getTargetTriple();
+ Triple TheTriple(TripleStr);
+
+ std::string ErrMsg;
+ const Target *TheTarget = TargetRegistry::lookupTarget(TripleStr, ErrMsg);
+ if (!TheTarget)
+ message(LDPL_FATAL, "Target not found: %s", ErrMsg.c_str());
+
+ if (unsigned NumOpts = options::extra.size())
+ cl::ParseCommandLineOptions(NumOpts, &options::extra[0]);
+
+ SubtargetFeatures Features;
+ Features.getDefaultSubtargetFeatures(TheTriple);
+ for (const std::string &A : MAttrs)
+ Features.AddFeature(A);
+
+ TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
+ TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
+ CodeModel::Default, CodeGenOpt::Aggressive));
+
+ runLTOPasses(M, *TM);
+
+ if (options::TheOutputType == options::OT_SAVE_TEMPS)
+ saveBCFile(output_name + ".opt.bc", M);
+
+ PassManager CodeGenPasses;
+ CodeGenPasses.add(new DataLayoutPass());
+
+ SmallString<128> Filename;
+ int FD;
+ if (options::obj_path.empty()) {
+ std::error_code EC =
+ sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename);
+ if (EC)
+ message(LDPL_FATAL, "Could not create temporary file: %s",
+ EC.message().c_str());
+ } else {
+ Filename = options::obj_path;
+ std::error_code EC =
+ sys::fs::openFileForWrite(Filename.c_str(), FD, sys::fs::F_None);
+ if (EC)
+ message(LDPL_FATAL, "Could not open file: %s", EC.message().c_str());
}
- std::string ObjPath;
{
- const char *Temp;
- std::string Error;
- if (!CodeGen->compile_to_file(&Temp, /*DisableOpt*/ false, /*DisableInline*/
- false, /*DisableGVNLoadPRE*/ false, Error))
- (*message)(LDPL_ERROR, "Could not produce a combined object file\n");
- ObjPath = Temp;
+ raw_fd_ostream OS(FD, true);
+ formatted_raw_ostream FOS(OS);
+
+ if (TM->addPassesToEmitFile(CodeGenPasses, FOS,
+ TargetMachine::CGFT_ObjectFile))
+ message(LDPL_FATAL, "Failed to setup codegen");
+ CodeGenPasses.run(M);
}
- delete CodeGen;
- for (std::list<claimed_file>::iterator I = Modules.begin(),
- E = Modules.end(); I != E; ++I) {
- for (unsigned i = 0; i != I->syms.size(); ++i) {
- ld_plugin_symbol &sym = I->syms[i];
- free(sym.name);
+ if (add_input_file(Filename.c_str()) != LDPS_OK)
+ message(LDPL_FATAL,
+ "Unable to add .o file to the link. File left behind in: %s",
+ Filename.c_str());
+
+ if (options::obj_path.empty())
+ Cleanup.push_back(Filename.c_str());
+}
+
+/// gold informs us that all symbols have been read. At this point, we use
+/// get_symbols to see if any of our definitions have been overridden by a
+/// native object file. Then, perform optimization and codegen.
+static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
+ if (Modules.empty())
+ return LDPS_OK;
+
+ LLVMContext Context;
+ std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
+ Linker L(Combined.get());
+
+ std::string DefaultTriple = sys::getDefaultTargetTriple();
+
+ StringSet<> Internalize;
+ StringSet<> Maybe;
+ for (claimed_file &F : Modules) {
+ std::unique_ptr<Module> M =
+ getModuleForFile(Context, F, ApiFile, Internalize, Maybe);
+ if (!options::triple.empty())
+ M->setTargetTriple(options::triple.c_str());
+ else if (M->getTargetTriple().empty()) {
+ M->setTargetTriple(DefaultTriple);
}
+
+ if (L.linkInModule(M.get()))
+ message(LDPL_FATAL, "Failed to link module");
}
- if ((*add_input_file)(ObjPath.c_str()) != LDPS_OK) {
- (*message)(LDPL_ERROR, "Unable to add .o file to the link.");
- (*message)(LDPL_ERROR, "File left behind in: %s", ObjPath.c_str());
- return LDPS_ERR;
+ for (const auto &Name : Internalize) {
+ GlobalValue *GV = Combined->getNamedValue(Name.first());
+ if (GV)
+ internalize(*GV);
}
- if (!options::extra_library_path.empty() &&
- set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK) {
- (*message)(LDPL_ERROR, "Unable to set the extra library path.");
- return LDPS_ERR;
+ for (const auto &Name : Maybe) {
+ GlobalValue *GV = Combined->getNamedValue(Name.first());
+ if (!GV)
+ continue;
+ GV->setLinkage(GlobalValue::LinkOnceODRLinkage);
+ if (canBeOmittedFromSymbolTable(GV))
+ internalize(*GV);
}
- if (options::obj_path.empty())
- Cleanup.push_back(ObjPath);
+ if (options::TheOutputType == options::OT_DISABLE)
+ return LDPS_OK;
+
+ if (options::TheOutputType != options::OT_NORMAL) {
+ std::string path;
+ if (options::TheOutputType == options::OT_BC_ONLY)
+ path = output_name;
+ else
+ path = output_name + ".bc";
+ saveBCFile(path, *L.getModule());
+ if (options::TheOutputType == options::OT_BC_ONLY)
+ return LDPS_OK;
+ }
+
+ codegen(*L.getModule());
+
+ if (!options::extra_library_path.empty() &&
+ set_extra_library_path(options::extra_library_path.c_str()) != LDPS_OK)
+ message(LDPL_FATAL, "Unable to set the extra library path.");
return LDPS_OK;
}
+static ld_plugin_status all_symbols_read_hook(void) {
+ ld_plugin_status Ret;
+ if (!options::generate_api_file) {
+ Ret = allSymbolsReadHook(nullptr);
+ } else {
+ std::error_code EC;
+ raw_fd_ostream ApiFile("apifile.txt", EC, sys::fs::F_None);
+ if (EC)
+ message(LDPL_FATAL, "Unable to open apifile.txt for writing: %s",
+ EC.message().c_str());
+ Ret = allSymbolsReadHook(&ApiFile);
+ }
+
+ llvm_shutdown();
+
+ if (options::TheOutputType == options::OT_BC_ONLY ||
+ options::TheOutputType == options::OT_DISABLE)
+ exit(0);
+
+ return Ret;
+}
+
static ld_plugin_status cleanup_hook(void) {
- for (int i = 0, e = Cleanup.size(); i != e; ++i) {
- std::error_code EC = sys::fs::remove(Cleanup[i]);
+ for (std::string &Name : Cleanup) {
+ std::error_code EC = sys::fs::remove(Name);
if (EC)
- (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(),
- EC.message().c_str());
+ message(LDPL_ERROR, "Failed to delete '%s': %s", Name.c_str(),
+ EC.message().c_str());
}
return LDPS_OK;
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index 09ff4613b972..35f965b2a300 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -41,6 +41,7 @@
#include "llvm/Support/ToolOutputFile.h"
#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
#include <memory>
using namespace llvm;
@@ -94,32 +95,20 @@ static cl::opt<bool> AsmVerbose("asm-verbose",
static int compileModule(char **, LLVMContext &);
-// GetFileNameRoot - Helper function to get the basename of a filename.
-static inline std::string
-GetFileNameRoot(const std::string &InputFilename) {
- std::string IFN = InputFilename;
- std::string outputFilename;
- int Len = IFN.length();
- if ((Len > 2) &&
- IFN[Len-3] == '.' &&
- ((IFN[Len-2] == 'b' && IFN[Len-1] == 'c') ||
- (IFN[Len-2] == 'l' && IFN[Len-1] == 'l'))) {
- outputFilename = std::string(IFN.begin(), IFN.end()-3); // s/.bc/.s/
- } else {
- outputFilename = IFN;
- }
- return outputFilename;
-}
-
-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 == "-")
OutputFilename = "-";
else {
- OutputFilename = GetFileNameRoot(InputFilename);
+ // If InputFilename ends in .bc or .ll, remove it.
+ StringRef IFN = InputFilename;
+ if (IFN.endswith(".bc") || IFN.endswith(".ll"))
+ OutputFilename = IFN.drop_back(3);
+ else
+ OutputFilename = IFN;
switch (FileType) {
case TargetMachine::CGFT_AssemblyFile:
@@ -158,15 +147,14 @@ static tool_output_file *GetOutputStream(const char *TargetName,
}
// Open the file.
- std::string error;
+ std::error_code EC;
sys::fs::OpenFlags OpenFlags = sys::fs::F_None;
if (!Binary)
OpenFlags |= sys::fs::F_Text;
- tool_output_file *FDOut = new tool_output_file(OutputFilename.c_str(), error,
- OpenFlags);
- if (!error.empty()) {
- errs() << error << '\n';
- delete FDOut;
+ auto FDOut = llvm::make_unique<tool_output_file>(OutputFilename, EC,
+ OpenFlags);
+ if (EC) {
+ errs() << EC.message() << '\n';
return nullptr;
}
@@ -217,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" ||
@@ -231,17 +218,16 @@ static int compileModule(char **argv, LLVMContext &Context) {
// If user just wants to list available options, skip module loading
if (!SkipModule) {
- M.reset(ParseIRFile(InputFilename, Err, Context));
- mod = M.get();
- if (mod == nullptr) {
+ M = parseIRFile(InputFilename, Err, Context);
+ 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));
}
@@ -285,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
@@ -296,15 +282,14 @@ 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.
@@ -317,9 +302,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
PM.add(TLI);
// Add the target data from the target machine, if it exists, or the module.
- if (const DataLayout *DL = Target.getDataLayout())
- mod->setDataLayout(DL);
- PM.add(new DataLayoutPass(mod));
+ if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
+ M->setDataLayout(DL);
+ PM.add(new DataLayoutPass());
if (RelaxAll.getNumOccurrences() > 0 &&
FileType != TargetMachine::CGFT_ObjectFile)
@@ -350,8 +335,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;
@@ -360,7 +345,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/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 41f75349dfeb..3610d76d8fd4 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -7,7 +7,6 @@ set(LLVM_LINK_COMPONENTS
IRReader
Instrumentation
Interpreter
- JIT
MC
MCJIT
Object
diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp
index 0d71b17c63dd..6c537d47df3d 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/LLVMBuild.txt b/tools/lli/LLVMBuild.txt
index aab2a208dee4..4c14c47bd0d5 100644
--- a/tools/lli/LLVMBuild.txt
+++ b/tools/lli/LLVMBuild.txt
@@ -22,4 +22,4 @@ subdirectories = ChildTarget
type = Tool
name = lli
parent = Tools
-required_libraries = AsmParser BitReader IRReader Instrumentation Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native
+required_libraries = AsmParser BitReader IRReader Instrumentation Interpreter MCJIT NativeCodeGen SelectionDAG Native
diff --git a/tools/lli/Makefile b/tools/lli/Makefile
index eca5d8331490..94d6f061c946 100644
--- a/tools/lli/Makefile
+++ b/tools/lli/Makefile
@@ -14,7 +14,7 @@ PARALLEL_DIRS := ChildTarget
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit jit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
+LINK_COMPONENTS := mcjit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
# If Intel JIT Events support is confiured, link against the LLVM Intel JIT
# Events interface library
diff --git a/tools/lli/RPCChannel.h b/tools/lli/RPCChannel.h
index 2d8c70812847..ebd3c65640bc 100644
--- a/tools/lli/RPCChannel.h
+++ b/tools/lli/RPCChannel.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLI_RPCCHANNEL_H
-#define LLI_RPCCHANNEL_H
+#ifndef LLVM_TOOLS_LLI_RPCCHANNEL_H
+#define LLVM_TOOLS_LLI_RPCCHANNEL_H
#include <stdlib.h>
#include <string>
@@ -46,4 +46,4 @@ public:
} // end namespace llvm
-#endif // LLI_RPCCHANNEL_H
+#endif
diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp
index 481651772afc..47da8fb60c98 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);
@@ -172,36 +171,3 @@ bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) {
return false;
}
-
-void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); }
-void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); }
-void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); }
-void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); }
-uint8_t *RemoteMemoryManager::getGOTBase() const {
- llvm_unreachable("Unexpected!");
- return nullptr;
-}
-uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){
- llvm_unreachable("Unexpected!");
- return nullptr;
-}
-uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize,
- unsigned Alignment) {
- llvm_unreachable("Unexpected!");
- return nullptr;
-}
-void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart,
- uint8_t *FunctionEnd) {
- llvm_unreachable("Unexpected!");
-}
-uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) {
- llvm_unreachable("Unexpected!");
- return nullptr;
-}
-uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) {
- llvm_unreachable("Unexpected!");
- return nullptr;
-}
-void RemoteMemoryManager::deallocateFunctionBody(void *Body) {
- llvm_unreachable("Unexpected!");
-}
diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h
index cf5d7c6e5db8..895bcdac4d14 100644
--- a/tools/lli/RemoteMemoryManager.h
+++ b/tools/lli/RemoteMemoryManager.h
@@ -12,20 +12,20 @@
//
//===----------------------------------------------------------------------===//
-#ifndef REMOTEMEMORYMANAGER_H
-#define REMOTEMEMORYMANAGER_H
+#ifndef LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
+#define LLVM_TOOLS_LLI_REMOTEMEMORYMANAGER_H
#include "RemoteTarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include <utility>
namespace llvm {
-class RemoteMemoryManager : public JITMemoryManager {
+class RemoteMemoryManager : public RTDyldMemoryManager {
public:
// Notice that this structure takes ownership of the memory allocated.
struct Allocation {
@@ -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;
@@ -93,22 +94,6 @@ public:
// This is a non-interface function used by lli
void setRemoteTarget(RemoteTarget *T) { Target = T; }
-
- // The following obsolete JITMemoryManager calls are stubbed out for
- // this model.
- void setMemoryWritable() override;
- void setMemoryExecutable() override;
- void setPoisonMemory(bool poison) override;
- void AllocateGOT() override;
- uint8_t *getGOTBase() const override;
- uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize) override;
- uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize,
- unsigned Alignment) override;
- void endFunctionBody(const Function *F, uint8_t *FunctionStart,
- uint8_t *FunctionEnd) override;
- uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) override;
- uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) override;
- void deallocateFunctionBody(void *Body) override;
};
} // end namespace llvm
diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h
index 73e8ae2284db..ee758a2747a4 100644
--- a/tools/lli/RemoteTarget.h
+++ b/tools/lli/RemoteTarget.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef REMOTEPROCESS_H
-#define REMOTEPROCESS_H
+#ifndef LLVM_TOOLS_LLI_REMOTETARGET_H
+#define LLVM_TOOLS_LLI_REMOTETARGET_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h
index f87fc6199f33..bb621f5c50f0 100644
--- a/tools/lli/RemoteTargetExternal.h
+++ b/tools/lli/RemoteTargetExternal.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLI_REMOTETARGETEXTERNAL_H
-#define LLI_REMOTETARGETEXTERNAL_H
+#ifndef LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
+#define LLVM_TOOLS_LLI_REMOTETARGETEXTERNAL_H
#include "RPCChannel.h"
#include "RemoteTarget.h"
@@ -140,4 +140,4 @@ private:
} // end namespace llvm
-#endif // LLI_REMOTETARGETEXTERNAL_H
+#endif
diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h
index cb934a1066b0..c210e4b3d6b8 100644
--- a/tools/lli/RemoteTargetMessage.h
+++ b/tools/lli/RemoteTargetMessage.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLI_REMOTETARGETMESSAGE_H
-#define LLI_REMOTETARGETMESSAGE_H
+#ifndef LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
+#define LLVM_TOOLS_LLI_REMOTETARGETMESSAGE_H
namespace llvm {
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index 48828c1d68a7..730911b07c65 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -22,9 +22,7 @@
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
-#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
@@ -76,14 +74,6 @@ namespace {
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
- cl::opt<bool> UseMCJIT(
- "use-mcjit", cl::desc("Enable use of the MC-based JIT (if available)"),
- cl::init(false));
-
- cl::opt<bool> DebugIR(
- "debug-ir", cl::desc("Generate debug information to allow debugging IR."),
- 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
// memory manager with IPC to execute using this functionality.
@@ -263,23 +253,23 @@ public:
}
virtual ~LLIObjectCache() {}
- void notifyObjectCompiled(const Module *M, const MemoryBuffer *Obj) override {
+ void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
const std::string ModuleID = M->getModuleIdentifier();
std::string CacheName;
if (!getCacheFilename(ModuleID, CacheName))
return;
- std::string errStr;
if (!CacheDir.empty()) { // Create user-defined cache dir.
SmallString<128> dir(CacheName);
sys::path::remove_filename(dir);
sys::fs::create_directories(Twine(dir));
}
- raw_fd_ostream outfile(CacheName.c_str(), errStr, sys::fs::F_None);
- outfile.write(Obj->getBufferStart(), Obj->getBufferSize());
+ std::error_code EC;
+ raw_fd_ostream outfile(CacheName, EC, sys::fs::F_None);
+ outfile.write(Obj.getBufferStart(), Obj.getBufferSize());
outfile.close();
}
- MemoryBuffer* getObject(const Module* M) override {
+ std::unique_ptr<MemoryBuffer> getObject(const Module* M) override {
const std::string ModuleID = M->getModuleIdentifier();
std::string CacheName;
if (!getCacheFilename(ModuleID, CacheName))
@@ -345,7 +335,7 @@ static void addCygMingExtraModule(ExecutionEngine *EE,
Triple TargetTriple(TargetTripleStr);
// Create a new module.
- Module *M = new Module("CygMingHelper", Context);
+ std::unique_ptr<Module> M = make_unique<Module>("CygMingHelper", Context);
M->setTargetTriple(TargetTripleStr);
// Create an empty function named "__main".
@@ -353,11 +343,11 @@ static void addCygMingExtraModule(ExecutionEngine *EE,
if (TargetTriple.isArch64Bit()) {
Result = Function::Create(
TypeBuilder<int64_t(void), false>::get(Context),
- GlobalValue::ExternalLinkage, "__main", M);
+ GlobalValue::ExternalLinkage, "__main", M.get());
} else {
Result = Function::Create(
TypeBuilder<int32_t(void), false>::get(Context),
- GlobalValue::ExternalLinkage, "__main", M);
+ GlobalValue::ExternalLinkage, "__main", M.get());
}
BasicBlock *BB = BasicBlock::Create(Context, "__main", Result);
Builder.SetInsertPoint(BB);
@@ -369,7 +359,7 @@ static void addCygMingExtraModule(ExecutionEngine *EE,
Builder.CreateRet(ReturnVal);
// Add this new module to the ExecutionEngine.
- EE->addModule(M);
+ EE->addModule(std::move(M));
}
@@ -398,19 +388,17 @@ int main(int argc, char **argv, char * const *envp) {
// Load the bitcode...
SMDiagnostic Err;
- Module *Mod = ParseIRFile(InputFile, Err, Context);
+ std::unique_ptr<Module> Owner = parseIRFile(InputFile, Err, Context);
+ Module *Mod = Owner.get();
if (!Mod) {
Err.print(argv[0], errs());
return 1;
}
if (EnableCacheManager) {
- if (UseMCJIT) {
- std::string CacheName("file:");
- CacheName.append(InputFile);
- Mod->setModuleIdentifier(CacheName);
- } else
- errs() << "warning: -enable-cache-manager can only be used with MCJIT.";
+ std::string CacheName("file:");
+ CacheName.append(InputFile);
+ Mod->setModuleIdentifier(CacheName);
}
// If not jitting lazily, load the whole bitcode file eagerly too.
@@ -422,19 +410,8 @@ int main(int argc, char **argv, char * const *envp) {
}
}
- if (DebugIR) {
- if (!UseMCJIT) {
- errs() << "warning: -debug-ir used without -use-mcjit. Only partial debug"
- << " information will be emitted by the non-MC JIT engine. To see full"
- << " source debug information, enable the flag '-use-mcjit'.\n";
-
- }
- ModulePass *DebugIRPass = createDebugIRPass();
- DebugIRPass->runOnModule(*Mod);
- }
-
std::string ErrorMsg;
- EngineBuilder builder(Mod);
+ EngineBuilder builder(std::move(Owner));
builder.setMArch(MArch);
builder.setMCPU(MCPU);
builder.setMAttrs(MAttrs);
@@ -451,20 +428,20 @@ int main(int argc, char **argv, char * const *envp) {
// Enable MCJIT if desired.
RTDyldMemoryManager *RTDyldMM = nullptr;
- if (UseMCJIT && !ForceInterpreter) {
- builder.setUseMCJIT(true);
+ if (!ForceInterpreter) {
if (RemoteMCJIT)
RTDyldMM = new RemoteMemoryManager();
else
RTDyldMM = new SectionMemoryManager();
- builder.setMCJITMemoryManager(RTDyldMM);
- } else {
- if (RemoteMCJIT) {
- errs() << "error: Remote process execution requires -use-mcjit\n";
- exit(1);
- }
- builder.setJITMemoryManager(ForceInterpreter ? nullptr :
- JITMemoryManager::CreateDefaultMemManager());
+
+ // 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";
+ exit(1);
}
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
@@ -511,46 +488,50 @@ int main(int argc, char **argv, char * const *envp) {
// Load any additional modules specified on the command line.
for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) {
- Module *XMod = ParseIRFile(ExtraModules[i], Err, Context);
+ std::unique_ptr<Module> XMod = parseIRFile(ExtraModules[i], Err, Context);
if (!XMod) {
Err.print(argv[0], errs());
return 1;
}
if (EnableCacheManager) {
- if (UseMCJIT) {
- std::string CacheName("file:");
- CacheName.append(ExtraModules[i]);
- XMod->setModuleIdentifier(CacheName);
- }
- // else, we already printed a warning above.
+ std::string CacheName("file:");
+ CacheName.append(ExtraModules[i]);
+ XMod->setModuleIdentifier(CacheName);
}
- EE->addModule(XMod);
+ EE->addModule(std::move(XMod));
}
for (unsigned i = 0, e = ExtraObjects.size(); i != e; ++i) {
- ErrorOr<object::ObjectFile *> Obj =
+ ErrorOr<object::OwningBinary<object::ObjectFile>> Obj =
object::ObjectFile::createObjectFile(ExtraObjects[i]);
if (!Obj) {
Err.print(argv[0], errs());
return 1;
}
- EE->addObjectFile(std::unique_ptr<object::ObjectFile>(Obj.get()));
+ object::OwningBinary<object::ObjectFile> &O = Obj.get();
+ EE->addObjectFile(std::move(O));
}
for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> ArBuf =
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ArBufOrErr =
MemoryBuffer::getFileOrSTDIN(ExtraArchives[i]);
- if (!ArBuf) {
+ if (!ArBufOrErr) {
Err.print(argv[0], errs());
return 1;
}
- std::error_code EC;
- object::Archive *Ar = new object::Archive(std::move(ArBuf.get()), EC);
- if (EC || !Ar) {
- Err.print(argv[0], errs());
+ std::unique_ptr<MemoryBuffer> &ArBuf = ArBufOrErr.get();
+
+ ErrorOr<std::unique_ptr<object::Archive>> ArOrErr =
+ object::Archive::create(ArBuf->getMemBufferRef());
+ if (std::error_code EC = ArOrErr.getError()) {
+ errs() << EC.message();
return 1;
}
- EE->addArchive(Ar);
+ std::unique_ptr<object::Archive> &Ar = ArOrErr.get();
+
+ object::OwningBinary<object::Archive> OB(std::move(Ar), std::move(ArBuf));
+
+ EE->addArchive(std::move(OB));
}
// If the target is Cygwin/MingW and we are generating remote code, we
@@ -610,20 +591,12 @@ int main(int argc, char **argv, char * const *envp) {
NULL);
// Run static constructors.
- if (UseMCJIT && !ForceInterpreter) {
+ if (!ForceInterpreter) {
// Give MCJIT a chance to apply relocations and set page permissions.
EE->finalizeObject();
}
EE->runStaticConstructorsDestructors(false);
- if (!UseMCJIT && NoLazyCompilation) {
- for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) {
- Function *Fn = &*I;
- if (Fn != EntryFn && !Fn->isDeclaration())
- EE->getPointerToFunction(Fn);
- }
- }
-
// Trigger compilation separately so code regions that need to be
// invalidated will be known.
(void)EE->getPointerToFunction(EntryFn);
diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt
index 5193def2aad5..3782c87e4d38 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 000000000000..e313897b8b3a
--- /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 f638e55c5c71..f72762ac174a 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -12,6 +12,7 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/Object/Archive.h"
@@ -20,6 +21,7 @@
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/LineIterator.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -45,7 +47,7 @@ static StringRef ToolName;
static const char *TemporaryOutput;
static int TmpArchiveFD = -1;
-// fail - Show the error message and exit.
+// Show the error message and exit.
LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) {
outs() << ToolName << ": " << Error << ".\n";
if (TmpArchiveFD != -1)
@@ -67,14 +69,16 @@ static void failIfError(std::error_code EC, Twine Context = "") {
// llvm-ar/llvm-ranlib remaining positional arguments.
static cl::list<std::string>
-RestOfArgs(cl::Positional, cl::OneOrMore,
- cl::desc("[relpos] [count] <archive-file> [members]..."));
+ RestOfArgs(cl::Positional, cl::ZeroOrMore,
+ cl::desc("[relpos] [count] <archive-file> [members]..."));
+
+static cl::opt<bool> MRI("M", cl::desc(""));
std::string Options;
-// MoreHelp - Provide additional help output explaining the operations and
-// modifiers of llvm-ar. This object instructs the CommandLine library
-// to print the text of the constructor when the --help option is given.
+// Provide additional help output explaining the operations and modifiers of
+// llvm-ar. This object instructs the CommandLine library to print the text of
+// the constructor when the --help option is given.
static cl::extrahelp MoreHelp(
"\nOPERATIONS:\n"
" d[NsS] - delete file(s) from the archive\n"
@@ -132,9 +136,9 @@ static std::string ArchiveName;
// This variable holds the list of member files to proecess, as given
// on the command line.
-static std::vector<std::string> Members;
+static std::vector<StringRef> Members;
-// show_help - Show the error message, the help message and exit.
+// Show the error message, the help message and exit.
LLVM_ATTRIBUTE_NORETURN static void
show_help(const std::string &msg) {
errs() << ToolName << ": " << msg << "\n\n";
@@ -142,8 +146,8 @@ show_help(const std::string &msg) {
std::exit(1);
}
-// getRelPos - Extract the member filename from the command line for
-// the [relpos] argument associated with a, b, and i modifiers
+// Extract the member filename from the command line for the [relpos] argument
+// associated with a, b, and i modifiers
static void getRelPos() {
if(RestOfArgs.size() == 0)
show_help("Expected [relpos] for a, b, or i modifier");
@@ -158,7 +162,7 @@ static void getOptions() {
RestOfArgs.erase(RestOfArgs.begin());
}
-// getArchive - Get the archive file name from the command line
+// Get the archive file name from the command line
static void getArchive() {
if(RestOfArgs.size() == 0)
show_help("An archive name must be specified");
@@ -166,17 +170,24 @@ static void getArchive() {
RestOfArgs.erase(RestOfArgs.begin());
}
-// getMembers - Copy over remaining items in RestOfArgs to our Members vector
-// This is just for clarity.
+// Copy over remaining items in RestOfArgs to our Members vector
static void getMembers() {
- if(RestOfArgs.size() > 0)
- Members = std::vector<std::string>(RestOfArgs);
+ for (auto &Arg : RestOfArgs)
+ Members.push_back(Arg);
}
-// parseCommandLine - Parse the command line options as presented and return the
-// operation specified. Process all modifiers and check to make sure that
-// constraints on modifier/operation pairs have not been violated.
+static void runMRIScript();
+
+// Parse the command line options as presented and return the operation
+// specified. Process all modifiers and check to make sure that constraints on
+// modifier/operation pairs have not been violated.
static ArchiveOperation parseCommandLine() {
+ if (MRI) {
+ if (!RestOfArgs.empty())
+ fail("Cannot mix -M and other options");
+ runMRIScript();
+ }
+
getOptions();
// Keep track of number of operations. We can only specify one
@@ -279,8 +290,8 @@ static void doPrint(StringRef Name, object::Archive::child_iterator I) {
outs().write(Data.data(), Data.size());
}
-// putMode - utility function for printing out the file mode when the 't'
-// operation is in verbose mode.
+// Utility function for printing out the file mode when the 't' operation is in
+// verbose mode.
static void printMode(unsigned mode) {
if (mode & 004)
outs() << "r";
@@ -401,21 +412,19 @@ class NewArchiveIterator {
object::Archive::child_iterator OldI;
- std::string NewFilename;
- mutable int NewFD;
- mutable sys::fs::file_status NewStatus;
+ StringRef NewFilename;
public:
NewArchiveIterator(object::Archive::child_iterator I, StringRef Name);
- NewArchiveIterator(std::string *I, StringRef Name);
+ NewArchiveIterator(StringRef I, StringRef Name);
NewArchiveIterator();
bool isNewMember() const;
StringRef getName() const;
object::Archive::child_iterator getOld() const;
- const char *getNew() const;
- int getFD() const;
+ StringRef getNew() const;
+ int getFD(sys::fs::file_status &NewStatus) const;
const sys::fs::file_status &getStatus() const;
};
}
@@ -426,8 +435,8 @@ NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I,
StringRef Name)
: IsNewMember(false), Name(Name), OldI(I) {}
-NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name)
- : IsNewMember(true), Name(Name), NewFilename(*NewFilename), NewFD(-1) {}
+NewArchiveIterator::NewArchiveIterator(StringRef NewFilename, StringRef Name)
+ : IsNewMember(true), Name(Name), NewFilename(NewFilename) {}
StringRef NewArchiveIterator::getName() const { return Name; }
@@ -438,15 +447,14 @@ object::Archive::child_iterator NewArchiveIterator::getOld() const {
return OldI;
}
-const char *NewArchiveIterator::getNew() const {
+StringRef NewArchiveIterator::getNew() const {
assert(IsNewMember);
- return NewFilename.c_str();
+ 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);
@@ -461,12 +469,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) {
@@ -485,16 +487,17 @@ enum InsertAction {
IA_MoveNewMember
};
-static InsertAction
-computeInsertAction(ArchiveOperation Operation,
- object::Archive::child_iterator I, StringRef Name,
- std::vector<std::string>::iterator &Pos) {
+static InsertAction computeInsertAction(ArchiveOperation Operation,
+ object::Archive::child_iterator I,
+ StringRef Name,
+ std::vector<StringRef>::iterator &Pos) {
if (Operation == QuickAppend || Members.empty())
return IA_AddOldMember;
- std::vector<std::string>::iterator MI = std::find_if(
- Members.begin(), Members.end(),
- [Name](StringRef Path) { return Name == sys::path::filename(Path); });
+ auto MI =
+ std::find_if(Members.begin(), Members.end(), [Name](StringRef Path) {
+ return Name == sys::path::filename(Path);
+ });
if (MI == Members.end())
return IA_AddOldMember;
@@ -542,11 +545,9 @@ computeNewArchiveMembers(ArchiveOperation Operation,
int InsertPos = -1;
StringRef PosName = sys::path::filename(RelPos);
if (OldArchive) {
- for (object::Archive::child_iterator I = OldArchive->child_begin(),
- E = OldArchive->child_end();
- I != E; ++I) {
+ for (auto &Child : OldArchive->children()) {
int Pos = Ret.size();
- ErrorOr<StringRef> NameOrErr = I->getName();
+ ErrorOr<StringRef> NameOrErr = Child.getName();
failIfError(NameOrErr.getError());
StringRef Name = NameOrErr.get();
if (Name == PosName) {
@@ -557,22 +558,23 @@ computeNewArchiveMembers(ArchiveOperation Operation,
InsertPos = Pos + 1;
}
- std::vector<std::string>::iterator MemberI = Members.end();
- InsertAction Action = computeInsertAction(Operation, I, Name, MemberI);
+ std::vector<StringRef>::iterator MemberI = Members.end();
+ InsertAction Action =
+ computeInsertAction(Operation, Child, Name, MemberI);
switch (Action) {
case IA_AddOldMember:
- addMember(Ret, I, Name);
+ addMember(Ret, Child, Name);
break;
case IA_AddNewMeber:
- addMember(Ret, &*MemberI, Name);
+ addMember(Ret, *MemberI, Name);
break;
case IA_Delete:
break;
case IA_MoveOldMember:
- addMember(Moved, I, Name);
+ addMember(Moved, Child, Name);
break;
case IA_MoveNewMember:
- addMember(Moved, &*MemberI, Name);
+ addMember(Moved, *MemberI, Name);
break;
}
if (MemberI != Members.end())
@@ -594,11 +596,10 @@ computeNewArchiveMembers(ArchiveOperation Operation,
Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator());
int Pos = InsertPos;
- for (std::vector<std::string>::iterator I = Members.begin(),
- E = Members.end();
- I != E; ++I, ++Pos) {
- StringRef Name = sys::path::filename(*I);
- addMember(Ret, &*I, Name, Pos);
+ for (auto &Member : Members) {
+ StringRef Name = sys::path::filename(Member);
+ addMember(Ret, Member, Name, Pos);
+ ++Pos;
}
return Ret;
@@ -684,10 +685,11 @@ static void writeStringTable(raw_fd_ostream &Out,
Out.seek(Pos);
}
-static void
-writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
- MutableArrayRef<std::unique_ptr<MemoryBuffer>> 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;
@@ -697,13 +699,13 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(),
E = Members.end();
I != E; ++I, ++MemberNum) {
- std::unique_ptr<MemoryBuffer> &MemberBuffer = Buffers[MemberNum];
- ErrorOr<object::SymbolicFile *> ObjOrErr =
+ MemoryBufferRef MemberBuffer = Buffers[MemberNum];
+ ErrorOr<std::unique_ptr<object::SymbolicFile>> ObjOrErr =
object::SymbolicFile::createSymbolicFile(
MemberBuffer, sys::fs::file_magic::unknown, &Context);
if (!ObjOrErr)
continue; // FIXME: check only for "not an object file" errors.
- std::unique_ptr<object::SymbolicFile> Obj(ObjOrErr.get());
+ object::SymbolicFile &Obj = *ObjOrErr.get();
if (!StartOffset) {
printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0);
@@ -711,7 +713,7 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
print32BE(Out, 0);
}
- for (const object::BasicSymbolRef &S : Obj->symbols()) {
+ for (const object::BasicSymbolRef &S : Obj.symbols()) {
uint32_t Symflags = S.getFlags();
if (Symflags & object::SymbolRef::SF_FormatSpecific)
continue;
@@ -722,15 +724,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);
}
- MemberBuffer.reset(Obj->releaseBuffer());
}
Out << NameOS.str();
if (StartOffset == 0)
- return;
+ return 0;
if (Out.tell() % 2)
Out << '\0';
@@ -741,10 +742,12 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
Out.seek(StartOffset);
print32BE(Out, NumSyms);
Out.seek(Pos);
+ return StartOffset + 4;
}
-static void performWriteOperation(ArchiveOperation Operation,
- object::Archive *OldArchive) {
+static void
+performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
+ std::vector<NewArchiveIterator> &NewMembers) {
SmallString<128> TmpArchive;
failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a",
TmpArchiveFD, TmpArchive));
@@ -754,65 +757,63 @@ static void performWriteOperation(ArchiveOperation Operation,
raw_fd_ostream &Out = Output.os();
Out << "!<arch>\n";
- std::vector<NewArchiveIterator> NewMembers =
- computeNewArchiveMembers(Operation, OldArchive);
-
- std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs;
+ std::vector<unsigned> MemberOffsetRefs;
- std::vector<std::unique_ptr<MemoryBuffer>> MemberBuffers;
- MemberBuffers.resize(NewMembers.size());
+ 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) {
- std::unique_ptr<MemoryBuffer> MemberBuffer;
NewArchiveIterator &Member = NewMembers[I];
+ MemoryBufferRef MemberRef;
if (Member.isNewMember()) {
- const char *Filename = Member.getNew();
- int FD = Member.getFD();
- const sys::fs::file_status &Status = Member.getStatus();
+ StringRef Filename = Member.getNew();
+ 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);
- MemberBuffer = std::move(MemberBufferOrErr.get());
+ if (close(FD) != 0)
+ fail("Could not close file");
+ Buffers.push_back(std::move(MemberBufferOrErr.get()));
+ MemberRef = Buffers.back()->getMemBufferRef();
} else {
object::Archive::child_iterator OldMember = Member.getOld();
- ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
- OldMember->getMemoryBuffer();
+ ErrorOr<MemoryBufferRef> MemberBufferOrErr =
+ OldMember->getMemoryBufferRef();
failIfError(MemberBufferOrErr.getError());
- MemberBuffer = std::move(MemberBufferOrErr.get());
+ MemberRef = MemberBufferOrErr.get();
}
- MemberBuffers[I].reset(MemberBuffer.release());
+ Members.push_back(MemberRef);
}
+ unsigned MemberReferenceOffset = 0;
if (Symtab) {
- writeSymbolTable(Out, NewMembers, MemberBuffers, 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);
- const MemoryBuffer *File = MemberBuffers[MemberNum].get();
+ MemoryBufferRef File = Members[MemberNum];
if (I->isNewMember()) {
- const char *FileName = I->getNew();
- const sys::fs::file_status &Status = I->getStatus();
+ StringRef FileName = I->getNew();
+ const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum];
+ NewMemberNum++;
StringRef Name = sys::path::filename(FileName);
if (Name.size() < 16)
@@ -839,18 +840,36 @@ static void performWriteOperation(ArchiveOperation Operation,
OldMember->getSize());
}
- Out << File->getBuffer();
+ Out << File.getBuffer();
if (Out.tell() % 2)
Out << '\n';
}
+ if (MemberReferenceOffset) {
+ Out.seek(MemberReferenceOffset);
+ for (unsigned MemberNum : MemberOffsetRefs)
+ print32BE(Out, MemberOffset[MemberNum]);
+ }
+
Output.keep();
Out.close();
sys::fs::rename(TemporaryOutput, ArchiveName);
TemporaryOutput = nullptr;
}
+static void
+performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive,
+ std::vector<NewArchiveIterator> *NewMembersP) {
+ if (NewMembersP) {
+ performWriteOperation(Operation, OldArchive, *NewMembersP);
+ return;
+ }
+ std::vector<NewArchiveIterator> NewMembers =
+ computeNewArchiveMembers(Operation, OldArchive);
+ performWriteOperation(Operation, OldArchive, NewMembers);
+}
+
static void createSymbolTable(object::Archive *OldArchive) {
// When an archive is created or modified, if the s option is given, the
// resulting archive will have a current symbol table. If the S option
@@ -861,11 +880,12 @@ static void createSymbolTable(object::Archive *OldArchive) {
if (OldArchive->hasSymbolTable())
return;
- performWriteOperation(CreateSymTab, OldArchive);
+ performWriteOperation(CreateSymTab, OldArchive, nullptr);
}
static void performOperation(ArchiveOperation Operation,
- object::Archive *OldArchive) {
+ object::Archive *OldArchive,
+ std::vector<NewArchiveIterator> *NewMembers) {
switch (Operation) {
case Print:
case DisplayTable:
@@ -877,7 +897,7 @@ static void performOperation(ArchiveOperation Operation,
case Move:
case QuickAppend:
case ReplaceOrInsert:
- performWriteOperation(Operation, OldArchive);
+ performWriteOperation(Operation, OldArchive, NewMembers);
return;
case CreateSymTab:
createSymbolTable(OldArchive);
@@ -886,53 +906,8 @@ static void performOperation(ArchiveOperation Operation,
llvm_unreachable("Unknown operation.");
}
-static int ar_main(char **argv);
-static int ranlib_main();
-
-// main - main program for llvm-ar .. see comments in the code
-int main(int argc, char **argv) {
- ToolName = argv[0];
- // Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(argc, argv);
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
- // Have the command line options parsed and handle things
- // like --help and --version.
- cl::ParseCommandLineOptions(argc, argv,
- "LLVM Archiver (llvm-ar)\n\n"
- " This program archives bitcode files into single libraries\n"
- );
-
- llvm::InitializeAllTargetInfos();
- llvm::InitializeAllTargetMCs();
- llvm::InitializeAllAsmParsers();
-
- StringRef Stem = sys::path::stem(ToolName);
- if (Stem.find("ar") != StringRef::npos)
- return ar_main(argv);
- if (Stem.find("ranlib") != StringRef::npos)
- return ranlib_main();
- fail("Not ranlib or ar!");
-}
-
-static int performOperation(ArchiveOperation Operation);
-
-int ranlib_main() {
- if (RestOfArgs.size() != 1)
- fail(ToolName + "takes just one archive as argument");
- ArchiveName = RestOfArgs[0];
- return performOperation(CreateSymTab);
-}
-
-int ar_main(char **argv) {
- // Do our own parsing of the command line because the CommandLine utility
- // can't handle the grouped positional parameters without a dash.
- ArchiveOperation Operation = parseCommandLine();
- return performOperation(Operation);
-}
-
-static int performOperation(ArchiveOperation Operation) {
+static int performOperation(ArchiveOperation Operation,
+ std::vector<NewArchiveIterator> *NewMembers) {
// Create or open the archive object.
ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
MemoryBuffer::getFile(ArchiveName, -1, false);
@@ -944,14 +919,14 @@ static int performOperation(ArchiveOperation Operation) {
}
if (!EC) {
- object::Archive Archive(std::move(Buf.get()), EC);
+ object::Archive Archive(Buf.get()->getMemBufferRef(), EC);
if (EC) {
errs() << ToolName << ": error loading '" << ArchiveName
<< "': " << EC.message() << "!\n";
return 1;
}
- performOperation(Operation, &Archive);
+ performOperation(Operation, &Archive, NewMembers);
return 0;
}
@@ -966,6 +941,116 @@ static int performOperation(ArchiveOperation Operation) {
}
}
- performOperation(Operation, nullptr);
+ performOperation(Operation, nullptr, NewMembers);
return 0;
}
+
+static void runMRIScript() {
+ enum class MRICommand { AddLib, AddMod, Create, Save, End, Invalid };
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getSTDIN();
+ failIfError(Buf.getError());
+ const MemoryBuffer &Ref = *Buf.get();
+ bool Saved = false;
+ std::vector<NewArchiveIterator> NewMembers;
+ std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers;
+ std::vector<std::unique_ptr<object::Archive>> Archives;
+
+ for (line_iterator I(Ref, /*SkipBlanks*/ true, ';'), E; I != E; ++I) {
+ StringRef Line = *I;
+ StringRef CommandStr, Rest;
+ std::tie(CommandStr, Rest) = Line.split(' ');
+ Rest = Rest.trim();
+ if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"')
+ Rest = Rest.drop_front().drop_back();
+ auto Command = StringSwitch<MRICommand>(CommandStr.lower())
+ .Case("addlib", MRICommand::AddLib)
+ .Case("addmod", MRICommand::AddMod)
+ .Case("create", MRICommand::Create)
+ .Case("save", MRICommand::Save)
+ .Case("end", MRICommand::End)
+ .Default(MRICommand::Invalid);
+
+ switch (Command) {
+ case MRICommand::AddLib: {
+ auto BufOrErr = MemoryBuffer::getFile(Rest, -1, false);
+ failIfError(BufOrErr.getError(), "Could not open library");
+ ArchiveBuffers.push_back(std::move(*BufOrErr));
+ auto LibOrErr =
+ object::Archive::create(ArchiveBuffers.back()->getMemBufferRef());
+ failIfError(LibOrErr.getError(), "Could not parse library");
+ Archives.push_back(std::move(*LibOrErr));
+ object::Archive &Lib = *Archives.back();
+ for (auto &Member : Lib.children()) {
+ ErrorOr<StringRef> NameOrErr = Member.getName();
+ failIfError(NameOrErr.getError());
+ addMember(NewMembers, Member, *NameOrErr);
+ }
+ break;
+ }
+ case MRICommand::AddMod:
+ addMember(NewMembers, Rest, sys::path::filename(Rest));
+ break;
+ case MRICommand::Create:
+ Create = true;
+ if (!ArchiveName.empty())
+ fail("Editing multiple archives not supported");
+ if (Saved)
+ fail("File already saved");
+ ArchiveName = Rest;
+ break;
+ case MRICommand::Save:
+ Saved = true;
+ break;
+ case MRICommand::End:
+ break;
+ case MRICommand::Invalid:
+ fail("Unknown command: " + CommandStr);
+ }
+ }
+
+ // Nothing to do if not saved.
+ if (Saved)
+ performOperation(ReplaceOrInsert, &NewMembers);
+ exit(0);
+}
+
+static int ar_main() {
+ // Do our own parsing of the command line because the CommandLine utility
+ // can't handle the grouped positional parameters without a dash.
+ ArchiveOperation Operation = parseCommandLine();
+ return performOperation(Operation, nullptr);
+}
+
+static int ranlib_main() {
+ if (RestOfArgs.size() != 1)
+ fail(ToolName + "takes just one archive as argument");
+ ArchiveName = RestOfArgs[0];
+ return performOperation(CreateSymTab, nullptr);
+}
+
+int main(int argc, char **argv) {
+ ToolName = argv[0];
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ // Have the command line options parsed and handle things
+ // like --help and --version.
+ cl::ParseCommandLineOptions(argc, argv,
+ "LLVM Archiver (llvm-ar)\n\n"
+ " This program archives bitcode files into single libraries\n"
+ );
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+
+ StringRef Stem = sys::path::stem(ToolName);
+ if (Stem.find("ar") != StringRef::npos)
+ return ar_main();
+ if (Stem.find("ranlib") != StringRef::npos)
+ return ranlib_main();
+ fail("Not ranlib or ar!");
+}
diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp
index 007241c5068d..5ccf505923f2 100644
--- a/tools/llvm-as/llvm-as.cpp
+++ b/tools/llvm-as/llvm-as.cpp
@@ -69,11 +69,11 @@ static void WriteOutputFile(const Module *M) {
}
}
- std::string ErrorInfo;
+ std::error_code EC;
std::unique_ptr<tool_output_file> Out(
- new tool_output_file(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ new tool_output_file(OutputFilename, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
exit(1);
}
@@ -94,7 +94,7 @@ int main(int argc, char **argv) {
// Parse the file now...
SMDiagnostic Err;
- std::unique_ptr<Module> M(ParseAssemblyFile(InputFilename, Err, Context));
+ std::unique_ptr<Module> M = parseAssemblyFile(InputFilename, Err, Context);
if (!M.get()) {
Err.print(argv[0], errs());
return 1;
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 15567cf31239..396e03036989 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -28,6 +28,7 @@
//===----------------------------------------------------------------------===//
#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"
@@ -61,6 +62,10 @@ NonSymbolic("non-symbolic",
cl::desc("Emit numeric info in dump even if"
" symbolic info is available"));
+static cl::opt<std::string>
+ BlockInfoFilename("block-info",
+ cl::desc("Use the BLOCK_INFO from the given file"));
+
namespace {
/// CurStreamTypeType - A type for CurStreamType
@@ -71,15 +76,11 @@ enum CurStreamTypeType {
}
-/// CurStreamType - If we can sniff the flavor of this stream, we can produce
-/// better dump info.
-static CurStreamTypeType CurStreamType;
-
-
/// GetBlockName - Return a symbolic block name if known, otherwise return
/// null.
static const char *GetBlockName(unsigned BlockID,
- const BitstreamReader &StreamFile) {
+ const BitstreamReader &StreamFile,
+ CurStreamTypeType CurStreamType) {
// Standard blocks for all bitcode files.
if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
if (BlockID == bitc::BLOCKINFO_BLOCK_ID)
@@ -115,7 +116,8 @@ static const char *GetBlockName(unsigned BlockID,
/// GetCodeName - Return a symbolic code name if known, otherwise return
/// null.
static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
- const BitstreamReader &StreamFile) {
+ const BitstreamReader &StreamFile,
+ CurStreamTypeType CurStreamType) {
// Standard blocks for all bitcode files.
if (BlockID < bitc::FIRST_APPLICATION_BLOCKID) {
if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
@@ -265,13 +267,16 @@ 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:
switch(CodeID) {
default:return nullptr;
- case bitc::USELIST_CODE_ENTRY: return "USELIST_CODE_ENTRY";
+ case bitc::USELIST_CODE_DEFAULT: return "USELIST_CODE_DEFAULT";
+ case bitc::USELIST_CODE_BB: return "USELIST_CODE_BB";
}
}
}
@@ -315,14 +320,14 @@ static std::map<unsigned, PerBlockIDStats> BlockIDStats;
/// Error - All bitcode analysis errors go through this function, making this a
/// good place to breakpoint if debugging.
-static bool Error(const std::string &Err) {
+static bool Error(const Twine &Err) {
errs() << Err << "\n";
return true;
}
/// ParseBlock - Read a block, updating statistics, etc.
static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
- unsigned IndentLevel) {
+ unsigned IndentLevel, CurStreamTypeType CurStreamType) {
std::string Indent(IndentLevel*2, ' ');
uint64_t BlockBitStart = Stream.GetCurrentBitNo();
@@ -348,7 +353,8 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
const char *BlockName = nullptr;
if (Dump) {
outs() << Indent << "<";
- if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader())))
+ if ((BlockName = GetBlockName(BlockID, *Stream.getBitStreamReader(),
+ CurStreamType)))
outs() << BlockName;
else
outs() << "UnknownBlock" << BlockID;
@@ -390,7 +396,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
case BitstreamEntry::SubBlock: {
uint64_t SubBlockBitStart = Stream.GetCurrentBitNo();
- if (ParseBlock(Stream, Entry.ID, IndentLevel+1))
+ if (ParseBlock(Stream, Entry.ID, IndentLevel+1, CurStreamType))
return true;
++BlockStats.NumSubBlocks;
uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo();
@@ -431,12 +437,14 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
if (Dump) {
outs() << Indent << " <";
if (const char *CodeName =
- GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
+ GetCodeName(Code, BlockID, *Stream.getBitStreamReader(),
+ CurStreamType))
outs() << CodeName;
else
outs() << "UnknownCode" << Code;
if (NonSymbolic &&
- GetCodeName(Code, BlockID, *Stream.getBitStreamReader()))
+ GetCodeName(Code, BlockID, *Stream.getBitStreamReader(),
+ CurStreamType))
outs() << " codeid=" << Code;
if (Entry.ID != bitc::UNABBREV_RECORD)
outs() << " abbrevid=" << Entry.ID;
@@ -474,21 +482,23 @@ static void PrintSize(uint64_t Bits) {
(double)Bits/8, (unsigned long)(Bits/32));
}
-
-/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
-static int AnalyzeBitcode() {
+static bool openBitcodeFile(StringRef Path,
+ std::unique_ptr<MemoryBuffer> &MemBuf,
+ BitstreamReader &StreamFile,
+ BitstreamCursor &Stream,
+ CurStreamTypeType &CurStreamType) {
// Read the input file.
ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr =
- MemoryBuffer::getFileOrSTDIN(InputFilename);
+ MemoryBuffer::getFileOrSTDIN(Path);
if (std::error_code EC = MemBufOrErr.getError())
- return Error("Error reading '" + InputFilename + "': " + EC.message());
- std::unique_ptr<MemoryBuffer> MemBuf = std::move(MemBufOrErr.get());
+ return Error(Twine("Error reading '") + Path + "': " + EC.message());
+ MemBuf = std::move(MemBufOrErr.get());
if (MemBuf->getBufferSize() & 3)
return Error("Bitcode stream should be a multiple of 4 bytes in length");
const unsigned char *BufPtr = (const unsigned char *)MemBuf->getBufferStart();
- const unsigned char *EndBufPtr = BufPtr+MemBuf->getBufferSize();
+ const unsigned char *EndBufPtr = BufPtr + MemBuf->getBufferSize();
// If we have a wrapper header, parse it and ignore the non-bc file contents.
// The magic number is 0x0B17C0DE stored in little endian.
@@ -496,8 +506,8 @@ static int AnalyzeBitcode() {
if (SkipBitcodeWrapperHeader(BufPtr, EndBufPtr, true))
return Error("Invalid bitcode wrapper header");
- BitstreamReader StreamFile(BufPtr, EndBufPtr);
- BitstreamCursor Stream(StreamFile);
+ StreamFile = BitstreamReader(BufPtr, EndBufPtr);
+ Stream = BitstreamCursor(StreamFile);
StreamFile.CollectBlockInfoNames();
// Read the stream signature.
@@ -516,6 +526,48 @@ static int AnalyzeBitcode() {
Signature[4] == 0xE && Signature[5] == 0xD)
CurStreamType = LLVMIRBitstream;
+ return false;
+}
+
+/// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename.
+static int AnalyzeBitcode() {
+ std::unique_ptr<MemoryBuffer> StreamBuffer;
+ BitstreamReader StreamFile;
+ BitstreamCursor Stream;
+ CurStreamTypeType CurStreamType;
+ if (openBitcodeFile(InputFilename, StreamBuffer, StreamFile, Stream,
+ CurStreamType))
+ return true;
+
+ // Read block info from BlockInfoFilename, if specified.
+ // The block info must be a top-level block.
+ if (!BlockInfoFilename.empty()) {
+ std::unique_ptr<MemoryBuffer> BlockInfoBuffer;
+ BitstreamReader BlockInfoFile;
+ BitstreamCursor BlockInfoCursor;
+ CurStreamTypeType BlockInfoStreamType;
+ if (openBitcodeFile(BlockInfoFilename, BlockInfoBuffer, BlockInfoFile,
+ BlockInfoCursor, BlockInfoStreamType))
+ return true;
+
+ while (!BlockInfoCursor.AtEndOfStream()) {
+ unsigned Code = BlockInfoCursor.ReadCode();
+ if (Code != bitc::ENTER_SUBBLOCK)
+ return Error("Invalid record at top-level in block info file");
+
+ unsigned BlockID = BlockInfoCursor.ReadSubBlockID();
+ if (BlockID == bitc::BLOCKINFO_BLOCK_ID) {
+ if (BlockInfoCursor.ReadBlockInfoBlock())
+ return Error("Malformed BlockInfoBlock in block info file");
+ break;
+ }
+
+ BlockInfoCursor.SkipBlock();
+ }
+
+ StreamFile.takeBlockInfo(std::move(BlockInfoFile));
+ }
+
unsigned NumTopBlocks = 0;
// Parse the top-level structure. We only allow blocks at the top-level.
@@ -526,14 +578,14 @@ static int AnalyzeBitcode() {
unsigned BlockID = Stream.ReadSubBlockID();
- if (ParseBlock(Stream, BlockID, 0))
+ if (ParseBlock(Stream, BlockID, 0, CurStreamType))
return true;
++NumTopBlocks;
}
if (Dump) outs() << "\n\n";
- uint64_t BufferSizeBits = (EndBufPtr-BufPtr)*CHAR_BIT;
+ uint64_t BufferSizeBits = StreamFile.getBitcodeBytes().getExtent() * CHAR_BIT;
// Print a summary of the read file.
outs() << "Summary of " << InputFilename << ":\n";
outs() << " Total size: ";
@@ -552,7 +604,8 @@ static int AnalyzeBitcode() {
for (std::map<unsigned, PerBlockIDStats>::iterator I = BlockIDStats.begin(),
E = BlockIDStats.end(); I != E; ++I) {
outs() << " Block ID #" << I->first;
- if (const char *BlockName = GetBlockName(I->first, StreamFile))
+ if (const char *BlockName = GetBlockName(I->first, StreamFile,
+ CurStreamType))
outs() << " (" << BlockName << ")";
outs() << ":\n";
@@ -610,7 +663,8 @@ static int AnalyzeBitcode() {
outs() << " ";
if (const char *CodeName =
- GetCodeName(FreqPairs[i].second, I->first, StreamFile))
+ GetCodeName(FreqPairs[i].second, I->first, StreamFile,
+ CurStreamType))
outs() << CodeName << "\n";
else
outs() << "UnknownCode" << FreqPairs[i].second << "\n";
diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt
index 34fea3d69c16..baf970a02781 100644
--- a/tools/llvm-c-test/CMakeLists.txt
+++ b/tools/llvm-c-test/CMakeLists.txt
@@ -7,6 +7,29 @@ set(LLVM_LINK_COMPONENTS
Target
)
+# 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()
+
if (LLVM_COMPILER_IS_GCC_COMPATIBLE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -Wstrict-prototypes")
endif ()
@@ -21,3 +44,7 @@ add_llvm_tool(llvm-c-test
object.c
targets.c
)
+
+if(USE_LLVM_DYLIB)
+ target_link_libraries(llvm-c-test LLVM)
+endif()
diff --git a/tools/llvm-c-test/disassemble.c b/tools/llvm-c-test/disassemble.c
index eb40bf3d4461..05a9218d014a 100644
--- a/tools/llvm-c-test/disassemble.c
+++ b/tools/llvm-c-test/disassemble.c
@@ -18,6 +18,7 @@
#include "llvm-c/Target.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
static void pprint(int pos, unsigned char *buf, int len, const char *disasm) {
int i;
@@ -33,13 +34,15 @@ static void pprint(int pos, unsigned char *buf, int len, const char *disasm) {
printf(" %s\n", disasm);
}
-static void do_disassemble(const char *triple, unsigned char *buf, int siz) {
- LLVMDisasmContextRef D = LLVMCreateDisasm(triple, NULL, 0, NULL, NULL);
+static void do_disassemble(const char *triple, const char *features,
+ unsigned char *buf, int siz) {
+ LLVMDisasmContextRef D = LLVMCreateDisasmCPUFeatures(triple, "", features,
+ NULL, 0, NULL, NULL);
char outline[1024];
int pos;
if (!D) {
- printf("ERROR: Couldn't create disassebler for triple %s\n", triple);
+ printf("ERROR: Couldn't create disassembler for triple %s\n", triple);
return;
}
@@ -62,19 +65,22 @@ static void do_disassemble(const char *triple, unsigned char *buf, int siz) {
static void handle_line(char **tokens, int ntokens) {
unsigned char disbuf[128];
size_t disbuflen = 0;
- char *triple = tokens[0];
+ const char *triple = tokens[0];
+ const char *features = tokens[1];
int i;
- printf("triple: %s\n", triple);
+ printf("triple: %s, features: %s\n", triple, features);
+ if (!strcmp(features, "NULL"))
+ features = "";
- for (i = 1; i < ntokens; i++) {
+ for (i = 2; i < ntokens; i++) {
disbuf[disbuflen++] = strtol(tokens[i], NULL, 16);
if (disbuflen >= sizeof(disbuf)) {
fprintf(stderr, "Warning: Too long line, truncating\n");
break;
}
}
- do_disassemble(triple, disbuf, disbuflen);
+ do_disassemble(triple, features, disbuf, disbuflen);
}
int disassemble(void) {
diff --git a/tools/llvm-config/BuildVariables.inc.in b/tools/llvm-config/BuildVariables.inc.in
index 2ec019ba622f..3f51f491a7a4 100644
--- a/tools/llvm-config/BuildVariables.inc.in
+++ b/tools/llvm-config/BuildVariables.inc.in
@@ -23,5 +23,6 @@
#define LLVM_LDFLAGS "@LLVM_LDFLAGS@"
#define LLVM_CXXFLAGS "@LLVM_CXXFLAGS@"
#define LLVM_BUILDMODE "@LLVM_BUILDMODE@"
+#define LLVM_LIBDIR_SUFFIX "@LLVM_LIBDIR_SUFFIX@"
#define LLVM_TARGETS_BUILT "@LLVM_TARGETS_BUILT@"
#define LLVM_SYSTEM_LIBS "@LLVM_SYSTEM_LIBS@"
diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt
index 8d8376271de8..50c84e6c3d08 100644
--- a/tools/llvm-config/CMakeLists.txt
+++ b/tools/llvm-config/CMakeLists.txt
@@ -33,3 +33,18 @@ add_llvm_tool(llvm-config
# Add the dependency on the generation step.
add_file_dependencies(${CMAKE_CURRENT_SOURCE_DIR}/llvm-config.cpp ${BUILDVARIABLES_OBJPATH})
+
+if(CMAKE_CROSSCOMPILING)
+ set(${project}_LLVM_CONFIG_EXE "${LLVM_NATIVE_BUILD}/bin/llvm-config")
+ set(${project}_LLVM_CONFIG_EXE ${${project}_LLVM_CONFIG_EXE} PARENT_SCOPE)
+
+ add_custom_command(OUTPUT "${${project}_LLVM_CONFIG_EXE}"
+ COMMAND ${CMAKE_COMMAND} --build . --target llvm-config --config $<CONFIGURATION>
+ DEPENDS ${LLVM_NATIVE_BUILD}/CMakeCache.txt
+ WORKING_DIRECTORY ${LLVM_NATIVE_BUILD}
+ COMMENT "Building native llvm-config...")
+ add_custom_target(${project}NativeLLVMConfig DEPENDS ${${project}_LLVM_CONFIG_EXE})
+ add_dependencies(${project}NativeLLVMConfig ConfigureNativeLLVM)
+
+ add_dependencies(llvm-config ${project}NativeLLVMConfig)
+endif(CMAKE_CROSSCOMPILING)
diff --git a/tools/llvm-config/Makefile b/tools/llvm-config/Makefile
index b78551e68a79..1ff8b6f04063 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 ed1c8c3b2ae7..224035ac497b 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/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt
index 67cea71dd016..b2d2b897ec95 100644
--- a/tools/llvm-cov/CMakeLists.txt
+++ b/tools/llvm-cov/CMakeLists.txt
@@ -1,5 +1,13 @@
-set(LLVM_LINK_COMPONENTS core support )
+set(LLVM_LINK_COMPONENTS core support object profiledata)
add_llvm_tool(llvm-cov
llvm-cov.cpp
+ gcov.cpp
+ 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
new file mode 100644
index 000000000000..7cee4d4b3f2e
--- /dev/null
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -0,0 +1,483 @@
+//===- CodeCoverage.cpp - Coverage tool based on profiling instrumentation-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// The 'CodeCoverageTool' class implements a command line tool to analyze and
+// report coverage information using the profiling instrumentation and code
+// coverage mapping.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RenderingSupport.h"
+#include "CoverageFilters.h"
+#include "CoverageReport.h"
+#include "CoverageSummary.h"
+#include "CoverageViewOptions.h"
+#include "SourceCoverageView.h"
+#include "llvm/ADT/SmallString.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/Format.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include <functional>
+#include <system_error>
+
+using namespace llvm;
+using namespace coverage;
+
+namespace {
+/// \brief The implementation of the coverage tool.
+class CodeCoverageTool {
+public:
+ enum Command {
+ /// \brief The show command.
+ Show,
+ /// \brief The report command.
+ Report
+ };
+
+ /// \brief Print the error message to the error output stream.
+ void error(const Twine &Message, StringRef Whence = "");
+
+ /// \brief Return a memory buffer for the given source file.
+ ErrorOr<const MemoryBuffer &> getSourceFile(StringRef SourceFile);
+
+ /// \brief Create source views for the expansions of the view.
+ void attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage);
+
+ /// \brief Create the source view of a particular function.
+ std::unique_ptr<SourceCoverageView>
+ createFunctionView(const FunctionRecord &Function, CoverageMapping &Coverage);
+
+ /// \brief Create the main source view of a particular source file.
+ std::unique_ptr<SourceCoverageView>
+ createSourceFileView(StringRef SourceFile, CoverageMapping &Coverage);
+
+ /// \brief Load the coverage mapping data. Return true if an error occured.
+ std::unique_ptr<CoverageMapping> load();
+
+ int run(Command Cmd, int argc, const char **argv);
+
+ typedef std::function<int(int, const char **)> CommandLineParserType;
+
+ int show(int argc, const char **argv,
+ CommandLineParserType commandLineParser);
+
+ int report(int argc, const char **argv,
+ CommandLineParserType commandLineParser);
+
+ std::string ObjectFilename;
+ CoverageViewOptions ViewOpts;
+ std::string PGOFilename;
+ CoverageFiltersMatchAll Filters;
+ std::vector<std::string> SourceFiles;
+ std::vector<std::pair<std::string, std::unique_ptr<MemoryBuffer>>>
+ LoadedSourceFiles;
+ bool CompareFilenamesOnly;
+ StringMap<std::string> RemappedFilenames;
+};
+}
+
+void CodeCoverageTool::error(const Twine &Message, StringRef Whence) {
+ errs() << "error: ";
+ if (!Whence.empty())
+ errs() << Whence << ": ";
+ errs() << Message << "\n";
+}
+
+ErrorOr<const MemoryBuffer &>
+CodeCoverageTool::getSourceFile(StringRef SourceFile) {
+ // If we've remapped filenames, look up the real location for this file.
+ if (!RemappedFilenames.empty()) {
+ auto Loc = RemappedFilenames.find(SourceFile);
+ if (Loc != RemappedFilenames.end())
+ SourceFile = Loc->second;
+ }
+ for (const auto &Files : LoadedSourceFiles)
+ if (sys::fs::equivalent(SourceFile, Files.first))
+ return *Files.second;
+ auto Buffer = MemoryBuffer::getFile(SourceFile);
+ if (auto EC = Buffer.getError()) {
+ error(EC.message(), SourceFile);
+ return EC;
+ }
+ LoadedSourceFiles.push_back(
+ std::make_pair(SourceFile, std::move(Buffer.get())));
+ return *LoadedSourceFiles.back().second;
+}
+
+void
+CodeCoverageTool::attachExpansionSubViews(SourceCoverageView &View,
+ ArrayRef<ExpansionRecord> Expansions,
+ CoverageMapping &Coverage) {
+ if (!ViewOpts.ShowExpandedRegions)
+ return;
+ for (const auto &Expansion : Expansions) {
+ auto ExpansionCoverage = Coverage.getCoverageForExpansion(Expansion);
+ if (ExpansionCoverage.empty())
+ continue;
+ auto SourceBuffer = getSourceFile(ExpansionCoverage.getFilename());
+ if (!SourceBuffer)
+ continue;
+
+ auto SubViewExpansions = ExpansionCoverage.getExpansions();
+ auto SubView = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(ExpansionCoverage));
+ attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+ View.addExpansion(Expansion.Region, std::move(SubView));
+ }
+}
+
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createFunctionView(const FunctionRecord &Function,
+ CoverageMapping &Coverage) {
+ auto FunctionCoverage = Coverage.getCoverageForFunction(Function);
+ if (FunctionCoverage.empty())
+ return nullptr;
+ auto SourceBuffer = getSourceFile(FunctionCoverage.getFilename());
+ if (!SourceBuffer)
+ return nullptr;
+
+ auto Expansions = FunctionCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FunctionCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
+
+ return View;
+}
+
+std::unique_ptr<SourceCoverageView>
+CodeCoverageTool::createSourceFileView(StringRef SourceFile,
+ CoverageMapping &Coverage) {
+ auto SourceBuffer = getSourceFile(SourceFile);
+ if (!SourceBuffer)
+ return nullptr;
+ auto FileCoverage = Coverage.getCoverageForFile(SourceFile);
+ if (FileCoverage.empty())
+ return nullptr;
+
+ auto Expansions = FileCoverage.getExpansions();
+ auto View = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(FileCoverage));
+ attachExpansionSubViews(*View, Expansions, Coverage);
+
+ for (auto Function : Coverage.getInstantiations(SourceFile)) {
+ auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
+ auto SubViewExpansions = SubViewCoverage.getExpansions();
+ auto SubView = llvm::make_unique<SourceCoverageView>(
+ SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+ attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+
+ if (SubView) {
+ unsigned FileID = Function->CountedRegions.front().FileID;
+ unsigned Line = 0;
+ for (const auto &CR : Function->CountedRegions)
+ if (CR.FileID == FileID)
+ Line = std::max(CR.LineEnd, Line);
+ View->addInstantiation(Function->Name, Line, std::move(SubView));
+ }
+ }
+ return View;
+}
+
+std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
+ auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename);
+ if (std::error_code EC = CoverageOrErr.getError()) {
+ colored_ostream(errs(), raw_ostream::RED)
+ << "error: Failed to load coverage: " << EC.message();
+ errs() << "\n";
+ return nullptr;
+ }
+ auto Coverage = std::move(CoverageOrErr.get());
+ unsigned Mismatched = Coverage->getMismatchedCount();
+ if (Mismatched) {
+ colored_ostream(errs(), raw_ostream::RED)
+ << "warning: " << Mismatched << " functions have mismatched data. ";
+ errs() << "\n";
+ }
+
+ if (CompareFilenamesOnly) {
+ auto CoveredFiles = Coverage.get()->getUniqueSourceFiles();
+ for (auto &SF : SourceFiles) {
+ StringRef SFBase = sys::path::filename(SF);
+ for (const auto &CF : CoveredFiles)
+ if (SFBase == sys::path::filename(CF)) {
+ RemappedFilenames[CF] = SF;
+ SF = CF;
+ break;
+ }
+ }
+ }
+
+ return Coverage;
+}
+
+int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::opt<std::string, true> ObjectFilename(
+ cl::Positional, cl::Required, cl::location(this->ObjectFilename),
+ cl::desc("Covered executable or object file."));
+
+ cl::list<std::string> InputSourceFiles(
+ cl::Positional, cl::desc("<Source files>"), cl::ZeroOrMore);
+
+ cl::opt<std::string, true> PGOFilename(
+ "instr-profile", cl::Required, cl::location(this->PGOFilename),
+ cl::desc(
+ "File with the profile data obtained after an instrumented run"));
+
+ cl::opt<bool> DebugDump("dump", cl::Optional,
+ cl::desc("Show internal debug dump"));
+
+ cl::opt<bool> FilenameEquivalence(
+ "filename-equivalence", cl::Optional,
+ cl::desc("Treat source files as equivalent to paths in the coverage data "
+ "when the file names match, even if the full paths do not"));
+
+ cl::OptionCategory FilteringCategory("Function filtering options");
+
+ cl::list<std::string> NameFilters(
+ "name", cl::Optional,
+ cl::desc("Show code coverage only for functions with the given name"),
+ cl::ZeroOrMore, cl::cat(FilteringCategory));
+
+ cl::list<std::string> NameRegexFilters(
+ "name-regex", cl::Optional,
+ cl::desc("Show code coverage only for functions that match the given "
+ "regular expression"),
+ cl::ZeroOrMore, cl::cat(FilteringCategory));
+
+ cl::opt<double> RegionCoverageLtFilter(
+ "region-coverage-lt", cl::Optional,
+ cl::desc("Show code coverage only for functions with region coverage "
+ "less than the given threshold"),
+ cl::cat(FilteringCategory));
+
+ cl::opt<double> RegionCoverageGtFilter(
+ "region-coverage-gt", cl::Optional,
+ cl::desc("Show code coverage only for functions with region coverage "
+ "greater than the given threshold"),
+ cl::cat(FilteringCategory));
+
+ cl::opt<double> LineCoverageLtFilter(
+ "line-coverage-lt", cl::Optional,
+ cl::desc("Show code coverage only for functions with line coverage less "
+ "than the given threshold"),
+ cl::cat(FilteringCategory));
+
+ cl::opt<double> LineCoverageGtFilter(
+ "line-coverage-gt", cl::Optional,
+ cl::desc("Show code coverage only for functions with line coverage "
+ "greater than the given threshold"),
+ cl::cat(FilteringCategory));
+
+ auto commandLineParser = [&, this](int argc, const char **argv) -> int {
+ cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
+ ViewOpts.Debug = DebugDump;
+ CompareFilenamesOnly = FilenameEquivalence;
+
+ // Create the function filters
+ if (!NameFilters.empty() || !NameRegexFilters.empty()) {
+ auto NameFilterer = new CoverageFilters;
+ for (const auto &Name : NameFilters)
+ NameFilterer->push_back(llvm::make_unique<NameCoverageFilter>(Name));
+ for (const auto &Regex : NameRegexFilters)
+ NameFilterer->push_back(
+ llvm::make_unique<NameRegexCoverageFilter>(Regex));
+ Filters.push_back(std::unique_ptr<CoverageFilter>(NameFilterer));
+ }
+ if (RegionCoverageLtFilter.getNumOccurrences() ||
+ RegionCoverageGtFilter.getNumOccurrences() ||
+ LineCoverageLtFilter.getNumOccurrences() ||
+ LineCoverageGtFilter.getNumOccurrences()) {
+ auto StatFilterer = new CoverageFilters;
+ if (RegionCoverageLtFilter.getNumOccurrences())
+ StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
+ RegionCoverageFilter::LessThan, RegionCoverageLtFilter));
+ if (RegionCoverageGtFilter.getNumOccurrences())
+ StatFilterer->push_back(llvm::make_unique<RegionCoverageFilter>(
+ RegionCoverageFilter::GreaterThan, RegionCoverageGtFilter));
+ if (LineCoverageLtFilter.getNumOccurrences())
+ StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
+ LineCoverageFilter::LessThan, LineCoverageLtFilter));
+ if (LineCoverageGtFilter.getNumOccurrences())
+ StatFilterer->push_back(llvm::make_unique<LineCoverageFilter>(
+ RegionCoverageFilter::GreaterThan, LineCoverageGtFilter));
+ Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
+ }
+
+ 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;
+ }
+ SourceFiles.push_back(Path.str());
+ }
+ return 0;
+ };
+
+ switch (Cmd) {
+ case Show:
+ return show(argc, argv, commandLineParser);
+ case Report:
+ return report(argc, argv, commandLineParser);
+ }
+ return 0;
+}
+
+int CodeCoverageTool::show(int argc, const char **argv,
+ CommandLineParserType commandLineParser) {
+
+ cl::OptionCategory ViewCategory("Viewing options");
+
+ cl::opt<bool> ShowLineExecutionCounts(
+ "show-line-counts", cl::Optional,
+ cl::desc("Show the execution counts for each line"), cl::init(true),
+ cl::cat(ViewCategory));
+
+ cl::opt<bool> ShowRegions(
+ "show-regions", cl::Optional,
+ cl::desc("Show the execution counts for each region"),
+ cl::cat(ViewCategory));
+
+ cl::opt<bool> ShowBestLineRegionsCounts(
+ "show-line-counts-or-regions", cl::Optional,
+ cl::desc("Show the execution counts for each line, or the execution "
+ "counts for each region on lines that have multiple regions"),
+ cl::cat(ViewCategory));
+
+ cl::opt<bool> ShowExpansions("show-expansions", cl::Optional,
+ cl::desc("Show expanded source regions"),
+ cl::cat(ViewCategory));
+
+ cl::opt<bool> ShowInstantiations("show-instantiations", cl::Optional,
+ cl::desc("Show function instantiations"),
+ cl::cat(ViewCategory));
+
+ cl::opt<bool> NoColors("no-colors", cl::Optional,
+ cl::desc("Don't show text colors"), cl::init(false),
+ cl::cat(ViewCategory));
+
+ auto Err = commandLineParser(argc, argv);
+ if (Err)
+ return Err;
+
+ ViewOpts.Colors = !NoColors;
+ ViewOpts.ShowLineNumbers = true;
+ ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
+ !ShowRegions || ShowBestLineRegionsCounts;
+ ViewOpts.ShowRegionMarkers = ShowRegions || ShowBestLineRegionsCounts;
+ ViewOpts.ShowLineStatsOrRegionMarkers = ShowBestLineRegionsCounts;
+ ViewOpts.ShowExpandedRegions = ShowExpansions;
+ ViewOpts.ShowFunctionInstantiations = ShowInstantiations;
+
+ auto Coverage = load();
+ if (!Coverage)
+ return 1;
+
+ if (!Filters.empty()) {
+ // Show functions
+ for (const auto &Function : Coverage->getCoveredFunctions()) {
+ if (!Filters.matches(Function))
+ continue;
+
+ auto mainView = createFunctionView(Function, *Coverage);
+ if (!mainView) {
+ ViewOpts.colored_ostream(outs(), raw_ostream::RED)
+ << "warning: Could not read coverage for '" << Function.Name;
+ outs() << "\n";
+ continue;
+ }
+ ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << Function.Name
+ << ":";
+ outs() << "\n";
+ mainView->render(outs(), /*WholeFile=*/false);
+ outs() << "\n";
+ }
+ return 0;
+ }
+
+ // Show files
+ bool ShowFilenames = SourceFiles.size() != 1;
+
+ if (SourceFiles.empty())
+ // Get the source files from the function coverage mapping
+ for (StringRef Filename : Coverage->getUniqueSourceFiles())
+ SourceFiles.push_back(Filename);
+
+ for (const auto &SourceFile : SourceFiles) {
+ auto mainView = createSourceFileView(SourceFile, *Coverage);
+ if (!mainView) {
+ ViewOpts.colored_ostream(outs(), raw_ostream::RED)
+ << "warning: The file '" << SourceFile << "' isn't covered.";
+ outs() << "\n";
+ continue;
+ }
+
+ if (ShowFilenames) {
+ ViewOpts.colored_ostream(outs(), raw_ostream::CYAN) << SourceFile << ":";
+ outs() << "\n";
+ }
+ mainView->render(outs(), /*Wholefile=*/true);
+ if (SourceFiles.size() > 1)
+ outs() << "\n";
+ }
+
+ return 0;
+}
+
+int CodeCoverageTool::report(int argc, const char **argv,
+ CommandLineParserType commandLineParser) {
+ cl::opt<bool> NoColors("no-colors", cl::Optional,
+ cl::desc("Don't show text colors"), cl::init(false));
+
+ auto Err = commandLineParser(argc, argv);
+ if (Err)
+ return Err;
+
+ ViewOpts.Colors = !NoColors;
+
+ auto Coverage = load();
+ if (!Coverage)
+ return 1;
+
+ CoverageSummary Summarizer;
+ Summarizer.createSummaries(*Coverage);
+ CoverageReport Report(ViewOpts, Summarizer);
+ if (SourceFiles.empty() && Filters.empty()) {
+ Report.renderFileReports(llvm::outs());
+ return 0;
+ }
+
+ Report.renderFunctionReports(llvm::outs());
+ return 0;
+}
+
+int showMain(int argc, const char *argv[]) {
+ CodeCoverageTool Tool;
+ return Tool.run(CodeCoverageTool::Show, argc, argv);
+}
+
+int reportMain(int argc, const char *argv[]) {
+ CodeCoverageTool Tool;
+ return Tool.run(CodeCoverageTool::Report, argc, argv);
+}
diff --git a/tools/llvm-cov/CoverageFilters.cpp b/tools/llvm-cov/CoverageFilters.cpp
new file mode 100644
index 000000000000..325dd7235789
--- /dev/null
+++ b/tools/llvm-cov/CoverageFilters.cpp
@@ -0,0 +1,59 @@
+//===- CoverageFilters.cpp - Function coverage mapping filters ------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes provide filtering for function coverage mapping records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageFilters.h"
+#include "CoverageSummaryInfo.h"
+#include "llvm/Support/Regex.h"
+
+using namespace llvm;
+
+bool NameCoverageFilter::matches(const coverage::FunctionRecord &Function) {
+ StringRef FuncName = Function.Name;
+ return FuncName.find(Name) != StringRef::npos;
+}
+
+bool
+NameRegexCoverageFilter::matches(const coverage::FunctionRecord &Function) {
+ return llvm::Regex(Regex).match(Function.Name);
+}
+
+bool RegionCoverageFilter::matches(const coverage::FunctionRecord &Function) {
+ return PassesThreshold(FunctionCoverageSummary::get(Function)
+ .RegionCoverage.getPercentCovered());
+}
+
+bool LineCoverageFilter::matches(const coverage::FunctionRecord &Function) {
+ return PassesThreshold(
+ FunctionCoverageSummary::get(Function).LineCoverage.getPercentCovered());
+}
+
+void CoverageFilters::push_back(std::unique_ptr<CoverageFilter> Filter) {
+ Filters.push_back(std::move(Filter));
+}
+
+bool CoverageFilters::matches(const coverage::FunctionRecord &Function) {
+ for (const auto &Filter : Filters) {
+ if (Filter->matches(Function))
+ return true;
+ }
+ return false;
+}
+
+bool
+CoverageFiltersMatchAll::matches(const coverage::FunctionRecord &Function) {
+ for (const auto &Filter : Filters) {
+ if (!Filter->matches(Function))
+ return false;
+ }
+ return true;
+}
diff --git a/tools/llvm-cov/CoverageFilters.h b/tools/llvm-cov/CoverageFilters.h
new file mode 100644
index 000000000000..dc5dc98807b1
--- /dev/null
+++ b/tools/llvm-cov/CoverageFilters.h
@@ -0,0 +1,127 @@
+//===- CoverageFilters.h - Function coverage mapping filters --------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These classes provide filtering for function coverage mapping records.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEFILTERS_H
+#define LLVM_COV_COVERAGEFILTERS_H
+
+#include "llvm/ProfileData/CoverageMapping.h"
+#include <memory>
+#include <vector>
+
+namespace llvm {
+
+/// \brief Matches specific functions that pass the requirement of this filter.
+class CoverageFilter {
+public:
+ virtual ~CoverageFilter() {}
+
+ /// \brief Return true if the function passes the requirements of this filter.
+ virtual bool matches(const coverage::FunctionRecord &Function) {
+ return true;
+ }
+};
+
+/// \brief Matches functions that contain a specific string in their name.
+class NameCoverageFilter : public CoverageFilter {
+ StringRef Name;
+
+public:
+ NameCoverageFilter(StringRef Name) : Name(Name) {}
+
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+/// \brief Matches functions whose name matches a certain regular expression.
+class NameRegexCoverageFilter : public CoverageFilter {
+ StringRef Regex;
+
+public:
+ NameRegexCoverageFilter(StringRef Regex) : Regex(Regex) {}
+
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+/// \brief Matches numbers that pass a certain threshold.
+template <typename T> class StatisticThresholdFilter {
+public:
+ enum Operation { LessThan, GreaterThan };
+
+protected:
+ Operation Op;
+ T Threshold;
+
+ StatisticThresholdFilter(Operation Op, T Threshold)
+ : Op(Op), Threshold(Threshold) {}
+
+ /// \brief Return true if the given number is less than
+ /// or greater than the certain threshold.
+ bool PassesThreshold(T Value) const {
+ switch (Op) {
+ case LessThan:
+ return Value < Threshold;
+ case GreaterThan:
+ return Value > Threshold;
+ }
+ return false;
+ }
+};
+
+/// \brief Matches functions whose region coverage percentage
+/// is above/below a certain percentage.
+class RegionCoverageFilter : public CoverageFilter,
+ public StatisticThresholdFilter<double> {
+public:
+ RegionCoverageFilter(Operation Op, double Threshold)
+ : StatisticThresholdFilter(Op, Threshold) {}
+
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+/// \brief Matches functions whose line coverage percentage
+/// is above/below a certain percentage.
+class LineCoverageFilter : public CoverageFilter,
+ public StatisticThresholdFilter<double> {
+public:
+ LineCoverageFilter(Operation Op, double Threshold)
+ : StatisticThresholdFilter(Op, Threshold) {}
+
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+/// \brief A collection of filters.
+/// Matches functions that match any filters contained
+/// in an instance of this class.
+class CoverageFilters : public CoverageFilter {
+protected:
+ std::vector<std::unique_ptr<CoverageFilter>> Filters;
+
+public:
+ /// \brief Append a filter to this collection.
+ void push_back(std::unique_ptr<CoverageFilter> Filter);
+
+ bool empty() const { return Filters.empty(); }
+
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+/// \brief A collection of filters.
+/// Matches functions that match all of the filters contained
+/// in an instance of this class.
+class CoverageFiltersMatchAll : public CoverageFilters {
+public:
+ bool matches(const coverage::FunctionRecord &Function) override;
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_COVERAGEFILTERS_H
diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp
new file mode 100644
index 000000000000..6ae6ba55eb9c
--- /dev/null
+++ b/tools/llvm-cov/CoverageReport.cpp
@@ -0,0 +1,202 @@
+//===- CoverageReport.cpp - Code coverage report -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering of a code coverage report.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageReport.h"
+#include "CoverageSummary.h"
+#include "RenderingSupport.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+namespace {
+/// \brief Helper struct which prints trimmed and aligned columns.
+struct Column {
+ enum TrimKind { NoTrim, LeftTrim, RightTrim };
+
+ enum AlignmentKind { LeftAlignment, RightAlignment };
+
+ StringRef Str;
+ unsigned Width;
+ TrimKind Trim;
+ AlignmentKind Alignment;
+
+ Column(StringRef Str, unsigned Width)
+ : Str(Str), Width(Width), Trim(NoTrim), Alignment(LeftAlignment) {}
+
+ Column &set(TrimKind Value) {
+ Trim = Value;
+ return *this;
+ }
+
+ Column &set(AlignmentKind Value) {
+ Alignment = Value;
+ return *this;
+ }
+
+ void render(raw_ostream &OS) const;
+};
+raw_ostream &operator<<(raw_ostream &OS, const Column &Value) {
+ Value.render(OS);
+ return OS;
+}
+}
+
+void Column::render(raw_ostream &OS) const {
+ if (Str.size() <= Width) {
+ if (Alignment == RightAlignment) {
+ OS.indent(Width - Str.size());
+ OS << Str;
+ return;
+ }
+ OS << Str;
+ OS.indent(Width - Str.size());
+ return;
+ }
+
+ switch (Trim) {
+ case NoTrim:
+ OS << Str.substr(0, Width);
+ break;
+ case LeftTrim:
+ OS << "..." << Str.substr(Str.size() - Width + 3);
+ break;
+ case RightTrim:
+ OS << Str.substr(0, Width - 3) << "...";
+ break;
+ }
+}
+
+static Column column(StringRef Str, unsigned Width) {
+ return Column(Str, Width);
+}
+
+template <typename T>
+static Column column(StringRef Str, unsigned Width, const T &Value) {
+ return Column(Str, Width).set(Value);
+}
+
+static const unsigned FileReportColumns[] = {25, 10, 8, 8, 10, 10};
+static const unsigned FunctionReportColumns[] = {25, 10, 8, 8, 10, 8, 8};
+
+/// \brief Prints a horizontal divider which spans across the given columns.
+template <typename T, size_t N>
+static void renderDivider(T (&Columns)[N], raw_ostream &OS) {
+ unsigned Length = 0;
+ for (unsigned I = 0; I < N; ++I)
+ Length += Columns[I];
+ for (unsigned I = 0; I < Length; ++I)
+ OS << '-';
+}
+
+/// \brief Return the color which correponds to the coverage
+/// percentage of a certain metric.
+template <typename T>
+static raw_ostream::Colors determineCoveragePercentageColor(const T &Info) {
+ if (Info.isFullyCovered())
+ return raw_ostream::GREEN;
+ return Info.getPercentCovered() >= 80.0 ? raw_ostream::YELLOW
+ : raw_ostream::RED;
+}
+
+void CoverageReport::render(const FileCoverageSummary &File, raw_ostream &OS) {
+ OS << column(File.Name, FileReportColumns[0], Column::LeftTrim)
+ << format("%*u", FileReportColumns[1], (unsigned)File.RegionCoverage.NumRegions);
+ Options.colored_ostream(OS, File.RegionCoverage.isFullyCovered()
+ ? raw_ostream::GREEN
+ : raw_ostream::RED)
+ << format("%*u", FileReportColumns[2], (unsigned)File.RegionCoverage.NotCovered);
+ Options.colored_ostream(OS,
+ determineCoveragePercentageColor(File.RegionCoverage))
+ << format("%*.2f", FileReportColumns[3] - 1,
+ File.RegionCoverage.getPercentCovered()) << '%';
+ OS << format("%*u", FileReportColumns[4],
+ (unsigned)File.FunctionCoverage.NumFunctions);
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(File.FunctionCoverage))
+ << format("%*.2f", FileReportColumns[5] - 1,
+ File.FunctionCoverage.getPercentCovered()) << '%';
+ OS << "\n";
+}
+
+void CoverageReport::render(const FunctionCoverageSummary &Function,
+ raw_ostream &OS) {
+ OS << column(Function.Name, FunctionReportColumns[0], Column::RightTrim)
+ << format("%*u", FunctionReportColumns[1],
+ (unsigned)Function.RegionCoverage.NumRegions);
+ Options.colored_ostream(OS, Function.RegionCoverage.isFullyCovered()
+ ? raw_ostream::GREEN
+ : raw_ostream::RED)
+ << format("%*u", FunctionReportColumns[2],
+ (unsigned)Function.RegionCoverage.NotCovered);
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.RegionCoverage))
+ << format("%*.2f", FunctionReportColumns[3] - 1,
+ Function.RegionCoverage.getPercentCovered()) << '%';
+ OS << format("%*u", FunctionReportColumns[4],
+ (unsigned)Function.LineCoverage.NumLines);
+ Options.colored_ostream(OS, Function.LineCoverage.isFullyCovered()
+ ? raw_ostream::GREEN
+ : raw_ostream::RED)
+ << format("%*u", FunctionReportColumns[5],
+ (unsigned)Function.LineCoverage.NotCovered);
+ Options.colored_ostream(
+ OS, determineCoveragePercentageColor(Function.LineCoverage))
+ << format("%*.2f", FunctionReportColumns[6] - 1,
+ Function.LineCoverage.getPercentCovered()) << '%';
+ OS << "\n";
+}
+
+void CoverageReport::renderFunctionReports(raw_ostream &OS) {
+ bool isFirst = true;
+ for (const auto &File : Summary.getFileSummaries()) {
+ if (isFirst)
+ isFirst = false;
+ else
+ OS << "\n";
+ OS << "File '" << File.Name << "':\n";
+ OS << column("Name", FunctionReportColumns[0])
+ << column("Regions", FunctionReportColumns[1], Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[2], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[3], Column::RightAlignment)
+ << column("Lines", FunctionReportColumns[4], Column::RightAlignment)
+ << column("Miss", FunctionReportColumns[5], Column::RightAlignment)
+ << column("Cover", FunctionReportColumns[6], Column::RightAlignment);
+ OS << "\n";
+ renderDivider(FunctionReportColumns, OS);
+ OS << "\n";
+ for (const auto &Function : File.FunctionSummaries)
+ render(Function, OS);
+ renderDivider(FunctionReportColumns, OS);
+ OS << "\n";
+ render(FunctionCoverageSummary("TOTAL", /*ExecutionCount=*/0,
+ File.RegionCoverage, File.LineCoverage),
+ OS);
+ }
+}
+
+void CoverageReport::renderFileReports(raw_ostream &OS) {
+ OS << column("Filename", FileReportColumns[0])
+ << column("Regions", FileReportColumns[1], Column::RightAlignment)
+ << column("Miss", FileReportColumns[2], Column::RightAlignment)
+ << column("Cover", FileReportColumns[3], Column::RightAlignment)
+ << column("Functions", FileReportColumns[4], Column::RightAlignment)
+ << column("Executed", FileReportColumns[5], Column::RightAlignment)
+ << "\n";
+ renderDivider(FileReportColumns, OS);
+ OS << "\n";
+ for (const auto &File : Summary.getFileSummaries())
+ render(File, OS);
+ renderDivider(FileReportColumns, OS);
+ OS << "\n";
+ render(Summary.getCombinedFileSummaries(), OS);
+}
diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h
new file mode 100644
index 000000000000..d18611740ae6
--- /dev/null
+++ b/tools/llvm-cov/CoverageReport.h
@@ -0,0 +1,40 @@
+//===- CoverageReport.h - Code coverage report ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering of a code coverage report.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEREPORT_H
+#define LLVM_COV_COVERAGEREPORT_H
+
+#include "CoverageSummary.h"
+#include "CoverageViewOptions.h"
+
+namespace llvm {
+
+/// \brief Displays the code coverage report.
+class CoverageReport {
+ const CoverageViewOptions &Options;
+ CoverageSummary &Summary;
+
+ 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) {}
+
+ void renderFunctionReports(raw_ostream &OS);
+
+ void renderFileReports(raw_ostream &OS);
+};
+}
+
+#endif // LLVM_COV_COVERAGEREPORT_H
diff --git a/tools/llvm-cov/CoverageSummary.cpp b/tools/llvm-cov/CoverageSummary.cpp
new file mode 100644
index 000000000000..059c8c857e45
--- /dev/null
+++ b/tools/llvm-cov/CoverageSummary.cpp
@@ -0,0 +1,64 @@
+//===- 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
new file mode 100644
index 000000000000..9dbebde949e5
--- /dev/null
+++ b/tools/llvm-cov/CoverageSummary.h
@@ -0,0 +1,45 @@
+//===- 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
new file mode 100644
index 000000000000..dd78ace86050
--- /dev/null
+++ b/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -0,0 +1,96 @@
+//===- CoverageSummaryInfo.cpp - Coverage summary for function/file -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These structures are used to represent code coverage metrics
+// for functions/files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CoverageSummaryInfo.h"
+
+using namespace llvm;
+using namespace coverage;
+
+FunctionCoverageSummary
+FunctionCoverageSummary::get(const coverage::FunctionRecord &Function) {
+ // Compute the region coverage
+ size_t NumCodeRegions = 0, CoveredRegions = 0;
+ for (auto &CR : Function.CountedRegions) {
+ if (CR.Kind != CounterMappingRegion::CodeRegion)
+ continue;
+ ++NumCodeRegions;
+ if (CR.ExecutionCount != 0)
+ ++CoveredRegions;
+ }
+
+ // Compute the line coverage
+ size_t NumLines = 0, CoveredLines = 0;
+ for (unsigned FileID = 0, E = Function.Filenames.size(); FileID < E;
+ ++FileID) {
+ // Find the line start and end of the function's source code
+ // in that particular file
+ unsigned LineStart = std::numeric_limits<unsigned>::max();
+ unsigned LineEnd = 0;
+ for (auto &CR : Function.CountedRegions) {
+ if (CR.FileID != FileID)
+ continue;
+ LineStart = std::min(LineStart, CR.LineStart);
+ LineEnd = std::max(LineEnd, CR.LineEnd);
+ }
+ unsigned LineCount = LineEnd - LineStart + 1;
+
+ // Get counters
+ llvm::SmallVector<uint64_t, 16> ExecutionCounts;
+ ExecutionCounts.resize(LineCount, 0);
+ for (auto &CR : Function.CountedRegions) {
+ if (CR.FileID != FileID)
+ continue;
+ // Ignore the lines that were skipped by the preprocessor.
+ auto ExecutionCount = CR.ExecutionCount;
+ if (CR.Kind == CounterMappingRegion::SkippedRegion) {
+ LineCount -= CR.LineEnd - CR.LineStart + 1;
+ ExecutionCount = 1;
+ }
+ for (unsigned I = CR.LineStart; I <= CR.LineEnd; ++I)
+ ExecutionCounts[I - LineStart] = ExecutionCount;
+ }
+ CoveredLines += LineCount - std::count(ExecutionCounts.begin(),
+ ExecutionCounts.end(), 0);
+ NumLines += LineCount;
+ }
+ return FunctionCoverageSummary(
+ Function.Name, Function.ExecutionCount,
+ 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
new file mode 100644
index 000000000000..0036032ab399
--- /dev/null
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -0,0 +1,133 @@
+//===- CoverageSummaryInfo.h - Coverage summary for function/file ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// These structures are used to represent code coverage metrics
+// for functions/files.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGESUMMARYINFO_H
+#define LLVM_COV_COVERAGESUMMARYINFO_H
+
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+/// \brief Provides information about region coverage for a function/file.
+struct RegionCoverageInfo {
+ /// \brief The number of regions that were executed at least once.
+ size_t Covered;
+
+ /// \brief The number of regions that weren't executed.
+ size_t NotCovered;
+
+ /// \brief The total number of regions in a function/file.
+ size_t NumRegions;
+
+ RegionCoverageInfo(size_t Covered, size_t NumRegions)
+ : Covered(Covered), NotCovered(NumRegions - Covered),
+ NumRegions(NumRegions) {}
+
+ bool isFullyCovered() const { return Covered == NumRegions; }
+
+ double getPercentCovered() const {
+ return double(Covered) / double(NumRegions) * 100.0;
+ }
+};
+
+/// \brief Provides information about line coverage for a function/file.
+struct LineCoverageInfo {
+ /// \brief The number of lines that were executed at least once.
+ size_t Covered;
+
+ /// \brief The number of lines that weren't executed.
+ size_t NotCovered;
+
+ /// \brief The number of lines that aren't code.
+ size_t NonCodeLines;
+
+ /// \brief The total number of lines in a function/file.
+ size_t NumLines;
+
+ LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines)
+ : Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered),
+ NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
+
+ bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
+
+ double getPercentCovered() const {
+ return double(Covered) / double(NumLines - NonCodeLines) * 100.0;
+ }
+};
+
+/// \brief Provides information about function coverage for a file.
+struct FunctionCoverageInfo {
+ /// \brief The number of functions that were executed.
+ size_t Executed;
+
+ /// \brief The total number of functions in this file.
+ size_t NumFunctions;
+
+ FunctionCoverageInfo(size_t Executed, size_t NumFunctions)
+ : Executed(Executed), NumFunctions(NumFunctions) {}
+
+ bool isFullyCovered() const { return Executed == NumFunctions; }
+
+ double getPercentCovered() const {
+ return double(Executed) / double(NumFunctions) * 100.0;
+ }
+};
+
+/// \brief A summary of function's code coverage.
+struct FunctionCoverageSummary {
+ StringRef Name;
+ uint64_t ExecutionCount;
+ RegionCoverageInfo RegionCoverage;
+ LineCoverageInfo LineCoverage;
+
+ FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount,
+ const RegionCoverageInfo &RegionCoverage,
+ const LineCoverageInfo &LineCoverage)
+ : Name(Name), ExecutionCount(ExecutionCount),
+ RegionCoverage(RegionCoverage), LineCoverage(LineCoverage) {
+ }
+
+ /// \brief Compute the code coverage summary for the given function coverage
+ /// mapping record.
+ static FunctionCoverageSummary
+ get(const coverage::FunctionRecord &Function);
+};
+
+/// \brief A summary of file's code coverage.
+struct FileCoverageSummary {
+ StringRef Name;
+ 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);
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_COVERAGESUMMARYINFO_H
diff --git a/tools/llvm-cov/CoverageViewOptions.h b/tools/llvm-cov/CoverageViewOptions.h
new file mode 100644
index 000000000000..94b55fe793fc
--- /dev/null
+++ b/tools/llvm-cov/CoverageViewOptions.h
@@ -0,0 +1,36 @@
+//===- CoverageViewOptions.h - Code coverage display options -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_COVERAGEVIEWOPTIONS_H
+#define LLVM_COV_COVERAGEVIEWOPTIONS_H
+
+#include "RenderingSupport.h"
+
+namespace llvm {
+
+/// \brief The options for displaying the code coverage information.
+struct CoverageViewOptions {
+ bool Debug;
+ bool Colors;
+ bool ShowLineNumbers;
+ bool ShowLineStats;
+ bool ShowRegionMarkers;
+ bool ShowLineStatsOrRegionMarkers;
+ bool ShowExpandedRegions;
+ bool ShowFunctionInstantiations;
+
+ /// \brief Change the output's stream color if the colors are enabled.
+ ColoredRawOstream colored_ostream(raw_ostream &OS,
+ raw_ostream::Colors Color) const {
+ return llvm::colored_ostream(OS, Color, Colors);
+ }
+};
+}
+
+#endif // LLVM_COV_COVERAGEVIEWOPTIONS_H
diff --git a/tools/llvm-cov/LLVMBuild.txt b/tools/llvm-cov/LLVMBuild.txt
index 87e00d170f90..d6eb74de0d4b 100644
--- a/tools/llvm-cov/LLVMBuild.txt
+++ b/tools/llvm-cov/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-cov
parent = Tools
-required_libraries = Instrumentation
+required_libraries = ProfileData Support Instrumentation
diff --git a/tools/llvm-cov/Makefile b/tools/llvm-cov/Makefile
index efed6cc7942e..6e32b4d233d7 100644
--- a/tools/llvm-cov/Makefile
+++ b/tools/llvm-cov/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-cov
-LINK_COMPONENTS := core support
+LINK_COMPONENTS := core support profiledata object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-cov/RenderingSupport.h b/tools/llvm-cov/RenderingSupport.h
new file mode 100644
index 000000000000..0271329997dc
--- /dev/null
+++ b/tools/llvm-cov/RenderingSupport.h
@@ -0,0 +1,60 @@
+//===- RenderingSupport.h - output stream rendering support functions ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_RENDERINGSUPPORT_H
+#define LLVM_COV_RENDERINGSUPPORT_H
+
+#include "llvm/Support/raw_ostream.h"
+#include <utility>
+
+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;
+
+public:
+ raw_ostream &OS;
+ bool IsColorUsed;
+
+ ColoredRawOstream(raw_ostream &OS, bool IsColorUsed)
+ : OS(OS), IsColorUsed(IsColorUsed) {}
+
+ ColoredRawOstream(ColoredRawOstream &&Other)
+ : OS(Other.OS), IsColorUsed(Other.IsColorUsed) {
+ // Reset the other IsColorUsed so that the other object won't reset the
+ // color when destroyed.
+ Other.IsColorUsed = false;
+ }
+
+ ~ColoredRawOstream() {
+ if (IsColorUsed)
+ OS.resetColor();
+ }
+};
+
+template <typename T>
+inline raw_ostream &operator<<(const ColoredRawOstream &OS, T &&Value) {
+ return OS.OS << std::forward<T>(Value);
+}
+
+/// \brief Change the color of the output stream if the `IsColorUsed` flag
+/// is true. Returns an object that resets the color when destroyed.
+inline ColoredRawOstream colored_ostream(raw_ostream &OS,
+ raw_ostream::Colors Color,
+ bool IsColorUsed = true,
+ bool Bold = false, bool BG = false) {
+ if (IsColorUsed)
+ OS.changeColor(Color, Bold, BG);
+ return ColoredRawOstream(OS, IsColorUsed);
+}
+}
+
+#endif // LLVM_COV_RENDERINGSUPPORT_H
diff --git a/tools/llvm-cov/SourceCoverageView.cpp b/tools/llvm-cov/SourceCoverageView.cpp
new file mode 100644
index 000000000000..015099c7d02b
--- /dev/null
+++ b/tools/llvm-cov/SourceCoverageView.cpp
@@ -0,0 +1,260 @@
+//===- SourceCoverageView.cpp - Code coverage view for source code --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering for code coverage of source code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SourceCoverageView.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/LineIterator.h"
+
+using namespace llvm;
+
+void SourceCoverageView::renderLine(
+ raw_ostream &OS, StringRef Line, int64_t LineNumber,
+ const coverage::CoverageSegment *WrappedSegment,
+ ArrayRef<const coverage::CoverageSegment *> Segments,
+ unsigned ExpansionCol) {
+ Optional<raw_ostream::Colors> Highlight;
+ SmallVector<std::pair<unsigned, unsigned>, 2> HighlightedRanges;
+
+ // The first segment overlaps from a previous line, so we treat it specially.
+ if (WrappedSegment && WrappedSegment->HasCount && WrappedSegment->Count == 0)
+ Highlight = raw_ostream::RED;
+
+ // Output each segment of the line, possibly highlighted.
+ unsigned Col = 1;
+ for (const auto *S : Segments) {
+ unsigned End = std::min(S->Col, static_cast<unsigned>(Line.size()) + 1);
+ colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
+ Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
+ << Line.substr(Col - 1, End - Col);
+ if (Options.Debug && Highlight)
+ HighlightedRanges.push_back(std::make_pair(Col, End));
+ Col = End;
+ if (Col == ExpansionCol)
+ Highlight = raw_ostream::CYAN;
+ else if (S->HasCount && S->Count == 0)
+ Highlight = raw_ostream::RED;
+ else
+ Highlight = None;
+ }
+
+ // Show the rest of the line
+ colored_ostream(OS, Highlight ? *Highlight : raw_ostream::SAVEDCOLOR,
+ Options.Colors && Highlight, /*Bold=*/false, /*BG=*/true)
+ << Line.substr(Col - 1, Line.size() - Col + 1);
+ OS << "\n";
+
+ if (Options.Debug) {
+ for (const auto &Range : HighlightedRanges)
+ errs() << "Highlighted line " << LineNumber << ", " << Range.first
+ << " -> " << Range.second << "\n";
+ if (Highlight)
+ errs() << "Highlighted line " << LineNumber << ", " << Col << " -> ?\n";
+ }
+}
+
+void SourceCoverageView::renderIndent(raw_ostream &OS, unsigned Level) {
+ for (unsigned I = 0; I < Level; ++I)
+ OS << " |";
+}
+
+void SourceCoverageView::renderViewDivider(unsigned Level, unsigned Length,
+ raw_ostream &OS) {
+ assert(Level != 0 && "Cannot render divider at top level");
+ renderIndent(OS, Level - 1);
+ OS.indent(2);
+ for (unsigned I = 0; I < Length; ++I)
+ OS << "-";
+}
+
+void
+SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
+ const LineCoverageInfo &Line) {
+ if (!Line.isMapped()) {
+ OS.indent(LineCoverageColumnWidth) << '|';
+ return;
+ }
+ SmallString<32> Buffer;
+ raw_svector_ostream BufferOS(Buffer);
+ BufferOS << Line.ExecutionCount;
+ auto Str = BufferOS.str();
+ // Trim
+ Str = Str.substr(0, std::min(Str.size(), (size_t)LineCoverageColumnWidth));
+ // Align to the right
+ OS.indent(LineCoverageColumnWidth - Str.size());
+ colored_ostream(OS, raw_ostream::MAGENTA,
+ Line.hasMultipleRegions() && Options.Colors)
+ << Str;
+ OS << '|';
+}
+
+void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
+ unsigned LineNo) {
+ SmallString<32> Buffer;
+ raw_svector_ostream BufferOS(Buffer);
+ BufferOS << LineNo;
+ auto Str = BufferOS.str();
+ // Trim and align to the right
+ Str = Str.substr(0, std::min(Str.size(), (size_t)LineNumberColumnWidth));
+ OS.indent(LineNumberColumnWidth - Str.size()) << Str << '|';
+}
+
+void SourceCoverageView::renderRegionMarkers(
+ raw_ostream &OS, ArrayRef<const coverage::CoverageSegment *> Segments) {
+ SmallString<32> Buffer;
+ raw_svector_ostream BufferOS(Buffer);
+
+ unsigned PrevColumn = 1;
+ for (const auto *S : Segments) {
+ if (!S->IsRegionEntry)
+ continue;
+ // Skip to the new region
+ if (S->Col > PrevColumn)
+ OS.indent(S->Col - PrevColumn);
+ PrevColumn = S->Col + 1;
+ BufferOS << S->Count;
+ StringRef Str = BufferOS.str();
+ // Trim the execution count
+ Str = Str.substr(0, std::min(Str.size(), (size_t)7));
+ PrevColumn += Str.size();
+ OS << '^' << Str;
+ Buffer.clear();
+ }
+ OS << "\n";
+
+ if (Options.Debug)
+ for (const auto *S : Segments)
+ errs() << "Marker at " << S->Line << ":" << S->Col << " = " << S->Count
+ << (S->IsRegionEntry ? "\n" : " (pop)\n");
+}
+
+void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
+ unsigned IndentLevel) {
+ // The width of the leading columns
+ unsigned CombinedColumnWidth =
+ (Options.ShowLineStats ? LineCoverageColumnWidth + 1 : 0) +
+ (Options.ShowLineNumbers ? LineNumberColumnWidth + 1 : 0);
+ // The width of the line that is used to divide between the view and the
+ // subviews.
+ unsigned DividerWidth = CombinedColumnWidth + 4;
+
+ // We need the expansions and instantiations sorted so we can go through them
+ // while we iterate lines.
+ std::sort(ExpansionSubViews.begin(), ExpansionSubViews.end());
+ std::sort(InstantiationSubViews.begin(), InstantiationSubViews.end());
+ auto NextESV = ExpansionSubViews.begin();
+ auto EndESV = ExpansionSubViews.end();
+ auto NextISV = InstantiationSubViews.begin();
+ auto EndISV = InstantiationSubViews.end();
+
+ // Get the coverage information for the file.
+ auto NextSegment = CoverageInfo.begin();
+ auto EndSegment = CoverageInfo.end();
+
+ unsigned FirstLine = NextSegment != EndSegment ? NextSegment->Line : 0;
+ const coverage::CoverageSegment *WrappedSegment = nullptr;
+ SmallVector<const coverage::CoverageSegment *, 8> LineSegments;
+ for (line_iterator LI(File, /*SkipBlanks=*/false); !LI.is_at_eof(); ++LI) {
+ // If we aren't rendering the whole file, we need to filter out the prologue
+ // and epilogue.
+ if (!WholeFile) {
+ if (NextSegment == EndSegment)
+ break;
+ else if (LI.line_number() < FirstLine)
+ continue;
+ }
+
+ // Collect the coverage information relevant to this line.
+ if (LineSegments.size())
+ WrappedSegment = LineSegments.back();
+ LineSegments.clear();
+ while (NextSegment != EndSegment && NextSegment->Line == LI.line_number())
+ LineSegments.push_back(&*NextSegment++);
+
+ // Calculate a count to be for the line as a whole.
+ LineCoverageInfo LineCount;
+ if (WrappedSegment && WrappedSegment->HasCount)
+ LineCount.addRegionCount(WrappedSegment->Count);
+ for (const auto *S : LineSegments)
+ if (S->HasCount && S->IsRegionEntry)
+ LineCount.addRegionStartCount(S->Count);
+
+ // Render the line prefix.
+ renderIndent(OS, IndentLevel);
+ if (Options.ShowLineStats)
+ renderLineCoverageColumn(OS, LineCount);
+ if (Options.ShowLineNumbers)
+ renderLineNumberColumn(OS, LI.line_number());
+
+ // If there are expansion subviews, we want to highlight the first one.
+ unsigned ExpansionColumn = 0;
+ if (NextESV != EndESV && NextESV->getLine() == LI.line_number() &&
+ Options.Colors)
+ ExpansionColumn = NextESV->getStartCol();
+
+ // Display the source code for the current line.
+ renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
+ ExpansionColumn);
+
+ // Show the region markers.
+ if (Options.ShowRegionMarkers && (!Options.ShowLineStatsOrRegionMarkers ||
+ LineCount.hasMultipleRegions()) &&
+ !LineSegments.empty()) {
+ renderIndent(OS, IndentLevel);
+ OS.indent(CombinedColumnWidth);
+ renderRegionMarkers(OS, LineSegments);
+ }
+
+ // Show the expansions and instantiations for this line.
+ unsigned NestedIndent = IndentLevel + 1;
+ bool RenderedSubView = false;
+ for (; NextESV != EndESV && NextESV->getLine() == LI.line_number();
+ ++NextESV) {
+ renderViewDivider(NestedIndent, DividerWidth, OS);
+ OS << "\n";
+ if (RenderedSubView) {
+ // Re-render the current line and highlight the expansion range for
+ // this subview.
+ ExpansionColumn = NextESV->getStartCol();
+ renderIndent(OS, IndentLevel);
+ OS.indent(CombinedColumnWidth + (IndentLevel == 0 ? 0 : 1));
+ renderLine(OS, *LI, LI.line_number(), WrappedSegment, LineSegments,
+ ExpansionColumn);
+ renderViewDivider(NestedIndent, DividerWidth, OS);
+ OS << "\n";
+ }
+ // Render the child subview
+ if (Options.Debug)
+ errs() << "Expansion at line " << NextESV->getLine() << ", "
+ << NextESV->getStartCol() << " -> " << NextESV->getEndCol()
+ << "\n";
+ NextESV->View->render(OS, false, NestedIndent);
+ RenderedSubView = true;
+ }
+ for (; NextISV != EndISV && NextISV->Line == LI.line_number(); ++NextISV) {
+ renderViewDivider(NestedIndent, DividerWidth, OS);
+ OS << "\n";
+ renderIndent(OS, NestedIndent);
+ OS << ' ';
+ Options.colored_ostream(OS, raw_ostream::CYAN) << NextISV->FunctionName
+ << ":";
+ OS << "\n";
+ NextISV->View->render(OS, false, NestedIndent);
+ RenderedSubView = true;
+ }
+ if (RenderedSubView) {
+ renderViewDivider(NestedIndent, DividerWidth, OS);
+ OS << "\n";
+ }
+ }
+}
diff --git a/tools/llvm-cov/SourceCoverageView.h b/tools/llvm-cov/SourceCoverageView.h
new file mode 100644
index 000000000000..d92a7486d9d3
--- /dev/null
+++ b/tools/llvm-cov/SourceCoverageView.h
@@ -0,0 +1,162 @@
+//===- SourceCoverageView.h - Code coverage view for source code ----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class implements rendering for code coverage of source code.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_COV_SOURCECOVERAGEVIEW_H
+#define LLVM_COV_SOURCECOVERAGEVIEW_H
+
+#include "CoverageViewOptions.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <vector>
+
+namespace llvm {
+
+class SourceCoverageView;
+
+/// \brief A view that represents a macro or include expansion
+struct ExpansionView {
+ coverage::CounterMappingRegion Region;
+ std::unique_ptr<SourceCoverageView> View;
+
+ ExpansionView(const coverage::CounterMappingRegion &Region,
+ std::unique_ptr<SourceCoverageView> View)
+ : Region(Region), View(std::move(View)) {}
+ ExpansionView(ExpansionView &&RHS)
+ : Region(std::move(RHS.Region)), View(std::move(RHS.View)) {}
+ ExpansionView &operator=(ExpansionView &&RHS) {
+ Region = std::move(RHS.Region);
+ View = std::move(RHS.View);
+ return *this;
+ }
+
+ unsigned getLine() const { return Region.LineStart; }
+ unsigned getStartCol() const { return Region.ColumnStart; }
+ unsigned getEndCol() const { return Region.ColumnEnd; }
+
+ friend bool operator<(const ExpansionView &LHS, const ExpansionView &RHS) {
+ return LHS.Region.startLoc() < RHS.Region.startLoc();
+ }
+};
+
+/// \brief A view that represents a function instantiation
+struct InstantiationView {
+ StringRef FunctionName;
+ unsigned Line;
+ std::unique_ptr<SourceCoverageView> View;
+
+ InstantiationView(StringRef FunctionName, unsigned Line,
+ std::unique_ptr<SourceCoverageView> View)
+ : FunctionName(FunctionName), Line(Line), View(std::move(View)) {}
+ InstantiationView(InstantiationView &&RHS)
+ : FunctionName(std::move(RHS.FunctionName)), Line(std::move(RHS.Line)),
+ View(std::move(RHS.View)) {}
+ InstantiationView &operator=(InstantiationView &&RHS) {
+ FunctionName = std::move(RHS.FunctionName);
+ Line = std::move(RHS.Line);
+ View = std::move(RHS.View);
+ return *this;
+ }
+
+ friend bool operator<(const InstantiationView &LHS,
+ const InstantiationView &RHS) {
+ return LHS.Line < RHS.Line;
+ }
+};
+
+/// \brief A code coverage view of a specific source file.
+/// It can have embedded coverage views.
+class SourceCoverageView {
+private:
+ /// \brief Coverage information for a single line.
+ struct LineCoverageInfo {
+ uint64_t ExecutionCount;
+ unsigned RegionCount;
+ bool Mapped;
+
+ LineCoverageInfo() : ExecutionCount(0), RegionCount(0), Mapped(false) {}
+
+ bool isMapped() const { return Mapped; }
+
+ bool hasMultipleRegions() const { return RegionCount > 1; }
+
+ void addRegionStartCount(uint64_t Count) {
+ Mapped = true;
+ ExecutionCount = Count;
+ ++RegionCount;
+ }
+
+ void addRegionCount(uint64_t Count) {
+ Mapped = true;
+ if (!RegionCount)
+ ExecutionCount = Count;
+ }
+ };
+
+ const MemoryBuffer &File;
+ const CoverageViewOptions &Options;
+ coverage::CoverageData CoverageInfo;
+ std::vector<ExpansionView> ExpansionSubViews;
+ std::vector<InstantiationView> InstantiationSubViews;
+
+ /// \brief Render a source line with highlighting.
+ void renderLine(raw_ostream &OS, StringRef Line, int64_t LineNumber,
+ const coverage::CoverageSegment *WrappedSegment,
+ ArrayRef<const coverage::CoverageSegment *> Segments,
+ unsigned ExpansionCol);
+
+ void renderIndent(raw_ostream &OS, unsigned Level);
+
+ void renderViewDivider(unsigned Offset, unsigned Length, raw_ostream &OS);
+
+ /// \brief Render the line's execution count column.
+ void renderLineCoverageColumn(raw_ostream &OS, const LineCoverageInfo &Line);
+
+ /// \brief Render the line number column.
+ void renderLineNumberColumn(raw_ostream &OS, unsigned LineNo);
+
+ /// \brief Render all the region's execution counts on a line.
+ void
+ renderRegionMarkers(raw_ostream &OS,
+ ArrayRef<const coverage::CoverageSegment *> Segments);
+
+ static const unsigned LineCoverageColumnWidth = 7;
+ static const unsigned LineNumberColumnWidth = 5;
+
+public:
+ SourceCoverageView(const MemoryBuffer &File,
+ const CoverageViewOptions &Options,
+ coverage::CoverageData &&CoverageInfo)
+ : File(File), Options(Options), CoverageInfo(std::move(CoverageInfo)) {}
+
+ const CoverageViewOptions &getOptions() const { return Options; }
+
+ /// \brief Add an expansion subview to this view.
+ void addExpansion(const coverage::CounterMappingRegion &Region,
+ std::unique_ptr<SourceCoverageView> View) {
+ ExpansionSubViews.emplace_back(Region, std::move(View));
+ }
+
+ /// \brief Add a function instantiation subview to this view.
+ void addInstantiation(StringRef FunctionName, unsigned Line,
+ std::unique_ptr<SourceCoverageView> View) {
+ InstantiationSubViews.emplace_back(FunctionName, Line, std::move(View));
+ }
+
+ /// \brief Print the code coverage information for a specific
+ /// portion of a source file to the output stream.
+ void render(raw_ostream &OS, bool WholeFile, unsigned IndentLevel = 0);
+};
+
+} // namespace llvm
+
+#endif // LLVM_COV_SOURCECOVERAGEVIEW_H
diff --git a/tools/llvm-cov/TestingSupport.cpp b/tools/llvm-cov/TestingSupport.cpp
new file mode 100644
index 000000000000..6959897482ca
--- /dev/null
+++ b/tools/llvm-cov/TestingSupport.cpp
@@ -0,0 +1,90 @@
+//===- TestingSupport.cpp - Convert objects files into test files --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <functional>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+int convertForTestingMain(int argc, const char *argv[]) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::opt<std::string> InputSourceFile(cl::Positional, cl::Required,
+ cl::desc("<Source file>"));
+
+ cl::opt<std::string> OutputFilename(
+ "o", cl::Required,
+ cl::desc(
+ "File with the profile data obtained after an instrumented run"));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
+
+ auto ObjErr = llvm::object::ObjectFile::createObjectFile(InputSourceFile);
+ if (auto Err = ObjErr.getError()) {
+ errs() << "error: " << Err.message() << "\n";
+ return 1;
+ }
+ ObjectFile *OF = ObjErr.get().getBinary();
+ auto BytesInAddress = OF->getBytesInAddress();
+ if (BytesInAddress != 8) {
+ errs() << "error: 64 bit binary expected\n";
+ return 1;
+ }
+
+ // Look for the sections that we are interested in.
+ int FoundSectionCount = 0;
+ SectionRef ProfileNames, CoverageMapping;
+ for (const auto &Section : OF->sections()) {
+ StringRef Name;
+ if (Section.getName(Name))
+ return 1;
+ if (Name == "__llvm_prf_names") {
+ ProfileNames = Section;
+ } else if (Name == "__llvm_covmap") {
+ CoverageMapping = Section;
+ } else
+ continue;
+ ++FoundSectionCount;
+ }
+ if (FoundSectionCount != 2)
+ return 1;
+
+ // Get the contents of the given sections.
+ uint64_t ProfileNamesAddress = ProfileNames.getAddress();
+ StringRef CoverageMappingData;
+ StringRef ProfileNamesData;
+ if (CoverageMapping.getContents(CoverageMappingData) ||
+ ProfileNames.getContents(ProfileNamesData))
+ return 1;
+
+ int FD;
+ if (auto Err =
+ sys::fs::openFileForWrite(OutputFilename, FD, sys::fs::F_None)) {
+ errs() << "error: " << Err.message() << "\n";
+ return 1;
+ }
+
+ raw_fd_ostream OS(FD, true);
+ OS << "llvmcovmtestdata";
+ encodeULEB128(ProfileNamesData.size(), OS);
+ encodeULEB128(ProfileNamesAddress, OS);
+ OS << ProfileNamesData << CoverageMappingData;
+
+ return 0;
+}
diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp
new file mode 100644
index 000000000000..12011cea7f26
--- /dev/null
+++ b/tools/llvm-cov/gcov.cpp
@@ -0,0 +1,152 @@
+//===- gcov.cpp - GCOV compatible LLVM coverage tool ----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// llvm-cov is a command line tools to analyze and report coverage information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/GCOV.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include <system_error>
+using namespace llvm;
+
+void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
+ const std::string &InputGCNO, const std::string &InputGCDA,
+ bool DumpGCOV, const GCOVOptions &Options) {
+ SmallString<128> CoverageFileStem(ObjectDir);
+ if (CoverageFileStem.empty()) {
+ // If no directory was specified with -o, look next to the source file.
+ CoverageFileStem = sys::path::parent_path(SourceFile);
+ sys::path::append(CoverageFileStem, sys::path::stem(SourceFile));
+ } else if (sys::fs::is_directory(ObjectDir))
+ // A directory name was given. Use it and the source file name.
+ sys::path::append(CoverageFileStem, sys::path::stem(SourceFile));
+ else
+ // A file was given. Ignore the source file and look next to this file.
+ sys::path::replace_extension(CoverageFileStem, "");
+
+ std::string GCNO = InputGCNO.empty()
+ ? std::string(CoverageFileStem.str()) + ".gcno"
+ : InputGCNO;
+ std::string GCDA = InputGCDA.empty()
+ ? std::string(CoverageFileStem.str()) + ".gcda"
+ : InputGCDA;
+ GCOVFile GF;
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff =
+ MemoryBuffer::getFileOrSTDIN(GCNO);
+ if (std::error_code EC = GCNO_Buff.getError()) {
+ errs() << GCNO << ": " << EC.message() << "\n";
+ return;
+ }
+ GCOVBuffer GCNO_GB(GCNO_Buff.get().get());
+ if (!GF.readGCNO(GCNO_GB)) {
+ errs() << "Invalid .gcno File!\n";
+ return;
+ }
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff =
+ MemoryBuffer::getFileOrSTDIN(GCDA);
+ if (std::error_code EC = GCDA_Buff.getError()) {
+ if (EC != errc::no_such_file_or_directory) {
+ errs() << GCDA << ": " << EC.message() << "\n";
+ return;
+ }
+ // Clear the filename to make it clear we didn't read anything.
+ GCDA = "-";
+ } else {
+ GCOVBuffer GCDA_GB(GCDA_Buff.get().get());
+ if (!GF.readGCDA(GCDA_GB)) {
+ errs() << "Invalid .gcda File!\n";
+ return;
+ }
+ }
+
+ if (DumpGCOV)
+ GF.dump();
+
+ FileInfo FI(Options);
+ GF.collectLineCounts(FI);
+ FI.print(SourceFile, GCNO, GCDA);
+}
+
+int gcovMain(int argc, const char *argv[]) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::list<std::string> SourceFiles(cl::Positional, cl::OneOrMore,
+ cl::desc("SOURCEFILE"));
+
+ cl::opt<bool> AllBlocks("a", cl::Grouping, cl::init(false),
+ cl::desc("Display all basic blocks"));
+ cl::alias AllBlocksA("all-blocks", cl::aliasopt(AllBlocks));
+
+ cl::opt<bool> BranchProb("b", cl::Grouping, cl::init(false),
+ cl::desc("Display branch probabilities"));
+ cl::alias BranchProbA("branch-probabilities", cl::aliasopt(BranchProb));
+
+ cl::opt<bool> BranchCount("c", cl::Grouping, cl::init(false),
+ cl::desc("Display branch counts instead "
+ "of percentages (requires -b)"));
+ cl::alias BranchCountA("branch-counts", cl::aliasopt(BranchCount));
+
+ cl::opt<bool> LongNames("l", cl::Grouping, cl::init(false),
+ cl::desc("Prefix filenames with the main file"));
+ cl::alias LongNamesA("long-file-names", cl::aliasopt(LongNames));
+
+ cl::opt<bool> FuncSummary("f", cl::Grouping, cl::init(false),
+ cl::desc("Show coverage for each function"));
+ cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary));
+
+ cl::opt<bool> NoOutput("n", cl::Grouping, cl::init(false),
+ cl::desc("Do not output any .gcov files"));
+ cl::alias NoOutputA("no-output", cl::aliasopt(NoOutput));
+
+ cl::opt<std::string> ObjectDir(
+ "o", cl::value_desc("DIR|FILE"), cl::init(""),
+ cl::desc("Find objects in DIR or based on FILE's path"));
+ cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir));
+ cl::alias ObjectDirB("object-file", cl::aliasopt(ObjectDir));
+
+ cl::opt<bool> PreservePaths("p", cl::Grouping, cl::init(false),
+ cl::desc("Preserve path components"));
+ cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths));
+
+ cl::opt<bool> UncondBranch("u", cl::Grouping, cl::init(false),
+ cl::desc("Display unconditional branch info "
+ "(requires -b)"));
+ cl::alias UncondBranchA("unconditional-branches", cl::aliasopt(UncondBranch));
+
+ cl::OptionCategory DebugCat("Internal and debugging options");
+ cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat),
+ cl::desc("Dump the gcov file to stderr"));
+ cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""),
+ cl::desc("Override inferred gcno file"));
+ cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""),
+ cl::desc("Override inferred gcda file"));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
+
+ GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
+ PreservePaths, UncondBranch, LongNames, NoOutput);
+
+ for (const auto &SourceFile : SourceFiles)
+ reportCoverage(SourceFile, ObjectDir, InputGCNO, InputGCDA, DumpGCOV,
+ Options);
+ return 0;
+}
diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp
index 18cc1b110e23..86ec26dbd188 100644
--- a/tools/llvm-cov/llvm-cov.cpp
+++ b/tools/llvm-cov/llvm-cov.cpp
@@ -11,140 +11,68 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/GCOV.h"
-#include "llvm/Support/ManagedStatic.h"
-#include "llvm/Support/MemoryObject.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Path.h"
-#include "llvm/Support/PrettyStackTrace.h"
-#include "llvm/Support/Signals.h"
-#include <system_error>
-using namespace llvm;
-
-static cl::list<std::string> SourceFiles(cl::Positional, cl::OneOrMore,
- cl::desc("SOURCEFILE"));
-
-static cl::opt<bool> AllBlocks("a", cl::Grouping, cl::init(false),
- cl::desc("Display all basic blocks"));
-static cl::alias AllBlocksA("all-blocks", cl::aliasopt(AllBlocks));
-
-static cl::opt<bool> BranchProb("b", cl::Grouping, cl::init(false),
- cl::desc("Display branch probabilities"));
-static cl::alias BranchProbA("branch-probabilities", cl::aliasopt(BranchProb));
-
-static cl::opt<bool> BranchCount("c", cl::Grouping, cl::init(false),
- cl::desc("Display branch counts instead "
- "of percentages (requires -b)"));
-static cl::alias BranchCountA("branch-counts", cl::aliasopt(BranchCount));
-
-static cl::opt<bool> LongNames("l", cl::Grouping, cl::init(false),
- cl::desc("Prefix filenames with the main file"));
-static cl::alias LongNamesA("long-file-names", cl::aliasopt(LongNames));
+#include "llvm/Support/raw_ostream.h"
+#include <string>
-static cl::opt<bool> FuncSummary("f", cl::Grouping, cl::init(false),
- cl::desc("Show coverage for each function"));
-static cl::alias FuncSummaryA("function-summaries", cl::aliasopt(FuncSummary));
-
-static cl::opt<bool> NoOutput("n", cl::Grouping, cl::init(false),
- cl::desc("Do not output any .gcov files"));
-static cl::alias NoOutputA("no-output", cl::aliasopt(NoOutput));
-
-static cl::opt<std::string>
-ObjectDir("o", cl::value_desc("DIR|FILE"), cl::init(""),
- cl::desc("Find objects in DIR or based on FILE's path"));
-static cl::alias ObjectDirA("object-directory", cl::aliasopt(ObjectDir));
-static cl::alias ObjectDirB("object-file", cl::aliasopt(ObjectDir));
-
-static cl::opt<bool> PreservePaths("p", cl::Grouping, cl::init(false),
- cl::desc("Preserve path components"));
-static cl::alias PreservePathsA("preserve-paths", cl::aliasopt(PreservePaths));
+using namespace llvm;
-static cl::opt<bool> UncondBranch("u", cl::Grouping, cl::init(false),
- cl::desc("Display unconditional branch info "
- "(requires -b)"));
-static cl::alias UncondBranchA("unconditional-branches",
- cl::aliasopt(UncondBranch));
+/// \brief The main entry point for the 'show' subcommand.
+int showMain(int argc, const char *argv[]);
-static cl::OptionCategory DebugCat("Internal and debugging options");
-static cl::opt<bool> DumpGCOV("dump", cl::init(false), cl::cat(DebugCat),
- cl::desc("Dump the gcov file to stderr"));
-static cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""),
- cl::desc("Override inferred gcno file"));
-static cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""),
- cl::desc("Override inferred gcda file"));
+/// \brief The main entry point for the 'report' subcommand.
+int reportMain(int argc, const char *argv[]);
-void reportCoverage(StringRef SourceFile) {
- SmallString<128> CoverageFileStem(ObjectDir);
- if (CoverageFileStem.empty()) {
- // If no directory was specified with -o, look next to the source file.
- CoverageFileStem = sys::path::parent_path(SourceFile);
- sys::path::append(CoverageFileStem, sys::path::stem(SourceFile));
- } else if (sys::fs::is_directory(ObjectDir))
- // A directory name was given. Use it and the source file name.
- sys::path::append(CoverageFileStem, sys::path::stem(SourceFile));
- else
- // A file was given. Ignore the source file and look next to this file.
- sys::path::replace_extension(CoverageFileStem, "");
+/// \brief The main entry point for the 'convert-for-testing' subcommand.
+int convertForTestingMain(int argc, const char *argv[]);
- std::string GCNO = InputGCNO.empty()
- ? std::string(CoverageFileStem.str()) + ".gcno"
- : InputGCNO;
- std::string GCDA = InputGCDA.empty()
- ? std::string(CoverageFileStem.str()) + ".gcda"
- : InputGCDA;
- GCOVFile GF;
+/// \brief The main entry point for the gcov compatible coverage tool.
+int gcovMain(int argc, const char *argv[]);
- ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff =
- MemoryBuffer::getFileOrSTDIN(GCNO);
- if (std::error_code EC = GCNO_Buff.getError()) {
- errs() << GCNO << ": " << EC.message() << "\n";
- return;
- }
- GCOVBuffer GCNO_GB(GCNO_Buff.get().get());
- if (!GF.readGCNO(GCNO_GB)) {
- errs() << "Invalid .gcno File!\n";
- return;
- }
+/// \brief Top level help.
+int helpMain(int argc, const char *argv[]) {
+ errs() << "OVERVIEW: LLVM code coverage tool\n\n"
+ << "USAGE: llvm-cov {gcov|report|show}\n";
+ return 0;
+}
- ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff =
- MemoryBuffer::getFileOrSTDIN(GCDA);
- if (std::error_code EC = GCDA_Buff.getError()) {
- if (EC != errc::no_such_file_or_directory) {
- errs() << GCDA << ": " << EC.message() << "\n";
- return;
- }
- // Clear the filename to make it clear we didn't read anything.
- GCDA = "-";
- } else {
- GCOVBuffer GCDA_GB(GCDA_Buff.get().get());
- if (!GF.readGCDA(GCDA_GB)) {
- errs() << "Invalid .gcda File!\n";
- return;
+int main(int argc, const char **argv) {
+ // If argv[0] is or ends with 'gcov', always be gcov compatible
+ if (sys::path::stem(argv[0]).endswith_lower("gcov"))
+ return gcovMain(argc, argv);
+
+ // Check if we are invoking a specific tool command.
+ if (argc > 1) {
+ typedef int (*MainFunction)(int, const char *[]);
+ MainFunction Func = StringSwitch<MainFunction>(argv[1])
+ .Case("convert-for-testing", convertForTestingMain)
+ .Case("gcov", gcovMain)
+ .Case("report", reportMain)
+ .Case("show", showMain)
+ .Cases("-h", "-help", "--help", helpMain)
+ .Default(nullptr);
+
+ if (Func) {
+ std::string Invocation = std::string(argv[0]) + " " + argv[1];
+ argv[1] = Invocation.c_str();
+ return Func(argc - 1, argv + 1);
}
}
- if (DumpGCOV)
- GF.dump();
-
- GCOVOptions Options(AllBlocks, BranchProb, BranchCount, FuncSummary,
- PreservePaths, UncondBranch, LongNames, NoOutput);
- FileInfo FI(Options);
- GF.collectLineCounts(FI);
- FI.print(SourceFile, GCNO, GCDA);
-}
-
-int main(int argc, char **argv) {
- // Print a stack trace if we signal out.
- sys::PrintStackTraceOnErrorSignal();
- PrettyStackTraceProgram X(argc, argv);
- llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
-
- cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
-
- for (const auto &SourceFile : SourceFiles)
- reportCoverage(SourceFile);
- return 0;
+ // Give a warning and fall back to gcov
+ errs().changeColor(raw_ostream::RED);
+ errs() << "warning:";
+ // Assume that argv[1] wasn't a command when it stats with a '-' or is a
+ // filename (i.e. contains a '.')
+ if (argc > 1 && !StringRef(argv[1]).startswith("-") &&
+ StringRef(argv[1]).find(".") == StringRef::npos)
+ errs() << " Unrecognized command '" << argv[1] << "'.";
+ errs() << " Using the gcov compatible mode "
+ "(this behaviour may be dropped in the future).";
+ errs().resetColor();
+ errs() << "\n";
+
+ return gcovMain(argc, argv);
}
diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h
index ac13a5e3e5cc..855f6884e65b 100644
--- a/tools/llvm-diff/DiffConsumer.h
+++ b/tools/llvm-diff/DiffConsumer.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LLVM_DIFFCONSUMER_H_
-#define _LLVM_DIFFCONSUMER_H_
+#ifndef LLVM_TOOLS_LLVM_DIFF_DIFFCONSUMER_H
+#define LLVM_TOOLS_LLVM_DIFF_DIFFCONSUMER_H
#include "DiffLog.h"
#include "llvm/ADT/DenseMap.h"
diff --git a/tools/llvm-diff/DiffLog.h b/tools/llvm-diff/DiffLog.h
index 43e318ac4e9f..8eb53ffffccf 100644
--- a/tools/llvm-diff/DiffLog.h
+++ b/tools/llvm-diff/DiffLog.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LLVM_DIFFLOG_H_
-#define _LLVM_DIFFLOG_H_
+#ifndef LLVM_TOOLS_LLVM_DIFF_DIFFLOG_H
+#define LLVM_TOOLS_LLVM_DIFF_DIFFLOG_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h
index 44709685a365..f0d831144a4c 100644
--- a/tools/llvm-diff/DifferenceEngine.h
+++ b/tools/llvm-diff/DifferenceEngine.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef _LLVM_DIFFERENCE_ENGINE_H_
-#define _LLVM_DIFFERENCE_ENGINE_H_
+#ifndef LLVM_TOOLS_LLVM_DIFF_DIFFERENCEENGINE_H
+#define LLVM_TOOLS_LLVM_DIFF_DIFFERENCEENGINE_H
#include "DiffConsumer.h"
#include "DiffLog.h"
diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp
index f70219eaf542..ae58f5caa913 100644
--- a/tools/llvm-diff/llvm-diff.cpp
+++ b/tools/llvm-diff/llvm-diff.cpp
@@ -32,21 +32,22 @@ using namespace llvm;
/// Reads a module from a file. On error, messages are written to stderr
/// and null is returned.
-static Module *ReadModule(LLVMContext &Context, StringRef Name) {
+static std::unique_ptr<Module> readModule(LLVMContext &Context,
+ StringRef Name) {
SMDiagnostic Diag;
- Module *M = ParseIRFile(Name, Diag, Context);
+ std::unique_ptr<Module> M = parseIRFile(Name, Diag, Context);
if (!M)
Diag.print("llvm-diff", errs());
return M;
}
-static void diffGlobal(DifferenceEngine &Engine, Module *L, Module *R,
+static void diffGlobal(DifferenceEngine &Engine, Module &L, Module &R,
StringRef Name) {
// Drop leading sigils from the global name.
if (Name.startswith("@")) Name = Name.substr(1);
- Function *LFn = L->getFunction(Name);
- Function *RFn = R->getFunction(Name);
+ Function *LFn = L.getFunction(Name);
+ Function *RFn = R.getFunction(Name);
if (LFn && RFn)
Engine.diff(LFn, RFn);
else if (!LFn && !RFn)
@@ -72,8 +73,8 @@ int main(int argc, char **argv) {
LLVMContext Context;
// Load both modules. Die if that fails.
- Module *LModule = ReadModule(Context, LeftFilename);
- Module *RModule = ReadModule(Context, RightFilename);
+ std::unique_ptr<Module> LModule = readModule(Context, LeftFilename);
+ std::unique_ptr<Module> RModule = readModule(Context, RightFilename);
if (!LModule || !RModule) return 1;
DiffConsumer Consumer;
@@ -82,15 +83,12 @@ int main(int argc, char **argv) {
// If any global names were given, just diff those.
if (!GlobalsToCompare.empty()) {
for (unsigned I = 0, E = GlobalsToCompare.size(); I != E; ++I)
- diffGlobal(Engine, LModule, RModule, GlobalsToCompare[I]);
+ diffGlobal(Engine, *LModule, *RModule, GlobalsToCompare[I]);
// Otherwise, diff everything in the module.
} else {
- Engine.diff(LModule, RModule);
+ Engine.diff(LModule.get(), RModule.get());
}
- delete LModule;
- delete RModule;
-
return Consumer.hadDifferences();
}
diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp
index 3b0f838f1d73..1349ecc85a4c 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,17 @@ public:
} // end anon namespace
+static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
+ assert(DI.getSeverity() == DS_Error && "Only expecting errors");
+
+ raw_ostream &OS = errs();
+ OS << (char *)Context << ": ";
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ OS << '\n';
+ exit(1);
+}
+
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
@@ -120,6 +133,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 +141,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.
@@ -171,11 +172,11 @@ int main(int argc, char **argv) {
}
}
- std::string ErrorInfo;
+ std::error_code EC;
std::unique_ptr<tool_output_file> Out(
- new tool_output_file(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ new tool_output_file(OutputFilename, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index f44b0e3ef5ed..cff8216403b7 100644
--- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -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"
@@ -45,6 +44,10 @@ DumpType("debug-dump", cl::init(DIDT_All),
clEnumValN(DIDT_All, "all", "Dump all debug sections"),
clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"),
clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"),
+ clEnumValN(DIDT_AppleNames, "apple_names", ".apple_names"),
+ clEnumValN(DIDT_AppleTypes, "apple_types", ".apple_types"),
+ clEnumValN(DIDT_AppleNamespaces, "apple_namespaces", ".apple_namespaces"),
+ clEnumValN(DIDT_AppleObjC, "apple_objc", ".apple_objc"),
clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"),
clEnumValN(DIDT_Info, "info", ".debug_info"),
clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"),
@@ -65,26 +68,28 @@ DumpType("debug-dump", cl::init(DIDT_All),
clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"),
clEnumValEnd));
-static void DumpInput(const StringRef &Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buff =
+static void DumpInput(StringRef Filename) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = Buff.getError()) {
+ if (std::error_code EC = BuffOrErr.getError()) {
errs() << Filename << ": " << EC.message() << "\n";
return;
}
+ std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
- ErrorOr<ObjectFile *> ObjOrErr(ObjectFile::createObjectFile(Buff.get()));
+ ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr =
+ ObjectFile::createObjectFile(Buff->getMemBufferRef());
if (std::error_code EC = ObjOrErr.getError()) {
errs() << Filename << ": " << EC.message() << '\n';
return;
}
- std::unique_ptr<ObjectFile> Obj(ObjOrErr.get());
+ ObjectFile &Obj = *ObjOrErr.get();
- std::unique_ptr<DIContext> DICtx(DIContext::getDWARFContext(Obj.get()));
+ std::unique_ptr<DIContext> DICtx(DIContext::getDWARFContext(Obj));
outs() << Filename
- << ":\tfile format " << Obj->getFileFormatName() << "\n\n";
+ << ":\tfile format " << Obj.getFileFormatName() << "\n\n";
// Dump the complete DWARF structure.
DICtx->dump(outs(), DumpType);
}
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 0f7086802a41..53b2f0d00f41 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -101,8 +101,7 @@ int main(int argc, char **argv) {
// Use lazy loading, since we only care about selected global values.
SMDiagnostic Err;
- std::unique_ptr<Module> M;
- M.reset(getLazyIRFileModule(InputFilename, Err, Context));
+ std::unique_ptr<Module> M = getLazyIRFileModule(InputFilename, Err, Context);
if (!M.get()) {
Err.print(argv[0], errs());
@@ -217,31 +216,28 @@ int main(int argc, char **argv) {
if (!DeleteFn)
for (size_t i = 0, e = GVs.size(); i != e; ++i) {
GlobalValue *GV = GVs[i];
- if (GV->isMaterializable()) {
- std::string ErrInfo;
- if (GV->Materialize(&ErrInfo)) {
- errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
- return 1;
- }
+ if (std::error_code EC = GV->materialize()) {
+ errs() << argv[0] << ": error reading input: " << EC.message() << "\n";
+ return 1;
}
}
else {
// Deleting. Materialize every GV that's *not* in GVs.
SmallPtrSet<GlobalValue *, 8> GVSet(GVs.begin(), GVs.end());
for (auto &G : M->globals()) {
- if (!GVSet.count(&G) && G.isMaterializable()) {
- std::string ErrInfo;
- if (G.Materialize(&ErrInfo)) {
- errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
+ if (!GVSet.count(&G)) {
+ if (std::error_code EC = G.materialize()) {
+ errs() << argv[0] << ": error reading input: " << EC.message()
+ << "\n";
return 1;
}
}
}
for (auto &F : *M) {
- if (!GVSet.count(&F) && F.isMaterializable()) {
- std::string ErrInfo;
- if (F.Materialize(&ErrInfo)) {
- errs() << argv[0] << ": error reading input: " << ErrInfo << "\n";
+ if (!GVSet.count(&F)) {
+ if (std::error_code EC = F.materialize()) {
+ errs() << argv[0] << ": error reading input: " << EC.message()
+ << "\n";
return 1;
}
}
@@ -251,7 +247,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;
- Passes.add(new DataLayoutPass(M.get())); // Use correct DataLayout
+ Passes.add(new DataLayoutPass()); // Use correct DataLayout
std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
@@ -261,10 +257,10 @@ int main(int argc, char **argv) {
Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info
Passes.add(createStripDeadPrototypesPass()); // Remove dead func decls
- std::string ErrorInfo;
- tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None);
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ std::error_code EC;
+ tool_output_file Out(OutputFilename, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
diff --git a/tools/llvm-go/CMakeLists.txt b/tools/llvm-go/CMakeLists.txt
new file mode 100644
index 000000000000..20393f728f8f
--- /dev/null
+++ b/tools/llvm-go/CMakeLists.txt
@@ -0,0 +1,9 @@
+if(LLVM_BINDINGS MATCHES "go")
+ set(binpath ${CMAKE_BINARY_DIR}/bin/llvm-go${CMAKE_EXECUTABLE_SUFFIX})
+ add_custom_command(OUTPUT ${binpath}
+ COMMAND ${GO_EXECUTABLE} build -o ${binpath} llvm-go.go
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/llvm-go.go
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ COMMENT "Building Go executable llvm-go")
+ add_custom_target(llvm-go ALL DEPENDS ${binpath})
+endif()
diff --git a/tools/llvm-go/Makefile b/tools/llvm-go/Makefile
new file mode 100644
index 000000000000..4465b2a4a9db
--- /dev/null
+++ b/tools/llvm-go/Makefile
@@ -0,0 +1,16 @@
+##===- tools/llvm-go/Makefile ------------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+include $(LEVEL)/Makefile.common
+
+all:: $(ToolDir)/llvm-go$(EXEEXT)
+
+$(ToolDir)/llvm-go$(EXEEXT): $(PROJ_SRC_DIR)/llvm-go.go
+ $(GO) build -o $@ $<
diff --git a/tools/llvm-go/llvm-go.go b/tools/llvm-go/llvm-go.go
new file mode 100644
index 000000000000..cf520bd90e9d
--- /dev/null
+++ b/tools/llvm-go/llvm-go.go
@@ -0,0 +1,290 @@
+//===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool lets us build LLVM components within the tree by setting up a
+// $GOPATH that resembles a tree fetched in the normal way with "go get".
+//
+//===----------------------------------------------------------------------===//
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+type pkg struct {
+ llvmpath, pkgpath string
+}
+
+var packages = []pkg{
+ {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
+ {"tools/llgo", "llvm.org/llgo"},
+}
+
+type compilerFlags struct {
+ cpp, cxx, ld string
+}
+
+var components = []string{
+ "all-targets",
+ "analysis",
+ "asmparser",
+ "asmprinter",
+ "bitreader",
+ "bitwriter",
+ "codegen",
+ "core",
+ "debuginfo",
+ "executionengine",
+ "instrumentation",
+ "interpreter",
+ "ipo",
+ "irreader",
+ "linker",
+ "mc",
+ "mcjit",
+ "objcarcopts",
+ "option",
+ "profiledata",
+ "scalaropts",
+ "support",
+ "target",
+}
+
+func llvmConfig(args ...string) string {
+ configpath := os.Getenv("LLVM_CONFIG")
+ if configpath == "" {
+ // strip llvm-go, add llvm-config
+ configpath = os.Args[0][:len(os.Args[0])-7] + "llvm-config"
+ }
+
+ cmd := exec.Command(configpath, args...)
+ out, err := cmd.Output()
+ if err != nil {
+ panic(err.Error())
+ }
+
+ outstr := string(out)
+ outstr = strings.TrimSuffix(outstr, "\n")
+ return strings.Replace(outstr, "\n", " ", -1)
+}
+
+func llvmFlags() compilerFlags {
+ ldflags := llvmConfig(append([]string{"--ldflags", "--libs", "--system-libs"}, components...)...)
+ if runtime.GOOS != "darwin" {
+ // OS X doesn't like -rpath with cgo. See:
+ // https://code.google.com/p/go/issues/detail?id=7293
+ ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
+ }
+ return compilerFlags{
+ cpp: llvmConfig("--cppflags"),
+ cxx: "-std=c++11",
+ ld: ldflags,
+ }
+}
+
+func addTag(args []string, tag string) []string {
+ args = append([]string{}, args...)
+ addedTag := false
+ for i, a := range args {
+ if strings.HasPrefix(a, "-tags=") {
+ args[i] = a + " " + tag
+ addedTag = true
+ } else if a == "-tags" && i+1 < len(args) {
+ args[i+1] = args[i+1] + " " + tag
+ addedTag = true
+ }
+ }
+ if !addedTag {
+ args = append([]string{args[0], "-tags", tag}, args[1:]...)
+ }
+ return args
+}
+
+func printComponents() {
+ fmt.Println(strings.Join(components, " "))
+}
+
+func printConfig() {
+ flags := llvmFlags()
+
+ fmt.Printf(`// +build !byollvm
+
+// This file is generated by llvm-go, do not edit.
+
+package llvm
+
+/*
+#cgo CPPFLAGS: %s
+#cgo CXXFLAGS: %s
+#cgo LDFLAGS: %s
+*/
+import "C"
+
+type (run_build_sh int)
+`, flags.cpp, flags.cxx, flags.ld)
+}
+
+func runGoWithLLVMEnv(args []string, cc, cxx, llgo, cppflags, cxxflags, ldflags string) {
+ args = addTag(args, "byollvm")
+
+ srcdir := llvmConfig("--src-root")
+
+ tmpgopath, err := ioutil.TempDir("", "gopath")
+ if err != nil {
+ panic(err.Error())
+ }
+
+ for _, p := range packages {
+ path := filepath.Join(tmpgopath, "src", p.pkgpath)
+ err := os.MkdirAll(filepath.Dir(path), os.ModePerm)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ err = os.Symlink(filepath.Join(srcdir, p.llvmpath), path)
+ if err != nil {
+ panic(err.Error())
+ }
+ }
+
+ newpath := os.Getenv("PATH")
+
+ if llgo != "" {
+ bindir := filepath.Join(tmpgopath, "bin")
+
+ err = os.MkdirAll(bindir, os.ModePerm)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ err = os.Symlink(llgo, filepath.Join(bindir, "gccgo"))
+ if err != nil {
+ panic(err.Error())
+ }
+
+ newpathlist := []string{bindir}
+ newpathlist = append(newpathlist, filepath.SplitList(newpath)...)
+ newpath = strings.Join(newpathlist, string(filepath.ListSeparator))
+
+ args = append([]string{args[0], "-compiler", "gccgo"}, args[1:]...)
+ }
+
+ newgopathlist := []string{tmpgopath}
+ newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
+ newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
+
+ flags := llvmFlags()
+
+ newenv := []string{
+ "CC=" + cc,
+ "CXX=" + cxx,
+ "CGO_CPPFLAGS=" + flags.cpp + " " + cppflags,
+ "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags,
+ "CGO_LDFLAGS=" + flags.ld + " " + ldflags,
+ "GOPATH=" + newgopath,
+ "PATH=" + newpath,
+ }
+ 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, "PATH=") {
+ newenv = append(newenv, v)
+ }
+ }
+
+ gocmdpath, err := exec.LookPath("go")
+ if err != nil {
+ panic(err.Error())
+ }
+
+ proc, err := os.StartProcess(gocmdpath, append([]string{"go"}, args...),
+ &os.ProcAttr{
+ Env: newenv,
+ Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
+ })
+ if err != nil {
+ panic(err.Error())
+ }
+ ps, err := proc.Wait()
+ if err != nil {
+ panic(err.Error())
+ }
+
+ os.RemoveAll(tmpgopath)
+
+ if !ps.Success() {
+ os.Exit(1)
+ }
+}
+
+func usage() {
+ fmt.Println(`Usage: llvm-go subcommand [flags]
+
+Available subcommands: build get install run test print-components print-config`)
+ os.Exit(0)
+}
+
+func main() {
+ cc := os.Getenv("CC")
+ cxx := os.Getenv("CXX")
+ cppflags := os.Getenv("CGO_CPPFLAGS")
+ cxxflags := os.Getenv("CGO_CXXFLAGS")
+ ldflags := os.Getenv("CGO_LDFLAGS")
+ llgo := ""
+
+ args := os.Args[1:]
+ DONE: for {
+ switch {
+ case len(args) == 0:
+ usage()
+ case strings.HasPrefix(args[0], "cc="):
+ cc = args[0][3:]
+ args = args[1:]
+ case strings.HasPrefix(args[0], "cxx="):
+ cxx = args[0][4:]
+ 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:]
+ case strings.HasPrefix(args[0], "cxxflags="):
+ cxxflags = args[0][9:]
+ args = args[1:]
+ case strings.HasPrefix(args[0], "ldflags="):
+ ldflags = args[0][8:]
+ args = args[1:]
+ default:
+ break DONE
+ }
+ }
+
+ switch args[0] {
+ case "build", "get", "install", "run", "test":
+ runGoWithLLVMEnv(args, cc, cxx, llgo, cppflags, cxxflags, ldflags)
+ case "print-components":
+ printComponents()
+ case "print-config":
+ printConfig()
+ default:
+ usage()
+ }
+}
diff --git a/tools/llvm-jitlistener/CMakeLists.txt b/tools/llvm-jitlistener/CMakeLists.txt
index c9704fb22489..68a4303acef0 100644
--- a/tools/llvm-jitlistener/CMakeLists.txt
+++ b/tools/llvm-jitlistener/CMakeLists.txt
@@ -1,22 +1,21 @@
-# This tool is excluded from the CMake build if Intel JIT events are disabled.
-
-link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )
-include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} )
-
-set(LLVM_LINK_COMPONENTS
- asmparser
- bitreader
- debuginfo
- inteljitevents
- interpreter
- irreader
- jit
- mcjit
- nativecodegen
- object
- selectiondag
- )
-
-add_llvm_tool(llvm-jitlistener
- llvm-jitlistener.cpp
- )
+# This tool is excluded from the CMake build if Intel JIT events are disabled.
+
+link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )
+include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} )
+
+set(LLVM_LINK_COMPONENTS
+ asmparser
+ bitreader
+ debuginfo
+ inteljitevents
+ interpreter
+ irreader
+ mcjit
+ nativecodegen
+ object
+ selectiondag
+ )
+
+add_llvm_tool(llvm-jitlistener
+ llvm-jitlistener.cpp
+ )
diff --git a/tools/llvm-jitlistener/LLVMBuild.txt b/tools/llvm-jitlistener/LLVMBuild.txt
index 1ce78acecbb6..e6ed20b24030 100644
--- a/tools/llvm-jitlistener/LLVMBuild.txt
+++ b/tools/llvm-jitlistener/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-jitlistener
parent = Tools
-required_libraries = AsmParser BitReader IRReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native
+required_libraries = AsmParser BitReader IRReader Interpreter MCJIT NativeCodeGen Object SelectionDAG Native
diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile
index b13222731745..6d72427e96e8 100644
--- a/tools/llvm-jitlistener/Makefile
+++ b/tools/llvm-jitlistener/Makefile
@@ -12,7 +12,7 @@ TOOLNAME := llvm-jitlistener
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag Object
+LINK_COMPONENTS := mcjit interpreter nativecodegen bitreader asmparser irreader selectiondag Object
# If Intel JIT Events support is configured, link against the LLVM Intel JIT
# Events interface library. If not, this tool will do nothing useful, but it
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp
index c159aa506d6a..c3091a559550 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/JITMemoryManager.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"
@@ -113,26 +113,18 @@ protected:
// Parse the bitcode...
SMDiagnostic Err;
- TheModule = ParseIRFile(IRFile, Err, Context);
+ std::unique_ptr<Module> TheModule(parseIRFile(IRFile, Err, Context));
if (!TheModule) {
errs() << Err.getMessage();
return;
}
- // FIXME: This is using the default legacy JITMemoryManager because it
- // supports poison memory. At some point, we'll need to update this to
- // use an MCJIT-specific memory manager. It might be nice to have the
- // poison memory option there too.
- JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
+ RTDyldMemoryManager *MemMgr = new SectionMemoryManager();
if (!MemMgr) {
errs() << "Unable to create memory manager.";
return;
}
- // Tell the memory manager to poison freed memory so that accessing freed
- // memory is more easily tested.
- MemMgr->setPoisonMemory(true);
-
// Override the triple to generate ELF on Windows since that's supported
Triple Tuple(TheModule->getTargetTriple());
if (Tuple.getTriple().empty())
@@ -145,11 +137,10 @@ protected:
// Compile the IR
std::string Error;
- TheJIT.reset(EngineBuilder(TheModule)
+ TheJIT.reset(EngineBuilder(std::move(TheModule))
.setEngineKind(EngineKind::JIT)
.setErrorStr(&Error)
- .setJITMemoryManager(MemMgr)
- .setUseMCJIT(true)
+ .setMCJITMemoryManager(std::unique_ptr<RTDyldMemoryManager>(MemMgr))
.create());
if (Error.empty() == false)
errs() << Error;
@@ -160,8 +151,6 @@ protected:
}
LLVMContext Context; // Global ownership
- Module *TheModule; // Owned by ExecutionEngine.
- JITMemoryManager *JMM; // Owned by ExecutionEngine.
std::unique_ptr<ExecutionEngine> TheJIT;
public:
diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp
index ed8c06e79843..828b9bb8ef70 100644
--- a/tools/llvm-link/llvm-link.cpp
+++ b/tools/llvm-link/llvm-link.cpp
@@ -14,6 +14,8 @@
#include "llvm/Linker/Linker.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/DiagnosticInfo.h"
+#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
@@ -55,20 +57,39 @@ static cl::opt<bool>
SuppressWarnings("suppress-warnings", cl::desc("Suppress all linking warnings"),
cl::init(false));
-// LoadFile - Read the specified bitcode file in and return it. This routine
-// searches the link path for the specified file to try to find it...
+// Read the specified bitcode file in and return it. This routine searches the
+// link path for the specified file to try to find it...
//
-static inline Module *LoadFile(const char *argv0, const std::string &FN,
- LLVMContext& Context) {
+static std::unique_ptr<Module>
+loadFile(const char *argv0, const std::string &FN, LLVMContext &Context) {
SMDiagnostic Err;
if (Verbose) errs() << "Loading '" << FN << "'\n";
- Module* Result = nullptr;
+ std::unique_ptr<Module> Result = getLazyIRFileModule(FN, Err, Context);
+ if (!Result)
+ Err.print(argv0, errs());
- Result = ParseIRFile(FN, Err, Context);
- if (Result) return Result; // Load successful!
+ return Result;
+}
+
+static void diagnosticHandler(const DiagnosticInfo &DI) {
+ unsigned Severity = DI.getSeverity();
+ switch (Severity) {
+ case DS_Error:
+ errs() << "ERROR: ";
+ break;
+ case DS_Warning:
+ if (SuppressWarnings)
+ return;
+ errs() << "WARNING: ";
+ break;
+ case DS_Remark:
+ case DS_Note:
+ llvm_unreachable("Only expecting warnings and errors");
+ }
- Err.print(argv0, errs());
- return nullptr;
+ DiagnosticPrinterRawOStream DP(errs());
+ DI.print(DP);
+ errs() << '\n';
}
int main(int argc, char **argv) {
@@ -80,20 +101,11 @@ int main(int argc, char **argv) {
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm linker\n");
- unsigned BaseArg = 0;
- std::string ErrorMessage;
+ auto Composite = make_unique<Module>("llvm-link", Context);
+ Linker L(Composite.get(), diagnosticHandler);
- std::unique_ptr<Module> Composite(
- LoadFile(argv[0], InputFilenames[BaseArg], Context));
- if (!Composite.get()) {
- errs() << argv[0] << ": error loading file '"
- << InputFilenames[BaseArg] << "'\n";
- return 1;
- }
-
- Linker L(Composite.get(), SuppressWarnings);
- for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
- std::unique_ptr<Module> M(LoadFile(argv[0], InputFilenames[i], Context));
+ for (unsigned i = 0; i < InputFilenames.size(); ++i) {
+ std::unique_ptr<Module> M = loadFile(argv[0], InputFilenames[i], Context);
if (!M.get()) {
errs() << argv[0] << ": error loading file '" <<InputFilenames[i]<< "'\n";
return 1;
@@ -101,19 +113,16 @@ int main(int argc, char **argv) {
if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n";
- if (L.linkInModule(M.get(), &ErrorMessage)) {
- errs() << argv[0] << ": link error in '" << InputFilenames[i]
- << "': " << ErrorMessage << "\n";
+ if (L.linkInModule(M.get()))
return 1;
- }
}
if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;
- std::string ErrorInfo;
- tool_output_file Out(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None);
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ std::error_code EC;
+ tool_output_file Out(OutputFilename, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp
index 8b39f1285f5f..9cd031eaf8d3 100644
--- a/tools/llvm-lto/llvm-lto.cpp
+++ b/tools/llvm-lto/llvm-lto.cpp
@@ -38,6 +38,14 @@ static cl::opt<bool>
DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
cl::desc("Do not run the GVN load PRE pass"));
+static cl::opt<bool>
+DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
+ cl::desc("Do not run loop or slp vectorization during LTO"));
+
+static cl::opt<bool>
+UseDiagnosticHandler("use-diagnostic-handler", cl::init(false),
+ cl::desc("Use a diagnostic handler to test the handler interface"));
+
static cl::list<std::string>
InputFilenames(cl::Positional, cl::OneOrMore,
cl::desc("<input bitcode files>"));
@@ -57,12 +65,75 @@ 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"));
+
namespace {
struct ModuleInfo {
std::vector<bool> CanBeHidden;
};
}
+void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
+ const char *Msg, void *) {
+ switch (Severity) {
+ case LTO_DS_NOTE:
+ errs() << "note: ";
+ break;
+ case LTO_DS_REMARK:
+ errs() << "remark: ";
+ break;
+ case LTO_DS_ERROR:
+ errs() << "error: ";
+ break;
+ case LTO_DS_WARNING:
+ errs() << "warning: ";
+ break;
+ }
+ 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();
@@ -80,10 +151,16 @@ 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;
+ if (UseDiagnosticHandler)
+ CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
+
switch (RelocModel) {
case Reloc::Static:
CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_STATIC);
@@ -117,12 +194,8 @@ int main(int argc, char **argv) {
return 1;
}
-
- if (!CodeGen.addModule(Module.get(), error)) {
- errs() << argv[0] << ": error adding file '" << InputFilenames[i]
- << "': " << error << "\n";
+ if (!CodeGen.addModule(Module.get()))
return 1;
- }
unsigned NumSyms = Module->getSymbolCount();
for (unsigned I = 0; I < NumSyms; ++I) {
@@ -157,19 +230,20 @@ int main(int argc, char **argv) {
if (!OutputFilename.empty()) {
size_t len = 0;
std::string ErrorInfo;
- const void *Code = CodeGen.compile(&len, DisableOpt, DisableInline,
- DisableGVNLoadPRE, ErrorInfo);
+ const void *Code =
+ CodeGen.compile(&len, DisableOpt, DisableInline, DisableGVNLoadPRE,
+ DisableLTOVectorization, ErrorInfo);
if (!Code) {
errs() << argv[0]
<< ": error compiling the code: " << ErrorInfo << "\n";
return 1;
}
- raw_fd_ostream FileStream(OutputFilename.c_str(), ErrorInfo,
- sys::fs::F_None);
- if (!ErrorInfo.empty()) {
+ std::error_code EC;
+ raw_fd_ostream FileStream(OutputFilename, EC, sys::fs::F_None);
+ if (EC) {
errs() << argv[0] << ": error opening the file '" << OutputFilename
- << "': " << ErrorInfo << "\n";
+ << "': " << EC.message() << "\n";
return 1;
}
@@ -178,7 +252,8 @@ int main(int argc, char **argv) {
std::string ErrorInfo;
const char *OutputName = nullptr;
if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline,
- DisableGVNLoadPRE, ErrorInfo)) {
+ DisableGVNLoadPRE, DisableLTOVectorization,
+ ErrorInfo)) {
errs() << argv[0]
<< ": error compiling the code: " << ErrorInfo
<< "\n";
diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp
index 936759039874..5ffeffc07682 100644
--- a/tools/llvm-mc/Disassembler.cpp
+++ b/tools/llvm-mc/Disassembler.cpp
@@ -22,55 +22,35 @@
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/MemoryObject.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
-typedef std::vector<std::pair<unsigned char, const char*> > ByteArrayTy;
-
-namespace {
-class VectorMemoryObject : public MemoryObject {
-private:
- const ByteArrayTy &Bytes;
-public:
- VectorMemoryObject(const ByteArrayTy &bytes) : Bytes(bytes) {}
-
- uint64_t getBase() const override { return 0; }
- uint64_t getExtent() const override { return Bytes.size(); }
-
- int readByte(uint64_t Addr, uint8_t *Byte) const override {
- if (Addr >= getExtent())
- return -1;
- *Byte = Bytes[Addr].first;
- return 0;
- }
-};
-}
+typedef std::pair<std::vector<unsigned char>, std::vector<const char *>>
+ ByteArrayTy;
static bool PrintInsts(const MCDisassembler &DisAsm,
const ByteArrayTy &Bytes,
SourceMgr &SM, raw_ostream &Out,
MCStreamer &Streamer, bool InAtomicBlock,
const MCSubtargetInfo &STI) {
- // Wrap the vector in a MemoryObject.
- VectorMemoryObject memoryObject(Bytes);
+ ArrayRef<uint8_t> Data(Bytes.first.data(), Bytes.first.size());
// Disassemble it to strings.
uint64_t Size;
uint64_t Index;
- for (Index = 0; Index < Bytes.size(); Index += Size) {
+ for (Index = 0; Index < Bytes.first.size(); Index += Size) {
MCInst Inst;
MCDisassembler::DecodeStatus S;
- S = DisAsm.getInstruction(Inst, Size, memoryObject, Index,
+ S = DisAsm.getInstruction(Inst, Size, Data.slice(Index), Index,
/*REMOVE*/ nulls(), nulls());
switch (S) {
case MCDisassembler::Fail:
- SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
+ SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
SourceMgr::DK_Warning,
"invalid instruction encoding");
// Don't try to resynchronise the stream in a block
@@ -83,7 +63,7 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
break;
case MCDisassembler::SoftFail:
- SM.PrintMessage(SMLoc::getFromPointer(Bytes[Index].second),
+ SM.PrintMessage(SMLoc::getFromPointer(Bytes.second[Index]),
SourceMgr::DK_Warning,
"potentially undefined instruction encoding");
// Fall through
@@ -98,29 +78,23 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
}
static bool SkipToToken(StringRef &Str) {
- while (!Str.empty() && Str.find_first_not_of(" \t\r\n#,") != 0) {
+ for (;;) {
+ if (Str.empty())
+ return false;
+
// Strip horizontal whitespace and commas.
- if (size_t Pos = Str.find_first_not_of(" \t\r,")) {
+ if (size_t Pos = Str.find_first_not_of(" \t\r\n,")) {
Str = Str.substr(Pos);
+ continue;
}
- // If this is the end of a line or start of a comment, remove the rest of
- // the line.
- if (Str[0] == '\n' || Str[0] == '#') {
- // Strip to the end of line if we already processed any bytes on this
- // line. This strips the comment and/or the \n.
- if (Str[0] == '\n') {
- Str = Str.substr(1);
- } else {
+ // If this is the start of a comment, remove the rest of the line.
+ if (Str[0] == '#') {
Str = Str.substr(Str.find_first_of('\n'));
- if (!Str.empty())
- Str = Str.substr(1);
- }
continue;
}
+ return true;
}
-
- return !Str.empty();
}
@@ -143,11 +117,13 @@ static bool ByteArrayFromString(ByteArrayTy &ByteArray,
SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error,
"invalid input token");
Str = Str.substr(Str.find('\n'));
- ByteArray.clear();
+ ByteArray.first.clear();
+ ByteArray.second.clear();
continue;
}
- ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data()));
+ ByteArray.first.push_back(ByteVal);
+ ByteArray.second.push_back(Value.data());
Str = Str.substr(Next);
}
@@ -185,7 +161,7 @@ int Disassembler::disassemble(const Target &T,
}
// Set up initial section manually here
- Streamer.InitSections();
+ Streamer.InitSections(false);
bool ErrorOccurred = false;
@@ -195,7 +171,8 @@ int Disassembler::disassemble(const Target &T,
bool InAtomicBlock = false;
while (SkipToToken(Str)) {
- ByteArray.clear();
+ ByteArray.first.clear();
+ ByteArray.second.clear();
if (Str[0] == '[') {
if (InAtomicBlock) {
@@ -220,7 +197,7 @@ int Disassembler::disassemble(const Target &T,
// It's a real token, get the bytes and emit them
ErrorOccurred |= ByteArrayFromString(ByteArray, Str, SM);
- if (!ByteArray.empty())
+ if (!ByteArray.first.empty())
ErrorOccurred |= PrintInsts(*DisAsm, ByteArray, SM, Out, Streamer,
InAtomicBlock, STI);
}
diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h
index 5615da8d3d36..1f18ac075f85 100644
--- a/tools/llvm-mc/Disassembler.h
+++ b/tools/llvm-mc/Disassembler.h
@@ -12,8 +12,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef DISASSEMBLER_H
-#define DISASSEMBLER_H
+#ifndef LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
+#define LLVM_TOOLS_LLVM_MC_DISASSEMBLER_H
#include <string>
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 4c5b230573b2..78fe9b72f208 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::string Err;
- tool_output_file *Out =
- new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_None);
- if (!Err.empty()) {
- errs() << Err << '\n';
- delete Out;
+ std::error_code EC;
+ auto Out = llvm::make_unique<tool_output_file>(OutputFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
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);
@@ -373,12 +372,12 @@ int main(int argc, char **argv) {
errs() << ProgName << ": " << EC.message() << '\n';
return 1;
}
- MemoryBuffer *Buffer = BufferPtr->release();
+ MemoryBuffer *Buffer = BufferPtr->get();
SourceMgr SrcMgr;
// Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
+ SrcMgr.AddNewSourceBuffer(std::move(*BufferPtr), SMLoc());
// Record the location of the include directories so that the lexer can find
// it later.
@@ -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;
@@ -471,16 +470,17 @@ int main(int argc, char **argv) {
assert(FileType == OFT_ObjectFile && "Invalid file type!");
MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU);
- Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB,
- FOS, CE, *STI, RelaxAll,
- NoExecStack));
+ Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, FOS, CE,
+ *STI, RelaxAll));
+ if (NoExecStack)
+ Str->InitSections(true);
}
int Res = 1;
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-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp
index a878f1157d57..56543139d6fa 100644
--- a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp
+++ b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp
@@ -141,14 +141,15 @@ static void parseMCMarkup(StringRef Filename) {
errs() << ToolName << ": " << EC.message() << '\n';
return;
}
- MemoryBuffer *Buffer = BufferPtr->release();
+ std::unique_ptr<MemoryBuffer> &Buffer = BufferPtr.get();
SourceMgr SrcMgr;
+ StringRef InputSource = Buffer->getBuffer();
+
// Tell SrcMgr about this buffer, which is what the parser will pick up.
- SrcMgr.AddNewSourceBuffer(Buffer, SMLoc());
+ SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
- StringRef InputSource = Buffer->getBuffer();
MarkupLexer Lex(InputSource);
MarkupParser Parser(Lex, SrcMgr);
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index 15304c40b887..f911c724646c 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>
@@ -149,6 +149,9 @@ cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
cl::opt<bool> FormatMachOasHex("x", cl::desc("Print symbol entry in hex, "
"Mach-O only"));
+cl::opt<bool> NoLLVMBitcode("no-llvm-bc",
+ cl::desc("Disable LLVM bitcode reader"));
+
bool PrintAddress = true;
bool MultipleFiles = false;
@@ -247,12 +250,12 @@ static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
}
}
-static char isSymbolList64Bit(SymbolicFile *Obj) {
+static char isSymbolList64Bit(SymbolicFile &Obj) {
if (isa<IRObjectFile>(Obj))
return false;
else if (isa<COFFObjectFile>(Obj))
return false;
- else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj))
+ else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
return MachO->is64Bit();
else if (isa<ELF32LEObjectFile>(Obj))
return false;
@@ -535,7 +538,9 @@ static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
outs() << Str;
}
-static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
+static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
+ std::string ArchiveName,
+ std::string ArchitectureName) {
if (!NoSort) {
if (NumericSort)
std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolAddress);
@@ -545,14 +550,16 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolName);
}
- if (OutputFormat == posix && MultipleFiles && printName) {
- outs() << '\n' << CurrentFilename << ":\n";
- } else if (OutputFormat == bsd && MultipleFiles && printName) {
- outs() << "\n" << CurrentFilename << ":\n";
- } else if (OutputFormat == sysv) {
- outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"
- << "Name Value Class Type"
- << " Size Line Section\n";
+ if (!PrintFileName) {
+ if (OutputFormat == posix && MultipleFiles && printName) {
+ outs() << '\n' << CurrentFilename << ":\n";
+ } else if (OutputFormat == bsd && MultipleFiles && printName) {
+ outs() << "\n" << CurrentFilename << ":\n";
+ } else if (OutputFormat == sysv) {
+ outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n"
+ << "Name Value Class Type"
+ << " Size Line Section\n";
+ }
}
const char *printBlanks, *printFormat;
@@ -572,7 +579,14 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
continue;
if (SizeSort && !PrintAddress && I->Size == UnknownAddressOrSize)
continue;
- if (JustSymbolName) {
+ if (PrintFileName) {
+ if (!ArchitectureName.empty())
+ outs() << "(for architecture " << ArchitectureName << "):";
+ if (!ArchiveName.empty())
+ outs() << ArchiveName << ":";
+ outs() << CurrentFilename << ": ";
+ }
+ if (JustSymbolName || (UndefinedOnly && isa<MachOObjectFile>(Obj))) {
outs() << I->Name << "\n";
continue;
}
@@ -596,7 +610,7 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
// nm(1) -m output or hex, else if OutputFormat is darwin or we are
// printing Mach-O symbols in hex and not a Mach-O object fall back to
// OutputFormat bsd (see below).
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if ((OutputFormat == darwin || FormatMachOasHex) && MachO) {
darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks);
} else if (OutputFormat == posix) {
@@ -675,7 +689,7 @@ static char getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj,
}
static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
- const coff_symbol *Symb = Obj.getCOFFSymbol(*I);
+ COFFSymbolRef Symb = Obj.getCOFFSymbol(*I);
// OK, this is COFF.
symbol_iterator SymI(I);
@@ -692,7 +706,7 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
return Ret;
uint32_t Characteristics = 0;
- if (!COFF::isReservedSectionNumber(Symb->SectionNumber)) {
+ if (!COFF::isReservedSectionNumber(Symb.getSectionNumber())) {
section_iterator SecI = Obj.section_end();
if (error(SymI->getSection(SecI)))
return '?';
@@ -700,25 +714,21 @@ static char getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I) {
Characteristics = Section->Characteristics;
}
- switch (Symb->SectionNumber) {
+ switch (Symb.getSectionNumber()) {
case COFF::IMAGE_SYM_DEBUG:
return 'n';
default:
// Check section type.
if (Characteristics & COFF::IMAGE_SCN_CNT_CODE)
return 't';
- else if (Characteristics & COFF::IMAGE_SCN_MEM_READ &&
- ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only.
- return 'r';
- else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
- return 'd';
- else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ return Characteristics & COFF::IMAGE_SCN_MEM_WRITE ? 'd' : 'r';
+ if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
return 'b';
- else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
+ if (Characteristics & COFF::IMAGE_SCN_LNK_INFO)
return 'i';
-
// Check for section symbol.
- else if (Symb->isSectionDefinition())
+ if (Symb.isSectionDefinition())
return 's';
}
@@ -783,7 +793,7 @@ static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) {
}
template <class ELFT>
-static bool isObject(ELFObjectFile<ELFT> &Obj, symbol_iterator I) {
+static bool isELFObject(ELFObjectFile<ELFT> &Obj, symbol_iterator I) {
typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym;
DataRefImpl Symb = I->getRawDataRefImpl();
@@ -792,19 +802,19 @@ static bool isObject(ELFObjectFile<ELFT> &Obj, symbol_iterator I) {
return ESym->getType() == ELF::STT_OBJECT;
}
-static bool isObject(SymbolicFile *Obj, basic_symbol_iterator I) {
- if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj))
- return isObject(*ELF, I);
- if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj))
- return isObject(*ELF, I);
- if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj))
- return isObject(*ELF, I);
- if (ELF64BEObjectFile *ELF = dyn_cast<ELF64BEObjectFile>(Obj))
- return isObject(*ELF, I);
+static bool isObject(SymbolicFile &Obj, basic_symbol_iterator I) {
+ if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(&Obj))
+ return isELFObject(*ELF, I);
+ if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(&Obj))
+ return isELFObject(*ELF, I);
+ if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(&Obj))
+ return isELFObject(*ELF, I);
+ if (ELF64BEObjectFile *ELF = dyn_cast<ELF64BEObjectFile>(&Obj))
+ return isELFObject(*ELF, I);
return false;
}
-static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) {
+static char getNMTypeChar(SymbolicFile &Obj, basic_symbol_iterator I) {
uint32_t Symflags = I->getFlags();
if ((Symflags & object::SymbolRef::SF_Weak) && !isa<MachOObjectFile>(Obj)) {
char Ret = isObject(Obj, I) ? 'v' : 'w';
@@ -822,20 +832,20 @@ static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) {
char Ret = '?';
if (Symflags & object::SymbolRef::SF_Absolute)
Ret = 'a';
- else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(Obj))
+ else if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*IR, I);
- else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj))
+ else if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*COFF, I);
- else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj))
+ else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*MachO, I);
- else if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj))
+ else if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*ELF, I);
- else if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj))
+ else if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*ELF, I);
- else if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj))
+ else if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(&Obj))
Ret = getSymbolNMTypeChar(*ELF, I);
else
- Ret = getSymbolNMTypeChar(*cast<ELF64BEObjectFile>(Obj), I);
+ Ret = getSymbolNMTypeChar(cast<ELF64BEObjectFile>(Obj), I);
if (Symflags & object::SymbolRef::SF_Global)
Ret = toupper(Ret);
@@ -883,16 +893,19 @@ static unsigned getNsectInMachO(MachOObjectFile &Obj, basic_symbol_iterator I) {
return 0;
}
-static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
- basic_symbol_iterator IBegin = Obj->symbol_begin();
- basic_symbol_iterator IEnd = Obj->symbol_end();
+static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
+ std::string ArchiveName = std::string(),
+ std::string ArchitectureName =
+ std::string()) {
+ basic_symbol_iterator IBegin = Obj.symbol_begin();
+ basic_symbol_iterator IEnd = Obj.symbol_end();
if (DynamicSyms) {
- if (!Obj->isELF()) {
- error("File format has no dynamic symbol table", Obj->getFileName());
+ if (!Obj.isELF()) {
+ error("File format has no dynamic symbol table", Obj.getFileName());
return;
}
std::pair<symbol_iterator, symbol_iterator> IDyn =
- getELFDynamicSymbolIterators(Obj);
+ getELFDynamicSymbolIterators(&Obj);
IBegin = IDyn.first;
IEnd = IDyn.second;
}
@@ -901,7 +914,7 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
// If a "-s segname sectname" option was specified and this is a Mach-O
// file get the section number for that section in this object file.
unsigned int Nsect = 0;
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj);
if (SegSect.size() != 0 && MachO) {
Nsect = getNsectForSegSect(MachO);
// If this section is not in the object file no symbols are printed.
@@ -913,7 +926,7 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
if (!DebugSyms && (SymFlags & SymbolRef::SF_FormatSpecific))
continue;
if (WithoutAliases) {
- if (IRObjectFile *IR = dyn_cast<IRObjectFile>(Obj)) {
+ if (IRObjectFile *IR = dyn_cast<IRObjectFile>(&Obj)) {
const GlobalValue *GV = IR->getSymbolGV(I->getRawDataRefImpl());
if (GV && isa<GlobalAlias>(GV))
continue;
@@ -950,8 +963,8 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
P += strlen(P) + 1;
}
- CurrentFilename = Obj->getFileName();
- sortAndPrintSymbolList(Obj, printName);
+ CurrentFilename = Obj.getFileName();
+ sortAndPrintSymbolList(Obj, printName, ArchiveName, ArchitectureName);
}
// checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file
@@ -995,13 +1008,13 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
return;
LLVMContext &Context = getGlobalContext();
- ErrorOr<Binary *> BinaryOrErr =
- createBinary(std::move(*BufferOrErr), &Context);
+ ErrorOr<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
+ BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context);
if (error(BinaryOrErr.getError(), Filename))
return;
- std::unique_ptr<Binary> Bin(BinaryOrErr.get());
+ Binary &Bin = *BinaryOrErr.get();
- if (Archive *A = dyn_cast<Archive>(Bin.get())) {
+ if (Archive *A = dyn_cast<Archive>(&Bin)) {
if (ArchiveMap) {
Archive::symbol_iterator I = A->symbol_begin();
Archive::symbol_iterator E = A->symbol_end();
@@ -1029,18 +1042,20 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
if (!checkMachOAndArchFlags(O, Filename))
return;
- outs() << "\n";
- if (isa<MachOObjectFile>(O)) {
- outs() << Filename << "(" << O->getFileName() << ")";
- } else
- outs() << O->getFileName();
- outs() << ":\n";
- dumpSymbolNamesFromObject(O, false);
+ if (!PrintFileName) {
+ outs() << "\n";
+ if (isa<MachOObjectFile>(O)) {
+ outs() << Filename << "(" << O->getFileName() << ")";
+ } else
+ outs() << O->getFileName();
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(*O, false, Filename);
}
}
return;
}
- if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin.get())) {
+ 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.
@@ -1054,16 +1069,25 @@ 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();
+ ArchitectureName.clear();
if (ObjOrErr) {
- std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
+ ObjectFile &Obj = *ObjOrErr.get();
if (ArchFlags.size() > 1) {
- outs() << "\n" << Obj->getFileName() << " (for architecture "
- << I->getArchTypeName() << ")"
- << ":\n";
+ if (PrintFileName)
+ ArchitectureName = I->getArchTypeName();
+ else
+ outs() << "\n" << Obj.getFileName() << " (for architecture "
+ << I->getArchTypeName() << ")"
+ << ":\n";
}
- dumpSymbolNamesFromObject(Obj.get(), false);
- } else if (!I->getAsArchive(A)) {
+ dumpSymbolNamesFromObject(Obj, false, ArchiveName,
+ ArchitectureName);
+ } 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) {
@@ -1073,14 +1097,21 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
continue;
if (SymbolicFile *O =
dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- outs() << "\n" << A->getFileName();
- outs() << "(" << O->getFileName() << ")";
- if (ArchFlags.size() > 1) {
- outs() << " (for architecture " << I->getArchTypeName()
- << ")";
+ if (PrintFileName) {
+ ArchiveName = A->getFileName();
+ if (ArchFlags.size() > 1)
+ ArchitectureName = I->getArchTypeName();
+ } else {
+ outs() << "\n" << A->getFileName();
+ outs() << "(" << O->getFileName() << ")";
+ if (ArchFlags.size() > 1) {
+ outs() << " (for architecture " << I->getArchTypeName()
+ << ")";
+ }
+ outs() << ":\n";
}
- outs() << ":\n";
- dumpSymbolNamesFromObject(O, false);
+ dumpSymbolNamesFromObject(*O, false, ArchiveName,
+ ArchitectureName);
}
}
}
@@ -1103,11 +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) {
- std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
- dumpSymbolNamesFromObject(Obj.get(), false);
- } else if (!I->getAsArchive(A)) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ dumpSymbolNamesFromObject(Obj, false);
+ } 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) {
@@ -1117,10 +1151,13 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
continue;
if (SymbolicFile *O =
dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- outs() << "\n" << A->getFileName() << "(" << O->getFileName()
- << ")"
- << ":\n";
- dumpSymbolNamesFromObject(O, false);
+ if (PrintFileName)
+ ArchiveName = A->getFileName();
+ else
+ outs() << "\n" << A->getFileName() << "(" << O->getFileName()
+ << ")"
+ << ":\n";
+ dumpSymbolNamesFromObject(*O, false, ArchiveName);
}
}
}
@@ -1135,17 +1172,26 @@ 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();
+ ArchitectureName.clear();
if (ObjOrErr) {
- std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
- if (moreThanOneArch)
- outs() << "\n";
- outs() << Obj->getFileName();
- if (isa<MachOObjectFile>(Obj.get()) && moreThanOneArch)
- outs() << " (for architecture " << I->getArchTypeName() << ")";
- outs() << ":\n";
- dumpSymbolNamesFromObject(Obj.get(), false);
- } else if (!I->getAsArchive(A)) {
+ ObjectFile &Obj = *ObjOrErr.get();
+ if (PrintFileName) {
+ if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
+ ArchitectureName = I->getArchTypeName();
+ } else {
+ if (moreThanOneArch)
+ outs() << "\n";
+ outs() << Obj.getFileName();
+ if (isa<MachOObjectFile>(Obj) && moreThanOneArch)
+ outs() << " (for architecture " << I->getArchTypeName() << ")";
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(Obj, false, ArchiveName, ArchitectureName);
+ } 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 =
@@ -1153,25 +1199,32 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
if (ChildOrErr.getError())
continue;
if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) {
- outs() << "\n" << A->getFileName();
- if (isa<MachOObjectFile>(O)) {
- outs() << "(" << O->getFileName() << ")";
- if (moreThanOneArch)
- outs() << " (for architecture " << I->getArchTypeName() << ")";
- } else
- outs() << ":" << O->getFileName();
- outs() << ":\n";
- dumpSymbolNamesFromObject(O, false);
+ if (PrintFileName) {
+ ArchiveName = A->getFileName();
+ if (isa<MachOObjectFile>(O) && moreThanOneArch)
+ ArchitectureName = I->getArchTypeName();
+ } else {
+ outs() << "\n" << A->getFileName();
+ if (isa<MachOObjectFile>(O)) {
+ outs() << "(" << O->getFileName() << ")";
+ if (moreThanOneArch)
+ outs() << " (for architecture " << I->getArchTypeName()
+ << ")";
+ } else
+ outs() << ":" << O->getFileName();
+ outs() << ":\n";
+ }
+ dumpSymbolNamesFromObject(*O, false, ArchiveName, ArchitectureName);
}
}
}
}
return;
}
- if (SymbolicFile *O = dyn_cast<SymbolicFile>(Bin.get())) {
+ if (SymbolicFile *O = dyn_cast<SymbolicFile>(&Bin)) {
if (!checkMachOAndArchFlags(O, Filename))
return;
- dumpSymbolNamesFromObject(O, true);
+ dumpSymbolNamesFromObject(*O, true);
return;
}
error("unrecognizable file type", Filename);
@@ -1223,8 +1276,7 @@ int main(int argc, char **argv) {
if (ArchFlags[i] == "all") {
ArchAll = true;
} else {
- Triple T = MachOObjectFile::getArch(ArchFlags[i]);
- if (T.getArch() == Triple::UnknownArch)
+ if (!MachOObjectFile::isValidArch(ArchFlags[i]))
error("Unknown architecture named '" + ArchFlags[i] + "'",
"for the -arch option");
}
diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt
index d63602bd0189..61bf3b32757b 100644
--- a/tools/llvm-objdump/CMakeLists.txt
+++ b/tools/llvm-objdump/CMakeLists.txt
@@ -2,7 +2,7 @@ set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
DebugInfo
MC
- MCAnalysis
+ MCDisassembler
Object
Support
)
diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp
index 39d8e8e39f8c..4a20b91b71fb 100644
--- a/tools/llvm-objdump/COFFDump.cpp
+++ b/tools/llvm-objdump/COFFDump.cpp
@@ -260,11 +260,8 @@ static void printLoadConfiguration(const COFFObjectFile *Obj) {
if (!PE32Header)
return;
- const coff_file_header *Header;
- if (error(Obj->getCOFFHeader(Header)))
- return;
// Currently only x86 is supported
- if (Header->Machine != COFF::IMAGE_FILE_MACHINE_I386)
+ if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_I386)
return;
const data_directory *DataDir;
@@ -325,7 +322,7 @@ static void printImportTables(const COFFObjectFile *Obj) {
const import_lookup_table_entry32 *entry;
if (I->getImportLookupEntry(entry))
return;
- for (; entry->data; ++entry) {
+ for (; entry->Data; ++entry) {
if (entry->isOrdinal()) {
outs() << format(" % 6d\n", entry->getOrdinal());
continue;
@@ -518,11 +515,7 @@ static void printRuntimeFunctionRels(const COFFObjectFile *Obj,
}
void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) {
- const coff_file_header *Header;
- if (error(Obj->getCOFFHeader(Header)))
- return;
-
- if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) {
+ if (Obj->getMachine() != COFF::IMAGE_FILE_MACHINE_AMD64) {
errs() << "Unsupported image machine type "
"(currently only AMD64 is supported).\n";
return;
diff --git a/tools/llvm-objdump/LLVMBuild.txt b/tools/llvm-objdump/LLVMBuild.txt
index d9c09b60034a..d16c501a6cca 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 MCAnalysis MCDisassembler MCParser Object all-targets
+required_libraries = DebugInfo MC MCDisassembler MCParser Object all-targets
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 4b46ac4fc0b9..03fad5f922fc 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -12,25 +12,29 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
+#include "llvm-c/Disassembler.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Config/config.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstPrinter.h"
-#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrDesc.h"
#include "llvm/MC/MCInstrInfo.h"
#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/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -40,31 +44,67 @@
#include <algorithm>
#include <cstring>
#include <system_error>
+
+#if HAVE_CXXABI_H
+#include <cxxabi.h>
+#endif
+
using namespace llvm;
using namespace object;
static cl::opt<bool>
- UseDbg("g", cl::desc("Print line information from debug info if available"));
+ UseDbg("g",
+ cl::desc("Print line information from debug info if available"));
+
+static cl::opt<std::string> DSYMFile("dsym",
+ cl::desc("Use .dSYM file for debug info"));
+
+static cl::opt<bool> FullLeadingAddr("full-leading-addr",
+ cl::desc("Print full leading address"));
+
+static cl::opt<bool>
+ PrintImmHex("print-imm-hex",
+ cl::desc("Use hex format for immediate values"));
-static cl::opt<std::string>
- DSYMFile("dsym", cl::desc("Use .dSYM file for debug info"));
+cl::opt<bool>
+ llvm::UniversalHeaders("universal-headers",
+ cl::desc("Print Mach-O universal headers"));
-static const Target *GetTarget(const MachOObjectFile *MachOObj) {
+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,
+ const char **McpuDefault,
+ const Target **ThumbTarget) {
// Figure out the target triple.
if (TripleName.empty()) {
llvm::Triple TT("unknown-unknown-unknown");
- TT.setArch(Triple::ArchType(MachOObj->getArch()));
+ llvm::Triple ThumbTriple = Triple();
+ TT = MachOObj->getArch(McpuDefault, &ThumbTriple);
TripleName = TT.str();
+ ThumbTripleName = ThumbTriple.str();
}
// Get the target specific parser.
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
- if (TheTarget)
+ if (TheTarget && ThumbTripleName.empty())
+ return TheTarget;
+
+ *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error);
+ if (*ThumbTarget)
return TheTarget;
- errs() << "llvm-objdump: error: unable to get target for '" << TripleName
- << "', see --version and --triple.\n";
+ errs() << "llvm-objdump: error: unable to get target for '";
+ if (!TheTarget)
+ errs() << TripleName;
+ else
+ errs() << ThumbTripleName;
+ errs() << "', see --version and --triple.\n";
return nullptr;
}
@@ -93,58 +133,80 @@ typedef std::pair<uint64_t, DiceRef> DiceTableEntry;
typedef std::vector<DiceTableEntry> DiceTable;
typedef DiceTable::iterator dice_table_iterator;
-static bool
-compareDiceTableEntries(const DiceTableEntry i,
- const DiceTableEntry j) {
- return i.first == j.first;
+// This is used to search for a data in code table entry for the PC being
+// disassembled. The j parameter has the PC in j.first. A single data in code
+// table entry can cover many bytes for each of its Kind's. So if the offset,
+// aka the i.first value, of the data in code table entry plus its Length
+// covers the PC being searched for this will return true. If not it will
+// return false.
+static bool compareDiceTableEntries(const DiceTableEntry &i,
+ const DiceTableEntry &j) {
+ uint16_t Length;
+ i.second.getLength(Length);
+
+ return j.first >= i.first && j.first < i.first + Length;
}
-static void DumpDataInCode(const char *bytes, uint64_t Size,
- unsigned short Kind) {
- uint64_t Value;
+static uint64_t DumpDataInCode(const char *bytes, uint64_t Length,
+ unsigned short Kind) {
+ uint32_t Value, Size = 1;
switch (Kind) {
+ default:
case MachO::DICE_KIND_DATA:
- switch (Size) {
- case 4:
- Value = bytes[3] << 24 |
- bytes[2] << 16 |
- bytes[1] << 8 |
- bytes[0];
+ if (Length >= 4) {
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 4));
+ Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
- break;
- case 2:
- Value = bytes[1] << 8 |
- bytes[0];
+ Size = 4;
+ } else if (Length >= 2) {
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 2));
+ Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << Value;
- break;
- case 1:
+ Size = 2;
+ } else {
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 2));
Value = bytes[0];
outs() << "\t.byte " << Value;
- break;
+ Size = 1;
}
- outs() << "\t@ KIND_DATA\n";
+ if (Kind == MachO::DICE_KIND_DATA)
+ outs() << "\t@ KIND_DATA\n";
+ else
+ outs() << "\t@ data in code kind = " << Kind << "\n";
break;
case MachO::DICE_KIND_JUMP_TABLE8:
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 1));
Value = bytes[0];
- outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8";
+ outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
+ Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE16:
- Value = bytes[1] << 8 |
- bytes[0];
- outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16";
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 2));
+ Value = bytes[1] << 8 | bytes[0];
+ outs() << "\t.short " << format("%5u", Value & 0xffff)
+ << "\t@ KIND_JUMP_TABLE16\n";
+ Size = 2;
break;
case MachO::DICE_KIND_JUMP_TABLE32:
- Value = bytes[3] << 24 |
- bytes[2] << 16 |
- bytes[1] << 8 |
- bytes[0];
- outs() << "\t.long " << Value << "\t@ KIND_JUMP_TABLE32";
- break;
- default:
- outs() << "\t@ data in code kind = " << Kind << "\n";
+ case MachO::DICE_KIND_ABS_JUMP_TABLE32:
+ if (!NoShowRawInsn)
+ DumpBytes(StringRef(bytes, 4));
+ Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
+ outs() << "\t.long " << Value;
+ if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
+ outs() << "\t@ KIND_JUMP_TABLE32\n";
+ else
+ outs() << "\t@ KIND_ABS_JUMP_TABLE32\n";
+ Size = 4;
break;
}
+ return Size;
}
static void getSectionsAndSymbols(const MachO::mach_header Header,
@@ -153,8 +215,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;
@@ -165,20 +231,18 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
MachOObjectFile::LoadCommandInfo Command =
MachOObj->getFirstLoadCommandInfo();
bool BaseSegmentAddressSet = false;
- for (unsigned i = 0; ; ++i) {
+ for (unsigned i = 0;; ++i) {
if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) {
// We found a function starts segment, parse the addresses for later
// consumption.
MachO::linkedit_data_command LLC =
- MachOObj->getLinkeditDataLoadCommand(Command);
+ MachOObj->getLinkeditDataLoadCommand(Command);
MachOObj->ReadULEB128s(LLC.dataoff, FoundFns);
- }
- else if (Command.C.cmd == MachO::LC_SEGMENT) {
- MachO::segment_command SLC =
- MachOObj->getSegmentLoadCommand(Command);
+ } else if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command);
StringRef SegName = SLC.segname;
- if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
+ if (!BaseSegmentAddressSet && SegName != "__PAGEZERO") {
BaseSegmentAddressSet = true;
BaseSegmentAddress = SLC.vmaddr;
}
@@ -191,33 +255,1792 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
}
}
-static void DisassembleInputMachO2(StringRef Filename,
- MachOObjectFile *MachOOF);
+// 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;
+}
+
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF);
+
+// 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.
+ if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
+ LazyBind || WeakBind) {
+ outs() << Filename;
+ if (!ArchiveMemberName.empty())
+ outs() << '(' << ArchiveMemberName << ')';
+ if (!ArchitectureName.empty())
+ outs() << " (architecture " << ArchitectureName << ")";
+ outs() << ":\n";
+ }
+
+ if (Disassemble)
+ DisassembleMachO(Filename, MachOOF);
+ // TODO: These should/could be printed in Darwin's otool(1) or nm(1) style
+ // for -macho. Or just used a new option that maps to the otool(1)
+ // option like -r, -l, etc. Or just the normal llvm-objdump option
+ // but now for this slice so that the -arch options can be used.
+ // if (Relocations)
+ // PrintRelocations(MachOOF);
+ // if (SectionHeaders)
+ // PrintSectionHeaders(MachOOF);
+ // if (SectionContents)
+ // PrintSectionContents(MachOOF);
+ // if (SymbolTable)
+ // PrintSymbolTable(MachOOF);
+ // if (UnwindInfo)
+ // PrintUnwindInfo(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";
-void llvm::DisassembleInputMachO(StringRef Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buff =
- MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = Buff.getError()) {
- errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\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";
+ }
+}
+
+// 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";
+ 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";
+ 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";
+ 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";
+ 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 DenseMap<uint64_t, StringRef> SymbolAddressMap;
+typedef std::pair<uint64_t, const char *> BindInfoEntry;
+typedef std::vector<BindInfoEntry> BindTable;
+typedef BindTable::iterator bind_table_iterator;
+
+// The block of info used by the Symbolizer call backs.
+struct DisassembleInfo {
+ bool verbose;
+ MachOObjectFile *O;
+ SectionRef S;
+ SymbolAddressMap *AddrMap;
+ std::vector<SectionRef> *Sections;
+ const char *class_name;
+ const char *selector_name;
+ char *method;
+ char *demangled_name;
+ uint64_t adrp_addr;
+ uint32_t adrp_inst;
+ 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
+// the relocation information, symbol table, etc. That block of information
+// is a pointer to the struct DisassembleInfo that was passed when the
+// disassembler context was created and passed to back to here when
+// called back by the disassembler for instruction operands that could have
+// relocation information. The address of the instruction containing operand is
+// at the Pc parameter. The immediate value the operand has is passed in
+// op_info->Value and is at Offset past the start of the instruction and has a
+// byte Size of 1, 2 or 4. The symbolc information is returned in TagBuf is the
+// LLVMOpInfo1 struct defined in the header "llvm-c/Disassembler.h" as symbol
+// names and addends of the symbolic expression to add for the operand. The
+// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
+// information is returned then this function returns 1 else it returns 0.
+int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
+ uint64_t Size, int TagType, void *TagBuf) {
+ struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
+ struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
+ uint64_t value = op_info->Value;
+
+ // Make sure all fields returned are zero if we don't set them.
+ memset((void *)op_info, '\0', sizeof(struct LLVMOpInfo1));
+ op_info->Value = value;
+
+ // If the TagType is not the value 1 which it code knows about or if no
+ // verbose symbolic information is wanted then just return 0, indicating no
+ // information is being returned.
+ if (TagType != 1 || info->verbose == false)
+ return 0;
+
+ unsigned int Arch = info->O->getArch();
+ if (Arch == Triple::x86) {
+ if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
+ return 0;
+ // First search the section's relocation entries (if any) for an entry
+ // for this section offset.
+ uint32_t sect_addr = info->S.getAddress();
+ uint32_t sect_offset = (Pc + Offset) - sect_addr;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ bool r_scattered = false;
+ uint32_t r_value, pair_r_value, r_type;
+ for (const RelocationRef &Reloc : info->S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ r_type = info->O->getAnyRelocationType(RE);
+ r_scattered = info->O->isRelocationScattered(RE);
+ if (r_scattered) {
+ r_value = info->O->getScatteredRelocationValue(RE);
+ if (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
+ r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext;
+ RENext = info->O->getRelocation(RelNext);
+ if (info->O->isRelocationScattered(RENext))
+ pair_r_value = info->O->getScatteredRelocationValue(RENext);
+ else
+ return 0;
+ }
+ } else {
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ StringRef SymName;
+ Symbol.getName(SymName);
+ const char *name = SymName.data();
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
+ // For i386 extern relocation entries the value in the instruction is
+ // the offset from the symbol, and value is already set in op_info->Value.
+ return 1;
+ }
+ 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);
+ uint32_t offset = value - (r_value - pair_r_value);
+ op_info->AddSymbol.Present = 1;
+ if (add != nullptr)
+ op_info->AddSymbol.Name = add;
+ else
+ op_info->AddSymbol.Value = r_value;
+ op_info->SubtractSymbol.Present = 1;
+ if (sub != nullptr)
+ op_info->SubtractSymbol.Name = sub;
+ else
+ op_info->SubtractSymbol.Value = pair_r_value;
+ op_info->Value = offset;
+ return 1;
+ }
+ // TODO:
+ // Second search the external relocation entries of a fully linked image
+ // (if any) for an entry that matches this segment offset.
+ // uint32_t seg_offset = (Pc + Offset);
+ return 0;
+ } else if (Arch == Triple::x86_64) {
+ if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
+ return 0;
+ // First search the section's relocation entries (if any) for an entry
+ // for this section offset.
+ uint64_t sect_addr = info->S.getAddress();
+ uint64_t sect_offset = (Pc + Offset) - sect_addr;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ for (const RelocationRef &Reloc : info->S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ // NOTE: Scattered relocations don't exist on x86_64.
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ // The Value passed in will be adjusted by the Pc if the instruction
+ // adds the Pc. But for x86_64 external relocation entries the Value
+ // is the offset from the external symbol.
+ if (info->O->getAnyRelocationPCRel(RE))
+ op_info->Value -= Pc + Offset + Size;
+ StringRef SymName;
+ Symbol.getName(SymName);
+ const char *name = SymName.data();
+ unsigned Type = info->O->getAnyRelocationType(RE);
+ if (Type == MachO::X86_64_RELOC_SUBTRACTOR) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
+ unsigned TypeNext = info->O->getAnyRelocationType(RENext);
+ bool isExternNext = info->O->getPlainRelocationExternal(RENext);
+ unsigned SymbolNum = info->O->getPlainRelocationSymbolNum(RENext);
+ if (TypeNext == MachO::X86_64_RELOC_UNSIGNED && isExternNext) {
+ op_info->SubtractSymbol.Present = 1;
+ op_info->SubtractSymbol.Name = name;
+ symbol_iterator RelocSymNext = info->O->getSymbolByIndex(SymbolNum);
+ Symbol = *RelocSymNext;
+ StringRef SymNameNext;
+ Symbol.getName(SymNameNext);
+ name = SymNameNext.data();
+ }
+ }
+ // TODO: add the VariantKinds to op_info->VariantKind for relocation types
+ // like: X86_64_RELOC_TLV, X86_64_RELOC_GOT_LOAD and X86_64_RELOC_GOT.
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
+ return 1;
+ }
+ // TODO:
+ // Second search the external relocation entries of a fully linked image
+ // (if any) for an entry that matches this segment offset.
+ // uint64_t seg_offset = (Pc + Offset);
+ return 0;
+ } else if (Arch == Triple::arm) {
+ if (Offset != 0 || (Size != 4 && Size != 2))
+ return 0;
+ // First search the section's relocation entries (if any) for an entry
+ // for this section offset.
+ uint32_t sect_addr = info->S.getAddress();
+ uint32_t sect_offset = (Pc + Offset) - sect_addr;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ bool r_scattered = false;
+ uint32_t r_value, pair_r_value, r_type, r_length, other_half;
+ for (const RelocationRef &Reloc : info->S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ r_length = info->O->getAnyRelocationLength(RE);
+ r_scattered = info->O->isRelocationScattered(RE);
+ if (r_scattered) {
+ r_value = info->O->getScatteredRelocationValue(RE);
+ r_type = info->O->getScatteredRelocationType(RE);
+ } else {
+ r_type = info->O->getAnyRelocationType(RE);
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ }
+ if (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_SECTDIFF ||
+ r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext;
+ RENext = info->O->getRelocation(RelNext);
+ other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
+ if (info->O->isRelocationScattered(RENext))
+ pair_r_value = info->O->getScatteredRelocationValue(RENext);
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ StringRef SymName;
+ Symbol.getName(SymName);
+ 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;
+ }
+ }
+ return 1;
+ }
+ // If we have a branch that is not an external relocation entry then
+ // return 0 so the code in tryAddingSymbolicOperand() can use the
+ // SymbolLookUp call back with the branch target address to look up the
+ // symbol and possiblity add an annotation for a symbol stub.
+ if (reloc_found && isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
+ r_type == MachO::ARM_THUMB_RELOC_BR22))
+ return 0;
+
+ uint32_t offset = 0;
+ if (reloc_found) {
+ if (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ if ((r_length & 0x1) == 1)
+ value = value << 16 | other_half;
+ else
+ value = other_half << 16 | value;
+ }
+ if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
+ r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
+ offset = value - r_value;
+ value = r_value;
+ }
+ }
+
+ if (reloc_found && r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ if ((r_length & 0x1) == 1)
+ 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);
+ int32_t offset = value - (r_value - pair_r_value);
+ op_info->AddSymbol.Present = 1;
+ if (add != nullptr)
+ op_info->AddSymbol.Name = add;
+ else
+ op_info->AddSymbol.Value = r_value;
+ op_info->SubtractSymbol.Present = 1;
+ if (sub != nullptr)
+ op_info->SubtractSymbol.Name = sub;
+ else
+ op_info->SubtractSymbol.Value = pair_r_value;
+ op_info->Value = offset;
+ return 1;
+ }
+
+ if (reloc_found == false)
+ return 0;
+
+ op_info->AddSymbol.Present = 1;
+ op_info->Value = offset;
+ if (reloc_found) {
+ if (r_type == MachO::ARM_RELOC_HALF) {
+ if ((r_length & 0x1) == 1)
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
+ else
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
+ }
+ }
+ const char *add = GuessSymbolName(value, info);
+ if (add != nullptr) {
+ op_info->AddSymbol.Name = add;
+ return 1;
+ }
+ op_info->AddSymbol.Value = value;
+ return 1;
+ } else if (Arch == Triple::aarch64) {
+ if (Offset != 0 || Size != 4)
+ return 0;
+ // First search the section's relocation entries (if any) for an entry
+ // for this section offset.
+ uint64_t sect_addr = info->S.getAddress();
+ uint64_t sect_offset = (Pc + Offset) - sect_addr;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ uint32_t r_type = 0;
+ for (const RelocationRef &Reloc : info->S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ r_type = info->O->getAnyRelocationType(RE);
+ if (r_type == MachO::ARM64_RELOC_ADDEND) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
+ if (value == 0) {
+ value = info->O->getPlainRelocationSymbolNum(RENext);
+ op_info->Value = value;
+ }
+ }
+ // NOTE: Scattered relocations don't exist on arm64.
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ if (reloc_found && isExtern) {
+ StringRef SymName;
+ Symbol.getName(SymName);
+ const char *name = SymName.data();
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
+
+ switch (r_type) {
+ case MachO::ARM64_RELOC_PAGE21:
+ /* @page */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
+ break;
+ case MachO::ARM64_RELOC_PAGEOFF12:
+ /* @pageoff */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
+ break;
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ /* @gotpage */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
+ break;
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ /* @gotpageoff */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
+ break;
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
+ /* @tvlppage is not implemented in llvm-mc */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
+ break;
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+ /* @tvlppageoff is not implemented in llvm-mc */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
+ break;
+ default:
+ case MachO::ARM64_RELOC_BRANCH26:
+ op_info->VariantKind = LLVMDisassembler_VariantKind_None;
+ break;
+ }
+ return 1;
+ }
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+// GuessCstringPointer is passed the address of what might be a pointer to a
+// literal string in a cstring section. If that address is in a cstring section
+// it returns a pointer to that string. Else it returns nullptr.
+const char *GuessCstringPointer(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ uint32_t LoadCommandCount = info->O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = info->O->getSection64(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_CSTRING_LITERALS &&
+ ReferenceValue >= Sec.addr &&
+ ReferenceValue < Sec.addr + Sec.size) {
+ uint64_t sect_offset = ReferenceValue - Sec.addr;
+ uint64_t object_offset = Sec.offset + sect_offset;
+ StringRef MachOContents = info->O->getData();
+ uint64_t object_size = MachOContents.size();
+ const char *object_addr = (const char *)MachOContents.data();
+ if (object_offset < object_size) {
+ const char *name = object_addr + object_offset;
+ return name;
+ } else {
+ return nullptr;
+ }
+ }
+ }
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = info->O->getSection(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_CSTRING_LITERALS &&
+ ReferenceValue >= Sec.addr &&
+ ReferenceValue < Sec.addr + Sec.size) {
+ uint64_t sect_offset = ReferenceValue - Sec.addr;
+ uint64_t object_offset = Sec.offset + sect_offset;
+ StringRef MachOContents = info->O->getData();
+ uint64_t object_size = MachOContents.size();
+ const char *object_addr = (const char *)MachOContents.data();
+ if (object_offset < object_size) {
+ const char *name = object_addr + object_offset;
+ return name;
+ } else {
+ return nullptr;
+ }
+ }
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = info->O->getNextLoadCommandInfo(Load);
+ }
+ return nullptr;
+}
+
+// GuessIndirectSymbol returns the name of the indirect symbol for the
+// ReferenceValue passed in or nullptr. This is used when ReferenceValue maybe
+// an address of a symbol stub or a lazy or non-lazy pointer to associate the
+// symbol name being referenced by the stub or pointer.
+static const char *GuessIndirectSymbol(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ uint32_t LoadCommandCount = info->O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
+ MachO::dysymtab_command Dysymtab = info->O->getDysymtabLoadCommand();
+ MachO::symtab_command Symtab = info->O->getSymtabLoadCommand();
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = info->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) &&
+ ReferenceValue >= Sec.addr &&
+ ReferenceValue < Sec.addr + Sec.size) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 8;
+ if (stride == 0)
+ return nullptr;
+ uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
+ if (index < Dysymtab.nindirectsyms) {
+ uint32_t indirect_symbol =
+ info->O->getIndirectSymbolTableEntry(Dysymtab, index);
+ if (indirect_symbol < Symtab.nsyms) {
+ symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
+ SymbolRef Symbol = *Sym;
+ StringRef SymName;
+ Symbol.getName(SymName);
+ const char *name = SymName.data();
+ return name;
+ }
+ }
+ }
+ }
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = info->O->getSegmentLoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = info->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) &&
+ ReferenceValue >= Sec.addr &&
+ ReferenceValue < Sec.addr + Sec.size) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 4;
+ if (stride == 0)
+ return nullptr;
+ uint32_t index = Sec.reserved1 + (ReferenceValue - Sec.addr) / stride;
+ if (index < Dysymtab.nindirectsyms) {
+ uint32_t indirect_symbol =
+ info->O->getIndirectSymbolTableEntry(Dysymtab, index);
+ if (indirect_symbol < Symtab.nsyms) {
+ symbol_iterator Sym = info->O->getSymbolByIndex(indirect_symbol);
+ SymbolRef Symbol = *Sym;
+ StringRef SymName;
+ Symbol.getName(SymName);
+ const char *name = SymName.data();
+ return name;
+ }
+ }
+ }
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = info->O->getNextLoadCommandInfo(Load);
+ }
+ return nullptr;
+}
+
+// method_reference() is called passing it the ReferenceName that might be
+// a reference it to an Objective-C method call. If so then it allocates and
+// assembles a method call string with the values last seen and saved in
+// the DisassembleInfo's class_name and selector_name fields. This is saved
+// into the method field of the info and any previous string is free'ed.
+// Then the class_name field in the info is set to nullptr. The method call
+// string is set into ReferenceName and ReferenceType is set to
+// LLVMDisassembler_ReferenceType_Out_Objc_Message. If this not a method call
+// then both ReferenceType and ReferenceName are left unchanged.
+static void method_reference(struct DisassembleInfo *info,
+ uint64_t *ReferenceType,
+ const char **ReferenceName) {
+ unsigned int Arch = info->O->getArch();
+ if (*ReferenceName != nullptr) {
+ if (strcmp(*ReferenceName, "_objc_msgSend") == 0) {
+ if (info->selector_name != nullptr) {
+ if (info->method != nullptr)
+ free(info->method);
+ if (info->class_name != nullptr) {
+ info->method = (char *)malloc(5 + strlen(info->class_name) +
+ strlen(info->selector_name));
+ if (info->method != nullptr) {
+ strcpy(info->method, "+[");
+ strcat(info->method, info->class_name);
+ strcat(info->method, " ");
+ strcat(info->method, info->selector_name);
+ strcat(info->method, "]");
+ *ReferenceName = info->method;
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
+ }
+ } else {
+ info->method = (char *)malloc(9 + strlen(info->selector_name));
+ if (info->method != nullptr) {
+ if (Arch == Triple::x86_64)
+ strcpy(info->method, "-[%rdi ");
+ else if (Arch == Triple::aarch64)
+ strcpy(info->method, "-[x0 ");
+ else
+ strcpy(info->method, "-[r? ");
+ strcat(info->method, info->selector_name);
+ strcat(info->method, "]");
+ *ReferenceName = info->method;
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
+ }
+ }
+ info->class_name = nullptr;
+ }
+ } else if (strcmp(*ReferenceName, "_objc_msgSendSuper2") == 0) {
+ if (info->selector_name != nullptr) {
+ if (info->method != nullptr)
+ free(info->method);
+ info->method = (char *)malloc(17 + strlen(info->selector_name));
+ if (info->method != nullptr) {
+ if (Arch == Triple::x86_64)
+ strcpy(info->method, "-[[%rdi super] ");
+ else if (Arch == Triple::aarch64)
+ strcpy(info->method, "-[[x0 super] ");
+ else
+ strcpy(info->method, "-[[r? super] ");
+ strcat(info->method, info->selector_name);
+ strcat(info->method, "]");
+ *ReferenceName = info->method;
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message;
+ }
+ info->class_name = nullptr;
+ }
+ }
+ }
+}
+
+// GuessPointerPointer() is passed the address of what might be a pointer to
+// a reference to an Objective-C class, selector, message ref or cfstring.
+// If so the value of the pointer is returned and one of the booleans are set
+// to true. If not zero is returned and all the booleans are set to false.
+static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
+ struct DisassembleInfo *info,
+ bool &classref, bool &selref, bool &msgref,
+ bool &cfstring) {
+ classref = false;
+ selref = false;
+ msgref = false;
+ cfstring = false;
+ uint32_t LoadCommandCount = info->O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = info->O->getSegment64LoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = info->O->getSection64(Load, J);
+ if ((strncmp(Sec.sectname, "__objc_selrefs", 16) == 0 ||
+ strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
+ strncmp(Sec.sectname, "__objc_superrefs", 16) == 0 ||
+ strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 ||
+ strncmp(Sec.sectname, "__cfstring", 16) == 0) &&
+ ReferenceValue >= Sec.addr &&
+ ReferenceValue < Sec.addr + Sec.size) {
+ uint64_t sect_offset = ReferenceValue - Sec.addr;
+ uint64_t object_offset = Sec.offset + sect_offset;
+ StringRef MachOContents = info->O->getData();
+ uint64_t object_size = MachOContents.size();
+ const char *object_addr = (const char *)MachOContents.data();
+ if (object_offset < object_size) {
+ uint64_t pointer_value;
+ memcpy(&pointer_value, object_addr + object_offset,
+ sizeof(uint64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ if (strncmp(Sec.sectname, "__objc_selrefs", 16) == 0)
+ selref = true;
+ else if (strncmp(Sec.sectname, "__objc_classrefs", 16) == 0 ||
+ strncmp(Sec.sectname, "__objc_superrefs", 16) == 0)
+ classref = true;
+ else if (strncmp(Sec.sectname, "__objc_msgrefs", 16) == 0 &&
+ ReferenceValue + 8 < Sec.addr + Sec.size) {
+ msgref = true;
+ memcpy(&pointer_value, object_addr + object_offset + 8,
+ sizeof(uint64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ } else if (strncmp(Sec.sectname, "__cfstring", 16) == 0)
+ cfstring = true;
+ return pointer_value;
+ } else {
+ return 0;
+ }
+ }
+ }
+ }
+ // TODO: Look for LC_SEGMENT for 32-bit Mach-O files.
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = info->O->getNextLoadCommandInfo(Load);
+ }
+ return 0;
+}
+
+// get_pointer_64 returns a pointer to the bytes in the object file at the
+// Address from a section in the Mach-O file. And indirectly returns the
+// offset into the section, number of bytes left in the section past the offset
+// and which section is was being referenced. If the Address is not in a
+// section nullptr is returned.
+const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left,
+ SectionRef &S, DisassembleInfo *info) {
+ offset = 0;
+ left = 0;
+ S = SectionRef();
+ for (unsigned SectIdx = 0; SectIdx != info->Sections->size(); SectIdx++) {
+ uint64_t SectAddress = ((*(info->Sections))[SectIdx]).getAddress();
+ uint64_t SectSize = ((*(info->Sections))[SectIdx]).getSize();
+ if (Address >= SectAddress && Address < SectAddress + SectSize) {
+ S = (*(info->Sections))[SectIdx];
+ offset = Address - SectAddress;
+ left = SectSize - offset;
+ StringRef SectContents;
+ ((*(info->Sections))[SectIdx]).getContents(SectContents);
+ return SectContents.data() + offset;
+ }
+ }
+ return nullptr;
+}
+
+// get_symbol_64() returns the name of a symbol (or nullptr) and the address of
+// the symbol indirectly through n_value. Based on the relocation information
+// for the specified section offset in the specified section reference.
+const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
+ DisassembleInfo *info, uint64_t &n_value) {
+ n_value = 0;
+ if (info->verbose == false)
+ return nullptr;
+
+ // See if there is an external relocation entry at the sect_offset.
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ for (const RelocationRef &Reloc : S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ if (info->O->isRelocationScattered(RE))
+ continue;
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ // If there is an external relocation entry for a symbol in this section
+ // at this section_offset then use that symbol's value for the n_value
+ // and return its name.
+ const char *SymbolName = nullptr;
+ if (reloc_found && isExtern) {
+ Symbol.getAddress(n_value);
+ StringRef name;
+ Symbol.getName(name);
+ if (!name.empty()) {
+ SymbolName = name.data();
+ return SymbolName;
+ }
+ }
+
+ // TODO: For fully linked images, look through the external relocation
+ // entries off the dynamic symtab command. For these the r_offset is from the
+ // start of the first writeable segment in the Mach-O file. So the offset
+ // to this section from that segment is passed to this routine by the caller,
+ // as the database_offset. Which is the difference of the section's starting
+ // address and the first writable segment.
+ //
+ // NOTE: need add passing the database_offset to this routine.
+
+ // TODO: We did not find an external relocation entry so look up the
+ // ReferenceValue as an address of a symbol and if found return that symbol's
+ // name.
+ //
+ // NOTE: need add passing the ReferenceValue to this routine. Then that code
+ // would simply be this:
+ // SymbolName = GuessSymbolName(ReferenceValue, info);
+
+ return SymbolName;
+}
+
+// These are structs in the Objective-C meta data and read to produce the
+// comments for disassembly. While these are part of the ABI they are no
+// public defintions. So the are here not in include/llvm/Support/MachO.h .
+
+// The cfstring object in a 64-bit Mach-O file.
+struct cfstring64_t {
+ uint64_t isa; // class64_t * (64-bit pointer)
+ uint64_t flags; // flag bits
+ uint64_t characters; // char * (64-bit pointer)
+ uint64_t length; // number of non-NULL characters in above
+};
+
+// The class object in a 64-bit Mach-O file.
+struct class64_t {
+ uint64_t isa; // class64_t * (64-bit pointer)
+ uint64_t superclass; // class64_t * (64-bit pointer)
+ uint64_t cache; // Cache (64-bit pointer)
+ uint64_t vtable; // IMP * (64-bit pointer)
+ uint64_t data; // class_ro64_t * (64-bit pointer)
+};
+
+struct class_ro64_t {
+ uint32_t flags;
+ uint32_t instanceStart;
+ uint32_t instanceSize;
+ uint32_t reserved;
+ uint64_t ivarLayout; // const uint8_t * (64-bit pointer)
+ uint64_t name; // const char * (64-bit pointer)
+ uint64_t baseMethods; // const method_list_t * (64-bit pointer)
+ uint64_t baseProtocols; // const protocol_list_t * (64-bit pointer)
+ uint64_t ivars; // const ivar_list_t * (64-bit pointer)
+ uint64_t weakIvarLayout; // const uint8_t * (64-bit pointer)
+ uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
+};
+
+inline void swapStruct(struct cfstring64_t &cfs) {
+ sys::swapByteOrder(cfs.isa);
+ sys::swapByteOrder(cfs.flags);
+ sys::swapByteOrder(cfs.characters);
+ sys::swapByteOrder(cfs.length);
+}
+
+inline void swapStruct(struct class64_t &c) {
+ sys::swapByteOrder(c.isa);
+ sys::swapByteOrder(c.superclass);
+ sys::swapByteOrder(c.cache);
+ sys::swapByteOrder(c.vtable);
+ sys::swapByteOrder(c.data);
+}
+
+inline void swapStruct(struct class_ro64_t &cro) {
+ sys::swapByteOrder(cro.flags);
+ sys::swapByteOrder(cro.instanceStart);
+ sys::swapByteOrder(cro.instanceSize);
+ sys::swapByteOrder(cro.reserved);
+ sys::swapByteOrder(cro.ivarLayout);
+ sys::swapByteOrder(cro.name);
+ sys::swapByteOrder(cro.baseMethods);
+ sys::swapByteOrder(cro.baseProtocols);
+ sys::swapByteOrder(cro.ivars);
+ sys::swapByteOrder(cro.weakIvarLayout);
+ sys::swapByteOrder(cro.baseProperties);
+}
+
+static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
+ struct DisassembleInfo *info);
+
+// get_objc2_64bit_class_name() is used for disassembly and is passed a pointer
+// to an Objective-C class and returns the class name. It is also passed the
+// address of the pointer, so when the pointer is zero as it can be in an .o
+// file, that is used to look for an external relocation entry with a symbol
+// name.
+const char *get_objc2_64bit_class_name(uint64_t pointer_value,
+ uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ const char *r;
+ uint32_t offset, left;
+ SectionRef S;
+
+ // The pointer_value can be 0 in an object file and have a relocation
+ // entry for the class symbol at the ReferenceValue (the address of the
+ // pointer).
+ if (pointer_value == 0) {
+ r = get_pointer_64(ReferenceValue, offset, left, S, info);
+ if (r == nullptr || left < sizeof(uint64_t))
+ return nullptr;
+ uint64_t n_value;
+ const char *symbol_name = get_symbol_64(offset, S, info, n_value);
+ if (symbol_name == nullptr)
+ return nullptr;
+ const char *class_name = strrchr(symbol_name, '$');
+ if (class_name != nullptr && class_name[1] == '_' && class_name[2] != '\0')
+ return class_name + 2;
+ else
+ return nullptr;
+ }
+
+ // The case were the pointer_value is non-zero and points to a class defined
+ // in this Mach-O file.
+ r = get_pointer_64(pointer_value, offset, left, S, info);
+ if (r == nullptr || left < sizeof(struct class64_t))
+ return nullptr;
+ struct class64_t c;
+ memcpy(&c, r, sizeof(struct class64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(c);
+ if (c.data == 0)
+ return nullptr;
+ r = get_pointer_64(c.data, offset, left, S, info);
+ if (r == nullptr || left < sizeof(struct class_ro64_t))
+ return nullptr;
+ struct class_ro64_t cro;
+ memcpy(&cro, r, sizeof(struct class_ro64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(cro);
+ if (cro.name == 0)
+ return nullptr;
+ const char *name = get_pointer_64(cro.name, offset, left, S, info);
+ return name;
+}
+
+// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
+// pointer to a cfstring and returns its name or nullptr.
+const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ const char *r, *name;
+ uint32_t offset, left;
+ SectionRef S;
+ struct cfstring64_t cfs;
+ uint64_t cfs_characters;
- std::unique_ptr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile *>(
- ObjectFile::createMachOObjectFile(Buff.get()).get()));
+ r = get_pointer_64(ReferenceValue, offset, left, S, info);
+ if (r == nullptr || left < sizeof(struct cfstring64_t))
+ return nullptr;
+ memcpy(&cfs, r, sizeof(struct cfstring64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(cfs);
+ if (cfs.characters == 0) {
+ uint64_t n_value;
+ const char *symbol_name = get_symbol_64(
+ offset + offsetof(struct cfstring64_t, characters), S, info, n_value);
+ if (symbol_name == nullptr)
+ return nullptr;
+ cfs_characters = n_value;
+ } else
+ cfs_characters = cfs.characters;
+ name = get_pointer_64(cfs_characters, offset, left, S, info);
- DisassembleInputMachO2(Filename, MachOOF.get());
+ return name;
}
-static void DisassembleInputMachO2(StringRef Filename,
- MachOObjectFile *MachOOF) {
- const Target *TheTarget = GetTarget(MachOOF);
+// get_objc2_64bit_selref() is used for disassembly and is passed a the address
+// of a pointer to an Objective-C selector reference when the pointer value is
+// zero as in a .o file and is likely to have a external relocation entry with
+// who's symbol's n_value is the real pointer to the selector name. If that is
+// the case the real pointer to the selector name is returned else 0 is
+// returned
+uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left;
+ SectionRef S;
+
+ const char *r = get_pointer_64(ReferenceValue, offset, left, S, info);
+ if (r == nullptr || left < sizeof(uint64_t))
+ return 0;
+ uint64_t n_value;
+ const char *symbol_name = get_symbol_64(offset, S, info, n_value);
+ if (symbol_name == nullptr)
+ return 0;
+ return n_value;
+}
+
+// GuessLiteralPointer returns a string which for the item in the Mach-O file
+// for the address passed in as ReferenceValue for printing as a comment with
+// the instruction and also returns the corresponding type of that item
+// indirectly through ReferenceType.
+//
+// If ReferenceValue is an address of literal cstring then a pointer to the
+// cstring is returned and ReferenceType is set to
+// LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr .
+//
+// If ReferenceValue is an address of an Objective-C CFString, Selector ref or
+// Class ref that name is returned and the ReferenceType is set accordingly.
+//
+// Lastly, literals which are Symbol address in a literal pool are looked for
+// and if found the symbol name is returned and ReferenceType is set to
+// LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr .
+//
+// If there is no item in the Mach-O file for the address passed in as
+// ReferenceValue nullptr is returned and ReferenceType is unchanged.
+const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
+ uint64_t *ReferenceType,
+ struct DisassembleInfo *info) {
+ // First see if there is an external relocation entry at the ReferencePC.
+ uint64_t sect_addr = info->S.getAddress();
+ uint64_t sect_offset = ReferencePC - sect_addr;
+ bool reloc_found = false;
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ SymbolRef Symbol;
+ for (const RelocationRef &Reloc : info->S.relocations()) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ if (RelocOffset == sect_offset) {
+ Rel = Reloc.getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ if (info->O->isRelocationScattered(RE))
+ continue;
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Symbol = *RelocSym;
+ }
+ reloc_found = true;
+ break;
+ }
+ }
+ // If there is an external relocation entry for a symbol in a section
+ // then used that symbol's value for the value of the reference.
+ if (reloc_found && isExtern) {
+ if (info->O->getAnyRelocationPCRel(RE)) {
+ unsigned Type = info->O->getAnyRelocationType(RE);
+ if (Type == MachO::X86_64_RELOC_SIGNED) {
+ Symbol.getAddress(ReferenceValue);
+ }
+ }
+ }
+
+ // Look for literals such as Objective-C CFStrings refs, Selector refs,
+ // Message refs and Class refs.
+ bool classref, selref, msgref, cfstring;
+ uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
+ selref, msgref, cfstring);
+ if (classref == true && pointer_value == 0) {
+ // Note the ReferenceValue is a pointer into the __objc_classrefs section.
+ // And the pointer_value in that section is typically zero as it will be
+ // set by dyld as part of the "bind information".
+ const char *name = get_dyld_bind_info_symbolname(ReferenceValue, info);
+ if (name != nullptr) {
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
+ const char *class_name = strrchr(name, '$');
+ if (class_name != nullptr && class_name[1] == '_' &&
+ class_name[2] != '\0') {
+ info->class_name = class_name + 2;
+ return name;
+ }
+ }
+ }
+
+ if (classref == true) {
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
+ const char *name =
+ get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
+ if (name != nullptr)
+ info->class_name = name;
+ else
+ name = "bad class ref";
+ return name;
+ }
+
+ if (cfstring == true) {
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
+ const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
+ return name;
+ }
+
+ if (selref == true && pointer_value == 0)
+ pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
+
+ if (pointer_value != 0)
+ ReferenceValue = pointer_value;
+
+ const char *name = GuessCstringPointer(ReferenceValue, info);
+ if (name) {
+ if (pointer_value != 0 && selref == true) {
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
+ info->selector_name = name;
+ } else if (pointer_value != 0 && msgref == true) {
+ info->class_name = nullptr;
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
+ info->selector_name = name;
+ } else
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr;
+ return name;
+ }
+
+ // Lastly look for an indirect symbol with this ReferenceValue which is in
+ // a literal pool. If found return that symbol name.
+ name = GuessIndirectSymbol(ReferenceValue, info);
+ if (name) {
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr;
+ return name;
+ }
+
+ return nullptr;
+}
+
+// SymbolizerSymbolLookUp is the symbol lookup function passed when creating
+// the Symbolizer. It looks up the ReferenceValue using the info passed via the
+// pointer to the struct DisassembleInfo that was passed when MCSymbolizer
+// is created and returns the symbol name that matches the ReferenceValue or
+// nullptr if none. The ReferenceType is passed in for the IN type of
+// reference the instruction is making from the values in defined in the header
+// "llvm-c/Disassembler.h". On return the ReferenceType can set to a specific
+// Out type and the ReferenceName will also be set which is added as a comment
+// to the disassembled instruction.
+//
+#if HAVE_CXXABI_H
+// If the symbol name is a C++ mangled name then the demangled name is
+// returned through ReferenceName and ReferenceType is set to
+// LLVMDisassembler_ReferenceType_DeMangled_Name .
+#endif
+//
+// When this is called to get a symbol name for a branch target then the
+// ReferenceType will be LLVMDisassembler_ReferenceType_In_Branch and then
+// SymbolValue will be looked for in the indirect symbol table to determine if
+// it is an address for a symbol stub. If so then the symbol name for that
+// stub is returned indirectly through ReferenceName and then ReferenceType is
+// set to LLVMDisassembler_ReferenceType_Out_SymbolStub.
+//
+// When this is called with an value loaded via a PC relative load then
+// ReferenceType will be LLVMDisassembler_ReferenceType_In_PCrel_Load then the
+// SymbolValue is checked to be an address of literal pointer, symbol pointer,
+// or an Objective-C meta data reference. If so the output ReferenceType is
+// set to correspond to that as well as setting the ReferenceName.
+const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName) {
+ struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
+ // If no verbose symbolic information is wanted then just return nullptr.
+ if (info->verbose == false) {
+ *ReferenceName = nullptr;
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ return nullptr;
+ }
+
+ const char *SymbolName = GuessSymbolName(ReferenceValue, info);
+
+ if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
+ *ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
+ if (*ReferenceName != nullptr) {
+ method_reference(info, ReferenceType, ReferenceName);
+ if (*ReferenceType != LLVMDisassembler_ReferenceType_Out_Objc_Message)
+ *ReferenceType = LLVMDisassembler_ReferenceType_Out_SymbolStub;
+ } else
+#if HAVE_CXXABI_H
+ if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
+ if (info->demangled_name != nullptr)
+ free(info->demangled_name);
+ int status;
+ info->demangled_name =
+ abi::__cxa_demangle(SymbolName + 1, nullptr, nullptr, &status);
+ if (info->demangled_name != nullptr) {
+ *ReferenceName = info->demangled_name;
+ *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
+ } else
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ } else
+#endif
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ } else if (*ReferenceType == LLVMDisassembler_ReferenceType_In_PCrel_Load) {
+ *ReferenceName =
+ GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
+ if (*ReferenceName)
+ method_reference(info, ReferenceType, ReferenceName);
+ else
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ // If this is arm64 and the reference is an adrp instruction save the
+ // instruction, passed in ReferenceValue and the address of the instruction
+ // for use later if we see and add immediate instruction.
+ } else if (info->O->getArch() == Triple::aarch64 &&
+ *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADRP) {
+ info->adrp_inst = ReferenceValue;
+ info->adrp_addr = ReferencePC;
+ SymbolName = nullptr;
+ *ReferenceName = nullptr;
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ // If this is arm64 and reference is an add immediate instruction and we
+ // have
+ // seen an adrp instruction just before it and the adrp's Xd register
+ // matches
+ // this add's Xn register reconstruct the value being referenced and look to
+ // see if it is a literal pointer. Note the add immediate instruction is
+ // passed in ReferenceValue.
+ } else if (info->O->getArch() == Triple::aarch64 &&
+ *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADDXri &&
+ ReferencePC - 4 == info->adrp_addr &&
+ (info->adrp_inst & 0x9f000000) == 0x90000000 &&
+ (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
+ uint32_t addxri_inst;
+ uint64_t adrp_imm, addxri_imm;
+
+ adrp_imm =
+ ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
+ if (info->adrp_inst & 0x0200000)
+ adrp_imm |= 0xfffffffffc000000LL;
+
+ addxri_inst = ReferenceValue;
+ addxri_imm = (addxri_inst >> 10) & 0xfff;
+ if (((addxri_inst >> 22) & 0x3) == 1)
+ addxri_imm <<= 12;
+
+ ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
+ (adrp_imm << 12) + addxri_imm;
+
+ *ReferenceName =
+ GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
+ if (*ReferenceName == nullptr)
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ // If this is arm64 and the reference is a load register instruction and we
+ // have seen an adrp instruction just before it and the adrp's Xd register
+ // matches this add's Xn register reconstruct the value being referenced and
+ // look to see if it is a literal pointer. Note the load register
+ // instruction is passed in ReferenceValue.
+ } else if (info->O->getArch() == Triple::aarch64 &&
+ *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXui &&
+ ReferencePC - 4 == info->adrp_addr &&
+ (info->adrp_inst & 0x9f000000) == 0x90000000 &&
+ (info->adrp_inst & 0x1f) == ((ReferenceValue >> 5) & 0x1f)) {
+ uint32_t ldrxui_inst;
+ uint64_t adrp_imm, ldrxui_imm;
+
+ adrp_imm =
+ ((info->adrp_inst & 0x00ffffe0) >> 3) | ((info->adrp_inst >> 29) & 0x3);
+ if (info->adrp_inst & 0x0200000)
+ adrp_imm |= 0xfffffffffc000000LL;
+
+ ldrxui_inst = ReferenceValue;
+ ldrxui_imm = (ldrxui_inst >> 10) & 0xfff;
+
+ ReferenceValue = (info->adrp_addr & 0xfffffffffffff000LL) +
+ (adrp_imm << 12) + (ldrxui_imm << 3);
+
+ *ReferenceName =
+ GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
+ if (*ReferenceName == nullptr)
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ }
+ // If this arm64 and is an load register (PC-relative) instruction the
+ // ReferenceValue is the PC plus the immediate value.
+ else if (info->O->getArch() == Triple::aarch64 &&
+ (*ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_LDRXl ||
+ *ReferenceType == LLVMDisassembler_ReferenceType_In_ARM64_ADR)) {
+ *ReferenceName =
+ GuessLiteralPointer(ReferenceValue, ReferencePC, ReferenceType, info);
+ if (*ReferenceName == nullptr)
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ }
+#if HAVE_CXXABI_H
+ else if (SymbolName != nullptr && strncmp(SymbolName, "__Z", 3) == 0) {
+ if (info->demangled_name != nullptr)
+ free(info->demangled_name);
+ int status;
+ info->demangled_name =
+ abi::__cxa_demangle(SymbolName + 1, nullptr, nullptr, &status);
+ if (info->demangled_name != nullptr) {
+ *ReferenceName = info->demangled_name;
+ *ReferenceType = LLVMDisassembler_ReferenceType_DeMangled_Name;
+ }
+ }
+#endif
+ else {
+ *ReferenceName = nullptr;
+ *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ }
+
+ return SymbolName;
+}
+
+/// \brief Emits the comments that are stored in the CommentStream.
+/// Each comment in the CommentStream must end with a newline.
+static void emitComments(raw_svector_ostream &CommentStream,
+ SmallString<128> &CommentsToEmit,
+ formatted_raw_ostream &FormattedOS,
+ const MCAsmInfo &MAI) {
+ // Flush the stream before taking its content.
+ CommentStream.flush();
+ StringRef Comments = CommentsToEmit.str();
+ // Get the default information for printing a comment.
+ const char *CommentBegin = MAI.getCommentString();
+ unsigned CommentColumn = MAI.getCommentColumn();
+ bool IsFirst = true;
+ while (!Comments.empty()) {
+ if (!IsFirst)
+ FormattedOS << '\n';
+ // Emit a line of comments.
+ FormattedOS.PadToColumn(CommentColumn);
+ size_t Position = Comments.find('\n');
+ FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
+ // Move after the newline character.
+ Comments = Comments.substr(Position + 1);
+ IsFirst = false;
+ }
+ FormattedOS.flush();
+
+ // Tell the comment stream that the vector changed underneath it.
+ CommentsToEmit.clear();
+ CommentStream.resync();
+}
+
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
+ const char *McpuDefault = nullptr;
+ const Target *ThumbTarget = nullptr;
+ const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
if (!TheTarget) {
// GetTarget prints out stuff.
return;
}
+ if (MCPU.empty() && McpuDefault)
+ MCPU = McpuDefault;
+
std::unique_ptr<const MCInstrInfo> InstrInfo(TheTarget->createMCInstrInfo());
- std::unique_ptr<MCInstrAnalysis> InstrAnalysis(
- TheTarget->createMCInstrAnalysis(InstrInfo.get()));
+ std::unique_ptr<const MCInstrInfo> ThumbInstrInfo;
+ if (ThumbTarget)
+ ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo());
+
+ // Package up features to be passed to target/subtarget
+ std::string FeaturesStr;
+ if (MAttrs.size()) {
+ SubtargetFeatures Features;
+ for (unsigned i = 0; i != MAttrs.size(); ++i)
+ Features.AddFeature(MAttrs[i]);
+ FeaturesStr = Features.getString();
+ }
// Set up disassembler.
std::unique_ptr<const MCRegisterInfo> MRI(
@@ -225,26 +2048,84 @@ static void DisassembleInputMachO2(StringRef Filename,
std::unique_ptr<const MCAsmInfo> AsmInfo(
TheTarget->createMCAsmInfo(*MRI, TripleName));
std::unique_ptr<const MCSubtargetInfo> STI(
- TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+ TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr);
- std::unique_ptr<const MCDisassembler> DisAsm(
- TheTarget->createMCDisassembler(*STI, Ctx));
+ std::unique_ptr<MCDisassembler> DisAsm(
+ TheTarget->createMCDisassembler(*STI, Ctx));
+ std::unique_ptr<MCSymbolizer> Symbolizer;
+ struct DisassembleInfo SymbolizerInfo;
+ std::unique_ptr<MCRelocationInfo> RelInfo(
+ TheTarget->createMCRelocationInfo(TripleName, Ctx));
+ if (RelInfo) {
+ Symbolizer.reset(TheTarget->createMCSymbolizer(
+ TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
+ &SymbolizerInfo, &Ctx, RelInfo.release()));
+ DisAsm->setSymbolizer(std::move(Symbolizer));
+ }
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI, *STI));
+ // Set the display preference for hex vs. decimal immediates.
+ IP->setPrintImmHex(PrintImmHex);
+ // 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 (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) {
+ if (!AsmInfo || !STI || !DisAsm || !IP) {
errs() << "error: couldn't initialize disassembler for target "
<< TripleName << '\n';
return;
}
- outs() << '\n' << Filename << ":\n\n";
+ // Set up thumb disassembler.
+ std::unique_ptr<const MCRegisterInfo> ThumbMRI;
+ std::unique_ptr<const MCAsmInfo> ThumbAsmInfo;
+ std::unique_ptr<const MCSubtargetInfo> ThumbSTI;
+ std::unique_ptr<MCDisassembler> ThumbDisAsm;
+ std::unique_ptr<MCInstPrinter> ThumbIP;
+ std::unique_ptr<MCContext> ThumbCtx;
+ std::unique_ptr<MCSymbolizer> ThumbSymbolizer;
+ struct DisassembleInfo ThumbSymbolizerInfo;
+ std::unique_ptr<MCRelocationInfo> ThumbRelInfo;
+ if (ThumbTarget) {
+ ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName));
+ ThumbAsmInfo.reset(
+ ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName));
+ ThumbSTI.reset(
+ ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MCPU, FeaturesStr));
+ ThumbCtx.reset(new MCContext(ThumbAsmInfo.get(), ThumbMRI.get(), nullptr));
+ ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx));
+ MCContext *PtrThumbCtx = ThumbCtx.get();
+ ThumbRelInfo.reset(
+ ThumbTarget->createMCRelocationInfo(ThumbTripleName, *PtrThumbCtx));
+ if (ThumbRelInfo) {
+ ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
+ ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
+ &ThumbSymbolizerInfo, PtrThumbCtx, ThumbRelInfo.release()));
+ ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
+ }
+ int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
+ ThumbIP.reset(ThumbTarget->createMCInstPrinter(
+ ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo, *ThumbMRI,
+ *ThumbSTI));
+ // Set the display preference for hex vs. decimal immediates.
+ ThumbIP->setPrintImmHex(PrintImmHex);
+ }
+
+ if (ThumbTarget && (!ThumbAsmInfo || !ThumbSTI || !ThumbDisAsm || !ThumbIP)) {
+ errs() << "error: couldn't initialize disassembler for target "
+ << ThumbTripleName << '\n';
+ return;
+ }
MachO::mach_header Header = MachOOF->getHeader();
- // FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to
- // determine function locations will eventually go in MCObjectDisassembler.
// FIXME: Using the -cfg command line option, this code used to be able to
// annotate relocations with the referenced symbol's name, and if this was
// inside a __[cf]string section, the data it points to. This is now replaced
@@ -263,7 +2144,7 @@ static void DisassembleInputMachO2(StringRef Filename,
// Build a data in code table that is sorted on by the address of each entry.
uint64_t BaseAddress = 0;
if (Header.filetype == MachO::MH_OBJECT)
- Sections[0].getAddress(BaseAddress);
+ BaseAddress = Sections[0].getAddress();
else
BaseAddress = BaseSegmentAddress;
DiceTable Dices;
@@ -288,29 +2169,38 @@ static void DisassembleInputMachO2(StringRef Filename,
// A separate DSym file path was specified, parse it as a macho file,
// get the sections and supply it to the section name parsing machinery.
if (!DSYMFile.empty()) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buf =
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
MemoryBuffer::getFileOrSTDIN(DSYMFile);
- if (std::error_code EC = Buf.getError()) {
+ if (std::error_code EC = BufOrErr.getError()) {
errs() << "llvm-objdump: " << Filename << ": " << EC.message() << '\n';
return;
}
- DbgObj = ObjectFile::createMachOObjectFile(Buf.get()).get();
+ DbgObj =
+ ObjectFile::createMachOObjectFile(BufOrErr.get()->getMemBufferRef())
+ .get()
+ .release();
}
// Setup the DIContext
- diContext.reset(DIContext::getDWARFContext(DbgObj));
+ diContext.reset(DIContext::getDWARFContext(*DbgObj));
}
+ // TODO: For now this only disassembles the (__TEXT,__text) section (see the
+ // checks in the code below at the top of this loop). It should allow a
+ // darwin otool(1) like -s option to disassemble any named segment & section
+ // that is marked as containing instructions with the attributes
+ // S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS in the flags field of
+ // the section structure.
+ outs() << "(__TEXT,__text) section\n";
+
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
- bool SectIsText = false;
- Sections[SectIdx].isText(SectIsText);
+ bool SectIsText = Sections[SectIdx].isText();
if (SectIsText == false)
continue;
StringRef SectName;
- if (Sections[SectIdx].getName(SectName) ||
- SectName != "__text")
+ if (Sections[SectIdx].getName(SectName) || SectName != "__text")
continue; // Skip non-text sections
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
@@ -319,17 +2209,20 @@ static void DisassembleInputMachO2(StringRef Filename,
if (SegmentName != "__TEXT")
continue;
- StringRef Bytes;
- Sections[SectIdx].getContents(Bytes);
- StringRefMemoryObject memoryObject(Bytes);
+ StringRef BytesStr;
+ Sections[SectIdx].getContents(BytesStr);
+ ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
+ BytesStr.size());
+ uint64_t SectAddress = Sections[SectIdx].getAddress();
+
bool symbolTableWorked = false;
// Parse relocations.
std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
for (const RelocationRef &Reloc : Sections[SectIdx].relocations()) {
- uint64_t RelocOffset, SectionAddress;
+ uint64_t RelocOffset;
Reloc.getOffset(RelocOffset);
- Sections[SectIdx].getAddress(SectionAddress);
+ uint64_t SectionAddress = Sections[SectIdx].getAddress();
RelocOffset -= SectionAddress;
symbol_iterator RelocSym = Reloc.getSymbol();
@@ -338,6 +2231,48 @@ static void DisassembleInputMachO2(StringRef Filename,
}
array_pod_sort(Relocs.begin(), Relocs.end());
+ // Create a map of symbol addresses to symbol names for use by
+ // the SymbolizerSymbolLookUp() routine.
+ SymbolAddressMap AddrMap;
+ for (const SymbolRef &Symbol : MachOOF->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;
+ }
+ }
+ // Set up the block of info used by the Symbolizer call backs.
+ SymbolizerInfo.verbose = true;
+ SymbolizerInfo.O = MachOOF;
+ SymbolizerInfo.S = Sections[SectIdx];
+ SymbolizerInfo.AddrMap = &AddrMap;
+ SymbolizerInfo.Sections = &Sections;
+ SymbolizerInfo.class_name = nullptr;
+ SymbolizerInfo.selector_name = nullptr;
+ SymbolizerInfo.method = nullptr;
+ SymbolizerInfo.demangled_name = nullptr;
+ SymbolizerInfo.bindtable = nullptr;
+ SymbolizerInfo.adrp_addr = 0;
+ SymbolizerInfo.adrp_inst = 0;
+ // Same for the ThumbSymbolizer
+ ThumbSymbolizerInfo.verbose = true;
+ ThumbSymbolizerInfo.O = MachOOF;
+ ThumbSymbolizerInfo.S = Sections[SectIdx];
+ ThumbSymbolizerInfo.AddrMap = &AddrMap;
+ ThumbSymbolizerInfo.Sections = &Sections;
+ ThumbSymbolizerInfo.class_name = nullptr;
+ ThumbSymbolizerInfo.selector_name = nullptr;
+ ThumbSymbolizerInfo.method = nullptr;
+ ThumbSymbolizerInfo.demangled_name = nullptr;
+ ThumbSymbolizerInfo.bindtable = nullptr;
+ ThumbSymbolizerInfo.adrp_addr = 0;
+ ThumbSymbolizerInfo.adrp_inst = 0;
+
// Disassemble symbol by symbol.
for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) {
StringRef SymName;
@@ -349,15 +2284,13 @@ static void DisassembleInputMachO2(StringRef Filename,
continue;
// Make sure the symbol is defined in this section.
- bool containsSym = false;
- Sections[SectIdx].containsSymbol(Symbols[SymIdx], containsSym);
+ bool containsSym = Sections[SectIdx].containsSymbol(Symbols[SymIdx]);
if (!containsSym)
continue;
// Start at the address of the symbol relative to the section's address.
- uint64_t SectionAddress = 0;
uint64_t Start = 0;
- Sections[SectIdx].getAddress(SectionAddress);
+ uint64_t SectionAddress = Sections[SectIdx].getAddress();
Symbols[SymIdx].getAddress(Start);
Start -= SectionAddress;
@@ -365,13 +2298,13 @@ static void DisassembleInputMachO2(StringRef Filename,
// the end of the section.
bool containsNextSym = false;
uint64_t NextSym = 0;
- uint64_t NextSymIdx = SymIdx+1;
+ uint64_t NextSymIdx = SymIdx + 1;
while (Symbols.size() > NextSymIdx) {
SymbolRef::Type NextSymType;
Symbols[NextSymIdx].getType(NextSymType);
if (NextSymType == SymbolRef::ST_Function) {
- Sections[SectIdx].containsSymbol(Symbols[NextSymIdx],
- containsNextSym);
+ containsNextSym =
+ Sections[SectIdx].containsSymbol(Symbols[NextSymIdx]);
Symbols[NextSymIdx].getAddress(NextSym);
NextSym -= SectionAddress;
break;
@@ -379,48 +2312,81 @@ static void DisassembleInputMachO2(StringRef Filename,
++NextSymIdx;
}
- uint64_t SectSize;
- Sections[SectIdx].getSize(SectSize);
- uint64_t End = containsNextSym ? NextSym : SectSize;
+ uint64_t SectSize = Sections[SectIdx].getSize();
+ uint64_t End = containsNextSym ? NextSym : SectSize;
uint64_t Size;
symbolTableWorked = true;
+ DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl();
+ bool isThumb =
+ (MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget;
+
outs() << SymName << ":\n";
DILineInfo lastLine;
for (uint64_t Index = Start; Index < End; Index += Size) {
MCInst Inst;
- uint64_t SectAddress = 0;
- Sections[SectIdx].getAddress(SectAddress);
- outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
+ uint64_t PC = SectAddress + Index;
+ if (FullLeadingAddr) {
+ if (MachOOF->is64Bit())
+ outs() << format("%016" PRIx64, PC);
+ else
+ outs() << format("%08" PRIx64, PC);
+ } else {
+ outs() << format("%8" PRIx64 ":", PC);
+ }
+ if (!NoShowRawInsn)
+ outs() << "\t";
// Check the data in code table here to see if this is data not an
// instruction to be disassembled.
DiceTable Dice;
- Dice.push_back(std::make_pair(SectAddress + Index, DiceRef()));
- dice_table_iterator DTI = std::search(Dices.begin(), Dices.end(),
- Dice.begin(), Dice.end(),
- compareDiceTableEntries);
- if (DTI != Dices.end()){
+ Dice.push_back(std::make_pair(PC, DiceRef()));
+ dice_table_iterator DTI =
+ std::search(Dices.begin(), Dices.end(), Dice.begin(), Dice.end(),
+ compareDiceTableEntries);
+ if (DTI != Dices.end()) {
uint16_t Length;
DTI->second.getLength(Length);
- DumpBytes(StringRef(Bytes.data() + Index, Length));
uint16_t Kind;
DTI->second.getKind(Kind);
- DumpDataInCode(Bytes.data() + Index, Length, Kind);
+ Size = DumpDataInCode(reinterpret_cast<const char *>(Bytes.data()) +
+ Index,
+ Length, Kind);
+ if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
+ (PC == (DTI->first + Length - 1)) && (Length & 1))
+ Size++;
continue;
}
- if (DisAsm->getInstruction(Inst, Size, memoryObject, Index,
- DebugOut, nulls())) {
- DumpBytes(StringRef(Bytes.data() + Index, Size));
- IP->printInst(&Inst, outs(), "");
+ SmallVector<char, 64> AnnotationsBytes;
+ raw_svector_ostream Annotations(AnnotationsBytes);
+
+ bool gotInst;
+ if (isThumb)
+ gotInst = ThumbDisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
+ PC, DebugOut, Annotations);
+ else
+ gotInst = DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), PC,
+ DebugOut, Annotations);
+ if (gotInst) {
+ if (!NoShowRawInsn) {
+ DumpBytes(StringRef(
+ reinterpret_cast<const char *>(Bytes.data()) + Index, Size));
+ }
+ formatted_raw_ostream FormattedOS(outs());
+ Annotations.flush();
+ StringRef AnnotationsStr = Annotations.str();
+ if (isThumb)
+ ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr);
+ else
+ IP->printInst(&Inst, FormattedOS, AnnotationsStr);
+ emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
// Print debug info.
if (diContext) {
- DILineInfo dli =
- diContext->getLineInfoForAddress(SectAddress + Index);
+ DILineInfo dli = diContext->getLineInfoForAddress(PC);
// Print valid line info if it changed.
if (dli != lastLine && dli.Line != 0)
outs() << "\t## " << dli.FileName << ':' << dli.Line << ':'
@@ -429,34 +2395,2508 @@ static void DisassembleInputMachO2(StringRef Filename,
}
outs() << "\n";
} else {
- errs() << "llvm-objdump: warning: invalid instruction encoding\n";
- if (Size == 0)
- Size = 1; // skip illegible bytes
+ unsigned int Arch = MachOOF->getArch();
+ if (Arch == Triple::x86_64 || Arch == Triple::x86) {
+ outs() << format("\t.byte 0x%02x #bad opcode\n",
+ *(Bytes.data() + Index) & 0xff);
+ Size = 1; // skip exactly one illegible byte and move on.
+ } else if (Arch == Triple::aarch64) {
+ uint32_t opcode = (*(Bytes.data() + Index) & 0xff) |
+ (*(Bytes.data() + Index + 1) & 0xff) << 8 |
+ (*(Bytes.data() + Index + 2) & 0xff) << 16 |
+ (*(Bytes.data() + Index + 3) & 0xff) << 24;
+ outs() << format("\t.long\t0x%08x\n", opcode);
+ Size = 4;
+ } else {
+ errs() << "llvm-objdump: warning: invalid instruction encoding\n";
+ if (Size == 0)
+ Size = 1; // skip illegible bytes
+ }
}
}
}
if (!symbolTableWorked) {
- // Reading the symbol table didn't work, disassemble the whole section.
- uint64_t SectAddress;
- Sections[SectIdx].getAddress(SectAddress);
- uint64_t SectSize;
- Sections[SectIdx].getSize(SectSize);
+ // Reading the symbol table didn't work, disassemble the whole section.
+ uint64_t SectAddress = Sections[SectIdx].getAddress();
+ uint64_t SectSize = Sections[SectIdx].getSize();
uint64_t InstSize;
for (uint64_t Index = 0; Index < SectSize; Index += InstSize) {
MCInst Inst;
- if (DisAsm->getInstruction(Inst, InstSize, memoryObject, Index,
+ uint64_t PC = SectAddress + Index;
+ if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
DebugOut, nulls())) {
- outs() << format("%8" PRIx64 ":\t", SectAddress + Index);
- DumpBytes(StringRef(Bytes.data() + Index, InstSize));
+ if (FullLeadingAddr) {
+ if (MachOOF->is64Bit())
+ outs() << format("%016" PRIx64, PC);
+ else
+ outs() << format("%08" PRIx64, PC);
+ } else {
+ outs() << format("%8" PRIx64 ":", PC);
+ }
+ if (!NoShowRawInsn) {
+ outs() << "\t";
+ DumpBytes(
+ StringRef(reinterpret_cast<const char *>(Bytes.data()) + Index,
+ InstSize));
+ }
IP->printInst(&Inst, outs(), "");
outs() << "\n";
} else {
- errs() << "llvm-objdump: warning: invalid instruction encoding\n";
- if (InstSize == 0)
- InstSize = 1; // skip illegible bytes
+ unsigned int Arch = MachOOF->getArch();
+ if (Arch == Triple::x86_64 || Arch == Triple::x86) {
+ outs() << format("\t.byte 0x%02x #bad opcode\n",
+ *(Bytes.data() + Index) & 0xff);
+ InstSize = 1; // skip exactly one illegible byte and move on.
+ } else {
+ errs() << "llvm-objdump: warning: invalid instruction encoding\n";
+ if (InstSize == 0)
+ InstSize = 1; // skip illegible bytes
+ }
}
}
}
+ // 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)
+ free(SymbolizerInfo.demangled_name);
+ if (SymbolizerInfo.bindtable != nullptr)
+ delete SymbolizerInfo.bindtable;
+ if (ThumbSymbolizerInfo.method != nullptr)
+ free(ThumbSymbolizerInfo.method);
+ if (ThumbSymbolizerInfo.demangled_name != nullptr)
+ free(ThumbSymbolizerInfo.demangled_name);
+ if (ThumbSymbolizerInfo.bindtable != nullptr)
+ delete ThumbSymbolizerInfo.bindtable;
}
}
+
+//===----------------------------------------------------------------------===//
+// __compact_unwind section dumping
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+template <typename T> static uint64_t readNext(const char *&Buf) {
+ using llvm::support::little;
+ using llvm::support::unaligned;
+
+ uint64_t Val = support::endian::read<T, little, unaligned>(Buf);
+ Buf += sizeof(T);
+ return Val;
+}
+
+struct CompactUnwindEntry {
+ uint32_t OffsetInSection;
+
+ uint64_t FunctionAddr;
+ uint32_t Length;
+ uint32_t CompactEncoding;
+ uint64_t PersonalityAddr;
+ uint64_t LSDAAddr;
+
+ RelocationRef FunctionReloc;
+ RelocationRef PersonalityReloc;
+ RelocationRef LSDAReloc;
+
+ CompactUnwindEntry(StringRef Contents, unsigned Offset, bool Is64)
+ : OffsetInSection(Offset) {
+ if (Is64)
+ read<uint64_t>(Contents.data() + Offset);
+ else
+ read<uint32_t>(Contents.data() + Offset);
+ }
+
+private:
+ template <typename UIntPtr> void read(const char *Buf) {
+ FunctionAddr = readNext<UIntPtr>(Buf);
+ Length = readNext<uint32_t>(Buf);
+ CompactEncoding = readNext<uint32_t>(Buf);
+ PersonalityAddr = readNext<UIntPtr>(Buf);
+ LSDAAddr = readNext<UIntPtr>(Buf);
+ }
+};
+}
+
+/// Given a relocation from __compact_unwind, consisting of the RelocationRef
+/// and data being relocated, determine the best base Name and Addend to use for
+/// display purposes.
+///
+/// 1. An Extern relocation will directly reference a symbol (and the data is
+/// then already an addend), so use that.
+/// 2. Otherwise the data is an offset in the object file's layout; try to find
+// a symbol before it in the same section, and use the offset from there.
+/// 3. Finally, if all that fails, fall back to an offset from the start of the
+/// referenced section.
+static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const RelocationRef &Reloc, uint64_t Addr,
+ StringRef &Name, uint64_t &Addend) {
+ if (Reloc.getSymbol() != Obj->symbol_end()) {
+ Reloc.getSymbol()->getName(Name);
+ Addend = Addr;
+ return;
+ }
+
+ auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
+ SectionRef RelocSection = Obj->getRelocationSection(RE);
+
+ uint64_t SectionAddr = RelocSection.getAddress();
+
+ auto Sym = Symbols.upper_bound(Addr);
+ if (Sym == Symbols.begin()) {
+ // The first symbol in the object is after this reference, the best we can
+ // do is section-relative notation.
+ RelocSection.getName(Name);
+ Addend = Addr - SectionAddr;
+ return;
+ }
+
+ // Go back one so that SymbolAddress <= Addr.
+ --Sym;
+
+ section_iterator SymSection = Obj->section_end();
+ Sym->second.getSection(SymSection);
+ if (RelocSection == *SymSection) {
+ // There's a valid symbol in the same section before this reference.
+ Sym->second.getName(Name);
+ Addend = Addr - Sym->first;
+ return;
+ }
+
+ // There is a symbol before this reference, but it's in a different
+ // section. Probably not helpful to mention it, so use the section name.
+ RelocSection.getName(Name);
+ Addend = Addr - SectionAddr;
+}
+
+static void printUnwindRelocDest(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const RelocationRef &Reloc, uint64_t Addr) {
+ StringRef Name;
+ uint64_t Addend;
+
+ if (!Reloc.getObjectFile())
+ return;
+
+ findUnwindRelocNameAddend(Obj, Symbols, Reloc, Addr, Name, Addend);
+
+ outs() << Name;
+ if (Addend)
+ outs() << " + " << format("0x%" PRIx64, Addend);
+}
+
+static void
+printMachOCompactUnwindSection(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const SectionRef &CompactUnwind) {
+
+ assert(Obj->isLittleEndian() &&
+ "There should not be a big-endian .o with __compact_unwind");
+
+ bool Is64 = Obj->is64Bit();
+ uint32_t PointerSize = Is64 ? sizeof(uint64_t) : sizeof(uint32_t);
+ uint32_t EntrySize = 3 * PointerSize + 2 * sizeof(uint32_t);
+
+ StringRef Contents;
+ CompactUnwind.getContents(Contents);
+
+ SmallVector<CompactUnwindEntry, 4> CompactUnwinds;
+
+ // First populate the initial raw offsets, encodings and so on from the entry.
+ for (unsigned Offset = 0; Offset < Contents.size(); Offset += EntrySize) {
+ CompactUnwindEntry Entry(Contents.data(), Offset, Is64);
+ CompactUnwinds.push_back(Entry);
+ }
+
+ // Next we need to look at the relocations to find out what objects are
+ // actually being referred to.
+ for (const RelocationRef &Reloc : CompactUnwind.relocations()) {
+ uint64_t RelocAddress;
+ Reloc.getOffset(RelocAddress);
+
+ uint32_t EntryIdx = RelocAddress / EntrySize;
+ uint32_t OffsetInEntry = RelocAddress - EntryIdx * EntrySize;
+ CompactUnwindEntry &Entry = CompactUnwinds[EntryIdx];
+
+ if (OffsetInEntry == 0)
+ Entry.FunctionReloc = Reloc;
+ else if (OffsetInEntry == PointerSize + 2 * sizeof(uint32_t))
+ Entry.PersonalityReloc = Reloc;
+ else if (OffsetInEntry == 2 * PointerSize + 2 * sizeof(uint32_t))
+ Entry.LSDAReloc = Reloc;
+ else
+ llvm_unreachable("Unexpected relocation in __compact_unwind section");
+ }
+
+ // Finally, we're ready to print the data we've gathered.
+ outs() << "Contents of __compact_unwind section:\n";
+ for (auto &Entry : CompactUnwinds) {
+ outs() << " Entry at offset "
+ << format("0x%" PRIx32, Entry.OffsetInSection) << ":\n";
+
+ // 1. Start of the region this entry applies to.
+ outs() << " start: " << format("0x%" PRIx64,
+ Entry.FunctionAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.FunctionReloc, Entry.FunctionAddr);
+ outs() << '\n';
+
+ // 2. Length of the region this entry applies to.
+ outs() << " length: " << format("0x%" PRIx32, Entry.Length)
+ << '\n';
+ // 3. The 32-bit compact encoding.
+ outs() << " compact encoding: "
+ << format("0x%08" PRIx32, Entry.CompactEncoding) << '\n';
+
+ // 4. The personality function, if present.
+ if (Entry.PersonalityReloc.getObjectFile()) {
+ outs() << " personality function: "
+ << format("0x%" PRIx64, Entry.PersonalityAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.PersonalityReloc,
+ Entry.PersonalityAddr);
+ outs() << '\n';
+ }
+
+ // 5. This entry's language-specific data area.
+ if (Entry.LSDAReloc.getObjectFile()) {
+ outs() << " LSDA: " << format("0x%" PRIx64,
+ Entry.LSDAAddr) << ' ';
+ printUnwindRelocDest(Obj, Symbols, Entry.LSDAReloc, Entry.LSDAAddr);
+ outs() << '\n';
+ }
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// __unwind_info section dumping
+//===----------------------------------------------------------------------===//
+
+static void printRegularSecondLevelUnwindPage(const char *PageStart) {
+ const char *Pos = PageStart;
+ uint32_t Kind = readNext<uint32_t>(Pos);
+ (void)Kind;
+ assert(Kind == 2 && "kind for a regular 2nd level index should be 2");
+
+ uint16_t EntriesStart = readNext<uint16_t>(Pos);
+ uint16_t NumEntries = readNext<uint16_t>(Pos);
+
+ Pos = PageStart + EntriesStart;
+ for (unsigned i = 0; i < NumEntries; ++i) {
+ uint32_t FunctionOffset = readNext<uint32_t>(Pos);
+ uint32_t Encoding = readNext<uint32_t>(Pos);
+
+ outs() << " [" << i << "]: "
+ << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
+ << ", "
+ << "encoding=" << format("0x%08" PRIx32, Encoding) << '\n';
+ }
+}
+
+static void printCompressedSecondLevelUnwindPage(
+ const char *PageStart, uint32_t FunctionBase,
+ const SmallVectorImpl<uint32_t> &CommonEncodings) {
+ const char *Pos = PageStart;
+ uint32_t Kind = readNext<uint32_t>(Pos);
+ (void)Kind;
+ assert(Kind == 3 && "kind for a compressed 2nd level index should be 3");
+
+ uint16_t EntriesStart = readNext<uint16_t>(Pos);
+ uint16_t NumEntries = readNext<uint16_t>(Pos);
+
+ uint16_t EncodingsStart = readNext<uint16_t>(Pos);
+ readNext<uint16_t>(Pos);
+ const auto *PageEncodings = reinterpret_cast<const support::ulittle32_t *>(
+ PageStart + EncodingsStart);
+
+ Pos = PageStart + EntriesStart;
+ for (unsigned i = 0; i < NumEntries; ++i) {
+ uint32_t Entry = readNext<uint32_t>(Pos);
+ uint32_t FunctionOffset = FunctionBase + (Entry & 0xffffff);
+ uint32_t EncodingIdx = Entry >> 24;
+
+ uint32_t Encoding;
+ if (EncodingIdx < CommonEncodings.size())
+ Encoding = CommonEncodings[EncodingIdx];
+ else
+ Encoding = PageEncodings[EncodingIdx - CommonEncodings.size()];
+
+ outs() << " [" << i << "]: "
+ << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
+ << ", "
+ << "encoding[" << EncodingIdx
+ << "]=" << format("0x%08" PRIx32, Encoding) << '\n';
+ }
+}
+
+static void printMachOUnwindInfoSection(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const SectionRef &UnwindInfo) {
+
+ assert(Obj->isLittleEndian() &&
+ "There should not be a big-endian .o with __unwind_info");
+
+ outs() << "Contents of __unwind_info section:\n";
+
+ StringRef Contents;
+ UnwindInfo.getContents(Contents);
+ const char *Pos = Contents.data();
+
+ //===----------------------------------
+ // Section header
+ //===----------------------------------
+
+ uint32_t Version = readNext<uint32_t>(Pos);
+ outs() << " Version: "
+ << format("0x%" PRIx32, Version) << '\n';
+ assert(Version == 1 && "only understand version 1");
+
+ uint32_t CommonEncodingsStart = readNext<uint32_t>(Pos);
+ outs() << " Common encodings array section offset: "
+ << format("0x%" PRIx32, CommonEncodingsStart) << '\n';
+ uint32_t NumCommonEncodings = readNext<uint32_t>(Pos);
+ outs() << " Number of common encodings in array: "
+ << format("0x%" PRIx32, NumCommonEncodings) << '\n';
+
+ uint32_t PersonalitiesStart = readNext<uint32_t>(Pos);
+ outs() << " Personality function array section offset: "
+ << format("0x%" PRIx32, PersonalitiesStart) << '\n';
+ uint32_t NumPersonalities = readNext<uint32_t>(Pos);
+ outs() << " Number of personality functions in array: "
+ << format("0x%" PRIx32, NumPersonalities) << '\n';
+
+ uint32_t IndicesStart = readNext<uint32_t>(Pos);
+ outs() << " Index array section offset: "
+ << format("0x%" PRIx32, IndicesStart) << '\n';
+ uint32_t NumIndices = readNext<uint32_t>(Pos);
+ outs() << " Number of indices in array: "
+ << format("0x%" PRIx32, NumIndices) << '\n';
+
+ //===----------------------------------
+ // A shared list of common encodings
+ //===----------------------------------
+
+ // These occupy indices in the range [0, N] whenever an encoding is referenced
+ // from a compressed 2nd level index table. In practice the linker only
+ // creates ~128 of these, so that indices are available to embed encodings in
+ // the 2nd level index.
+
+ SmallVector<uint32_t, 64> CommonEncodings;
+ outs() << " Common encodings: (count = " << NumCommonEncodings << ")\n";
+ Pos = Contents.data() + CommonEncodingsStart;
+ for (unsigned i = 0; i < NumCommonEncodings; ++i) {
+ uint32_t Encoding = readNext<uint32_t>(Pos);
+ CommonEncodings.push_back(Encoding);
+
+ outs() << " encoding[" << i << "]: " << format("0x%08" PRIx32, Encoding)
+ << '\n';
+ }
+
+ //===----------------------------------
+ // Personality functions used in this executable
+ //===----------------------------------
+
+ // There should be only a handful of these (one per source language,
+ // roughly). Particularly since they only get 2 bits in the compact encoding.
+
+ outs() << " Personality functions: (count = " << NumPersonalities << ")\n";
+ Pos = Contents.data() + PersonalitiesStart;
+ for (unsigned i = 0; i < NumPersonalities; ++i) {
+ uint32_t PersonalityFn = readNext<uint32_t>(Pos);
+ outs() << " personality[" << i + 1
+ << "]: " << format("0x%08" PRIx32, PersonalityFn) << '\n';
+ }
+
+ //===----------------------------------
+ // The level 1 index entries
+ //===----------------------------------
+
+ // These specify an approximate place to start searching for the more detailed
+ // information, sorted by PC.
+
+ struct IndexEntry {
+ uint32_t FunctionOffset;
+ uint32_t SecondLevelPageStart;
+ uint32_t LSDAStart;
+ };
+
+ SmallVector<IndexEntry, 4> IndexEntries;
+
+ outs() << " Top level indices: (count = " << NumIndices << ")\n";
+ Pos = Contents.data() + IndicesStart;
+ for (unsigned i = 0; i < NumIndices; ++i) {
+ IndexEntry Entry;
+
+ Entry.FunctionOffset = readNext<uint32_t>(Pos);
+ Entry.SecondLevelPageStart = readNext<uint32_t>(Pos);
+ Entry.LSDAStart = readNext<uint32_t>(Pos);
+ IndexEntries.push_back(Entry);
+
+ outs() << " [" << i << "]: "
+ << "function offset=" << format("0x%08" PRIx32, Entry.FunctionOffset)
+ << ", "
+ << "2nd level page offset="
+ << format("0x%08" PRIx32, Entry.SecondLevelPageStart) << ", "
+ << "LSDA offset=" << format("0x%08" PRIx32, Entry.LSDAStart) << '\n';
+ }
+
+ //===----------------------------------
+ // Next come the LSDA tables
+ //===----------------------------------
+
+ // The LSDA layout is rather implicit: it's a contiguous array of entries from
+ // the first top-level index's LSDAOffset to the last (sentinel).
+
+ outs() << " LSDA descriptors:\n";
+ Pos = Contents.data() + IndexEntries[0].LSDAStart;
+ int NumLSDAs = (IndexEntries.back().LSDAStart - IndexEntries[0].LSDAStart) /
+ (2 * sizeof(uint32_t));
+ for (int i = 0; i < NumLSDAs; ++i) {
+ uint32_t FunctionOffset = readNext<uint32_t>(Pos);
+ uint32_t LSDAOffset = readNext<uint32_t>(Pos);
+ outs() << " [" << i << "]: "
+ << "function offset=" << format("0x%08" PRIx32, FunctionOffset)
+ << ", "
+ << "LSDA offset=" << format("0x%08" PRIx32, LSDAOffset) << '\n';
+ }
+
+ //===----------------------------------
+ // Finally, the 2nd level indices
+ //===----------------------------------
+
+ // Generally these are 4K in size, and have 2 possible forms:
+ // + Regular stores up to 511 entries with disparate encodings
+ // + Compressed stores up to 1021 entries if few enough compact encoding
+ // values are used.
+ outs() << " Second level indices:\n";
+ for (unsigned i = 0; i < IndexEntries.size() - 1; ++i) {
+ // The final sentinel top-level index has no associated 2nd level page
+ if (IndexEntries[i].SecondLevelPageStart == 0)
+ break;
+
+ outs() << " Second level index[" << i << "]: "
+ << "offset in section="
+ << format("0x%08" PRIx32, IndexEntries[i].SecondLevelPageStart)
+ << ", "
+ << "base function offset="
+ << format("0x%08" PRIx32, IndexEntries[i].FunctionOffset) << '\n';
+
+ Pos = Contents.data() + IndexEntries[i].SecondLevelPageStart;
+ uint32_t Kind = *reinterpret_cast<const support::ulittle32_t *>(Pos);
+ if (Kind == 2)
+ printRegularSecondLevelUnwindPage(Pos);
+ else if (Kind == 3)
+ printCompressedSecondLevelUnwindPage(Pos, IndexEntries[i].FunctionOffset,
+ CommonEncodings);
+ else
+ llvm_unreachable("Do not know how to print this kind of 2nd level page");
+ }
+}
+
+void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
+ std::map<uint64_t, SymbolRef> Symbols;
+ for (const SymbolRef &SymRef : Obj->symbols()) {
+ // Discard any undefined or absolute symbols. They're not going to take part
+ // in the convenience lookup for unwind info and just take up resources.
+ section_iterator Section = Obj->section_end();
+ SymRef.getSection(Section);
+ if (Section == Obj->section_end())
+ continue;
+
+ uint64_t Addr;
+ SymRef.getAddress(Addr);
+ Symbols.insert(std::make_pair(Addr, SymRef));
+ }
+
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ if (SectName == "__compact_unwind")
+ printMachOCompactUnwindSection(Obj, Symbols, Section);
+ else if (SectName == "__unwind_info")
+ printMachOUnwindInfoSection(Obj, Symbols, Section);
+ else if (SectName == "__eh_frame")
+ outs() << "llvm-objdump: warning: unhandled __eh_frame section\n";
+ }
+}
+
+static void PrintMachHeader(uint32_t magic, uint32_t cputype,
+ uint32_t cpusubtype, uint32_t filetype,
+ uint32_t ncmds, uint32_t sizeofcmds, uint32_t flags,
+ bool verbose) {
+ outs() << "Mach header\n";
+ outs() << " magic cputype cpusubtype caps filetype ncmds "
+ "sizeofcmds flags\n";
+ if (verbose) {
+ if (magic == MachO::MH_MAGIC)
+ outs() << " MH_MAGIC";
+ else if (magic == MachO::MH_MAGIC_64)
+ outs() << "MH_MAGIC_64";
+ else
+ outs() << format(" 0x%08" PRIx32, magic);
+ switch (cputype) {
+ case MachO::CPU_TYPE_I386:
+ outs() << " I386";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_I386_ALL:
+ outs() << " ALL";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_X86_64:
+ outs() << " X86_64";
+ 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";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM_ALL:
+ outs() << " ALL";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V4T:
+ outs() << " V4T";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V5TEJ:
+ outs() << " V5TEJ";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_XSCALE:
+ outs() << " XSCALE";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V6:
+ outs() << " V6";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V6M:
+ outs() << " V6M";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7:
+ outs() << " V7";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7EM:
+ outs() << " V7EM";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7K:
+ outs() << " V7K";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7M:
+ outs() << " V7M";
+ break;
+ case MachO::CPU_SUBTYPE_ARM_V7S:
+ outs() << " V7S";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_ARM64:
+ outs() << " ARM64";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_ALL:
+ outs() << " ALL";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_POWERPC:
+ outs() << " PPC";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ outs() << " ALL";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ case MachO::CPU_TYPE_POWERPC64:
+ outs() << " PPC64";
+ switch (cpusubtype & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ outs() << " ALL";
+ break;
+ default:
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ break;
+ }
+ break;
+ }
+ if ((cpusubtype & MachO::CPU_SUBTYPE_MASK) == MachO::CPU_SUBTYPE_LIB64) {
+ outs() << " LIB64";
+ } else {
+ outs() << format(" 0x%02" PRIx32,
+ (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
+ }
+ switch (filetype) {
+ case MachO::MH_OBJECT:
+ outs() << " OBJECT";
+ break;
+ case MachO::MH_EXECUTE:
+ outs() << " EXECUTE";
+ break;
+ case MachO::MH_FVMLIB:
+ outs() << " FVMLIB";
+ break;
+ case MachO::MH_CORE:
+ outs() << " CORE";
+ break;
+ case MachO::MH_PRELOAD:
+ outs() << " PRELOAD";
+ break;
+ case MachO::MH_DYLIB:
+ outs() << " DYLIB";
+ break;
+ case MachO::MH_DYLIB_STUB:
+ outs() << " DYLIB_STUB";
+ break;
+ case MachO::MH_DYLINKER:
+ outs() << " DYLINKER";
+ break;
+ case MachO::MH_BUNDLE:
+ outs() << " BUNDLE";
+ break;
+ case MachO::MH_DSYM:
+ outs() << " DSYM";
+ break;
+ case MachO::MH_KEXT_BUNDLE:
+ outs() << " KEXTBUNDLE";
+ break;
+ default:
+ outs() << format(" %10u", filetype);
+ break;
+ }
+ outs() << format(" %5u", ncmds);
+ outs() << format(" %10u", sizeofcmds);
+ uint32_t f = flags;
+ if (f & MachO::MH_NOUNDEFS) {
+ outs() << " NOUNDEFS";
+ f &= ~MachO::MH_NOUNDEFS;
+ }
+ if (f & MachO::MH_INCRLINK) {
+ outs() << " INCRLINK";
+ f &= ~MachO::MH_INCRLINK;
+ }
+ if (f & MachO::MH_DYLDLINK) {
+ outs() << " DYLDLINK";
+ f &= ~MachO::MH_DYLDLINK;
+ }
+ if (f & MachO::MH_BINDATLOAD) {
+ outs() << " BINDATLOAD";
+ f &= ~MachO::MH_BINDATLOAD;
+ }
+ if (f & MachO::MH_PREBOUND) {
+ outs() << " PREBOUND";
+ f &= ~MachO::MH_PREBOUND;
+ }
+ if (f & MachO::MH_SPLIT_SEGS) {
+ outs() << " SPLIT_SEGS";
+ f &= ~MachO::MH_SPLIT_SEGS;
+ }
+ if (f & MachO::MH_LAZY_INIT) {
+ outs() << " LAZY_INIT";
+ f &= ~MachO::MH_LAZY_INIT;
+ }
+ if (f & MachO::MH_TWOLEVEL) {
+ outs() << " TWOLEVEL";
+ f &= ~MachO::MH_TWOLEVEL;
+ }
+ if (f & MachO::MH_FORCE_FLAT) {
+ outs() << " FORCE_FLAT";
+ f &= ~MachO::MH_FORCE_FLAT;
+ }
+ if (f & MachO::MH_NOMULTIDEFS) {
+ outs() << " NOMULTIDEFS";
+ f &= ~MachO::MH_NOMULTIDEFS;
+ }
+ if (f & MachO::MH_NOFIXPREBINDING) {
+ outs() << " NOFIXPREBINDING";
+ f &= ~MachO::MH_NOFIXPREBINDING;
+ }
+ if (f & MachO::MH_PREBINDABLE) {
+ outs() << " PREBINDABLE";
+ f &= ~MachO::MH_PREBINDABLE;
+ }
+ if (f & MachO::MH_ALLMODSBOUND) {
+ outs() << " ALLMODSBOUND";
+ f &= ~MachO::MH_ALLMODSBOUND;
+ }
+ if (f & MachO::MH_SUBSECTIONS_VIA_SYMBOLS) {
+ outs() << " SUBSECTIONS_VIA_SYMBOLS";
+ f &= ~MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+ }
+ if (f & MachO::MH_CANONICAL) {
+ outs() << " CANONICAL";
+ f &= ~MachO::MH_CANONICAL;
+ }
+ if (f & MachO::MH_WEAK_DEFINES) {
+ outs() << " WEAK_DEFINES";
+ f &= ~MachO::MH_WEAK_DEFINES;
+ }
+ if (f & MachO::MH_BINDS_TO_WEAK) {
+ outs() << " BINDS_TO_WEAK";
+ f &= ~MachO::MH_BINDS_TO_WEAK;
+ }
+ if (f & MachO::MH_ALLOW_STACK_EXECUTION) {
+ outs() << " ALLOW_STACK_EXECUTION";
+ f &= ~MachO::MH_ALLOW_STACK_EXECUTION;
+ }
+ if (f & MachO::MH_DEAD_STRIPPABLE_DYLIB) {
+ outs() << " DEAD_STRIPPABLE_DYLIB";
+ f &= ~MachO::MH_DEAD_STRIPPABLE_DYLIB;
+ }
+ if (f & MachO::MH_PIE) {
+ outs() << " PIE";
+ f &= ~MachO::MH_PIE;
+ }
+ if (f & MachO::MH_NO_REEXPORTED_DYLIBS) {
+ outs() << " NO_REEXPORTED_DYLIBS";
+ f &= ~MachO::MH_NO_REEXPORTED_DYLIBS;
+ }
+ if (f & MachO::MH_HAS_TLV_DESCRIPTORS) {
+ outs() << " MH_HAS_TLV_DESCRIPTORS";
+ f &= ~MachO::MH_HAS_TLV_DESCRIPTORS;
+ }
+ if (f & MachO::MH_NO_HEAP_EXECUTION) {
+ outs() << " MH_NO_HEAP_EXECUTION";
+ f &= ~MachO::MH_NO_HEAP_EXECUTION;
+ }
+ if (f & MachO::MH_APP_EXTENSION_SAFE) {
+ outs() << " APP_EXTENSION_SAFE";
+ f &= ~MachO::MH_APP_EXTENSION_SAFE;
+ }
+ if (f != 0 || flags == 0)
+ outs() << format(" 0x%08" PRIx32, f);
+ } else {
+ outs() << format(" 0x%08" PRIx32, magic);
+ outs() << format(" %7d", cputype);
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ outs() << format(" 0x%02" PRIx32,
+ (cpusubtype & MachO::CPU_SUBTYPE_MASK) >> 24);
+ outs() << format(" %10u", filetype);
+ outs() << format(" %5u", ncmds);
+ outs() << format(" %10u", sizeofcmds);
+ outs() << format(" 0x%08" PRIx32, flags);
+ }
+ outs() << "\n";
+}
+
+static void PrintSegmentCommand(uint32_t cmd, uint32_t cmdsize,
+ StringRef SegName, uint64_t vmaddr,
+ uint64_t vmsize, uint64_t fileoff,
+ uint64_t filesize, uint32_t maxprot,
+ uint32_t initprot, uint32_t nsects,
+ uint32_t flags, uint32_t object_size,
+ bool verbose) {
+ uint64_t expected_cmdsize;
+ if (cmd == MachO::LC_SEGMENT) {
+ outs() << " cmd LC_SEGMENT\n";
+ expected_cmdsize = nsects;
+ expected_cmdsize *= sizeof(struct MachO::section);
+ expected_cmdsize += sizeof(struct MachO::segment_command);
+ } else {
+ outs() << " cmd LC_SEGMENT_64\n";
+ expected_cmdsize = nsects;
+ expected_cmdsize *= sizeof(struct MachO::section_64);
+ expected_cmdsize += sizeof(struct MachO::segment_command_64);
+ }
+ outs() << " cmdsize " << cmdsize;
+ if (cmdsize != expected_cmdsize)
+ outs() << " Inconsistent size\n";
+ else
+ outs() << "\n";
+ outs() << " segname " << SegName << "\n";
+ if (cmd == MachO::LC_SEGMENT_64) {
+ outs() << " vmaddr " << format("0x%016" PRIx64, vmaddr) << "\n";
+ outs() << " vmsize " << format("0x%016" PRIx64, vmsize) << "\n";
+ } else {
+ outs() << " vmaddr " << format("0x%08" PRIx64, vmaddr) << "\n";
+ outs() << " vmsize " << format("0x%08" PRIx64, vmsize) << "\n";
+ }
+ outs() << " fileoff " << fileoff;
+ if (fileoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " filesize " << filesize;
+ if (fileoff + filesize > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ if (verbose) {
+ if ((maxprot &
+ ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
+ MachO::VM_PROT_EXECUTE)) != 0)
+ outs() << " maxprot ?" << format("0x%08" PRIx32, maxprot) << "\n";
+ else {
+ if (maxprot & MachO::VM_PROT_READ)
+ outs() << " maxprot r";
+ else
+ outs() << " maxprot -";
+ if (maxprot & MachO::VM_PROT_WRITE)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (maxprot & MachO::VM_PROT_EXECUTE)
+ outs() << "x\n";
+ else
+ outs() << "-\n";
+ }
+ if ((initprot &
+ ~(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE |
+ MachO::VM_PROT_EXECUTE)) != 0)
+ outs() << " initprot ?" << format("0x%08" PRIx32, initprot) << "\n";
+ else {
+ if (initprot & MachO::VM_PROT_READ)
+ outs() << " initprot r";
+ else
+ outs() << " initprot -";
+ if (initprot & MachO::VM_PROT_WRITE)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (initprot & MachO::VM_PROT_EXECUTE)
+ outs() << "x\n";
+ else
+ outs() << "-\n";
+ }
+ } else {
+ outs() << " maxprot " << format("0x%08" PRIx32, maxprot) << "\n";
+ outs() << " initprot " << format("0x%08" PRIx32, initprot) << "\n";
+ }
+ outs() << " nsects " << nsects << "\n";
+ if (verbose) {
+ outs() << " flags";
+ if (flags == 0)
+ outs() << " (none)\n";
+ else {
+ if (flags & MachO::SG_HIGHVM) {
+ outs() << " HIGHVM";
+ flags &= ~MachO::SG_HIGHVM;
+ }
+ if (flags & MachO::SG_FVMLIB) {
+ outs() << " FVMLIB";
+ flags &= ~MachO::SG_FVMLIB;
+ }
+ if (flags & MachO::SG_NORELOC) {
+ outs() << " NORELOC";
+ flags &= ~MachO::SG_NORELOC;
+ }
+ if (flags & MachO::SG_PROTECTED_VERSION_1) {
+ outs() << " PROTECTED_VERSION_1";
+ flags &= ~MachO::SG_PROTECTED_VERSION_1;
+ }
+ if (flags)
+ outs() << format(" 0x%08" PRIx32, flags) << " (unknown flags)\n";
+ else
+ outs() << "\n";
+ }
+ } else {
+ outs() << " flags " << format("0x%" PRIx32, flags) << "\n";
+ }
+}
+
+static void PrintSection(const char *sectname, const char *segname,
+ uint64_t addr, uint64_t size, uint32_t offset,
+ uint32_t align, uint32_t reloff, uint32_t nreloc,
+ uint32_t flags, uint32_t reserved1, uint32_t reserved2,
+ uint32_t cmd, const char *sg_segname,
+ uint32_t filetype, uint32_t object_size,
+ bool verbose) {
+ outs() << "Section\n";
+ outs() << " sectname " << format("%.16s\n", sectname);
+ outs() << " segname " << format("%.16s", segname);
+ if (filetype != MachO::MH_OBJECT && strncmp(sg_segname, segname, 16) != 0)
+ outs() << " (does not match segment)\n";
+ else
+ outs() << "\n";
+ if (cmd == MachO::LC_SEGMENT_64) {
+ outs() << " addr " << format("0x%016" PRIx64, addr) << "\n";
+ outs() << " size " << format("0x%016" PRIx64, size);
+ } else {
+ 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";
+ else
+ outs() << "\n";
+ outs() << " offset " << offset;
+ if (offset > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ uint32_t align_shifted = 1 << align;
+ outs() << " align 2^" << align << " (" << align_shifted << ")\n";
+ outs() << " reloff " << reloff;
+ if (reloff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nreloc " << nreloc;
+ if (reloff + nreloc * sizeof(struct MachO::relocation_info) > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ uint32_t section_type = flags & MachO::SECTION_TYPE;
+ if (verbose) {
+ outs() << " type";
+ if (section_type == MachO::S_REGULAR)
+ outs() << " S_REGULAR\n";
+ else if (section_type == MachO::S_ZEROFILL)
+ outs() << " S_ZEROFILL\n";
+ else if (section_type == MachO::S_CSTRING_LITERALS)
+ outs() << " S_CSTRING_LITERALS\n";
+ else if (section_type == MachO::S_4BYTE_LITERALS)
+ outs() << " S_4BYTE_LITERALS\n";
+ else if (section_type == MachO::S_8BYTE_LITERALS)
+ outs() << " S_8BYTE_LITERALS\n";
+ else if (section_type == MachO::S_16BYTE_LITERALS)
+ outs() << " S_16BYTE_LITERALS\n";
+ else if (section_type == MachO::S_LITERAL_POINTERS)
+ outs() << " S_LITERAL_POINTERS\n";
+ else if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS)
+ outs() << " S_NON_LAZY_SYMBOL_POINTERS\n";
+ else if (section_type == MachO::S_LAZY_SYMBOL_POINTERS)
+ outs() << " S_LAZY_SYMBOL_POINTERS\n";
+ else if (section_type == MachO::S_SYMBOL_STUBS)
+ outs() << " S_SYMBOL_STUBS\n";
+ else if (section_type == MachO::S_MOD_INIT_FUNC_POINTERS)
+ outs() << " S_MOD_INIT_FUNC_POINTERS\n";
+ else if (section_type == MachO::S_MOD_TERM_FUNC_POINTERS)
+ outs() << " S_MOD_TERM_FUNC_POINTERS\n";
+ else if (section_type == MachO::S_COALESCED)
+ outs() << " S_COALESCED\n";
+ else if (section_type == MachO::S_INTERPOSING)
+ outs() << " S_INTERPOSING\n";
+ else if (section_type == MachO::S_DTRACE_DOF)
+ outs() << " S_DTRACE_DOF\n";
+ else if (section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS)
+ outs() << " S_LAZY_DYLIB_SYMBOL_POINTERS\n";
+ else if (section_type == MachO::S_THREAD_LOCAL_REGULAR)
+ outs() << " S_THREAD_LOCAL_REGULAR\n";
+ else if (section_type == MachO::S_THREAD_LOCAL_ZEROFILL)
+ outs() << " S_THREAD_LOCAL_ZEROFILL\n";
+ else if (section_type == MachO::S_THREAD_LOCAL_VARIABLES)
+ outs() << " S_THREAD_LOCAL_VARIABLES\n";
+ else if (section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
+ outs() << " S_THREAD_LOCAL_VARIABLE_POINTERS\n";
+ else if (section_type == MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS)
+ outs() << " S_THREAD_LOCAL_INIT_FUNCTION_POINTERS\n";
+ else
+ outs() << format("0x%08" PRIx32, section_type) << "\n";
+ outs() << "attributes";
+ uint32_t section_attributes = flags & MachO::SECTION_ATTRIBUTES;
+ if (section_attributes & MachO::S_ATTR_PURE_INSTRUCTIONS)
+ outs() << " PURE_INSTRUCTIONS";
+ if (section_attributes & MachO::S_ATTR_NO_TOC)
+ outs() << " NO_TOC";
+ if (section_attributes & MachO::S_ATTR_STRIP_STATIC_SYMS)
+ outs() << " STRIP_STATIC_SYMS";
+ if (section_attributes & MachO::S_ATTR_NO_DEAD_STRIP)
+ outs() << " NO_DEAD_STRIP";
+ if (section_attributes & MachO::S_ATTR_LIVE_SUPPORT)
+ outs() << " LIVE_SUPPORT";
+ if (section_attributes & MachO::S_ATTR_SELF_MODIFYING_CODE)
+ outs() << " SELF_MODIFYING_CODE";
+ if (section_attributes & MachO::S_ATTR_DEBUG)
+ outs() << " DEBUG";
+ if (section_attributes & MachO::S_ATTR_SOME_INSTRUCTIONS)
+ outs() << " SOME_INSTRUCTIONS";
+ if (section_attributes & MachO::S_ATTR_EXT_RELOC)
+ outs() << " EXT_RELOC";
+ if (section_attributes & MachO::S_ATTR_LOC_RELOC)
+ outs() << " LOC_RELOC";
+ if (section_attributes == 0)
+ outs() << " (none)";
+ outs() << "\n";
+ } else
+ outs() << " flags " << format("0x%08" PRIx32, flags) << "\n";
+ outs() << " reserved1 " << reserved1;
+ if (section_type == MachO::S_SYMBOL_STUBS ||
+ section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
+ section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
+ outs() << " (index into indirect symbol table)\n";
+ else
+ outs() << "\n";
+ outs() << " reserved2 " << reserved2;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ outs() << " (size of stubs)\n";
+ else
+ outs() << "\n";
+}
+
+static void PrintSymtabLoadCommand(MachO::symtab_command st, bool Is64Bit,
+ uint32_t object_size) {
+ outs() << " cmd LC_SYMTAB\n";
+ outs() << " cmdsize " << st.cmdsize;
+ if (st.cmdsize != sizeof(struct MachO::symtab_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " symoff " << st.symoff;
+ if (st.symoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nsyms " << st.nsyms;
+ uint64_t big_size;
+ if (Is64Bit) {
+ big_size = st.nsyms;
+ big_size *= sizeof(struct MachO::nlist_64);
+ big_size += st.symoff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ } else {
+ big_size = st.nsyms;
+ big_size *= sizeof(struct MachO::nlist);
+ big_size += st.symoff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ }
+ outs() << " stroff " << st.stroff;
+ if (st.stroff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " strsize " << st.strsize;
+ big_size = st.stroff;
+ big_size += st.strsize;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+}
+
+static void PrintDysymtabLoadCommand(MachO::dysymtab_command dyst,
+ uint32_t nsyms, uint32_t object_size,
+ bool Is64Bit) {
+ outs() << " cmd LC_DYSYMTAB\n";
+ outs() << " cmdsize " << dyst.cmdsize;
+ if (dyst.cmdsize != sizeof(struct MachO::dysymtab_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " ilocalsym " << dyst.ilocalsym;
+ if (dyst.ilocalsym > nsyms)
+ outs() << " (greater than the number of symbols)\n";
+ else
+ outs() << "\n";
+ outs() << " nlocalsym " << dyst.nlocalsym;
+ uint64_t big_size;
+ big_size = dyst.ilocalsym;
+ big_size += dyst.nlocalsym;
+ if (big_size > nsyms)
+ outs() << " (past the end of the symbol table)\n";
+ else
+ outs() << "\n";
+ outs() << " iextdefsym " << dyst.iextdefsym;
+ if (dyst.iextdefsym > nsyms)
+ outs() << " (greater than the number of symbols)\n";
+ else
+ outs() << "\n";
+ outs() << " nextdefsym " << dyst.nextdefsym;
+ big_size = dyst.iextdefsym;
+ big_size += dyst.nextdefsym;
+ if (big_size > nsyms)
+ outs() << " (past the end of the symbol table)\n";
+ else
+ outs() << "\n";
+ outs() << " iundefsym " << dyst.iundefsym;
+ if (dyst.iundefsym > nsyms)
+ outs() << " (greater than the number of symbols)\n";
+ else
+ outs() << "\n";
+ outs() << " nundefsym " << dyst.nundefsym;
+ big_size = dyst.iundefsym;
+ big_size += dyst.nundefsym;
+ if (big_size > nsyms)
+ outs() << " (past the end of the symbol table)\n";
+ else
+ outs() << "\n";
+ outs() << " tocoff " << dyst.tocoff;
+ if (dyst.tocoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " ntoc " << dyst.ntoc;
+ big_size = dyst.ntoc;
+ big_size *= sizeof(struct MachO::dylib_table_of_contents);
+ big_size += dyst.tocoff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " modtaboff " << dyst.modtaboff;
+ if (dyst.modtaboff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nmodtab " << dyst.nmodtab;
+ uint64_t modtabend;
+ if (Is64Bit) {
+ modtabend = dyst.nmodtab;
+ modtabend *= sizeof(struct MachO::dylib_module_64);
+ modtabend += dyst.modtaboff;
+ } else {
+ modtabend = dyst.nmodtab;
+ modtabend *= sizeof(struct MachO::dylib_module);
+ modtabend += dyst.modtaboff;
+ }
+ if (modtabend > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " extrefsymoff " << dyst.extrefsymoff;
+ if (dyst.extrefsymoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nextrefsyms " << dyst.nextrefsyms;
+ big_size = dyst.nextrefsyms;
+ big_size *= sizeof(struct MachO::dylib_reference);
+ big_size += dyst.extrefsymoff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " indirectsymoff " << dyst.indirectsymoff;
+ if (dyst.indirectsymoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nindirectsyms " << dyst.nindirectsyms;
+ big_size = dyst.nindirectsyms;
+ big_size *= sizeof(uint32_t);
+ big_size += dyst.indirectsymoff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " extreloff " << dyst.extreloff;
+ if (dyst.extreloff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nextrel " << dyst.nextrel;
+ big_size = dyst.nextrel;
+ big_size *= sizeof(struct MachO::relocation_info);
+ big_size += dyst.extreloff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " locreloff " << dyst.locreloff;
+ if (dyst.locreloff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " nlocrel " << dyst.nlocrel;
+ big_size = dyst.nlocrel;
+ big_size *= sizeof(struct MachO::relocation_info);
+ big_size += dyst.locreloff;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+}
+
+static void PrintDyldInfoLoadCommand(MachO::dyld_info_command dc,
+ uint32_t object_size) {
+ if (dc.cmd == MachO::LC_DYLD_INFO)
+ outs() << " cmd LC_DYLD_INFO\n";
+ else
+ outs() << " cmd LC_DYLD_INFO_ONLY\n";
+ outs() << " cmdsize " << dc.cmdsize;
+ if (dc.cmdsize != sizeof(struct MachO::dyld_info_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " rebase_off " << dc.rebase_off;
+ if (dc.rebase_off > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " rebase_size " << dc.rebase_size;
+ uint64_t big_size;
+ big_size = dc.rebase_off;
+ big_size += dc.rebase_size;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " bind_off " << dc.bind_off;
+ if (dc.bind_off > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " bind_size " << dc.bind_size;
+ big_size = dc.bind_off;
+ big_size += dc.bind_size;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " weak_bind_off " << dc.weak_bind_off;
+ if (dc.weak_bind_off > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " weak_bind_size " << dc.weak_bind_size;
+ big_size = dc.weak_bind_off;
+ big_size += dc.weak_bind_size;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " lazy_bind_off " << dc.lazy_bind_off;
+ if (dc.lazy_bind_off > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " lazy_bind_size " << dc.lazy_bind_size;
+ big_size = dc.lazy_bind_off;
+ big_size += dc.lazy_bind_size;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " export_off " << dc.export_off;
+ if (dc.export_off > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " export_size " << dc.export_size;
+ big_size = dc.export_off;
+ big_size += dc.export_size;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+}
+
+static void PrintDyldLoadCommand(MachO::dylinker_command dyld,
+ const char *Ptr) {
+ if (dyld.cmd == MachO::LC_ID_DYLINKER)
+ outs() << " cmd LC_ID_DYLINKER\n";
+ else if (dyld.cmd == MachO::LC_LOAD_DYLINKER)
+ outs() << " cmd LC_LOAD_DYLINKER\n";
+ else if (dyld.cmd == MachO::LC_DYLD_ENVIRONMENT)
+ outs() << " cmd LC_DYLD_ENVIRONMENT\n";
+ else
+ outs() << " cmd ?(" << dyld.cmd << ")\n";
+ outs() << " cmdsize " << dyld.cmdsize;
+ if (dyld.cmdsize < sizeof(struct MachO::dylinker_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (dyld.name >= dyld.cmdsize)
+ outs() << " name ?(bad offset " << dyld.name << ")\n";
+ else {
+ const char *P = (const char *)(Ptr) + dyld.name;
+ outs() << " name " << P << " (offset " << dyld.name << ")\n";
+ }
+}
+
+static void PrintUuidLoadCommand(MachO::uuid_command uuid) {
+ outs() << " cmd LC_UUID\n";
+ outs() << " cmdsize " << uuid.cmdsize;
+ if (uuid.cmdsize != sizeof(struct MachO::uuid_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " uuid ";
+ outs() << format("%02" PRIX32, uuid.uuid[0]);
+ outs() << format("%02" PRIX32, uuid.uuid[1]);
+ outs() << format("%02" PRIX32, uuid.uuid[2]);
+ outs() << format("%02" PRIX32, uuid.uuid[3]);
+ outs() << "-";
+ outs() << format("%02" PRIX32, uuid.uuid[4]);
+ outs() << format("%02" PRIX32, uuid.uuid[5]);
+ outs() << "-";
+ outs() << format("%02" PRIX32, uuid.uuid[6]);
+ outs() << format("%02" PRIX32, uuid.uuid[7]);
+ outs() << "-";
+ outs() << format("%02" PRIX32, uuid.uuid[8]);
+ outs() << format("%02" PRIX32, uuid.uuid[9]);
+ outs() << "-";
+ outs() << format("%02" PRIX32, uuid.uuid[10]);
+ outs() << format("%02" PRIX32, uuid.uuid[11]);
+ outs() << format("%02" PRIX32, uuid.uuid[12]);
+ outs() << format("%02" PRIX32, uuid.uuid[13]);
+ outs() << format("%02" PRIX32, uuid.uuid[14]);
+ outs() << format("%02" PRIX32, uuid.uuid[15]);
+ 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";
+ else if (vd.cmd == MachO::LC_VERSION_MIN_IPHONEOS)
+ outs() << " cmd LC_VERSION_MIN_IPHONEOS\n";
+ else
+ outs() << " cmd " << vd.cmd << " (?)\n";
+ outs() << " cmdsize " << vd.cmdsize;
+ if (vd.cmdsize != sizeof(struct MachO::version_min_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " version " << ((vd.version >> 16) & 0xffff) << "."
+ << ((vd.version >> 8) & 0xff);
+ if ((vd.version & 0xff) != 0)
+ outs() << "." << (vd.version & 0xff);
+ outs() << "\n";
+ if (vd.sdk == 0)
+ outs() << " sdk n/a";
+ else {
+ outs() << " sdk " << ((vd.sdk >> 16) & 0xffff) << "."
+ << ((vd.sdk >> 8) & 0xff);
+ }
+ if ((vd.sdk & 0xff) != 0)
+ outs() << "." << (vd.sdk & 0xff);
+ outs() << "\n";
+}
+
+static void PrintSourceVersionCommand(MachO::source_version_command sd) {
+ outs() << " cmd LC_SOURCE_VERSION\n";
+ outs() << " cmdsize " << sd.cmdsize;
+ if (sd.cmdsize != sizeof(struct MachO::source_version_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ uint64_t a = (sd.version >> 40) & 0xffffff;
+ uint64_t b = (sd.version >> 30) & 0x3ff;
+ uint64_t c = (sd.version >> 20) & 0x3ff;
+ uint64_t d = (sd.version >> 10) & 0x3ff;
+ uint64_t e = sd.version & 0x3ff;
+ outs() << " version " << a << "." << b;
+ if (e != 0)
+ outs() << "." << c << "." << d << "." << e;
+ else if (d != 0)
+ outs() << "." << c << "." << d;
+ else if (c != 0)
+ outs() << "." << c;
+ outs() << "\n";
+}
+
+static void PrintEntryPointCommand(MachO::entry_point_command ep) {
+ outs() << " cmd LC_MAIN\n";
+ outs() << " cmdsize " << ep.cmdsize;
+ if (ep.cmdsize != sizeof(struct MachO::entry_point_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " entryoff " << ep.entryoff << "\n";
+ 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";
+ else if (dl.cmd == MachO::LC_LOAD_DYLIB)
+ outs() << " cmd LC_LOAD_DYLIB\n";
+ else if (dl.cmd == MachO::LC_LOAD_WEAK_DYLIB)
+ outs() << " cmd LC_LOAD_WEAK_DYLIB\n";
+ else if (dl.cmd == MachO::LC_REEXPORT_DYLIB)
+ outs() << " cmd LC_REEXPORT_DYLIB\n";
+ else if (dl.cmd == MachO::LC_LAZY_LOAD_DYLIB)
+ outs() << " cmd LC_LAZY_LOAD_DYLIB\n";
+ else if (dl.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
+ outs() << " cmd LC_LOAD_UPWARD_DYLIB\n";
+ else
+ outs() << " cmd " << dl.cmd << " (unknown)\n";
+ outs() << " cmdsize " << dl.cmdsize;
+ if (dl.cmdsize < sizeof(struct MachO::dylib_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ if (dl.dylib.name < dl.cmdsize) {
+ const char *P = (const char *)(Ptr) + dl.dylib.name;
+ outs() << " name " << P << " (offset " << dl.dylib.name << ")\n";
+ } else {
+ outs() << " name ?(bad offset " << dl.dylib.name << ")\n";
+ }
+ outs() << " time stamp " << dl.dylib.timestamp << " ";
+ time_t t = dl.dylib.timestamp;
+ outs() << ctime(&t);
+ outs() << " current version ";
+ if (dl.dylib.current_version == 0xffffffff)
+ outs() << "n/a\n";
+ else
+ outs() << ((dl.dylib.current_version >> 16) & 0xffff) << "."
+ << ((dl.dylib.current_version >> 8) & 0xff) << "."
+ << (dl.dylib.current_version & 0xff) << "\n";
+ outs() << "compatibility version ";
+ if (dl.dylib.compatibility_version == 0xffffffff)
+ outs() << "n/a\n";
+ else
+ outs() << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
+ << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
+ << (dl.dylib.compatibility_version & 0xff) << "\n";
+}
+
+static void PrintLinkEditDataCommand(MachO::linkedit_data_command ld,
+ uint32_t object_size) {
+ if (ld.cmd == MachO::LC_CODE_SIGNATURE)
+ outs() << " cmd LC_FUNCTION_STARTS\n";
+ else if (ld.cmd == MachO::LC_SEGMENT_SPLIT_INFO)
+ outs() << " cmd LC_SEGMENT_SPLIT_INFO\n";
+ else if (ld.cmd == MachO::LC_FUNCTION_STARTS)
+ outs() << " cmd LC_FUNCTION_STARTS\n";
+ else if (ld.cmd == MachO::LC_DATA_IN_CODE)
+ outs() << " cmd LC_DATA_IN_CODE\n";
+ else if (ld.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS)
+ outs() << " cmd LC_DYLIB_CODE_SIGN_DRS\n";
+ else if (ld.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT)
+ outs() << " cmd LC_LINKER_OPTIMIZATION_HINT\n";
+ else
+ outs() << " cmd " << ld.cmd << " (?)\n";
+ outs() << " cmdsize " << ld.cmdsize;
+ if (ld.cmdsize != sizeof(struct MachO::linkedit_data_command))
+ outs() << " Incorrect size\n";
+ else
+ outs() << "\n";
+ outs() << " dataoff " << ld.dataoff;
+ if (ld.dataoff > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+ outs() << " datasize " << ld.datasize;
+ uint64_t big_size = ld.dataoff;
+ big_size += ld.datasize;
+ if (big_size > object_size)
+ outs() << " (past end of file)\n";
+ else
+ outs() << "\n";
+}
+
+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) {
+ outs() << "Load command " << i << "\n";
+ if (Command.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command SLC = Obj->getSegmentLoadCommand(Command);
+ const char *sg_segname = SLC.segname;
+ PrintSegmentCommand(SLC.cmd, SLC.cmdsize, SLC.segname, SLC.vmaddr,
+ SLC.vmsize, SLC.fileoff, SLC.filesize, SLC.maxprot,
+ SLC.initprot, SLC.nsects, SLC.flags, Buf.size(),
+ verbose);
+ for (unsigned j = 0; j < SLC.nsects; 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);
+ }
+ } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 SLC_64 = Obj->getSegment64LoadCommand(Command);
+ const char *sg_segname = SLC_64.segname;
+ PrintSegmentCommand(SLC_64.cmd, SLC_64.cmdsize, SLC_64.segname,
+ SLC_64.vmaddr, SLC_64.vmsize, SLC_64.fileoff,
+ SLC_64.filesize, SLC_64.maxprot, SLC_64.initprot,
+ SLC_64.nsects, SLC_64.flags, Buf.size(), verbose);
+ for (unsigned j = 0; j < SLC_64.nsects; j++) {
+ MachO::section_64 S_64 = Obj->getSection64(Command, j);
+ PrintSection(S_64.sectname, S_64.segname, S_64.addr, S_64.size,
+ S_64.offset, S_64.align, S_64.reloff, S_64.nreloc,
+ S_64.flags, S_64.reserved1, S_64.reserved2, SLC_64.cmd,
+ sg_segname, filetype, Buf.size(), verbose);
+ }
+ } else if (Command.C.cmd == MachO::LC_SYMTAB) {
+ MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
+ PrintSymtabLoadCommand(Symtab, Obj->is64Bit(), Buf.size());
+ } else if (Command.C.cmd == MachO::LC_DYSYMTAB) {
+ MachO::dysymtab_command Dysymtab = Obj->getDysymtabLoadCommand();
+ MachO::symtab_command Symtab = Obj->getSymtabLoadCommand();
+ PrintDysymtabLoadCommand(Dysymtab, Symtab.nsyms, Buf.size(),
+ Obj->is64Bit());
+ } else if (Command.C.cmd == MachO::LC_DYLD_INFO ||
+ Command.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
+ MachO::dyld_info_command DyldInfo = Obj->getDyldInfoLoadCommand(Command);
+ PrintDyldInfoLoadCommand(DyldInfo, Buf.size());
+ } else if (Command.C.cmd == MachO::LC_LOAD_DYLINKER ||
+ Command.C.cmd == MachO::LC_ID_DYLINKER ||
+ Command.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
+ MachO::dylinker_command Dyld = Obj->getDylinkerCommand(Command);
+ PrintDyldLoadCommand(Dyld, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_UUID) {
+ MachO::uuid_command Uuid = Obj->getUuidCommand(Command);
+ PrintUuidLoadCommand(Uuid);
+ } 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) {
+ MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command);
+ PrintSourceVersionCommand(Sd);
+ } 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 ||
+ Command.C.cmd == MachO::LC_REEXPORT_DYLIB ||
+ Command.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
+ Command.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
+ MachO::dylib_command Dl = Obj->getDylibIDLoadCommand(Command);
+ PrintDylibCommand(Dl, Command.Ptr);
+ } else if (Command.C.cmd == MachO::LC_CODE_SIGNATURE ||
+ Command.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO ||
+ Command.C.cmd == MachO::LC_FUNCTION_STARTS ||
+ Command.C.cmd == MachO::LC_DATA_IN_CODE ||
+ Command.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS ||
+ Command.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
+ MachO::linkedit_data_command Ld =
+ Obj->getLinkeditDataLoadCommand(Command);
+ PrintLinkEditDataCommand(Ld, Buf.size());
+ } else {
+ outs() << " cmd ?(" << format("0x%08" PRIx32, Command.C.cmd)
+ << ")\n";
+ outs() << " cmdsize " << Command.C.cmdsize << "\n";
+ // TODO: get and print the raw bytes of the load command.
+ }
+ // TODO: print all the other kinds of load commands.
+ if (i == ncmds - 1)
+ break;
+ else
+ Command = Obj->getNextLoadCommandInfo(Command);
+ }
+}
+
+static void getAndPrintMachHeader(const MachOObjectFile *Obj, uint32_t &ncmds,
+ uint32_t &filetype, uint32_t &cputype,
+ bool verbose) {
+ if (Obj->is64Bit()) {
+ MachO::mach_header_64 H_64;
+ H_64 = Obj->getHeader64();
+ PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
+ H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
+ ncmds = H_64.ncmds;
+ filetype = H_64.filetype;
+ cputype = H_64.cputype;
+ } else {
+ MachO::mach_header H;
+ H = Obj->getHeader();
+ PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
+ H.sizeofcmds, H.flags, verbose);
+ ncmds = H.ncmds;
+ filetype = H.filetype;
+ cputype = H.cputype;
+ }
+}
+
+void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
+ const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
+ uint32_t ncmds = 0;
+ uint32_t filetype = 0;
+ uint32_t cputype = 0;
+ getAndPrintMachHeader(file, ncmds, filetype, cputype, true);
+ PrintLoadCommands(file, ncmds, filetype, cputype, true);
+}
+
+//===----------------------------------------------------------------------===//
+// export trie dumping
+//===----------------------------------------------------------------------===//
+
+void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) {
+ for (const llvm::object::ExportEntry &Entry : Obj->exports()) {
+ uint64_t Flags = Entry.flags();
+ bool ReExport = (Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
+ bool WeakDef = (Flags & MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+ bool ThreadLocal = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+ bool Abs = ((Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK) ==
+ MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+ bool Resolver = (Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+ if (ReExport)
+ outs() << "[re-export] ";
+ else
+ outs() << format("0x%08llX ",
+ Entry.address()); // FIXME:add in base address
+ outs() << Entry.name();
+ if (WeakDef || ThreadLocal || Resolver || Abs) {
+ bool NeedsComma = false;
+ outs() << " [";
+ if (WeakDef) {
+ outs() << "weak_def";
+ NeedsComma = true;
+ }
+ if (ThreadLocal) {
+ if (NeedsComma)
+ outs() << ", ";
+ outs() << "per-thread";
+ NeedsComma = true;
+ }
+ if (Abs) {
+ if (NeedsComma)
+ outs() << ", ";
+ outs() << "absolute";
+ NeedsComma = true;
+ }
+ if (Resolver) {
+ if (NeedsComma)
+ outs() << ", ";
+ outs() << format("resolver=0x%08llX", Entry.other());
+ NeedsComma = true;
+ }
+ outs() << "]";
+ }
+ if (ReExport) {
+ StringRef DylibName = "unknown";
+ int Ordinal = Entry.other() - 1;
+ Obj->getLibraryShortNameByIndex(Ordinal, DylibName);
+ if (Entry.otherName().empty())
+ outs() << " (from " << DylibName << ")";
+ else
+ outs() << " (" << Entry.otherName() << " from " << DylibName << ")";
+ }
+ outs() << "\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// rebase table dumping
+//===----------------------------------------------------------------------===//
+
+namespace {
+class SegInfo {
+public:
+ SegInfo(const object::MachOObjectFile *Obj);
+
+ StringRef segmentName(uint32_t SegIndex);
+ StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset);
+ uint64_t address(uint32_t SegIndex, uint64_t SegOffset);
+
+private:
+ struct SectionInfo {
+ uint64_t Address;
+ uint64_t Size;
+ StringRef SectionName;
+ StringRef SegmentName;
+ uint64_t OffsetInSegment;
+ uint64_t SegmentStartAddress;
+ uint32_t SegmentIndex;
+ };
+ const SectionInfo &findSection(uint32_t SegIndex, uint64_t SegOffset);
+ SmallVector<SectionInfo, 32> Sections;
+};
+}
+
+SegInfo::SegInfo(const object::MachOObjectFile *Obj) {
+ // Build table of sections so segIndex/offset pairs can be translated.
+ uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
+ StringRef CurSegName;
+ uint64_t CurSegAddress;
+ for (const SectionRef &Section : Obj->sections()) {
+ SectionInfo Info;
+ if (error(Section.getName(Info.SectionName)))
+ return;
+ Info.Address = Section.getAddress();
+ Info.Size = Section.getSize();
+ Info.SegmentName =
+ Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
+ if (!Info.SegmentName.equals(CurSegName)) {
+ ++CurSegIndex;
+ CurSegName = Info.SegmentName;
+ CurSegAddress = Info.Address;
+ }
+ Info.SegmentIndex = CurSegIndex - 1;
+ Info.OffsetInSegment = Info.Address - CurSegAddress;
+ Info.SegmentStartAddress = CurSegAddress;
+ Sections.push_back(Info);
+ }
+}
+
+StringRef SegInfo::segmentName(uint32_t SegIndex) {
+ for (const SectionInfo &SI : Sections) {
+ if (SI.SegmentIndex == SegIndex)
+ return SI.SegmentName;
+ }
+ llvm_unreachable("invalid segIndex");
+}
+
+const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex,
+ uint64_t OffsetInSeg) {
+ for (const SectionInfo &SI : Sections) {
+ if (SI.SegmentIndex != SegIndex)
+ continue;
+ if (SI.OffsetInSegment > OffsetInSeg)
+ continue;
+ if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size))
+ continue;
+ return SI;
+ }
+ llvm_unreachable("segIndex and offset not in any section");
+}
+
+StringRef SegInfo::sectionName(uint32_t SegIndex, uint64_t OffsetInSeg) {
+ return findSection(SegIndex, OffsetInSeg).SectionName;
+}
+
+uint64_t SegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
+ const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
+ return SI.SegmentStartAddress + OffsetInSeg;
+}
+
+void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) {
+ // Build table of sections so names can used in final output.
+ SegInfo sectionTable(Obj);
+
+ outs() << "segment section address type\n";
+ for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) {
+ uint32_t SegIndex = Entry.segmentIndex();
+ uint64_t OffsetInSeg = Entry.segmentOffset();
+ StringRef SegmentName = sectionTable.segmentName(SegIndex);
+ StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
+ uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+
+ // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer
+ outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n",
+ SegmentName.str().c_str(), SectionName.str().c_str(),
+ Address, Entry.typeName().str().c_str());
+ }
+}
+
+static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) {
+ StringRef DylibName;
+ switch (Ordinal) {
+ case MachO::BIND_SPECIAL_DYLIB_SELF:
+ return "this-image";
+ case MachO::BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE:
+ return "main-executable";
+ case MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
+ return "flat-namespace";
+ default:
+ if (Ordinal > 0) {
+ std::error_code EC =
+ Obj->getLibraryShortNameByIndex(Ordinal - 1, DylibName);
+ if (EC)
+ return "<<bad library ordinal>>";
+ return DylibName;
+ }
+ }
+ return "<<unknown special ordinal>>";
+}
+
+//===----------------------------------------------------------------------===//
+// bind table dumping
+//===----------------------------------------------------------------------===//
+
+void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) {
+ // Build table of sections so names can used in final output.
+ SegInfo sectionTable(Obj);
+
+ outs() << "segment section address type "
+ "addend dylib symbol\n";
+ for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) {
+ uint32_t SegIndex = Entry.segmentIndex();
+ uint64_t OffsetInSeg = Entry.segmentOffset();
+ StringRef SegmentName = sectionTable.segmentName(SegIndex);
+ StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
+ uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+
+ // Table lines look like:
+ // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard
+ StringRef Attr;
+ if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_WEAK_IMPORT)
+ Attr = " (weak_import)";
+ outs() << left_justify(SegmentName, 8) << " "
+ << left_justify(SectionName, 18) << " "
+ << format_hex(Address, 10, true) << " "
+ << left_justify(Entry.typeName(), 8) << " "
+ << format_decimal(Entry.addend(), 8) << " "
+ << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
+ << Entry.symbolName() << Attr << "\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// lazy bind table dumping
+//===----------------------------------------------------------------------===//
+
+void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) {
+ // Build table of sections so names can used in final output.
+ SegInfo sectionTable(Obj);
+
+ outs() << "segment section address "
+ "dylib symbol\n";
+ for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) {
+ uint32_t SegIndex = Entry.segmentIndex();
+ uint64_t OffsetInSeg = Entry.segmentOffset();
+ StringRef SegmentName = sectionTable.segmentName(SegIndex);
+ StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
+ uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+
+ // Table lines look like:
+ // __DATA __got 0x00012010 libSystem ___stack_chk_guard
+ outs() << left_justify(SegmentName, 8) << " "
+ << left_justify(SectionName, 18) << " "
+ << format_hex(Address, 10, true) << " "
+ << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " "
+ << Entry.symbolName() << "\n";
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// weak bind table dumping
+//===----------------------------------------------------------------------===//
+
+void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) {
+ // Build table of sections so names can used in final output.
+ SegInfo sectionTable(Obj);
+
+ outs() << "segment section address "
+ "type addend symbol\n";
+ for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) {
+ // Strong symbols don't have a location to update.
+ if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) {
+ outs() << " strong "
+ << Entry.symbolName() << "\n";
+ continue;
+ }
+ uint32_t SegIndex = Entry.segmentIndex();
+ uint64_t OffsetInSeg = Entry.segmentOffset();
+ StringRef SegmentName = sectionTable.segmentName(SegIndex);
+ StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg);
+ uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+
+ // Table lines look like:
+ // __DATA __data 0x00001000 pointer 0 _foo
+ outs() << left_justify(SegmentName, 8) << " "
+ << left_justify(SectionName, 18) << " "
+ << format_hex(Address, 10, true) << " "
+ << left_justify(Entry.typeName(), 8) << " "
+ << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName()
+ << "\n";
+ }
+}
+
+// get_dyld_bind_info_symbolname() is used for disassembly and passed an
+// address, ReferenceValue, in the Mach-O file and looks in the dyld bind
+// information for that address. If the address is found its binding symbol
+// name is returned. If not nullptr is returned.
+static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
+ if (info->bindtable == nullptr) {
+ info->bindtable = new (BindTable);
+ SegInfo sectionTable(info->O);
+ for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) {
+ uint32_t SegIndex = Entry.segmentIndex();
+ uint64_t OffsetInSeg = Entry.segmentOffset();
+ uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg);
+ const char *SymbolName = nullptr;
+ StringRef name = Entry.symbolName();
+ if (!name.empty())
+ SymbolName = name.data();
+ info->bindtable->push_back(std::make_pair(Address, SymbolName));
+ }
+ }
+ for (bind_table_iterator BI = info->bindtable->begin(),
+ BE = info->bindtable->end();
+ BI != BE; ++BI) {
+ uint64_t Address = BI->first;
+ if (ReferenceValue == Address) {
+ const char *SymbolName = BI->second;
+ return SymbolName;
+ }
+ }
+ return nullptr;
+}
diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile
index c3601ebc14ee..4616b78adb2e 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 MCAnalysis MCParser MCDisassembler Object
+LINK_COMPONENTS := all-targets DebugInfo 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 3cd48e7f0d1b..aff6272d2fa3 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -20,10 +20,6 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
-#include "llvm/MC/MCAnalysis/MCAtom.h"
-#include "llvm/MC/MCAnalysis/MCFunction.h"
-#include "llvm/MC/MCAnalysis/MCModule.h"
-#include "llvm/MC/MCAnalysis/MCModuleYAML.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
@@ -31,9 +27,7 @@
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectDisassembler.h"
#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCObjectSymbolizer.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCRelocationInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
@@ -50,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"
@@ -68,8 +61,8 @@ 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"),
@@ -84,6 +77,21 @@ 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::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
+
+cl::opt<bool>
+llvm::Rebase("rebase", cl::desc("Display mach-o rebasing info"));
+
+cl::opt<bool>
+llvm::Bind("bind", cl::desc("Display mach-o binding info"));
+
+cl::opt<bool>
+llvm::LazyBind("lazy-bind", cl::desc("Display mach-o lazy 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"));
static cl::alias
@@ -94,7 +102,13 @@ llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
"see -version for available targets"));
cl::opt<std::string>
-llvm::ArchName("arch", cl::desc("Target arch to disassemble for, "
+llvm::MCPU("mcpu",
+ cl::desc("Target a specific cpu type (-mcpu=help for details)"),
+ cl::value_desc("cpu-name"),
+ cl::init(""));
+
+cl::opt<std::string>
+llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
"see -version for available targets"));
static cl::opt<bool>
@@ -107,15 +121,16 @@ static cl::alias
SectionHeadersShorter("h", cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders));
-static cl::list<std::string>
-MAttrs("mattr",
+cl::list<std::string>
+llvm::MAttrs("mattr",
cl::CommaSeparated,
cl::desc("Target specific attributes"),
cl::value_desc("a1,+a2,-a3,..."));
-static cl::opt<bool>
-NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling instructions, "
- "do not print the instruction bytes."));
+cl::opt<bool>
+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"));
@@ -124,29 +139,16 @@ 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 cl::opt<bool>
-Symbolize("symbolize", cl::desc("When disassembling instructions, "
- "try to symbolize operands."));
-
-static cl::opt<bool>
-CFG("cfg", cl::desc("Create a CFG for every function found in the object"
- " and write it to a graphviz file"));
-
-// FIXME: Does it make sense to have a dedicated tool for yaml cfg output?
-static cl::opt<std::string>
-YAMLCFG("yaml-cfg",
- cl::desc("Create a CFG and write it as a YAML MCModule."),
- cl::value_desc("yaml output file"));
-
static StringRef ToolName;
+static int ReturnValue = EXIT_SUCCESS;
bool llvm::error(std::error_code EC) {
if (!EC)
@@ -154,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;
}
@@ -191,53 +194,6 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
return TheTarget;
}
-// Write a graphviz file for the CFG inside an MCFunction.
-// FIXME: Use GraphWriter
-static void emitDOTFile(const char *FileName, const MCFunction &f,
- MCInstPrinter *IP) {
- // Start a new dot file.
- std::string Error;
- raw_fd_ostream Out(FileName, Error, sys::fs::F_Text);
- if (!Error.empty()) {
- errs() << "llvm-objdump: warning: " << Error << '\n';
- return;
- }
-
- Out << "digraph \"" << f.getName() << "\" {\n";
- Out << "graph [ rankdir = \"LR\" ];\n";
- for (MCFunction::const_iterator i = f.begin(), e = f.end(); i != e; ++i) {
- // Only print blocks that have predecessors.
- bool hasPreds = (*i)->pred_begin() != (*i)->pred_end();
-
- if (!hasPreds && i != f.begin())
- continue;
-
- Out << '"' << (*i)->getInsts()->getBeginAddr() << "\" [ label=\"<a>";
- // Print instructions.
- for (unsigned ii = 0, ie = (*i)->getInsts()->size(); ii != ie;
- ++ii) {
- if (ii != 0) // Not the first line, start a new row.
- Out << '|';
- if (ii + 1 == ie) // Last line, add an end id.
- Out << "<o>";
-
- // Escape special chars and print the instruction in mnemonic form.
- std::string Str;
- raw_string_ostream OS(Str);
- IP->printInst(&(*i)->getInsts()->at(ii).Inst, OS, "");
- Out << DOT::EscapeString(OS.str());
- }
- Out << "\" shape=\"record\" ];\n";
-
- // Add edges.
- for (MCBasicBlock::succ_const_iterator si = (*i)->succ_begin(),
- se = (*i)->succ_end(); si != se; ++si)
- Out << (*i)->getInsts()->getBeginAddr() << ":o -> "
- << (*si)->getInsts()->getBeginAddr() << ":a\n";
- }
- Out << "}\n";
-}
-
void llvm::DumpBytes(StringRef bytes) {
static const char hex_rep[] = "0123456789abcdef";
// FIXME: The real way to do this is to figure out the longest instruction
@@ -303,7 +259,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
}
std::unique_ptr<const MCSubtargetInfo> STI(
- TheTarget->createMCSubtargetInfo(TripleName, "", FeaturesStr));
+ TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr));
if (!STI) {
errs() << "error: no subtarget info for target " << TripleName << "\n";
return;
@@ -326,19 +282,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
return;
}
-
- if (Symbolize) {
- std::unique_ptr<MCRelocationInfo> RelInfo(
- TheTarget->createMCRelocationInfo(TripleName, Ctx));
- if (RelInfo) {
- std::unique_ptr<MCSymbolizer> Symzer(
- MCObjectSymbolizer::createObjectSymbolizer(Ctx, std::move(RelInfo),
- Obj));
- if (Symzer)
- DisAsm->setSymbolizer(std::move(Symzer));
- }
- }
-
std::unique_ptr<const MCInstrAnalysis> MIA(
TheTarget->createMCInstrAnalysis(MII.get()));
@@ -351,45 +294,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
return;
}
- if (CFG || !YAMLCFG.empty()) {
- std::unique_ptr<MCObjectDisassembler> OD(
- new MCObjectDisassembler(*Obj, *DisAsm, *MIA));
- std::unique_ptr<MCModule> Mod(OD->buildModule(/* withCFG */ true));
- for (MCModule::const_atom_iterator AI = Mod->atom_begin(),
- AE = Mod->atom_end();
- AI != AE; ++AI) {
- outs() << "Atom " << (*AI)->getName() << ": \n";
- if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI)) {
- for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end();
- II != IE;
- ++II) {
- IP->printInst(&II->Inst, outs(), "");
- outs() << "\n";
- }
- }
- }
- if (CFG) {
- for (MCModule::const_func_iterator FI = Mod->func_begin(),
- FE = Mod->func_end();
- FI != FE; ++FI) {
- static int filenum = 0;
- emitDOTFile((Twine((*FI)->getName()) + "_" +
- utostr(filenum) + ".dot").str().c_str(),
- **FI, IP.get());
- ++filenum;
- }
- }
- if (!YAMLCFG.empty()) {
- std::string Error;
- raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error, sys::fs::F_Text);
- if (!Error.empty()) {
- errs() << ToolName << ": warning: " << Error << '\n';
- return;
- }
- mcmodule2yaml(YAMLOut, *Mod, *MII, *MRI);
- }
- }
-
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "\t\t%016" PRIx64 ": " :
"\t\t\t%08" PRIx64 ": ";
@@ -404,25 +308,18 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
}
for (const SectionRef &Section : Obj->sections()) {
- bool Text;
- if (error(Section.isText(Text)))
- break;
- if (!Text)
+ if (!Section.isText() || Section.isVirtual())
continue;
- uint64_t SectionAddr;
- if (error(Section.getAddress(SectionAddr)))
- break;
-
- uint64_t SectSize;
- if (error(Section.getSize(SectSize)))
- break;
+ uint64_t SectionAddr = Section.getAddress();
+ uint64_t SectSize = Section.getSize();
+ if (!SectSize)
+ continue;
// Make a list of all the symbols in this section.
std::vector<std::pair<uint64_t, StringRef>> Symbols;
for (const SymbolRef &Symbol : Obj->symbols()) {
- bool contains;
- if (!error(Section.containsSymbol(Symbol, contains)) && contains) {
+ if (Section.containsSymbol(Symbol)) {
uint64_t Address;
if (error(Symbol.getAddress(Address)))
break;
@@ -477,10 +374,12 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
SmallString<40> Comments;
raw_svector_ostream CommentStream(Comments);
- StringRef Bytes;
- if (error(Section.getContents(Bytes)))
+ StringRef BytesStr;
+ if (error(Section.getContents(BytesStr)))
break;
- StringRefMemoryObject memoryObject(Bytes, SectionAddr);
+ ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
+ BytesStr.size());
+
uint64_t Size;
uint64_t Index;
@@ -488,17 +387,12 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
std::vector<RelocationRef>::const_iterator rel_end = Rels.end();
// Disassemble symbol by symbol.
for (unsigned si = 0, se = Symbols.size(); si != se; ++si) {
+
uint64_t Start = Symbols[si].first;
- uint64_t End;
- // The end is either the size of the section or the beginning of the next
- // symbol.
- if (si == se - 1)
- End = SectSize;
- // Make sure this symbol takes up space.
- else if (Symbols[si + 1].first != Start)
- End = Symbols[si + 1].first - 1;
- else
- // This symbol has the same address as the next symbol. Skip it.
+ // The end is either the section end or the beginning of the next symbol.
+ uint64_t End = (si == se - 1) ? SectSize : Symbols[si + 1].first;
+ // If this symbol has the same address as the next symbol, then skip it.
+ if (Start == End)
continue;
outs() << '\n' << Symbols[si].second << ":\n";
@@ -512,13 +406,14 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
for (Index = Start; Index < End; Index += Size) {
MCInst Inst;
- if (DisAsm->getInstruction(Inst, Size, memoryObject,
- SectionAddr + Index,
- DebugOut, CommentStream)) {
+ if (DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
+ SectionAddr + Index, DebugOut,
+ CommentStream)) {
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
if (!NoShowRawInsn) {
outs() << "\t";
- DumpBytes(StringRef(Bytes.data() + Index, Size));
+ DumpBytes(StringRef(
+ reinterpret_cast<const char *>(Bytes.data()) + Index, Size));
}
IP->printInst(&Inst, outs(), "");
outs() << CommentStream.str();
@@ -561,6 +456,11 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
static void PrintRelocations(const ObjectFile *Obj) {
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
"%08" PRIx64;
+ // Regular objdump doesn't print relocations in non-relocatable object
+ // files.
+ if (!Obj->isRelocatableObject())
+ return;
+
for (const SectionRef &Section : Obj->sections()) {
if (Section.relocation_begin() == Section.relocation_end())
continue;
@@ -598,19 +498,11 @@ static void PrintSectionHeaders(const ObjectFile *Obj) {
StringRef Name;
if (error(Section.getName(Name)))
return;
- uint64_t Address;
- if (error(Section.getAddress(Address)))
- return;
- uint64_t Size;
- if (error(Section.getSize(Size)))
- return;
- bool Text, Data, BSS;
- if (error(Section.isText(Text)))
- return;
- if (error(Section.isData(Data)))
- return;
- if (error(Section.isBSS(BSS)))
- return;
+ uint64_t Address = Section.getAddress();
+ uint64_t Size = Section.getSize();
+ bool Text = Section.isText();
+ bool Data = Section.isData();
+ bool BSS = Section.isBSS();
std::string Type = (std::string(Text ? "TEXT " : "") +
(Data ? "DATA " : "") + (BSS ? "BSS" : ""));
outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", i,
@@ -624,20 +516,15 @@ static void PrintSectionContents(const ObjectFile *Obj) {
for (const SectionRef &Section : Obj->sections()) {
StringRef Name;
StringRef Contents;
- uint64_t BaseAddr;
- bool BSS;
if (error(Section.getName(Name)))
continue;
- if (error(Section.getAddress(BaseAddr)))
- continue;
- if (error(Section.isBSS(BSS)))
+ uint64_t BaseAddr = Section.getAddress();
+ uint64_t Size = Section.getSize();
+ if (!Size)
continue;
outs() << "Contents of section " << Name << ":\n";
- if (BSS) {
- uint64_t Size;
- if (error(Section.getSize(Size)))
- continue;
+ if (Section.isBSS()) {
outs() << format("<skipping contents of bss section at [%04" PRIx64
", %04" PRIx64 ")>\n",
BaseAddr, BaseAddr + Size);
@@ -674,34 +561,32 @@ static void PrintSectionContents(const ObjectFile *Obj) {
}
static void PrintCOFFSymbolTable(const COFFObjectFile *coff) {
- const coff_file_header *header;
- if (error(coff->getHeader(header)))
- return;
-
- for (unsigned SI = 0, SE = header->NumberOfSymbols; SI != SE; ++SI) {
- const coff_symbol *Symbol;
+ for (unsigned SI = 0, SE = coff->getNumberOfSymbols(); SI != SE; ++SI) {
+ ErrorOr<COFFSymbolRef> Symbol = coff->getSymbol(SI);
StringRef Name;
- if (error(coff->getSymbol(SI, Symbol)))
+ if (error(Symbol.getError()))
return;
- if (error(coff->getSymbolName(Symbol, Name)))
+ if (error(coff->getSymbolName(*Symbol, Name)))
return;
outs() << "[" << format("%2d", SI) << "]"
- << "(sec " << format("%2d", int(Symbol->SectionNumber)) << ")"
+ << "(sec " << format("%2d", int(Symbol->getSectionNumber())) << ")"
<< "(fl 0x00)" // Flag bits, which COFF doesn't have.
- << "(ty " << format("%3x", unsigned(Symbol->Type)) << ")"
- << "(scl " << format("%3x", unsigned(Symbol->StorageClass)) << ") "
- << "(nx " << unsigned(Symbol->NumberOfAuxSymbols) << ") "
- << "0x" << format("%08x", unsigned(Symbol->Value)) << " "
+ << "(ty " << format("%3x", unsigned(Symbol->getType())) << ")"
+ << "(scl " << format("%3x", unsigned(Symbol->getStorageClass())) << ") "
+ << "(nx " << unsigned(Symbol->getNumberOfAuxSymbols()) << ") "
+ << "0x" << format("%08x", unsigned(Symbol->getValue())) << " "
<< Name << "\n";
- for (unsigned AI = 0, AE = Symbol->NumberOfAuxSymbols; AI < AE; ++AI, ++SI) {
+ for (unsigned AI = 0, AE = Symbol->getNumberOfAuxSymbols(); AI < AE; ++AI, ++SI) {
if (Symbol->isSectionDefinition()) {
const coff_aux_section_definition *asd;
if (error(coff->getAuxSymbol<coff_aux_section_definition>(SI + 1, asd)))
return;
+ int32_t AuxNumber = asd->getNumber(Symbol->isBigObj());
+
outs() << "AUX "
<< format("scnlen 0x%x nreloc %d nlnno %d checksum 0x%x "
, unsigned(asd->Length)
@@ -709,18 +594,18 @@ static void PrintCOFFSymbolTable(const COFFObjectFile *coff) {
, unsigned(asd->NumberOfLinenumbers)
, unsigned(asd->CheckSum))
<< format("assoc %d comdat %d\n"
- , unsigned(asd->Number)
+ , unsigned(AuxNumber)
, unsigned(asd->Selection));
} else if (Symbol->isFileRecord()) {
- const coff_aux_file *AF;
- if (error(coff->getAuxSymbol<coff_aux_file>(SI + 1, AF)))
+ const char *FileName;
+ if (error(coff->getAuxSymbol<char>(SI + 1, FileName)))
return;
- StringRef Name(AF->FileName,
- Symbol->NumberOfAuxSymbols * COFF::SymbolSize);
+ StringRef Name(FileName, Symbol->getNumberOfAuxSymbols() *
+ coff->getSymbolTableEntrySize());
outs() << "AUX " << Name.rtrim(StringRef("\0", 1)) << '\n';
- SI = SI + Symbol->NumberOfAuxSymbols;
+ SI = SI + Symbol->getNumberOfAuxSymbols();
break;
} else {
outs() << "AUX Unknown\n";
@@ -813,10 +698,67 @@ static void PrintUnwindInfo(const ObjectFile *o) {
if (const COFFObjectFile *coff = dyn_cast<COFFObjectFile>(o)) {
printCOFFUnwindInfo(coff);
- } else {
+ } else if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOUnwindInfo(MachO);
+ else {
// TODO: Extract DWARF dump tool to objdump.
errs() << "This operation is only currently supported "
- "for COFF object files.\n";
+ "for COFF and MachO object files.\n";
+ return;
+ }
+}
+
+void llvm::printExportsTrie(const ObjectFile *o) {
+ outs() << "Exports trie:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOExportsTrie(MachO);
+ else {
+ errs() << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+ return;
+ }
+}
+
+void llvm::printRebaseTable(const ObjectFile *o) {
+ outs() << "Rebase table:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachORebaseTable(MachO);
+ else {
+ errs() << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+ return;
+ }
+}
+
+void llvm::printBindTable(const ObjectFile *o) {
+ outs() << "Bind table:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOBindTable(MachO);
+ else {
+ errs() << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+ return;
+ }
+}
+
+void llvm::printLazyBindTable(const ObjectFile *o) {
+ outs() << "Lazy bind table:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOLazyBindTable(MachO);
+ else {
+ errs() << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
+ return;
+ }
+}
+
+void llvm::printWeakBindTable(const ObjectFile *o) {
+ outs() << "Weak bind table:\n";
+ if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o))
+ printMachOWeakBindTable(MachO);
+ else {
+ errs() << "This operation is only currently supported "
+ "for Mach-O executable files.\n";
return;
}
}
@@ -826,6 +768,8 @@ static void printPrivateFileHeader(const ObjectFile *o) {
printELFFileHeader(o);
} else if (o->isCOFF()) {
printCOFFFileHeader(o);
+ } else if (o->isMachO()) {
+ printMachOFileHeader(o);
}
}
@@ -848,6 +792,16 @@ static void DumpObject(const ObjectFile *o) {
PrintUnwindInfo(o);
if (PrivateHeaders)
printPrivateFileHeader(o);
+ if (ExportsTrie)
+ printExportsTrie(o);
+ if (Rebase)
+ printRebaseTable(o);
+ if (Bind)
+ printBindTable(o);
+ if (LazyBind)
+ printLazyBindTable(o);
+ if (WeakBind)
+ printWeakBindTable(o);
}
/// @brief Dump each object file in \a a;
@@ -878,22 +832,25 @@ 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;
}
// Attempt to open the binary.
- ErrorOr<Binary *> BinaryOrErr = createBinary(file);
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
if (std::error_code EC = BinaryOrErr.getError()) {
errs() << ToolName << ": '" << file << "': " << EC.message() << ".\n";
return;
}
- std::unique_ptr<Binary> binary(BinaryOrErr.get());
+ Binary &Binary = *BinaryOrErr.get().getBinary();
- if (Archive *a = dyn_cast<Archive>(binary.get()))
+ if (Archive *a = dyn_cast<Archive>(&Binary))
DumpArchive(a);
- else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get()))
+ else if (ObjectFile *o = dyn_cast<ObjectFile>(&Binary))
DumpObject(o);
else
errs() << ToolName << ": '" << file << "': " << "Unrecognized file type.\n";
@@ -929,7 +886,13 @@ int main(int argc, char **argv) {
&& !SectionContents
&& !SymbolTable
&& !UnwindInfo
- && !PrivateHeaders) {
+ && !PrivateHeaders
+ && !ExportsTrie
+ && !Rebase
+ && !Bind
+ && !LazyBind
+ && !WeakBind
+ && !(UniversalHeaders && MachOOpt)) {
cl::PrintHelpMessage();
return 2;
}
@@ -937,5 +900,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 80f8f581a880..f829dd1a71c3 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -7,32 +7,55 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_OBJDUMP_H
-#define LLVM_OBJDUMP_H
+#ifndef LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H
+#define LLVM_TOOLS_LLVM_OBJDUMP_LLVM_OBJDUMP_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DataTypes.h"
-#include "llvm/Support/StringRefMemoryObject.h"
namespace llvm {
namespace object {
class COFFObjectFile;
+ class MachOObjectFile;
class ObjectFile;
class RelocationRef;
}
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::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;
// 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);
+void printMachORebaseTable(const object::MachOObjectFile* o);
+void printMachOBindTable(const object::MachOObjectFile* o);
+void printMachOLazyBindTable(const object::MachOObjectFile* o);
+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);
} // end namespace llvm
diff --git a/tools/llvm-profdata/CMakeLists.txt b/tools/llvm-profdata/CMakeLists.txt
index 3529114371f1..0e330fd0751e 100644
--- a/tools/llvm-profdata/CMakeLists.txt
+++ b/tools/llvm-profdata/CMakeLists.txt
@@ -1,4 +1,8 @@
-set(LLVM_LINK_COMPONENTS profiledata support)
+set(LLVM_LINK_COMPONENTS
+ Core
+ ProfileData
+ Support
+ )
add_llvm_tool(llvm-profdata
llvm-profdata.cpp
diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp
index 49ad37eeed3c..25531c776a31 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -12,8 +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/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -33,32 +36,24 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") {
::exit(1);
}
-int merge_main(int argc, const char *argv[]) {
- cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
- cl::desc("<filenames...>"));
-
- cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"), cl::Required,
- cl::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
- cl::aliasopt(OutputFilename));
-
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
+enum ProfileKinds { instr, sample };
+void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
if (OutputFilename.compare("-") == 0)
exitWithError("Cannot write indexed profdata format to stdout.");
- std::string ErrorInfo;
- raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_None);
- if (!ErrorInfo.empty())
- exitWithError(ErrorInfo, OutputFilename);
+ std::error_code EC;
+ raw_fd_ostream Output(OutputFilename.data(), EC, sys::fs::F_None);
+ if (EC)
+ exitWithError(EC.message(), OutputFilename);
InstrProfWriter Writer;
for (const auto &Filename : Inputs) {
- std::unique_ptr<InstrProfReader> Reader;
- if (std::error_code ec = InstrProfReader::create(Filename, Reader))
+ auto ReaderOrErr = InstrProfReader::create(Filename);
+ if (std::error_code ec = ReaderOrErr.getError())
exitWithError(ec.message(), Filename);
+ auto Reader = std::move(ReaderOrErr.get());
for (const auto &I : *Reader)
if (std::error_code EC =
Writer.addFunctionCounts(I.Name, I.Hash, I.Counts))
@@ -67,50 +62,86 @@ int merge_main(int argc, const char *argv[]) {
exitWithError(Reader->getError().message(), Filename);
}
Writer.write(Output);
-
- return 0;
}
-int show_main(int argc, const char *argv[]) {
- cl::opt<std::string> Filename(cl::Positional, cl::Required,
- cl::desc("<profdata-file>"));
+void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
+ sampleprof::SampleProfileFormat OutputFormat) {
+ using namespace sampleprof;
+ auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat);
+ if (std::error_code EC = WriterOrErr.getError())
+ exitWithError(EC.message(), OutputFilename);
- cl::opt<bool> ShowCounts("counts", cl::init(false),
- cl::desc("Show counter values for shown functions"));
- cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
- cl::desc("Details for every function"));
- cl::opt<std::string> ShowFunction("function",
- cl::desc("Details for matching functions"));
+ auto Writer = std::move(WriterOrErr.get());
+ StringMap<FunctionSamples> ProfileMap;
+ for (const auto &Filename : Inputs) {
+ auto ReaderOrErr =
+ SampleProfileReader::create(Filename, getGlobalContext());
+ if (std::error_code EC = ReaderOrErr.getError())
+ exitWithError(EC.message(), Filename);
+
+ auto Reader = std::move(ReaderOrErr.get());
+ if (std::error_code EC = Reader->read())
+ exitWithError(EC.message(), Filename);
+
+ StringMap<FunctionSamples> &Profiles = Reader->getProfiles();
+ for (StringMap<FunctionSamples>::iterator I = Profiles.begin(),
+ E = Profiles.end();
+ I != E; ++I) {
+ StringRef FName = I->first();
+ FunctionSamples &Samples = I->second;
+ ProfileMap[FName].merge(Samples);
+ }
+ }
+ Writer->write(ProfileMap);
+}
+
+int merge_main(int argc, const char *argv[]) {
+ cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
+ cl::desc("<filenames...>"));
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
- cl::init("-"),
+ cl::init("-"), cl::Required,
cl::desc("Output file"));
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+ cl::opt<sampleprof::SampleProfileFormat> OutputFormat(
+ cl::desc("Format of output profile (only meaningful with --sample)"),
+ cl::init(sampleprof::SPF_Binary),
+ cl::values(clEnumValN(sampleprof::SPF_Binary, "binary",
+ "Binary encoding (default)"),
+ clEnumValN(sampleprof::SPF_Text, "text", "Text encoding"),
+ clEnumValN(sampleprof::SPF_GCC, "gcc", "GCC encoding"),
+ clEnumValEnd));
- cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
-
- std::unique_ptr<InstrProfReader> Reader;
- if (std::error_code EC = InstrProfReader::create(Filename, Reader))
- exitWithError(EC.message(), Filename);
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
- if (OutputFilename.empty())
- OutputFilename = "-";
+ if (ProfileKind == instr)
+ mergeInstrProfile(Inputs, OutputFilename);
+ else
+ mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
- std::string ErrorInfo;
- raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
- if (!ErrorInfo.empty())
- exitWithError(ErrorInfo, OutputFilename);
+ return 0;
+}
- if (ShowAllFunctions && !ShowFunction.empty())
- errs() << "warning: -function argument ignored: showing all functions\n";
+int showInstrProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
+ auto ReaderOrErr = InstrProfReader::create(Filename);
+ if (std::error_code EC = ReaderOrErr.getError())
+ exitWithError(EC.message(), Filename);
+ auto Reader = std::move(ReaderOrErr.get());
uint64_t MaxFunctionCount = 0, MaxBlockCount = 0;
size_t ShownFunctions = 0, TotalFunctions = 0;
for (const auto &Func : *Reader) {
- bool Show = ShowAllFunctions ||
- (!ShowFunction.empty() &&
- Func.Name.find(ShowFunction) != Func.Name.npos);
+ bool Show =
+ ShowAllFunctions || (!ShowFunction.empty() &&
+ Func.Name.find(ShowFunction) != Func.Name.npos);
++TotalFunctions;
assert(Func.Counts.size() > 0 && "function missing entry counter");
@@ -150,6 +181,65 @@ int show_main(int argc, const char *argv[]) {
return 0;
}
+int showSampleProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
+ using namespace sampleprof;
+ auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext());
+ if (std::error_code EC = ReaderOrErr.getError())
+ exitWithError(EC.message(), Filename);
+
+ auto Reader = std::move(ReaderOrErr.get());
+ Reader->read();
+ if (ShowAllFunctions || ShowFunction.empty())
+ Reader->dump(OS);
+ else
+ Reader->dumpFunctionProfile(ShowFunction, OS);
+
+ return 0;
+}
+
+int show_main(int argc, const char *argv[]) {
+ cl::opt<std::string> Filename(cl::Positional, cl::Required,
+ cl::desc("<profdata-file>"));
+
+ cl::opt<bool> ShowCounts("counts", cl::init(false),
+ cl::desc("Show counter values for shown functions"));
+ cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false),
+ cl::desc("Details for every function"));
+ cl::opt<std::string> ShowFunction("function",
+ cl::desc("Details for matching functions"));
+
+ cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
+ cl::init("-"), cl::desc("Output file"));
+ cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
+ cl::aliasopt(OutputFilename));
+ cl::opt<ProfileKinds> ProfileKind(
+ cl::desc("Profile kind:"), cl::init(instr),
+ cl::values(clEnumVal(instr, "Instrumentation profile (default)"),
+ clEnumVal(sample, "Sample profile"), clEnumValEnd));
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
+
+ if (OutputFilename.empty())
+ OutputFilename = "-";
+
+ std::error_code EC;
+ raw_fd_ostream OS(OutputFilename.data(), EC, sys::fs::F_Text);
+ if (EC)
+ exitWithError(EC.message(), OutputFilename);
+
+ if (ShowAllFunctions && !ShowFunction.empty())
+ errs() << "warning: -function argument ignored: showing all functions\n";
+
+ if (ProfileKind == instr)
+ return showInstrProfile(Filename, ShowCounts, ShowAllFunctions,
+ ShowFunction, OS);
+ else
+ return showSampleProfile(Filename, ShowCounts, ShowAllFunctions,
+ ShowFunction, OS);
+}
+
int main(int argc, const char *argv[]) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
diff --git a/tools/llvm-readobj/ARMAttributeParser.cpp b/tools/llvm-readobj/ARMAttributeParser.cpp
index d35cd14265fb..e2d71912a21e 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/ARMAttributeParser.h b/tools/llvm-readobj/ARMAttributeParser.h
index c2862513b751..f924c835d3ea 100644
--- a/tools/llvm-readobj/ARMAttributeParser.h
+++ b/tools/llvm-readobj/ARMAttributeParser.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_ARMATTRIBUTE_PARSER_H
-#define LLVM_READOBJ_ARMATTRIBUTE_PARSER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMATTRIBUTEPARSER_H
#include "StreamWriter.h"
#include "llvm/Support/ARMBuildAttributes.h"
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h
index 7608cfbbd8d1..b15421d7571f 100644
--- a/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_ARMEHABI_PRINTER_H
-#define LLVM_READOBJ_ARMEHABI_PRINTER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H
#include "Error.h"
#include "StreamWriter.h"
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp
index b486e4ad0e51..62252fcda5f9 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"
@@ -186,13 +186,8 @@ void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask)
ErrorOr<object::SectionRef>
Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) {
for (const auto &Section : COFF.sections()) {
- uint64_t Address;
- uint64_t Size;
-
- if (std::error_code EC = Section.getAddress(Address))
- return EC;
- if (std::error_code EC = Section.getSize(Size))
- return EC;
+ uint64_t Address = Section.getAddress();
+ uint64_t Size = Section.getSize();
if (VA >= Address && (VA - Address) <= Size)
return Section;
@@ -233,7 +228,7 @@ ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &,
return readobj_error::unknown_symbol;
}
-bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint8_t Imm = OC[Offset] & 0x7f;
SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n",
@@ -244,7 +239,7 @@ bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_10Lxxxxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Link = (OC[Offset] & 0x20) >> 5;
uint16_t RegisterMask = (Link << (Prologue ? 14 : 15))
@@ -263,7 +258,7 @@ bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_1100xxxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
if (Prologue)
SW.startLine() << format("0x%02x ; mov r%u, sp\n",
@@ -275,7 +270,7 @@ bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11010Lxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Link = (OC[Offset] & 0x4) >> 3;
unsigned Count = (OC[Offset] & 0x3);
@@ -292,7 +287,7 @@ bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11011Lxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Link = (OC[Offset] & 0x4) >> 2;
unsigned Count = (OC[Offset] & 0x3) + 4;
@@ -309,7 +304,7 @@ bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11100xxx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned High = (OC[Offset] & 0x7);
uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8);
@@ -323,7 +318,7 @@ bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_111010xx(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0);
@@ -336,7 +331,7 @@ bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_1110110L(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15))
| ((OC[Offset + 1] & 0xff) << 0);
@@ -350,7 +345,7 @@ bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11101110(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
assert(!Prologue && "may not be used in prologue");
@@ -366,7 +361,7 @@ bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11101111(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
assert(!Prologue && "may not be used in prologue");
@@ -382,7 +377,7 @@ bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11110101(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
@@ -397,7 +392,7 @@ bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11110110(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
unsigned Start = (OC[Offset + 1] & 0xf0) >> 4;
unsigned End = (OC[Offset + 1] & 0x0f) >> 0;
@@ -412,7 +407,7 @@ bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11110111(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
@@ -425,7 +420,7 @@ bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111000(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint32_t Imm = (OC[Offset + 1] << 16)
| (OC[Offset + 2] << 8)
@@ -440,7 +435,7 @@ bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111001(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0);
@@ -453,7 +448,7 @@ bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111010(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
uint32_t Imm = (OC[Offset + 1] << 16)
| (OC[Offset + 2] << 8)
@@ -468,41 +463,41 @@ bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset,
return false;
}
-bool Decoder::opcode_11111011(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111011(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; nop\n", OC[Offset]);
++Offset;
return false;
}
-bool Decoder::opcode_11111100(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111100(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]);
++Offset;
return false;
}
-bool Decoder::opcode_11111101(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111101(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; b\n", OC[Offset]);
++Offset;
return true;
}
-bool Decoder::opcode_11111110(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111110(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]);
++Offset;
return true;
}
-bool Decoder::opcode_11111111(const ulittle8_t *OC, unsigned &Offset,
+bool Decoder::opcode_11111111(const uint8_t *OC, unsigned &Offset,
unsigned Length, bool Prologue) {
++Offset;
return true;
}
-void Decoder::decodeOpcodes(ArrayRef<ulittle8_t> Opcodes, unsigned Offset,
+void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
bool Prologue) {
assert((!Prologue || Offset == 0) && "prologue should always use offset 0");
@@ -525,10 +520,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents))
return false;
- uint64_t SectionVA;
- if (Section.getAddress(SectionVA))
- return false;
-
+ uint64_t SectionVA = Section.getAddress();
uint64_t Offset = VA - SectionVA;
const ulittle32_t *Data =
reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset);
@@ -546,7 +538,7 @@ bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF,
static_cast<uint64_t>(XData.CodeWords() * sizeof(uint32_t)));
if (XData.E()) {
- ArrayRef<ulittle8_t> UC = XData.UnwindByteCode();
+ ArrayRef<uint8_t> UC = XData.UnwindByteCode();
if (!XData.F()) {
ListScope PS(SW, "Prologue");
decodeOpcodes(UC, 0, /*Prologue=*/true);
@@ -741,4 +733,3 @@ std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
}
}
}
-
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.h b/tools/llvm-readobj/ARMWinEHPrinter.h
index 740c8b5841b5..274ef114841c 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_ARMWINEHPRINTER_H
-#define LLVM_READOBJ_ARMWINEHPRINTER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H
+#define LLVM_TOOLS_LLVM_READOBJ_ARMWINEHPRINTER_H
#include "StreamWriter.h"
#include "llvm/Object/COFF.h"
@@ -28,55 +28,54 @@ class Decoder {
struct RingEntry {
uint8_t Mask;
uint8_t Value;
- bool (Decoder::*Routine)(const support::ulittle8_t *, unsigned &, unsigned,
- bool);
+ bool (Decoder::*Routine)(const uint8_t *, unsigned &, unsigned, bool);
};
static const RingEntry Ring[];
- bool opcode_0xxxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_0xxxxxxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_10Lxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_10Lxxxxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_1100xxxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_1100xxxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11010Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11010Lxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11011Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11011Lxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11100xxx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11100xxx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_111010xx(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_111010xx(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_1110110L(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_1110110L(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11101110(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11101110(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11101111(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11101111(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11110101(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11110101(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11110110(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11110110(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11110111(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11110111(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111000(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111000(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111001(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111001(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111010(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111010(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111011(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111011(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111100(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111100(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111101(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111101(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111110(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111110(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- bool opcode_11111111(const support::ulittle8_t *Opcodes, unsigned &Offset,
+ bool opcode_11111111(const uint8_t *Opcodes, unsigned &Offset,
unsigned Length, bool Prologue);
- void decodeOpcodes(ArrayRef<support::ulittle8_t> Opcodes, unsigned Offset,
+ void decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset,
bool Prologue);
void printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask);
@@ -116,4 +115,3 @@ public:
}
#endif
-
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 7842cd4d44fe..156e39a35fd5 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -20,6 +20,7 @@
#include "Win64EHDumper.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/COFF.h"
@@ -49,35 +50,50 @@ public:
cacheRelocations();
}
- virtual void printFileHeaders() override;
- virtual void printSections() override;
- virtual void printRelocations() override;
- virtual void printSymbols() override;
- virtual void printDynamicSymbols() override;
- virtual void printUnwindInfo() override;
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+ void printCOFFImports() override;
+ void printCOFFExports() override;
+ void printCOFFDirectives() override;
+ void printCOFFBaseReloc() override;
private:
void printSymbol(const SymbolRef &Sym);
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
void printDataDirectory(uint32_t Index, const std::string &FieldName);
+ void printDOSHeader(const dos_header *DH);
template <class PEHeader> void printPEHeader(const PEHeader *Hdr);
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);
void printCodeViewLineTables(const SectionRef &Section);
+ void printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t Offset);
+
void cacheRelocations();
std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset,
SymbolRef &Sym);
std::error_code resolveSymbolName(const coff_section *Section,
uint64_t Offset, StringRef &Name);
+ void printImportedSymbols(iterator_range<imported_symbol_iterator> Range);
+ void printDelayImportedSymbols(
+ const DelayImportDirectoryEntryRef &I,
+ iterator_range<imported_symbol_iterator> Range);
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
const llvm::object::COFFObjectFile *Obj;
RelocMapTy RelocMap;
+ StringRef CVFileIndexToStringOffsetTable;
+ StringRef CVStringTable;
};
} // namespace
@@ -313,9 +329,10 @@ WeakExternalCharacteristics[] = {
template <typename T>
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
- const coff_symbol *Symbol,
- const T *&Aux) {
+ COFFSymbolRef Symbol,
+ uint8_t AuxSymbolIdx, const T *&Aux) {
ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol);
+ AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize());
Aux = reinterpret_cast<const T*>(AuxData.data());
return readobj_error::success;
}
@@ -342,25 +359,20 @@ void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName
}
void COFFDumper::printFileHeaders() {
- // Print COFF header
- const coff_file_header *COFFHeader = nullptr;
- if (error(Obj->getCOFFHeader(COFFHeader)))
- return;
-
- time_t TDS = COFFHeader->TimeDateStamp;
+ time_t TDS = Obj->getTimeDateStamp();
char FormattedTime[20] = { };
strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS));
{
DictScope D(W, "ImageFileHeader");
- W.printEnum ("Machine", COFFHeader->Machine,
+ W.printEnum ("Machine", Obj->getMachine(),
makeArrayRef(ImageFileMachineType));
- W.printNumber("SectionCount", COFFHeader->NumberOfSections);
- W.printHex ("TimeDateStamp", FormattedTime, COFFHeader->TimeDateStamp);
- W.printHex ("PointerToSymbolTable", COFFHeader->PointerToSymbolTable);
- W.printNumber("SymbolCount", COFFHeader->NumberOfSymbols);
- W.printNumber("OptionalHeaderSize", COFFHeader->SizeOfOptionalHeader);
- W.printFlags ("Characteristics", COFFHeader->Characteristics,
+ W.printNumber("SectionCount", Obj->getNumberOfSections());
+ W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
+ W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
+ W.printNumber("SymbolCount", Obj->getNumberOfSymbols());
+ W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
+ W.printFlags ("Characteristics", Obj->getCharacteristics(),
makeArrayRef(ImageFileCharacteristics));
}
@@ -377,6 +389,30 @@ void COFFDumper::printFileHeaders() {
return;
if (PEPlusHeader)
printPEHeader<pe32plus_header>(PEPlusHeader);
+
+ if (const dos_header *DH = Obj->getDOSHeader())
+ printDOSHeader(DH);
+}
+
+void COFFDumper::printDOSHeader(const dos_header *DH) {
+ DictScope D(W, "DOSHeader");
+ W.printString("Magic", StringRef(DH->Magic, sizeof(DH->Magic)));
+ W.printNumber("UsedBytesInTheLastPage", DH->UsedBytesInTheLastPage);
+ W.printNumber("FileSizeInPages", DH->FileSizeInPages);
+ W.printNumber("NumberOfRelocationItems", DH->NumberOfRelocationItems);
+ W.printNumber("HeaderSizeInParagraphs", DH->HeaderSizeInParagraphs);
+ W.printNumber("MinimumExtraParagraphs", DH->MinimumExtraParagraphs);
+ W.printNumber("MaximumExtraParagraphs", DH->MaximumExtraParagraphs);
+ W.printNumber("InitialRelativeSS", DH->InitialRelativeSS);
+ W.printNumber("InitialSP", DH->InitialSP);
+ W.printNumber("Checksum", DH->Checksum);
+ W.printNumber("InitialIP", DH->InitialIP);
+ W.printNumber("InitialRelativeCS", DH->InitialRelativeCS);
+ W.printNumber("AddressOfRelocationTable", DH->AddressOfRelocationTable);
+ W.printNumber("OverlayNumber", DH->OverlayNumber);
+ W.printNumber("OEMid", DH->OEMid);
+ W.printNumber("OEMinfo", DH->OEMinfo);
+ W.printNumber("AddressOfNewExeHeader", DH->AddressOfNewExeHeader);
}
template <class PEHeader>
@@ -404,7 +440,7 @@ void COFFDumper::printPEHeader(const PEHeader *Hdr) {
W.printNumber("SizeOfImage", Hdr->SizeOfImage);
W.printNumber("SizeOfHeaders", Hdr->SizeOfHeaders);
W.printEnum ("Subsystem", Hdr->Subsystem, makeArrayRef(PEWindowsSubsystem));
- W.printFlags ("Subsystem", Hdr->DLLCharacteristics,
+ W.printFlags ("Characteristics", Hdr->DLLCharacteristics,
makeArrayRef(PEDLLCharacteristics));
W.printNumber("SizeOfStackReserve", Hdr->SizeOfStackReserve);
W.printNumber("SizeOfStackCommit", Hdr->SizeOfStackCommit);
@@ -440,11 +476,10 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
SmallVector<StringRef, 10> FunctionNames;
StringMap<StringRef> FunctionLineTables;
- StringRef FileIndexToStringOffsetTable;
- StringRef StringTable;
ListScope D(W, "CodeViewLineTables");
{
+ // FIXME: Add more offset correctness checks.
DataExtractor DE(Data, true, 4);
uint32_t Offset = 0,
Magic = DE.getU32(&Offset);
@@ -474,6 +509,9 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
W.printBinaryBlock("Contents", Contents);
switch (SubSectionType) {
+ case COFF::DEBUG_SYMBOL_SUBSECTION:
+ 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
// stored in the other subsections, so just check sanity and store the
@@ -502,25 +540,25 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
break;
}
case COFF::DEBUG_STRING_TABLE_SUBSECTION:
- if (PayloadSize == 0 || StringTable.data() != nullptr ||
+ if (PayloadSize == 0 || CVStringTable.data() != nullptr ||
Contents.back() != '\0') {
// Empty or duplicate or non-null-terminated subsection.
error(object_error::parse_failed);
return;
}
- StringTable = Contents;
+ CVStringTable = Contents;
break;
case COFF::DEBUG_INDEX_SUBSECTION:
// Holds the translation table from file indices
// to offsets in the string table.
if (PayloadSize == 0 ||
- FileIndexToStringOffsetTable.data() != nullptr) {
+ CVFileIndexToStringOffsetTable.data() != nullptr) {
// Empty or duplicate subsection.
error(object_error::parse_failed);
return;
}
- FileIndexToStringOffsetTable = Contents;
+ CVFileIndexToStringOffsetTable = Contents;
break;
}
Offset += PayloadSize;
@@ -555,7 +593,7 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
uint32_t FilenameOffset;
{
- DataExtractor SDE(FileIndexToStringOffsetTable, true, 4);
+ DataExtractor SDE(CVFileIndexToStringOffsetTable, true, 4);
uint32_t OffsetInSDE = OffsetInIndex;
if (!SDE.isValidOffset(OffsetInSDE)) {
error(object_error::parse_failed);
@@ -564,15 +602,15 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
FilenameOffset = SDE.getU32(&OffsetInSDE);
}
- if (FilenameOffset == 0 || FilenameOffset + 1 >= StringTable.size() ||
- StringTable.data()[FilenameOffset - 1] != '\0') {
+ if (FilenameOffset == 0 || FilenameOffset + 1 >= CVStringTable.size() ||
+ CVStringTable.data()[FilenameOffset - 1] != '\0') {
// Each string in an F3 subsection should be preceded by a null
// character.
error(object_error::parse_failed);
return;
}
- StringRef Filename(StringTable.data() + FilenameOffset);
+ StringRef Filename(CVStringTable.data() + FilenameOffset);
ListScope S(W, "FilenameSegment");
W.printString("Filename", Filename);
for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
@@ -593,6 +631,80 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
}
}
+void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
+ const SectionRef &Section,
+ uint32_t OffsetInSection) {
+ if (Subsection.size() == 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ DataExtractor DE(Subsection, true, 4);
+ uint32_t Offset = 0;
+
+ // Function-level subsections have "procedure start" and "procedure end"
+ // commands that should come in pairs and surround relevant info.
+ bool InFunctionScope = false;
+ while (DE.isValidOffset(Offset)) {
+ // Read subsection segments one by one.
+ uint16_t Size = DE.getU16(&Offset);
+ // The section size includes the size of the type identifier.
+ if (Size < 2 || !DE.isValidOffsetForDataOfSize(Offset, Size)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ Size -= 2;
+ uint16_t Type = DE.getU16(&Offset);
+ switch (Type) {
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_START: {
+ DictScope S(W, "ProcStart");
+ if (InFunctionScope || Size < 36) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = true;
+
+ // We're currently interested in a limited subset of fields in this
+ // segment, just ignore the rest of the fields for now.
+ uint8_t Unused[12];
+ DE.getU8(&Offset, Unused, 12);
+ uint32_t CodeSize = DE.getU32(&Offset);
+ DE.getU8(&Offset, Unused, 12);
+ StringRef SectionName;
+ if (error(resolveSymbolName(Obj->getCOFFSection(Section),
+ OffsetInSection + Offset, SectionName)))
+ return;
+ Offset += 4;
+ DE.getU8(&Offset, Unused, 3);
+ StringRef DisplayName = DE.getCStr(&Offset);
+ if (!DE.isValidOffset(Offset)) {
+ error(object_error::parse_failed);
+ return;
+ }
+ W.printString("DisplayName", DisplayName);
+ W.printString("Section", SectionName);
+ W.printHex("CodeSize", CodeSize);
+
+ break;
+ }
+ case COFF::DEBUG_SYMBOL_TYPE_PROC_END: {
+ W.startLine() << "ProcEnd\n";
+ if (!InFunctionScope || Size > 0) {
+ error(object_error::parse_failed);
+ return;
+ }
+ InFunctionScope = false;
+ break;
+ }
+ default:
+ Offset += Size;
+ break;
+ }
+ }
+
+ if (InFunctionScope)
+ error(object_error::parse_failed);
+}
+
void COFFDumper::printSections() {
ListScope SectionsD(W, "Sections");
int SectionNumber = 0;
@@ -628,8 +740,7 @@ void COFFDumper::printSections() {
if (opts::SectionSymbols) {
ListScope D(W, "Symbols");
for (const SymbolRef &Symbol : Obj->symbols()) {
- bool Contained = false;
- if (Sec.containsSymbol(Symbol, Contained) || !Contained)
+ if (!Sec.containsSymbol(Symbol))
continue;
printSymbol(Symbol);
@@ -639,7 +750,8 @@ void COFFDumper::printSections() {
if (Name == ".debug$S" && opts::CodeViewLineTables)
printCodeViewLineTables(Sec);
- if (opts::SectionData) {
+ if (opts::SectionData &&
+ !(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
StringRef Data;
if (error(Sec.getContents(Data)))
break;
@@ -683,7 +795,6 @@ void COFFDumper::printRelocation(const SectionRef &Section,
uint64_t RelocType;
SmallString<32> RelocName;
StringRef SymbolName;
- StringRef Contents;
if (error(Reloc.getOffset(Offset)))
return;
if (error(Reloc.getType(RelocType)))
@@ -691,21 +802,19 @@ void COFFDumper::printRelocation(const SectionRef &Section,
if (error(Reloc.getTypeName(RelocName)))
return;
symbol_iterator Symbol = Reloc.getSymbol();
- if (error(Symbol->getName(SymbolName)))
- return;
- if (error(Section.getContents(Contents)))
+ if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName)))
return;
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
W.printHex("Offset", Offset);
W.printNumber("Type", RelocName, RelocType);
- W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ W.printString("Symbol", SymbolName.empty() ? "-" : SymbolName);
} else {
raw_ostream& OS = W.startLine();
OS << W.hex(Offset)
<< " " << RelocName
- << " " << (SymbolName.size() > 0 ? SymbolName : "-")
+ << " " << (SymbolName.empty() ? "-" : SymbolName)
<< "\n";
}
}
@@ -719,12 +828,30 @@ void COFFDumper::printSymbols() {
void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
+static ErrorOr<StringRef>
+getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
+ const coff_section *Section) {
+ if (Section) {
+ StringRef SectionName;
+ if (std::error_code EC = Obj->getSectionName(Section, SectionName))
+ return EC;
+ return SectionName;
+ }
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
+ return StringRef("IMAGE_SYM_DEBUG");
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE)
+ return StringRef("IMAGE_SYM_ABSOLUTE");
+ if (SectionNumber == llvm::COFF::IMAGE_SYM_UNDEFINED)
+ return StringRef("IMAGE_SYM_UNDEFINED");
+ return StringRef("");
+}
+
void COFFDumper::printSymbol(const SymbolRef &Sym) {
DictScope D(W, "Symbol");
- const coff_symbol *Symbol = Obj->getCOFFSymbol(Sym);
+ COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym);
const coff_section *Section;
- if (std::error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) {
+ if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) {
W.startLine() << "Invalid section number: " << EC.message() << "\n";
W.flush();
return;
@@ -735,23 +862,25 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
SymbolName = "";
StringRef SectionName = "";
- if (Section)
- Obj->getSectionName(Section, SectionName);
+ ErrorOr<StringRef> Res =
+ getSectionName(Obj, Symbol.getSectionNumber(), Section);
+ if (Res)
+ SectionName = *Res;
W.printString("Name", SymbolName);
- W.printNumber("Value", Symbol->Value);
- W.printNumber("Section", SectionName, Symbol->SectionNumber);
- W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType));
- W.printEnum ("ComplexType", Symbol->getComplexType(),
+ W.printNumber("Value", Symbol.getValue());
+ W.printNumber("Section", SectionName, Symbol.getSectionNumber());
+ W.printEnum ("BaseType", Symbol.getBaseType(), makeArrayRef(ImageSymType));
+ W.printEnum ("ComplexType", Symbol.getComplexType(),
makeArrayRef(ImageSymDType));
- W.printEnum ("StorageClass", Symbol->StorageClass,
+ W.printEnum ("StorageClass", Symbol.getStorageClass(),
makeArrayRef(ImageSymClass));
- W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols);
+ W.printNumber("AuxSymbolCount", Symbol.getNumberOfAuxSymbols());
- for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) {
- if (Symbol->isFunctionDefinition()) {
+ for (uint8_t I = 0; I < Symbol.getNumberOfAuxSymbols(); ++I) {
+ if (Symbol.isFunctionDefinition()) {
const coff_aux_function_definition *Aux;
- if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
break;
DictScope AS(W, "AuxFunctionDef");
@@ -759,18 +888,16 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
W.printNumber("TotalSize", Aux->TotalSize);
W.printHex("PointerToLineNumber", Aux->PointerToLinenumber);
W.printHex("PointerToNextFunction", Aux->PointerToNextFunction);
- W.printBinary("Unused", makeArrayRef(Aux->Unused));
- } else if (Symbol->isWeakExternal()) {
+ } else if (Symbol.isAnyUndefined()) {
const coff_aux_weak_external *Aux;
- if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
break;
- const coff_symbol *Linked;
+ ErrorOr<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex);
StringRef LinkedName;
- std::error_code EC;
- if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) ||
- (EC = Obj->getSymbolName(Linked, LinkedName))) {
+ std::error_code EC = Linked.getError();
+ if (EC || (EC = Obj->getSymbolName(*Linked, LinkedName))) {
LinkedName = "";
error(EC);
}
@@ -779,56 +906,60 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
W.printNumber("Linked", LinkedName, Aux->TagIndex);
W.printEnum ("Search", Aux->Characteristics,
makeArrayRef(WeakExternalCharacteristics));
- W.printBinary("Unused", makeArrayRef(Aux->Unused));
- } else if (Symbol->isFileRecord()) {
- const coff_aux_file *Aux;
- if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ } else if (Symbol.isFileRecord()) {
+ const char *FileName;
+ if (error(getSymbolAuxData(Obj, Symbol, I, FileName)))
break;
DictScope AS(W, "AuxFileRecord");
- StringRef Name(Aux->FileName,
- Symbol->NumberOfAuxSymbols * COFF::SymbolSize);
+ StringRef Name(FileName, Symbol.getNumberOfAuxSymbols() *
+ Obj->getSymbolTableEntrySize());
W.printString("FileName", Name.rtrim(StringRef("\0", 1)));
break;
- } else if (Symbol->isSectionDefinition()) {
+ } else if (Symbol.isSectionDefinition()) {
const coff_aux_section_definition *Aux;
- if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
break;
+ int32_t AuxNumber = Aux->getNumber(Symbol.isBigObj());
+
DictScope AS(W, "AuxSectionDef");
W.printNumber("Length", Aux->Length);
W.printNumber("RelocationCount", Aux->NumberOfRelocations);
W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers);
W.printHex("Checksum", Aux->CheckSum);
- W.printNumber("Number", Aux->Number);
+ W.printNumber("Number", AuxNumber);
W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect));
- W.printBinary("Unused", makeArrayRef(Aux->Unused));
if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
const coff_section *Assoc;
- StringRef AssocName;
- std::error_code EC;
- if ((EC = Obj->getSection(Aux->Number, Assoc)) ||
- (EC = Obj->getSectionName(Assoc, AssocName))) {
+ StringRef AssocName = "";
+ std::error_code EC = Obj->getSection(AuxNumber, Assoc);
+ ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
+ if (Res)
+ AssocName = *Res;
+ if (!EC)
+ EC = Res.getError();
+ if (EC) {
AssocName = "";
error(EC);
}
- W.printNumber("AssocSection", AssocName, Aux->Number);
+ W.printNumber("AssocSection", AssocName, AuxNumber);
}
- } else if (Symbol->isCLRToken()) {
+ } else if (Symbol.isCLRToken()) {
const coff_aux_clr_token *Aux;
- if (error(getSymbolAuxData(Obj, Symbol + I, Aux)))
+ if (error(getSymbolAuxData(Obj, Symbol, I, Aux)))
break;
- const coff_symbol *ReferredSym;
+ ErrorOr<COFFSymbolRef> ReferredSym =
+ Obj->getSymbol(Aux->SymbolTableIndex);
StringRef ReferredName;
- std::error_code EC;
- if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) ||
- (EC = Obj->getSymbolName(ReferredSym, ReferredName))) {
+ std::error_code EC = ReferredSym.getError();
+ if (EC || (EC = Obj->getSymbolName(*ReferredSym, ReferredName))) {
ReferredName = "";
error(EC);
}
@@ -837,7 +968,6 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
W.printNumber("AuxType", Aux->AuxType);
W.printNumber("Reserved", Aux->Reserved);
W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex);
- W.printBinary("Unused", makeArrayRef(Aux->Unused));
} else {
W.startLine() << "<unhandled auxiliary record>\n";
@@ -846,12 +976,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
}
void COFFDumper::printUnwindInfo() {
- const coff_file_header *Header;
- if (error(Obj->getCOFFHeader(Header)))
- return;
-
ListScope D(W, "UnwindInformation");
- switch (Header->Machine) {
+ switch (Obj->getMachine()) {
case COFF::IMAGE_FILE_MACHINE_AMD64: {
Win64EH::Dumper Dumper(W);
Win64EH::Dumper::SymbolResolver
@@ -870,9 +996,133 @@ void COFFDumper::printUnwindInfo() {
break;
}
default:
- W.printEnum("unsupported Image Machine", Header->Machine,
+ W.printEnum("unsupported Image Machine", Obj->getMachine(),
makeArrayRef(ImageFileMachineType));
break;
}
}
+void COFFDumper::printImportedSymbols(
+ iterator_range<imported_symbol_iterator> Range) {
+ for (const ImportedSymbolRef &I : Range) {
+ StringRef Sym;
+ if (error(I.getSymbolName(Sym))) return;
+ uint16_t Ordinal;
+ if (error(I.getOrdinal(Ordinal))) return;
+ W.printNumber("Symbol", Sym, Ordinal);
+ }
+}
+
+void COFFDumper::printDelayImportedSymbols(
+ const DelayImportDirectoryEntryRef &I,
+ iterator_range<imported_symbol_iterator> Range) {
+ int Index = 0;
+ for (const ImportedSymbolRef &S : Range) {
+ DictScope Import(W, "Import");
+ StringRef Sym;
+ if (error(S.getSymbolName(Sym))) return;
+ uint16_t Ordinal;
+ if (error(S.getOrdinal(Ordinal))) return;
+ W.printNumber("Symbol", Sym, Ordinal);
+ uint64_t Addr;
+ if (error(I.getImportAddress(Index++, Addr))) return;
+ W.printHex("Address", Addr);
+ }
+}
+
+void COFFDumper::printCOFFImports() {
+ // Regular imports
+ for (const ImportDirectoryEntryRef &I : Obj->import_directories()) {
+ DictScope Import(W, "Import");
+ StringRef Name;
+ if (error(I.getName(Name))) return;
+ W.printString("Name", Name);
+ uint32_t Addr;
+ if (error(I.getImportLookupTableRVA(Addr))) return;
+ W.printHex("ImportLookupTableRVA", Addr);
+ if (error(I.getImportAddressTableRVA(Addr))) return;
+ W.printHex("ImportAddressTableRVA", Addr);
+ printImportedSymbols(I.imported_symbols());
+ }
+
+ // Delay imports
+ for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) {
+ DictScope Import(W, "DelayImport");
+ StringRef Name;
+ if (error(I.getName(Name))) return;
+ W.printString("Name", Name);
+ const delay_import_directory_table_entry *Table;
+ if (error(I.getDelayImportTable(Table))) return;
+ W.printHex("Attributes", Table->Attributes);
+ W.printHex("ModuleHandle", Table->ModuleHandle);
+ W.printHex("ImportAddressTable", Table->DelayImportAddressTable);
+ W.printHex("ImportNameTable", Table->DelayImportNameTable);
+ W.printHex("BoundDelayImportTable", Table->BoundDelayImportTable);
+ W.printHex("UnloadDelayImportTable", Table->UnloadDelayImportTable);
+ printDelayImportedSymbols(I, I.imported_symbols());
+ }
+}
+
+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;
+ StringRef Name;
+
+ if (error(Section.getName(Name)))
+ continue;
+ if (Name != ".drectve")
+ continue;
+
+ if (error(Section.getContents(Contents)))
+ return;
+
+ W.printString("Directive(s)", Contents);
+ }
+}
+
+static StringRef getBaseRelocTypeName(uint8_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_BASED_ABSOLUTE: return "ABSOLUTE";
+ case COFF::IMAGE_REL_BASED_HIGH: return "HIGH";
+ 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_DIR64: return "DIR64";
+ default: return "unknown (" + llvm::utostr(Type) + ")";
+ }
+}
+
+void COFFDumper::printCOFFBaseReloc() {
+ ListScope D(W, "BaseReloc");
+ for (const BaseRelocRef &I : Obj->base_relocs()) {
+ uint8_t Type;
+ uint32_t RVA;
+ if (error(I.getRVA(RVA)))
+ continue;
+ if (error(I.getType(Type)))
+ continue;
+ DictScope Import(W, "Entry");
+ W.printString("Type", getBaseRelocTypeName(Type));
+ W.printHex("Address", RVA);
+ }
+}
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index 1791f5a32471..d68c78682d23 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -604,7 +604,7 @@ void ELFDumper<ELFT>::printSections() {
}
}
- if (opts::SectionData) {
+ if (opts::SectionData && Section->sh_type != ELF::SHT_NOBITS) {
ArrayRef<uint8_t> Data = errorOrDefault(Obj->getSectionContents(Section));
W.printBinaryBlock("SectionData",
StringRef((const char *)Data.data(), Data.size()));
@@ -676,7 +676,8 @@ void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec,
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);
W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL()));
- W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-");
+ W.printNumber("Symbol", SymbolName.size() > 0 ? SymbolName : "-",
+ Rel.getSymbol(Obj->isMips64EL()));
W.printHex("Addend", Rel.r_addend);
} else {
raw_ostream& OS = W.startLine();
diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp
index a078f5c095c7..7e6f780c5d1a 100644
--- a/tools/llvm-readobj/Error.cpp
+++ b/tools/llvm-readobj/Error.cpp
@@ -24,7 +24,7 @@ public:
};
} // namespace
-const char *_readobj_error_category::name() const {
+const char *_readobj_error_category::name() const LLVM_NOEXCEPT {
return "llvm.readobj";
}
diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h
index 81ce4082aab9..f3e24bbe5dbf 100644
--- a/tools/llvm-readobj/Error.h
+++ b/tools/llvm-readobj/Error.h
@@ -11,8 +11,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_ERROR_H
-#define LLVM_READOBJ_ERROR_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_ERROR_H
+#define LLVM_TOOLS_LLVM_READOBJ_ERROR_H
#include <system_error>
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
index a5e5cf850a3b..7e8fdadd855b 100644
--- a/tools/llvm-readobj/MachODumper.cpp
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -31,14 +31,17 @@ public:
: ObjDumper(Writer)
, Obj(Obj) { }
- virtual void printFileHeaders() override;
- virtual void printSections() override;
- virtual void printRelocations() override;
- virtual void printSymbols() override;
- virtual void printDynamicSymbols() override;
- virtual void printUnwindInfo() override;
+ void printFileHeaders() override;
+ void printSections() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
private:
+ template<class MachHeader>
+ void printFileHeaders(const MachHeader &Header);
+
void printSymbol(const SymbolRef &Symbol);
void printRelocation(const RelocationRef &Reloc);
@@ -68,6 +71,137 @@ std::error_code createMachODumper(const object::ObjectFile *Obj,
} // namespace llvm
+static const EnumEntry<uint32_t> MachOMagics[] = {
+ { "Magic", MachO::MH_MAGIC },
+ { "Cigam", MachO::MH_CIGAM },
+ { "Magic64", MachO::MH_MAGIC_64 },
+ { "Cigam64", MachO::MH_CIGAM_64 },
+ { "FatMagic", MachO::FAT_MAGIC },
+ { "FatCigam", MachO::FAT_CIGAM },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderFileTypes[] = {
+ { "Relocatable", MachO::MH_OBJECT },
+ { "Executable", MachO::MH_EXECUTE },
+ { "FixedVMLibrary", MachO::MH_FVMLIB },
+ { "Core", MachO::MH_CORE },
+ { "PreloadedExecutable", MachO::MH_PRELOAD },
+ { "DynamicLibrary", MachO::MH_DYLIB },
+ { "DynamicLinker", MachO::MH_DYLINKER },
+ { "Bundle", MachO::MH_BUNDLE },
+ { "DynamicLibraryStub", MachO::MH_DYLIB_STUB },
+ { "DWARFSymbol", MachO::MH_DSYM },
+ { "KextBundle", MachO::MH_KEXT_BUNDLE },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuTypes[] = {
+ { "Any" , static_cast<uint32_t>(MachO::CPU_TYPE_ANY) },
+ { "X86" , MachO::CPU_TYPE_X86 },
+ { "X86-64" , MachO::CPU_TYPE_X86_64 },
+ { "Mc98000" , MachO::CPU_TYPE_MC98000 },
+ { "Arm" , MachO::CPU_TYPE_ARM },
+ { "Arm64" , MachO::CPU_TYPE_ARM64 },
+ { "Sparc" , MachO::CPU_TYPE_SPARC },
+ { "PowerPC" , MachO::CPU_TYPE_POWERPC },
+ { "PowerPC64" , MachO::CPU_TYPE_POWERPC64 },
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX86[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_I386_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_386),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_486SX),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_586),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTPRO),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M3),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTII_M5),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_CELERON_MOBILE),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_3_XEON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_PENTIUM_4_M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ITANIUM_2),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_XEON_MP),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesX64[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_ARCH1),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_X86_64_H),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V4T),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V5TEJ),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_XSCALE),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7S),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7K),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V6M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7M),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM_V7EM),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_SPARC_ALL),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesPPC[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_601),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_602),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603e),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_603ev),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_604e),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_620),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_750),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7400),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_7450),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_POWERPC_970),
+};
+
+static const EnumEntry<uint32_t> MachOHeaderFlags[] = {
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOUNDEFS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_INCRLINK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_DYLDLINK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDATLOAD),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBOUND),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SPLIT_SEGS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_LAZY_INIT),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_TWOLEVEL),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_FORCE_FLAT),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOMULTIDEFS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NOFIXPREBINDING),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PREBINDABLE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLMODSBOUND),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SUBSECTIONS_VIA_SYMBOLS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_CANONICAL),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_WEAK_DEFINES),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_BINDS_TO_WEAK),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ALLOW_STACK_EXECUTION),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_ROOT_SAFE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_SETUID_SAFE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_REEXPORTED_DYLIBS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_PIE),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_DEAD_STRIPPABLE_DYLIB),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_HAS_TLV_DESCRIPTORS),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_NO_HEAP_EXECUTION),
+ LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
+};
static const EnumEntry<unsigned> MachOSectionTypes[] = {
{ "Regular" , 0x00 },
@@ -205,7 +339,47 @@ static void getSymbol(const MachOObjectFile *Obj,
}
void MachODumper::printFileHeaders() {
- W.startLine() << "FileHeaders not implemented.\n";
+ DictScope H(W, "MachHeader");
+ if (!Obj->is64Bit()) {
+ printFileHeaders(Obj->getHeader());
+ } else {
+ printFileHeaders(Obj->getHeader64());
+ W.printHex("Reserved", Obj->getHeader64().reserved);
+ }
+}
+
+template<class MachHeader>
+void MachODumper::printFileHeaders(const MachHeader &Header) {
+ W.printEnum("Magic", Header.magic, makeArrayRef(MachOMagics));
+ W.printEnum("CpuType", Header.cputype, makeArrayRef(MachOHeaderCpuTypes));
+ uint32_t subtype = Header.cpusubtype & ~MachO::CPU_SUBTYPE_MASK;
+ switch (Header.cputype) {
+ case MachO::CPU_TYPE_X86:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX86));
+ break;
+ case MachO::CPU_TYPE_X86_64:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesX64));
+ break;
+ case MachO::CPU_TYPE_ARM:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM));
+ break;
+ case MachO::CPU_TYPE_POWERPC:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesPPC));
+ break;
+ case MachO::CPU_TYPE_SPARC:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesSPARC));
+ break;
+ case MachO::CPU_TYPE_ARM64:
+ W.printEnum("CpuSubType", subtype, makeArrayRef(MachOHeaderCpuSubtypesARM64));
+ break;
+ case MachO::CPU_TYPE_POWERPC64:
+ default:
+ W.printHex("CpuSubtype", subtype);
+ }
+ W.printEnum("FileType", Header.filetype, makeArrayRef(MachOHeaderFileTypes));
+ W.printNumber("NumOfLoadCommands", Header.ncmds);
+ W.printNumber("SizeOfLoadCommands", Header.sizeofcmds);
+ W.printFlags("Flags", Header.flags, makeArrayRef(MachOHeaderFlags));
}
void MachODumper::printSections() {
@@ -257,8 +431,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) {
if (opts::SectionSymbols) {
ListScope D(W, "Symbols");
for (const SymbolRef &Symbol : Obj->symbols()) {
- bool Contained = false;
- if (Section.containsSymbol(Symbol, Contained) || !Contained)
+ if (!Section.containsSymbol(Symbol))
continue;
printSymbol(Symbol);
@@ -266,11 +439,14 @@ void MachODumper::printSections(const MachOObjectFile *Obj) {
}
if (opts::SectionData) {
- StringRef Data;
- if (error(Section.getContents(Data)))
- break;
+ bool IsBSS = Section.isBSS();
+ if (!IsBSS) {
+ StringRef Data;
+ if (error(Section.getContents(Data)))
+ break;
- W.printBinaryBlock("SectionData", Data);
+ W.printBinaryBlock("SectionData", Data);
+ }
}
}
}
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index f80a28b25cfc..27e658fc731a 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_OBJDUMPER_H
-#define LLVM_READOBJ_OBJDUMPER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_OBJDUMPER_H
+#define LLVM_TOOLS_LLVM_READOBJ_OBJDUMPER_H
#include <memory>
#include <system_error>
@@ -43,6 +43,12 @@ public:
// Only implemented for MIPS ELF at this time.
virtual void printMipsPLTGOT() { }
+ // Only implemented for PE/COFF.
+ virtual void printCOFFImports() { }
+ virtual void printCOFFExports() { }
+ virtual void printCOFFDirectives() { }
+ virtual void printCOFFBaseReloc() { }
+
protected:
StreamWriter& W;
};
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
index 04b38fbe25ea..2fc53eeeec4a 100644
--- a/tools/llvm-readobj/StreamWriter.h
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_READOBJ_STREAMWRITER_H
-#define LLVM_READOBJ_STREAMWRITER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
+#define LLVM_TOOLS_LLVM_READOBJ_STREAMWRITER_H
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
@@ -214,8 +214,8 @@ public:
}
void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
- ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
- Value.size());
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
printBinaryImpl(Label, Str, V, false);
}
@@ -224,20 +224,20 @@ public:
}
void printBinary(StringRef Label, ArrayRef<char> Value) {
- ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
- Value.size());
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
printBinaryImpl(Label, StringRef(), V, false);
}
void printBinary(StringRef Label, StringRef Value) {
- ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
- Value.size());
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
printBinaryImpl(Label, StringRef(), V, false);
}
void printBinaryBlock(StringRef Label, StringRef Value) {
- ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()),
- Value.size());
+ auto V = makeArrayRef(reinterpret_cast<const uint8_t*>(Value.data()),
+ Value.size());
printBinaryImpl(Label, StringRef(), V, true);
}
diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h
index 9ce4d39a6912..a80df9c4f94d 100644
--- a/tools/llvm-readobj/Win64EHDumper.h
+++ b/tools/llvm-readobj/Win64EHDumper.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H
-#define LLVM_TOOLS_READOBJ_WIN64EHPRINTER_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H
+#define LLVM_TOOLS_LLVM_READOBJ_WIN64EHDUMPER_H
#include "StreamWriter.h"
#include "llvm/Support/Win64EH.h"
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 8d2a997a2312..f95fea8ec3e8 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -24,6 +24,7 @@
#include "ObjDumper.h"
#include "StreamWriter.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
@@ -140,6 +141,24 @@ namespace opts {
cl::opt<bool>
MipsPLTGOT("mips-plt-got",
cl::desc("Display the MIPS GOT and PLT GOT sections"));
+
+ // -coff-imports
+ 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",
+ cl::desc("Display the PE/COFF .drectve section"));
+
+ // -coff-basereloc
+ cl::opt<bool>
+ COFFBaseRelocs("coff-basereloc",
+ cl::desc("Display the PE/COFF .reloc section"));
} // namespace opts
static int ReturnValue = EXIT_SUCCESS;
@@ -158,8 +177,8 @@ bool error(std::error_code EC) {
bool relocAddressLess(RelocationRef a, RelocationRef b) {
uint64_t a_addr, b_addr;
- if (error(a.getOffset(a_addr))) return false;
- if (error(b.getOffset(b_addr))) return false;
+ if (error(a.getOffset(a_addr))) exit(ReturnValue);
+ if (error(b.getOffset(b_addr))) exit(ReturnValue);
return a_addr < b_addr;
}
@@ -210,6 +229,17 @@ static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer,
return readobj_error::unsupported_obj_file_format;
}
+static StringRef getLoadName(const ObjectFile *Obj) {
+ if (auto *ELF = dyn_cast<ELF32LEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF64LEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF32BEObjectFile>(Obj))
+ return ELF->getLoadName();
+ if (auto *ELF = dyn_cast<ELF64BEObjectFile>(Obj))
+ return ELF->getLoadName();
+ llvm_unreachable("Not ELF");
+}
/// @brief Dumps the specified object file.
static void dumpObject(const ObjectFile *Obj) {
@@ -228,7 +258,7 @@ static void dumpObject(const ObjectFile *Obj) {
<< "\n";
outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n";
if (Obj->isELF())
- outs() << "LoadName: " << Obj->getLoadName() << "\n";
+ outs() << "LoadName: " << getLoadName(Obj) << "\n";
if (opts::FileHeaders)
Dumper->printFileHeaders();
@@ -254,6 +284,14 @@ static void dumpObject(const ObjectFile *Obj) {
if (isMipsArch(Obj->getArch()) && Obj->isELF())
if (opts::MipsPLTGOT)
Dumper->printMipsPLTGOT();
+ if (opts::COFFImports)
+ Dumper->printCOFFImports();
+ if (opts::COFFExports)
+ Dumper->printCOFFExports();
+ if (opts::COFFDirectives)
+ Dumper->printCOFFDirectives();
+ if (opts::COFFBaseRelocs)
+ Dumper->printCOFFBaseReloc();
}
@@ -287,16 +325,16 @@ static void dumpInput(StringRef File) {
}
// Attempt to open the binary.
- ErrorOr<Binary *> BinaryOrErr = createBinary(File);
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (std::error_code EC = BinaryOrErr.getError()) {
reportError(File, EC);
return;
}
- std::unique_ptr<Binary> Binary(BinaryOrErr.get());
+ Binary &Binary = *BinaryOrErr.get().getBinary();
- if (Archive *Arc = dyn_cast<Archive>(Binary.get()))
+ if (Archive *Arc = dyn_cast<Archive>(&Binary))
dumpArchive(Arc);
- else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get()))
+ else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
dumpObject(Obj);
else
reportError(File, readobj_error::unrecognized_file_format);
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index 04139480a6d8..1c334178a24e 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_READ_OBJ_H
-#define LLVM_TOOLS_READ_OBJ_H
+#ifndef LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
+#define LLVM_TOOLS_LLVM_READOBJ_LLVM_READOBJ_H
#include "llvm/Support/CommandLine.h"
#include <string>
diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt
index feb213489d3f..e294760801bb 100644
--- a/tools/llvm-rtdyld/CMakeLists.txt
+++ b/tools/llvm-rtdyld/CMakeLists.txt
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS
DebugInfo
ExecutionEngine
MC
+ Object
RuntimeDyld
Support
)
diff --git a/tools/llvm-rtdyld/LLVMBuild.txt b/tools/llvm-rtdyld/LLVMBuild.txt
index b36d13c75a0b..c4ed49bdff29 100644
--- a/tools/llvm-rtdyld/LLVMBuild.txt
+++ b/tools/llvm-rtdyld/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-rtdyld
parent = Tools
-required_libraries = JIT MC Object RuntimeDyld Support all-targets
+required_libraries = MC Object RuntimeDyld Support all-targets
diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile
index fabdd683a997..9de753ef22ad 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 JIT debuginfo
+LINK_COMPONENTS := all-targets support MC object RuntimeDyld MCJIT debuginfo
# 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 45734f4b7ba6..5b6f301994db 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -13,15 +13,13 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/DebugInfo/DIContext.h"
-#include "llvm/ExecutionEngine/ObjectBuffer.h"
-#include "llvm/ExecutionEngine/ObjectImage.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,11 @@
#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>
using namespace llvm;
@@ -78,6 +77,31 @@ CheckFiles("check",
cl::desc("File containing RuntimeDyld verifier checks."),
cl::ZeroOrMore);
+static cl::opt<uint64_t>
+TargetAddrStart("target-addr-start",
+ cl::desc("For -verify only: start of phony target address "
+ "range."),
+ cl::init(4096), // Start at "page 1" - no allocating at "null".
+ cl::Hidden);
+
+static cl::opt<uint64_t>
+TargetAddrEnd("target-addr-end",
+ cl::desc("For -verify only: end of phony target address range."),
+ cl::init(~0ULL),
+ cl::Hidden);
+
+static cl::opt<uint64_t>
+TargetSectionSep("target-section-sep",
+ cl::desc("For -verify only: Separation between sections in "
+ "phony target address space."),
+ cl::init(0),
+ cl::Hidden);
+
+static cl::list<std::string>
+SpecificSectionMappings("map-section",
+ cl::desc("Map a section to a specific address."),
+ cl::ZeroOrMore);
+
/* *** */
// A trivial memory manager that doesn't do anything fancy, just uses the
@@ -181,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.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
- 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;
@@ -242,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.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
- if (!LoadedObject) {
+ Dyld.loadObject(Obj);
+ if (Dyld.hasError()) {
return Error(Dyld.getErrorString());
}
}
@@ -300,6 +339,134 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) {
return 0;
}
+std::map<void*, uint64_t>
+applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
+
+ std::map<void*, uint64_t> SpecificMappings;
+
+ for (StringRef Mapping : SpecificSectionMappings) {
+
+ size_t EqualsIdx = Mapping.find_first_of("=");
+ StringRef SectionIDStr = Mapping.substr(0, EqualsIdx);
+ size_t ComaIdx = Mapping.find_first_of(",");
+
+ if (ComaIdx == StringRef::npos) {
+ errs() << "Invalid section specification '" << Mapping
+ << "'. Should be '<file name>,<section name>=<addr>'\n";
+ exit(1);
+ }
+
+ StringRef FileName = SectionIDStr.substr(0, ComaIdx);
+ StringRef SectionName = SectionIDStr.substr(ComaIdx + 1);
+
+ uint64_t OldAddrInt;
+ std::string ErrorMsg;
+ std::tie(OldAddrInt, ErrorMsg) =
+ Checker.getSectionAddr(FileName, SectionName, true);
+
+ if (ErrorMsg != "") {
+ errs() << ErrorMsg;
+ exit(1);
+ }
+
+ void* OldAddr = reinterpret_cast<void*>(static_cast<uintptr_t>(OldAddrInt));
+
+ StringRef NewAddrStr = Mapping.substr(EqualsIdx + 1);
+ uint64_t NewAddr;
+
+ if (NewAddrStr.getAsInteger(0, NewAddr)) {
+ errs() << "Invalid section address in mapping: " << Mapping << "\n";
+ exit(1);
+ }
+
+ Checker.getRTDyld().mapSectionAddress(OldAddr, NewAddr);
+ SpecificMappings[OldAddr] = NewAddr;
+ }
+
+ return SpecificMappings;
+}
+
+// Scatter sections in all directions!
+// Remaps section addresses for -verify mode. The following command line options
+// can be used to customize the layout of the memory within the phony target's
+// address space:
+// -target-addr-start <s> -- Specify where the phony target addres range starts.
+// -target-addr-end <e> -- Specify where the phony target address range ends.
+// -target-section-sep <d> -- Specify how big a gap should be left between the
+// end of one section and the start of the next.
+// Defaults to zero. Set to something big
+// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.
+//
+void remapSections(const llvm::Triple &TargetTriple,
+ const TrivialMemoryManager &MemMgr,
+ RuntimeDyldChecker &Checker) {
+
+ // Set up a work list (section addr/size pairs).
+ typedef std::list<std::pair<void*, uint64_t>> WorklistT;
+ WorklistT Worklist;
+
+ for (const auto& CodeSection : MemMgr.FunctionMemory)
+ Worklist.push_back(std::make_pair(CodeSection.base(), CodeSection.size()));
+ for (const auto& DataSection : MemMgr.DataMemory)
+ Worklist.push_back(std::make_pair(DataSection.base(), DataSection.size()));
+
+ // Apply any section-specific mappings that were requested on the command
+ // line.
+ typedef std::map<void*, uint64_t> AppliedMappingsT;
+ AppliedMappingsT AppliedMappings = applySpecificSectionMappings(Checker);
+
+ // Keep an "already allocated" mapping of section target addresses to sizes.
+ // Sections whose address mappings aren't specified on the command line will
+ // allocated around the explicitly mapped sections while maintaining the
+ // minimum separation.
+ std::map<uint64_t, uint64_t> AlreadyAllocated;
+
+ // Move the previously applied mappings into the already-allocated map.
+ for (WorklistT::iterator I = Worklist.begin(), E = Worklist.end();
+ I != E;) {
+ WorklistT::iterator Tmp = I;
+ ++I;
+ AppliedMappingsT::iterator AI = AppliedMappings.find(Tmp->first);
+
+ if (AI != AppliedMappings.end()) {
+ AlreadyAllocated[AI->second] = Tmp->second;
+ Worklist.erase(Tmp);
+ }
+ }
+
+ // If the -target-addr-end option wasn't explicitly passed, then set it to a
+ // sensible default based on the target triple.
+ if (TargetAddrEnd.getNumOccurrences() == 0) {
+ if (TargetTriple.isArch16Bit())
+ TargetAddrEnd = (1ULL << 16) - 1;
+ else if (TargetTriple.isArch32Bit())
+ TargetAddrEnd = (1ULL << 32) - 1;
+ // TargetAddrEnd already has a sensible default for 64-bit systems, so
+ // there's nothing to do in the 64-bit case.
+ }
+
+ // Process any elements remaining in the worklist.
+ while (!Worklist.empty()) {
+ std::pair<void*, uint64_t> CurEntry = Worklist.front();
+ Worklist.pop_front();
+
+ uint64_t NextSectionAddr = TargetAddrStart;
+
+ for (const auto &Alloc : AlreadyAllocated)
+ if (NextSectionAddr + CurEntry.second + TargetSectionSep <= Alloc.first)
+ break;
+ else
+ NextSectionAddr = Alloc.first + Alloc.second + TargetSectionSep;
+
+ AlreadyAllocated[NextSectionAddr] = CurEntry.second;
+ Checker.getRTDyld().mapSectionAddress(CurEntry.first, NextSectionAddr);
+ }
+
+}
+
+// Load and link the objects specified on the command line, but do not execute
+// anything. Instead, attach a RuntimeDyldChecker instance and call it to
+// verify the correctness of the linked memory.
static int linkAndVerify() {
// Check for missing triple.
@@ -347,6 +514,9 @@ static int linkAndVerify() {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
RuntimeDyld Dyld(&MemMgr);
+ Dyld.setProcessAllSections(true);
+ RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
+ llvm::dbgs());
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
@@ -355,24 +525,42 @@ 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.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
- if (!LoadedObject) {
+ Dyld.loadObject(Obj);
+ if (Dyld.hasError()) {
return Error(Dyld.getErrorString());
}
}
+ // Re-map the section addresses into the phony target address space.
+ remapSections(TheTriple, MemMgr, Checker);
+
// Resolve all the relocations we can.
Dyld.resolveRelocations();
- RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
- llvm::dbgs());
- return checkAllExpressions(Checker);
+ // Register EH frames.
+ Dyld.registerEHFrames();
+
+ int ErrorCode = checkAllExpressions(Checker);
+ if (Dyld.hasError()) {
+ errs() << "RTDyld reported an error applying relocations:\n "
+ << Dyld.getErrorString() << "\n";
+ ErrorCode = 1;
+ }
+
+ return ErrorCode;
}
int main(int argc, char **argv) {
diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt
new file mode 100644
index 000000000000..a896a8a26b52
--- /dev/null
+++ b/tools/llvm-shlib/CMakeLists.txt
@@ -0,0 +1,100 @@
+# This tool creates a shared library from the LLVM libraries. Generating this
+# library is enabled by setting LLVM_BUILD_LLVM_DYLIB=yes on the CMake
+# commandline. By default the shared library only exports the LLVM C API.
+
+
+# You can configure which libraries from LLVM you want to include in the shared
+# library by setting LLVM_DYLIB_COMPONENTS to a semi-colon delimited list of
+# LLVM components. All compoenent names handled by llvm-config are valid.
+
+if(NOT DEFINED LLVM_DYLIB_COMPONENTS)
+ set(LLVM_DYLIB_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Analysis
+ BitReader
+ BitWriter
+ CodeGen
+ Core
+ ExecutionEngine
+ IPA
+ IPO
+ IRReader
+ InstCombine
+ Instrumentation
+ Interpreter
+ Linker
+ MCDisassembler
+ MCJIT
+ ObjCARCOpts
+ Object
+ ScalarOpts
+ Support
+ Target
+ TransformUtils
+ Vectorize
+ native
+ )
+endif()
+
+add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" )
+
+set(SOURCES
+ libllvm.cpp
+ )
+
+if(NOT DEFINED LLVM_EXPORTED_SYMBOL_FILE)
+
+ if( WIN32 AND NOT CYGWIN )
+ message(FATAL_ERROR "Auto-generation not implemented for Win32 without GNU utils. Please specify LLVM_EXPORTED_SYMBOL_FILE.")
+ endif()
+
+ # To get the export list for a single llvm library:
+ # nm ${LIB_PATH} | awk "/T _LLVM/ { print $3 }" | sort -u | sed -e "s/^_//g" > ${LIB_PATH}.exports
+
+ set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_BINARY_DIR}/libllvm.exports)
+
+ llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS})
+
+ foreach (lib ${LIB_NAMES})
+
+ 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)
+
+ list(APPEND LLVM_DYLIB_REQUIRED_EXPORTS ${LIB_EXPORTS_PATH})
+
+ add_custom_command(OUTPUT ${LIB_EXPORTS_PATH}
+ COMMAND nm ${LIB_PATH} | awk "/T _LLVM/ || /T LLVM/ { print $3 }" | sort -u | sed -e "s/^_//g" > ${LIB_EXPORTS_PATH}
+ WORKING_DIRECTORY ${LIB_DIR}
+ DEPENDS ${lib}
+ COMMENT "Generating Export list for ${lib}..."
+ VERBATIM )
+ endforeach ()
+
+ add_custom_command(OUTPUT ${LLVM_EXPORTED_SYMBOL_FILE}
+ COMMAND cat ${LLVM_DYLIB_REQUIRED_EXPORTS} > ${LLVM_EXPORTED_SYMBOL_FILE}
+ WORKING_DIRECTORY ${LIB_DIR}
+ DEPENDS ${LLVM_DYLIB_REQUIRED_EXPORTS}
+ COMMENT "Generating combined export list...")
+
+endif()
+
+add_llvm_library(LLVM SHARED ${SOURCES})
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # FIXME: It should be "GNU ld for elf"
+ # GNU ld doesn't resolve symbols in the version script.
+ list(REMOVE_DUPLICATES LIB_NAMES)
+ set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
+endif()
+
+target_link_libraries(LLVM ${cmake_2_8_12_PRIVATE} ${LIB_NAMES})
+
+add_dependencies(LLVM ${LLVM_EXPORTED_SYMBOL_FILE})
+
+if (APPLE)
+ set_property(TARGET LLVM APPEND_STRING PROPERTY
+ LINK_FLAGS
+ " -compatibility_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR} -current_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
+endif()
+
diff --git a/tools/llvm-shlib/libllvm.cpp b/tools/llvm-shlib/libllvm.cpp
new file mode 100644
index 000000000000..8424d660c9d0
--- /dev/null
+++ b/tools/llvm-shlib/libllvm.cpp
@@ -0,0 +1,20 @@
+//===-libllvm.cpp - LLVM Shared Library -----------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is empty and serves only the purpose of making CMake happy because
+// 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 50b52200ff46..fc211e3180b4 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"
@@ -297,17 +297,13 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
std::size_t max_size_len = strlen("size");
std::size_t max_addr_len = strlen("addr");
for (const SectionRef &Section : Obj->sections()) {
- uint64_t size = 0;
- if (error(Section.getSize(size)))
- return;
+ uint64_t size = Section.getSize();
total += size;
StringRef name;
- uint64_t addr = 0;
if (error(Section.getName(name)))
return;
- if (error(Section.getAddress(addr)))
- return;
+ uint64_t addr = Section.getAddress();
max_name_len = std::max(max_name_len, name.size());
max_size_len = std::max(max_size_len, getNumLengthAsString(size));
max_addr_len = std::max(max_addr_len, getNumLengthAsString(addr));
@@ -337,14 +333,10 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
// Print each section.
for (const SectionRef &Section : Obj->sections()) {
StringRef name;
- uint64_t size = 0;
- uint64_t addr = 0;
if (error(Section.getName(name)))
return;
- if (error(Section.getSize(size)))
- return;
- if (error(Section.getAddress(addr)))
- return;
+ uint64_t size = Section.getSize();
+ uint64_t addr = Section.getAddress();
std::string namestr = name;
outs() << format(fmt.str().c_str(), namestr.c_str(), size, addr);
@@ -365,18 +357,10 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) {
// Make one pass over the section table to calculate sizes.
for (const SectionRef &Section : Obj->sections()) {
- uint64_t size = 0;
- bool isText = false;
- bool isData = false;
- bool isBSS = false;
- if (error(Section.getSize(size)))
- return;
- if (error(Section.isText(isText)))
- return;
- if (error(Section.isData(isData)))
- return;
- if (error(Section.isBSS(isBSS)))
- return;
+ uint64_t size = Section.getSize();
+ bool isText = Section.isText();
+ bool isData = Section.isData();
+ bool isBSS = Section.isBSS();
if (isText)
total_text += size;
else if (isData)
@@ -444,8 +428,7 @@ static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) {
static void PrintFileSectionSizes(StringRef file) {
// If file is not stdin, check that it exists.
if (file != "-") {
- bool exists;
- if (sys::fs::exists(file, exists) || !exists) {
+ if (!sys::fs::exists(file)) {
errs() << ToolName << ": '" << file << "': "
<< "No such file\n";
return;
@@ -453,14 +436,14 @@ static void PrintFileSectionSizes(StringRef file) {
}
// Attempt to open the binary.
- ErrorOr<Binary *> BinaryOrErr = createBinary(file);
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(file);
if (std::error_code EC = BinaryOrErr.getError()) {
errs() << ToolName << ": " << file << ": " << EC.message() << ".\n";
return;
}
- std::unique_ptr<Binary> binary(BinaryOrErr.get());
+ Binary &Bin = *BinaryOrErr.get().getBinary();
- if (Archive *a = dyn_cast<Archive>(binary.get())) {
+ if (Archive *a = dyn_cast<Archive>(&Bin)) {
// This is an archive. Iterate over each member and display its sizes.
for (object::Archive::child_iterator i = a->child_begin(),
e = a->child_end();
@@ -488,7 +471,7 @@ static void PrintFileSectionSizes(StringRef file) {
}
}
} else if (MachOUniversalBinary *UB =
- dyn_cast<MachOUniversalBinary>(binary.get())) {
+ 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.
@@ -501,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);
@@ -520,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(),
@@ -577,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);
@@ -596,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(),
@@ -640,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);
@@ -660,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();
@@ -692,7 +678,7 @@ static void PrintFileSectionSizes(StringRef file) {
}
}
}
- } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) {
+ } else if (ObjectFile *o = dyn_cast<ObjectFile>(&Bin)) {
if (!checkMachOAndArchFlags(o, file))
return;
if (OutputFormat == sysv)
@@ -731,8 +717,7 @@ int main(int argc, char **argv) {
if (ArchFlags[i] == "all") {
ArchAll = true;
} else {
- Triple T = MachOObjectFile::getArch(ArchFlags[i]);
- if (T.getArch() == Triple::UnknownArch) {
+ if (!MachOObjectFile::isValidArch(ArchFlags[i])) {
outs() << ToolName << ": for the -arch option: Unknown architecture "
<< "named '" << ArchFlags[i] << "'";
return 1;
diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp
index 23d3b636b190..21a79e3294a0 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -704,11 +704,10 @@ int main(int argc, char **argv) {
if (OutputFilename.empty())
OutputFilename = "-";
- std::string ErrorInfo;
- Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ std::error_code EC;
+ Out.reset(new tool_output_file(OutputFilename, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp
index c1d39efc1b81..36061d7e684f 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.cpp
+++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp
@@ -45,8 +45,26 @@ getDILineInfoSpecifier(const LLVMSymbolizer::Options &Opts) {
ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
: Module(Obj), DebugInfoContext(DICtx) {
+ std::unique_ptr<DataExtractor> OpdExtractor;
+ uint64_t OpdAddress = 0;
+ // Find the .opd (function descriptor) section if any, for big-endian
+ // PowerPC64 ELF.
+ if (Module->getArch() == Triple::ppc64) {
+ for (section_iterator Section : Module->sections()) {
+ StringRef Name;
+ if (!error(Section->getName(Name)) && Name == ".opd") {
+ StringRef Data;
+ if (!error(Section->getContents(Data))) {
+ OpdExtractor.reset(new DataExtractor(Data, Module->isLittleEndian(),
+ Module->getBytesInAddress()));
+ OpdAddress = Section->getAddress();
+ }
+ break;
+ }
+ }
+ }
for (const SymbolRef &Symbol : Module->symbols()) {
- addSymbol(Symbol);
+ addSymbol(Symbol, OpdExtractor.get(), OpdAddress);
}
bool NoSymbolTable = (Module->symbol_begin() == Module->symbol_end());
if (NoSymbolTable && Module->isELF()) {
@@ -54,12 +72,13 @@ ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx)
std::pair<symbol_iterator, symbol_iterator> IDyn =
getELFDynamicSymbolIterators(Module);
for (symbol_iterator si = IDyn.first, se = IDyn.second; si != se; ++si) {
- addSymbol(*si);
+ addSymbol(*si, OpdExtractor.get(), OpdAddress);
}
}
}
-void ModuleInfo::addSymbol(const SymbolRef &Symbol) {
+void ModuleInfo::addSymbol(const SymbolRef &Symbol, DataExtractor *OpdExtractor,
+ uint64_t OpdAddress) {
SymbolRef::Type SymbolType;
if (error(Symbol.getType(SymbolType)))
return;
@@ -69,6 +88,18 @@ void ModuleInfo::addSymbol(const SymbolRef &Symbol) {
if (error(Symbol.getAddress(SymbolAddress)) ||
SymbolAddress == UnknownAddressOrSize)
return;
+ if (OpdExtractor) {
+ // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
+ // function descriptors. The first word of the descriptor is a pointer to
+ // the function's code.
+ // For the purposes of symbolization, pretend the symbol's address is that
+ // of the function's code, not the descriptor.
+ uint64_t OpdOffset = SymbolAddress - OpdAddress;
+ uint32_t OpdOffset32 = OpdOffset;
+ if (OpdOffset == OpdOffset32 &&
+ OpdExtractor->isValidOffsetForAddress(OpdOffset32))
+ SymbolAddress = OpdExtractor->getAddress(&OpdOffset32);
+ }
uint64_t SymbolSize;
// Getting symbol size is linear for Mach-O files, so assume that symbol
// occupies the memory range up to the following symbol.
@@ -85,7 +116,7 @@ void ModuleInfo::addSymbol(const SymbolRef &Symbol) {
SymbolName = SymbolName.drop_front();
// FIXME: If a function has alias, there are two entries in symbol table
// with same address size. Make sure we choose the correct one.
- SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
+ auto &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects;
SymbolDesc SD = { SymbolAddress, SymbolSize };
M.insert(std::make_pair(SD, SymbolName));
}
@@ -93,19 +124,20 @@ void ModuleInfo::addSymbol(const SymbolRef &Symbol) {
bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
std::string &Name, uint64_t &Addr,
uint64_t &Size) const {
- const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects;
- if (M.empty())
+ const auto &SymbolMap = Type == SymbolRef::ST_Function ? Functions : Objects;
+ if (SymbolMap.empty())
return false;
SymbolDesc SD = { Address, Address };
- SymbolMapTy::const_iterator it = M.upper_bound(SD);
- if (it == M.begin())
+ auto SymbolIterator = SymbolMap.upper_bound(SD);
+ if (SymbolIterator == SymbolMap.begin())
return false;
- --it;
- if (it->first.Size != 0 && it->first.Addr + it->first.Size <= Address)
+ --SymbolIterator;
+ if (SymbolIterator->first.Size != 0 &&
+ SymbolIterator->first.Addr + SymbolIterator->first.Size <= Address)
return false;
- Name = it->second.str();
- Addr = it->first.Addr;
- Size = it->first.Size;
+ Name = SymbolIterator->second.str();
+ Addr = SymbolIterator->first.Addr;
+ Size = SymbolIterator->first.Size;
return true;
}
@@ -206,14 +238,21 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
void LLVMSymbolizer::flush() {
DeleteContainerSeconds(Modules);
- BinaryForPath.clear();
+ ObjectPairForPathArch.clear();
ObjectFileForArch.clear();
}
-static std::string getDarwinDWARFResourceForPath(const std::string &Path) {
- StringRef Basename = sys::path::filename(Path);
- const std::string &DSymDirectory = Path + ".dSYM";
- SmallString<16> ResourceName = StringRef(DSymDirectory);
+// For Path="/path/to/foo" and Basename="foo" assume that debug info is in
+// /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
+// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
+// /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
+static
+std::string getDarwinDWARFResourceForPath(
+ const std::string &Path, const std::string &Basename) {
+ SmallString<16> ResourceName = StringRef(Path);
+ if (sys::path::extension(Path) != ".dSYM") {
+ ResourceName += ".dSYM";
+ }
sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
sys::path::append(ResourceName, Basename);
return ResourceName.str();
@@ -264,9 +303,8 @@ static bool findDebugBinary(const std::string &OrigPath,
return false;
}
-static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName,
+static bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
uint32_t &CRCHash) {
- const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin);
if (!Obj)
return false;
for (const SectionRef &Section : Obj->sections()) {
@@ -293,60 +331,96 @@ static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName,
return false;
}
-LLVMSymbolizer::BinaryPair
-LLVMSymbolizer::getOrCreateBinary(const std::string &Path) {
- BinaryMapTy::iterator I = BinaryForPath.find(Path);
- if (I != BinaryForPath.end())
+static
+bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
+ const MachOObjectFile *Obj) {
+ ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
+ ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
+ if (dbg_uuid.empty() || bin_uuid.empty())
+ return false;
+ return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
+}
+
+ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
+ const MachOObjectFile *MachExeObj, const std::string &ArchName) {
+ // On Darwin we may find DWARF in separate object file in
+ // resource directory.
+ std::vector<std::string> DsymPaths;
+ StringRef Filename = sys::path::filename(ExePath);
+ DsymPaths.push_back(getDarwinDWARFResourceForPath(ExePath, Filename));
+ for (const auto &Path : Opts.DsymHints) {
+ DsymPaths.push_back(getDarwinDWARFResourceForPath(Path, Filename));
+ }
+ for (const auto &path : DsymPaths) {
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(path);
+ std::error_code EC = BinaryOrErr.getError();
+ if (EC != errc::no_such_file_or_directory && !error(EC)) {
+ OwningBinary<Binary> B = std::move(BinaryOrErr.get());
+ ObjectFile *DbgObj =
+ getObjectFileFromBinary(B.getBinary(), ArchName);
+ const MachOObjectFile *MachDbgObj =
+ dyn_cast<const MachOObjectFile>(DbgObj);
+ if (!MachDbgObj) continue;
+ if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj)) {
+ addOwningBinary(std::move(B));
+ return DbgObj;
+ }
+ }
+ }
+ return nullptr;
+}
+
+LLVMSymbolizer::ObjectPair
+LLVMSymbolizer::getOrCreateObjects(const std::string &Path,
+ const std::string &ArchName) {
+ const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
+ if (I != ObjectPairForPathArch.end())
return I->second;
- Binary *Bin = nullptr;
- Binary *DbgBin = nullptr;
- ErrorOr<Binary *> BinaryOrErr = createBinary(Path);
+ ObjectFile *Obj = nullptr;
+ ObjectFile *DbgObj = nullptr;
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Path);
if (!error(BinaryOrErr.getError())) {
- std::unique_ptr<Binary> ParsedBinary(BinaryOrErr.get());
- // Check if it's a universal binary.
- Bin = ParsedBinary.get();
- ParsedBinariesAndObjects.push_back(std::move(ParsedBinary));
- if (Bin->isMachO() || Bin->isMachOUniversalBinary()) {
- // On Darwin we may find DWARF in separate object file in
- // resource directory.
- const std::string &ResourcePath =
- getDarwinDWARFResourceForPath(Path);
- BinaryOrErr = createBinary(ResourcePath);
- std::error_code EC = BinaryOrErr.getError();
- if (EC != errc::no_such_file_or_directory && !error(EC)) {
- DbgBin = BinaryOrErr.get();
- ParsedBinariesAndObjects.push_back(std::unique_ptr<Binary>(DbgBin));
- }
+ OwningBinary<Binary> &B = BinaryOrErr.get();
+ Obj = getObjectFileFromBinary(B.getBinary(), ArchName);
+ if (!Obj) {
+ ObjectPair Res = std::make_pair(nullptr, nullptr);
+ ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
+ return Res;
}
+ addOwningBinary(std::move(B));
+ if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
+ DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
// Try to locate the debug binary using .gnu_debuglink section.
- if (!DbgBin) {
+ if (!DbgObj) {
std::string DebuglinkName;
uint32_t CRCHash;
std::string DebugBinaryPath;
- if (getGNUDebuglinkContents(Bin, DebuglinkName, CRCHash) &&
+ if (getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash) &&
findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath)) {
BinaryOrErr = createBinary(DebugBinaryPath);
if (!error(BinaryOrErr.getError())) {
- DbgBin = BinaryOrErr.get();
- ParsedBinariesAndObjects.push_back(std::unique_ptr<Binary>(DbgBin));
+ OwningBinary<Binary> B = std::move(BinaryOrErr.get());
+ DbgObj = getObjectFileFromBinary(B.getBinary(), ArchName);
+ addOwningBinary(std::move(B));
}
}
}
}
- if (!DbgBin)
- DbgBin = Bin;
- BinaryPair Res = std::make_pair(Bin, DbgBin);
- BinaryForPath[Path] = Res;
+ if (!DbgObj)
+ DbgObj = Obj;
+ ObjectPair Res = std::make_pair(Obj, DbgObj);
+ ObjectPairForPathArch[std::make_pair(Path, ArchName)] = Res;
return Res;
}
ObjectFile *
-LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName) {
+LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin,
+ const std::string &ArchName) {
if (!Bin)
return nullptr;
ObjectFile *Res = nullptr;
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin)) {
- ObjectFileForArchMapTy::iterator I = ObjectFileForArch.find(
+ const auto &I = ObjectFileForArch.find(
std::make_pair(UB, ArchName));
if (I != ObjectFileForArch.end())
return I->second;
@@ -365,7 +439,7 @@ LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName
ModuleInfo *
LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
- ModuleMapTy::iterator I = Modules.find(ModuleName);
+ const auto &I = Modules.find(ModuleName);
if (I != Modules.end())
return I->second;
std::string BinaryName = ModuleName;
@@ -379,18 +453,16 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
ArchName = ArchStr;
}
}
- BinaryPair Binaries = getOrCreateBinary(BinaryName);
- ObjectFile *Obj = getObjectFileFromBinary(Binaries.first, ArchName);
- ObjectFile *DbgObj = getObjectFileFromBinary(Binaries.second, ArchName);
+ ObjectPair Objects = getOrCreateObjects(BinaryName, ArchName);
- if (!Obj) {
+ if (!Objects.first) {
// Failed to find valid object file.
Modules.insert(make_pair(ModuleName, (ModuleInfo *)nullptr));
return nullptr;
}
- DIContext *Context = DIContext::getDWARFContext(DbgObj);
+ DIContext *Context = DIContext::getDWARFContext(*Objects.second);
assert(Context);
- ModuleInfo *Info = new ModuleInfo(Obj, Context);
+ ModuleInfo *Info = new ModuleInfo(Objects.first, Context);
Modules.insert(make_pair(ModuleName, Info));
return Info;
}
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h
index 45febe07847c..ff848fceb242 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.h
+++ b/tools/llvm-symbolizer/LLVMSymbolize.h
@@ -10,13 +10,14 @@
// Header for LLVM symbolization library.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SYMBOLIZE_H
-#define LLVM_SYMBOLIZE_H
+#ifndef LLVM_TOOLS_LLVM_SYMBOLIZER_LLVMSYMBOLIZE_H
+#define LLVM_TOOLS_LLVM_SYMBOLIZER_LLVMSYMBOLIZE_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/MemoryBuffer.h"
#include <map>
#include <memory>
@@ -39,13 +40,14 @@ public:
bool PrintInlining : 1;
bool Demangle : 1;
std::string DefaultArch;
+ std::vector<std::string> DsymHints;
Options(bool UseSymbolTable = true,
FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName,
bool PrintInlining = true, bool Demangle = true,
std::string DefaultArch = "")
- : UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions),
- PrintInlining(PrintInlining), Demangle(Demangle),
- DefaultArch(DefaultArch) {}
+ : UseSymbolTable(UseSymbolTable),
+ PrintFunctions(PrintFunctions), PrintInlining(PrintInlining),
+ Demangle(Demangle), DefaultArch(DefaultArch) {}
};
LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {}
@@ -62,11 +64,15 @@ public:
void flush();
static std::string DemangleName(const std::string &Name);
private:
- typedef std::pair<Binary*, Binary*> BinaryPair;
+ typedef std::pair<ObjectFile*, ObjectFile*> ObjectPair;
ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName);
- /// \brief Returns pair of pointers to binary and debug binary.
- BinaryPair getOrCreateBinary(const std::string &Path);
+ ObjectFile *lookUpDsymFile(const std::string &Path, const MachOObjectFile *ExeObj,
+ const std::string &ArchName);
+
+ /// \brief Returns pair of pointers to object and debug object.
+ ObjectPair getOrCreateObjects(const std::string &Path,
+ const std::string &ArchName);
/// \brief Returns a parsed object file for a given architecture in a
/// universal binary (or the binary itself if it is an object file).
ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName);
@@ -75,14 +81,21 @@ private:
// Owns all the parsed binaries and object files.
SmallVector<std::unique_ptr<Binary>, 4> ParsedBinariesAndObjects;
+ SmallVector<std::unique_ptr<MemoryBuffer>, 4> MemoryBuffers;
+ void addOwningBinary(OwningBinary<Binary> OwningBin) {
+ std::unique_ptr<Binary> Bin;
+ std::unique_ptr<MemoryBuffer> MemBuf;
+ std::tie(Bin, MemBuf) = OwningBin.takeBinary();
+ ParsedBinariesAndObjects.push_back(std::move(Bin));
+ MemoryBuffers.push_back(std::move(MemBuf));
+ }
+
// Owns module info objects.
- typedef std::map<std::string, ModuleInfo *> ModuleMapTy;
- ModuleMapTy Modules;
- typedef std::map<std::string, BinaryPair> BinaryMapTy;
- BinaryMapTy BinaryForPath;
- typedef std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
- ObjectFileForArchMapTy;
- ObjectFileForArchMapTy ObjectFileForArch;
+ std::map<std::string, ModuleInfo *> Modules;
+ std::map<std::pair<MachOUniversalBinary *, std::string>, ObjectFile *>
+ ObjectFileForArch;
+ std::map<std::pair<std::string, std::string>, ObjectPair>
+ ObjectPairForPathArch;
Options Opts;
static const char kBadString[];
@@ -103,7 +116,11 @@ private:
bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address,
std::string &Name, uint64_t &Addr,
uint64_t &Size) const;
- void addSymbol(const SymbolRef &Symbol);
+ // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd
+ // (function descriptor) section and OpdExtractor refers to its contents.
+ void addSymbol(const SymbolRef &Symbol,
+ DataExtractor *OpdExtractor = nullptr,
+ uint64_t OpdAddress = 0);
ObjectFile *Module;
std::unique_ptr<DIContext> DebugInfoContext;
@@ -116,12 +133,11 @@ private:
return s1.Addr < s2.Addr;
}
};
- typedef std::map<SymbolDesc, StringRef> SymbolMapTy;
- SymbolMapTy Functions;
- SymbolMapTy Objects;
+ std::map<SymbolDesc, StringRef> Functions;
+ std::map<SymbolDesc, StringRef> Objects;
};
} // namespace symbolize
} // namespace llvm
-#endif // LLVM_SYMBOLIZE_H
+#endif
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 29db172531ba..d554022e450c 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
@@ -61,6 +62,11 @@ ClBinaryName("obj", cl::init(""),
cl::desc("Path to object file to be symbolized (if not provided, "
"object file should be specified for each input line)"));
+static cl::list<std::string>
+ClDsymHint("dsym-hint", cl::ZeroOrMore,
+ cl::desc("Path to .dSYM bundles to search for debug info for the "
+ "object files"));
+
static bool parseCommand(bool &IsData, std::string &ModuleName,
uint64_t &ModuleOffset) {
const char *kDataCmd = "DATA ";
@@ -119,6 +125,14 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n");
LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
ClPrintInlining, ClDemangle, ClDefaultArch);
+ for (const auto &hint : ClDsymHint) {
+ if (sys::path::extension(hint) == ".dSYM") {
+ Opts.DsymHints.push_back(hint);
+ } else {
+ errs() << "Warning: invalid dSYM hint: \"" << hint <<
+ "\" (must have the '.dSYM' extension).\n";
+ }
+ }
LLVMSymbolizer Symbolizer(Opts);
bool IsData = false;
diff --git a/tools/llvm-vtabledump/CMakeLists.txt b/tools/llvm-vtabledump/CMakeLists.txt
new file mode 100644
index 000000000000..4fe205b6efd4
--- /dev/null
+++ b/tools/llvm-vtabledump/CMakeLists.txt
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ Object
+ Support
+ )
+
+add_llvm_tool(llvm-vtabledump
+ llvm-vtabledump.cpp
+ Error.cpp
+ )
diff --git a/tools/llvm-vtabledump/Error.cpp b/tools/llvm-vtabledump/Error.cpp
new file mode 100644
index 000000000000..c5de8951636d
--- /dev/null
+++ b/tools/llvm-vtabledump/Error.cpp
@@ -0,0 +1,43 @@
+//===- Error.cpp - system_error extensions for llvm-vtabledump --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines a new error_category for the llvm-vtabledump tool.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+class vtabledump_error_category : public std::error_category {
+public:
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.vtabledump"; }
+ std::string message(int ev) const override {
+ switch (static_cast<vtabledump_error>(ev)) {
+ case vtabledump_error::success:
+ return "Success";
+ case vtabledump_error::file_not_found:
+ return "No such file.";
+ case vtabledump_error::unrecognized_file_format:
+ return "Unrecognized file type.";
+ }
+ llvm_unreachable(
+ "An enumerator of vtabledump_error does not have a message defined.");
+ }
+};
+} // namespace
+
+namespace llvm {
+const std::error_category &vtabledump_category() {
+ static vtabledump_error_category o;
+ return o;
+}
+} // namespace llvm
diff --git a/tools/llvm-vtabledump/Error.h b/tools/llvm-vtabledump/Error.h
new file mode 100644
index 000000000000..fd8bb18994df
--- /dev/null
+++ b/tools/llvm-vtabledump/Error.h
@@ -0,0 +1,39 @@
+//===- Error.h - system_error extensions for llvm-vtabledump ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This declares a new error_category for the llvm-vtabledump tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H
+#define LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H
+
+#include <system_error>
+
+namespace llvm {
+const std::error_category &vtabledump_category();
+
+enum class vtabledump_error {
+ success = 0,
+ file_not_found,
+ unrecognized_file_format,
+};
+
+inline std::error_code make_error_code(vtabledump_error e) {
+ return std::error_code(static_cast<int>(e), vtabledump_category());
+}
+
+} // namespace llvm
+
+namespace std {
+template <>
+struct is_error_code_enum<llvm::vtabledump_error> : std::true_type {};
+}
+
+#endif
diff --git a/tools/llvm-vtabledump/LLVMBuild.txt b/tools/llvm-vtabledump/LLVMBuild.txt
new file mode 100644
index 000000000000..6a3cbfff4c13
--- /dev/null
+++ b/tools/llvm-vtabledump/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/llvm-vtabledump/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-vtabledump
+parent = Tools
+required_libraries = all-targets BitReader Object
diff --git a/tools/llvm-vtabledump/Makefile b/tools/llvm-vtabledump/Makefile
new file mode 100644
index 000000000000..596c64c67b6b
--- /dev/null
+++ b/tools/llvm-vtabledump/Makefile
@@ -0,0 +1,18 @@
+##===- tools/llvm-vtabledump/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-vtabledump
+LINK_COMPONENTS := bitreader object all-targets
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
+
diff --git a/tools/llvm-vtabledump/llvm-vtabledump.cpp b/tools/llvm-vtabledump/llvm-vtabledump.cpp
new file mode 100644
index 000000000000..a21acae02c3a
--- /dev/null
+++ b/tools/llvm-vtabledump/llvm-vtabledump.cpp
@@ -0,0 +1,464 @@
+//===- llvm-vtabledump.cpp - Dump vtables in an Object File -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Dumps VTables resident in object files and archives. Note, it currently only
+// supports MS-ABI style object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-vtabledump.h"
+#include "Error.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include <map>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::support;
+
+namespace opts {
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input object files>"),
+ cl::ZeroOrMore);
+} // namespace opts
+
+static int ReturnValue = EXIT_SUCCESS;
+
+namespace llvm {
+
+bool error(std::error_code EC) {
+ if (!EC)
+ return false;
+
+ ReturnValue = EXIT_FAILURE;
+ outs() << "\nError reading file: " << EC.message() << ".\n";
+ outs().flush();
+ return true;
+}
+
+} // namespace llvm
+
+static void reportError(StringRef Input, StringRef Message) {
+ if (Input == "-")
+ Input = "<stdin>";
+
+ errs() << Input << ": " << Message << "\n";
+ errs().flush();
+ ReturnValue = EXIT_FAILURE;
+}
+
+static void reportError(StringRef Input, std::error_code EC) {
+ reportError(Input, EC.message());
+}
+
+static SmallVectorImpl<SectionRef> &getRelocSections(const ObjectFile *Obj,
+ const SectionRef &Sec) {
+ static bool MappingDone = false;
+ static std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap;
+ if (!MappingDone) {
+ for (const SectionRef &Section : Obj->sections()) {
+ section_iterator Sec2 = Section.getRelocatedSection();
+ if (Sec2 != Obj->section_end())
+ SectionRelocMap[*Sec2].push_back(Section);
+ }
+ MappingDone = true;
+ }
+ return SectionRelocMap[Sec];
+}
+
+static bool collectRelocatedSymbols(const ObjectFile *Obj,
+ const SectionRef &Sec, uint64_t SecAddress,
+ uint64_t SymAddress, uint64_t SymSize,
+ StringRef *I, StringRef *E) {
+ uint64_t SymOffset = SymAddress - SecAddress;
+ uint64_t SymEnd = SymOffset + SymSize;
+ for (const SectionRef &SR : getRelocSections(Obj, Sec)) {
+ for (const object::RelocationRef &Reloc : SR.relocations()) {
+ if (I == E)
+ break;
+ const object::symbol_iterator RelocSymI = Reloc.getSymbol();
+ if (RelocSymI == Obj->symbol_end())
+ continue;
+ StringRef RelocSymName;
+ if (error(RelocSymI->getName(RelocSymName)))
+ return true;
+ uint64_t Offset;
+ if (error(Reloc.getOffset(Offset)))
+ return true;
+ if (Offset >= SymOffset && Offset < SymEnd) {
+ *I = RelocSymName;
+ ++I;
+ }
+ }
+ }
+ return false;
+}
+
+static bool collectRelocationOffsets(
+ const ObjectFile *Obj, const SectionRef &Sec, uint64_t SecAddress,
+ uint64_t SymAddress, uint64_t SymSize, StringRef SymName,
+ std::map<std::pair<StringRef, uint64_t>, StringRef> &Collection) {
+ uint64_t SymOffset = SymAddress - SecAddress;
+ uint64_t SymEnd = SymOffset + SymSize;
+ for (const SectionRef &SR : getRelocSections(Obj, Sec)) {
+ for (const object::RelocationRef &Reloc : SR.relocations()) {
+ const object::symbol_iterator RelocSymI = Reloc.getSymbol();
+ if (RelocSymI == Obj->symbol_end())
+ continue;
+ StringRef RelocSymName;
+ if (error(RelocSymI->getName(RelocSymName)))
+ return true;
+ uint64_t Offset;
+ if (error(Reloc.getOffset(Offset)))
+ return true;
+ if (Offset >= SymOffset && Offset < SymEnd)
+ Collection[std::make_pair(SymName, Offset - SymOffset)] = RelocSymName;
+ }
+ }
+ return false;
+}
+
+static void dumpVTables(const ObjectFile *Obj) {
+ struct CompleteObjectLocator {
+ StringRef Symbols[2];
+ ArrayRef<little32_t> Data;
+ };
+ struct ClassHierarchyDescriptor {
+ StringRef Symbols[1];
+ ArrayRef<little32_t> Data;
+ };
+ struct BaseClassDescriptor {
+ StringRef Symbols[2];
+ ArrayRef<little32_t> Data;
+ };
+ struct TypeDescriptor {
+ StringRef Symbols[1];
+ uint64_t AlwaysZero;
+ StringRef MangledName;
+ };
+ std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries;
+ std::map<StringRef, ArrayRef<little32_t>> VBTables;
+ std::map<StringRef, CompleteObjectLocator> COLs;
+ std::map<StringRef, ClassHierarchyDescriptor> CHDs;
+ std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries;
+ std::map<StringRef, BaseClassDescriptor> BCDs;
+ std::map<StringRef, TypeDescriptor> TDs;
+
+ std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries;
+ std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries;
+ std::map<std::pair<StringRef, uint64_t>, StringRef> VTTEntries;
+ std::map<StringRef, StringRef> TINames;
+
+ uint8_t BytesInAddress = Obj->getBytesInAddress();
+
+ for (const object::SymbolRef &Sym : Obj->symbols()) {
+ StringRef SymName;
+ if (error(Sym.getName(SymName)))
+ return;
+ object::section_iterator SecI(Obj->section_begin());
+ if (error(Sym.getSection(SecI)))
+ return;
+ // Skip external symbols.
+ if (SecI == Obj->section_end())
+ continue;
+ const SectionRef &Sec = *SecI;
+ // Skip virtual or BSS sections.
+ if (Sec.isBSS() || Sec.isVirtual())
+ continue;
+ StringRef SecContents;
+ if (error(Sec.getContents(SecContents)))
+ return;
+ uint64_t SymAddress, SymSize;
+ if (error(Sym.getAddress(SymAddress)) || error(Sym.getSize(SymSize)))
+ return;
+ uint64_t SecAddress = Sec.getAddress();
+ uint64_t SecSize = Sec.getSize();
+ uint64_t SymOffset = SymAddress - SecAddress;
+ StringRef SymContents = SecContents.substr(SymOffset, SymSize);
+
+ // VFTables in the MS-ABI start with '??_7' and are contained within their
+ // own COMDAT section. We then determine the contents of the VFTable by
+ // looking at each relocation in the section.
+ if (SymName.startswith("??_7")) {
+ // Each relocation either names a virtual method or a thunk. We note the
+ // offset into the section and the symbol used for the relocation.
+ collectRelocationOffsets(Obj, Sec, SecAddress, SecAddress, SecSize,
+ SymName, VFTableEntries);
+ }
+ // VBTables in the MS-ABI start with '??_8' and are filled with 32-bit
+ // offsets of virtual bases.
+ else if (SymName.startswith("??_8")) {
+ ArrayRef<little32_t> VBTableData(
+ reinterpret_cast<const little32_t *>(SymContents.data()),
+ SymContents.size() / sizeof(little32_t));
+ VBTables[SymName] = VBTableData;
+ }
+ // Complete object locators in the MS-ABI start with '??_R4'
+ else if (SymName.startswith("??_R4")) {
+ CompleteObjectLocator COL;
+ COL.Data = ArrayRef<little32_t>(
+ reinterpret_cast<const little32_t *>(SymContents.data()), 3);
+ StringRef *I = std::begin(COL.Symbols), *E = std::end(COL.Symbols);
+ if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I,
+ E))
+ return;
+ COLs[SymName] = COL;
+ }
+ // Class hierarchy descriptors in the MS-ABI start with '??_R3'
+ else if (SymName.startswith("??_R3")) {
+ ClassHierarchyDescriptor CHD;
+ CHD.Data = ArrayRef<little32_t>(
+ reinterpret_cast<const little32_t *>(SymContents.data()), 3);
+ StringRef *I = std::begin(CHD.Symbols), *E = std::end(CHD.Symbols);
+ if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I,
+ E))
+ return;
+ CHDs[SymName] = CHD;
+ }
+ // Class hierarchy descriptors in the MS-ABI start with '??_R2'
+ else if (SymName.startswith("??_R2")) {
+ // Each relocation names a base class descriptor. We note the offset into
+ // the section and the symbol used for the relocation.
+ collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
+ SymName, BCAEntries);
+ }
+ // Base class descriptors in the MS-ABI start with '??_R1'
+ else if (SymName.startswith("??_R1")) {
+ BaseClassDescriptor BCD;
+ BCD.Data = ArrayRef<little32_t>(
+ reinterpret_cast<const little32_t *>(SymContents.data()) + 1, 5);
+ StringRef *I = std::begin(BCD.Symbols), *E = std::end(BCD.Symbols);
+ if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I,
+ E))
+ return;
+ BCDs[SymName] = BCD;
+ }
+ // Type descriptors in the MS-ABI start with '??_R0'
+ else if (SymName.startswith("??_R0")) {
+ const char *DataPtr = SymContents.drop_front(BytesInAddress).data();
+ TypeDescriptor TD;
+ if (BytesInAddress == 8)
+ TD.AlwaysZero = *reinterpret_cast<const little64_t *>(DataPtr);
+ else
+ TD.AlwaysZero = *reinterpret_cast<const little32_t *>(DataPtr);
+ TD.MangledName = SymContents.drop_front(BytesInAddress * 2);
+ StringRef *I = std::begin(TD.Symbols), *E = std::end(TD.Symbols);
+ if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I,
+ E))
+ return;
+ TDs[SymName] = TD;
+ }
+ // Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
+ else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) {
+ collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
+ SymName, VTTEntries);
+ }
+ // Typeinfo names in the Itanium ABI start with '_ZTS' or '__ZTS'.
+ else if (SymName.startswith("_ZTS") || SymName.startswith("__ZTS")) {
+ TINames[SymName] = SymContents.slice(0, SymContents.find('\0'));
+ }
+ // Vtables in the Itanium ABI start with '_ZTV' or '__ZTV'.
+ else if (SymName.startswith("_ZTV") || SymName.startswith("__ZTV")) {
+ collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
+ SymName, VTableSymEntries);
+ for (uint64_t SymOffI = 0; SymOffI < SymSize; SymOffI += BytesInAddress) {
+ auto Key = std::make_pair(SymName, SymOffI);
+ if (VTableSymEntries.count(Key))
+ continue;
+ const char *DataPtr = SymContents.substr(SymOffI, BytesInAddress).data();
+ int64_t VData;
+ if (BytesInAddress == 8)
+ VData = *reinterpret_cast<const little64_t *>(DataPtr);
+ else
+ VData = *reinterpret_cast<const little32_t *>(DataPtr);
+ VTableDataEntries[Key] = VData;
+ }
+ }
+ // Typeinfo structures in the Itanium ABI start with '_ZTI' or '__ZTI'.
+ else if (SymName.startswith("_ZTI") || SymName.startswith("__ZTI")) {
+ // FIXME: Do something with these!
+ }
+ }
+ for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VFTableEntry :
+ VFTableEntries) {
+ StringRef VFTableName = VFTableEntry.first.first;
+ uint64_t Offset = VFTableEntry.first.second;
+ StringRef SymName = VFTableEntry.second;
+ outs() << VFTableName << '[' << Offset << "]: " << SymName << '\n';
+ }
+ for (const std::pair<StringRef, ArrayRef<little32_t>> &VBTable : VBTables) {
+ StringRef VBTableName = VBTable.first;
+ uint32_t Idx = 0;
+ for (little32_t Offset : VBTable.second) {
+ outs() << VBTableName << '[' << Idx << "]: " << Offset << '\n';
+ Idx += sizeof(Offset);
+ }
+ }
+ for (const std::pair<StringRef, CompleteObjectLocator> &COLPair : COLs) {
+ StringRef COLName = COLPair.first;
+ const CompleteObjectLocator &COL = COLPair.second;
+ outs() << COLName << "[IsImageRelative]: " << COL.Data[0] << '\n';
+ outs() << COLName << "[OffsetToTop]: " << COL.Data[1] << '\n';
+ outs() << COLName << "[VFPtrOffset]: " << COL.Data[2] << '\n';
+ outs() << COLName << "[TypeDescriptor]: " << COL.Symbols[0] << '\n';
+ outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1] << '\n';
+ }
+ for (const std::pair<StringRef, ClassHierarchyDescriptor> &CHDPair : CHDs) {
+ StringRef CHDName = CHDPair.first;
+ const ClassHierarchyDescriptor &CHD = CHDPair.second;
+ outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n';
+ outs() << CHDName << "[Flags]: " << CHD.Data[1] << '\n';
+ outs() << CHDName << "[NumClasses]: " << CHD.Data[2] << '\n';
+ outs() << CHDName << "[BaseClassArray]: " << CHD.Symbols[0] << '\n';
+ }
+ for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &BCAEntry :
+ BCAEntries) {
+ StringRef BCAName = BCAEntry.first.first;
+ uint64_t Offset = BCAEntry.first.second;
+ StringRef SymName = BCAEntry.second;
+ outs() << BCAName << '[' << Offset << "]: " << SymName << '\n';
+ }
+ for (const std::pair<StringRef, BaseClassDescriptor> &BCDPair : BCDs) {
+ StringRef BCDName = BCDPair.first;
+ const BaseClassDescriptor &BCD = BCDPair.second;
+ outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n';
+ outs() << BCDName << "[NumBases]: " << BCD.Data[0] << '\n';
+ outs() << BCDName << "[OffsetInVBase]: " << BCD.Data[1] << '\n';
+ outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n';
+ outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n';
+ outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n';
+ outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n';
+ }
+ for (const std::pair<StringRef, TypeDescriptor> &TDPair : TDs) {
+ StringRef TDName = TDPair.first;
+ const TypeDescriptor &TD = TDPair.second;
+ outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n';
+ outs() << TDName << "[AlwaysZero]: " << TD.AlwaysZero << '\n';
+ outs() << TDName << "[MangledName]: ";
+ outs().write_escaped(TD.MangledName.rtrim(StringRef("\0", 1)),
+ /*UseHexEscapes=*/true)
+ << '\n';
+ }
+ for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VTTPair :
+ VTTEntries) {
+ StringRef VTTName = VTTPair.first.first;
+ uint64_t VTTOffset = VTTPair.first.second;
+ StringRef VTTEntry = VTTPair.second;
+ outs() << VTTName << '[' << VTTOffset << "]: " << VTTEntry << '\n';
+ }
+ for (const std::pair<StringRef, StringRef> &TIPair : TINames) {
+ StringRef TIName = TIPair.first;
+ outs() << TIName << ": " << TIPair.second << '\n';
+ }
+ auto VTableSymI = VTableSymEntries.begin();
+ auto VTableSymE = VTableSymEntries.end();
+ auto VTableDataI = VTableDataEntries.begin();
+ auto VTableDataE = VTableDataEntries.end();
+ for (;;) {
+ bool SymDone = VTableSymI == VTableSymE;
+ bool DataDone = VTableDataI == VTableDataE;
+ if (SymDone && DataDone)
+ break;
+ if (!SymDone && (DataDone || VTableSymI->first < VTableDataI->first)) {
+ StringRef VTableName = VTableSymI->first.first;
+ uint64_t Offset = VTableSymI->first.second;
+ StringRef VTableEntry = VTableSymI->second;
+ outs() << VTableName << '[' << Offset << "]: ";
+ outs() << VTableEntry;
+ outs() << '\n';
+ ++VTableSymI;
+ continue;
+ }
+ if (!DataDone && (SymDone || VTableDataI->first < VTableSymI->first)) {
+ StringRef VTableName = VTableDataI->first.first;
+ uint64_t Offset = VTableDataI->first.second;
+ int64_t VTableEntry = VTableDataI->second;
+ outs() << VTableName << '[' << Offset << "]: ";
+ outs() << VTableEntry;
+ outs() << '\n';
+ ++VTableDataI;
+ continue;
+ }
+ }
+}
+
+static void dumpArchive(const Archive *Arc) {
+ for (const Archive::Child &ArcC : Arc->children()) {
+ ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcC.getAsBinary();
+ if (std::error_code EC = ChildOrErr.getError()) {
+ // Ignore non-object files.
+ if (EC != object_error::invalid_file_type)
+ reportError(Arc->getFileName(), EC.message());
+ continue;
+ }
+
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
+ dumpVTables(Obj);
+ else
+ reportError(Arc->getFileName(),
+ vtabledump_error::unrecognized_file_format);
+ }
+}
+
+static void dumpInput(StringRef File) {
+ // If file isn't stdin, check that it exists.
+ if (File != "-" && !sys::fs::exists(File)) {
+ reportError(File, vtabledump_error::file_not_found);
+ return;
+ }
+
+ // Attempt to open the binary.
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
+ if (std::error_code EC = BinaryOrErr.getError()) {
+ reportError(File, EC);
+ return;
+ }
+ Binary &Binary = *BinaryOrErr.get().getBinary();
+
+ if (Archive *Arc = dyn_cast<Archive>(&Binary))
+ dumpArchive(Arc);
+ else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
+ dumpVTables(Obj);
+ else
+ reportError(File, vtabledump_error::unrecognized_file_format);
+}
+
+int main(int argc, const char *argv[]) {
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc, argv);
+ llvm_shutdown_obj Y;
+
+ // Initialize targets.
+ llvm::InitializeAllTargetInfos();
+
+ // Register the target printer for --version.
+ cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
+
+ cl::ParseCommandLineOptions(argc, argv, "LLVM VTable Dumper\n");
+
+ // Default to stdin if no filename is specified.
+ if (opts::InputFilenames.size() == 0)
+ opts::InputFilenames.push_back("-");
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
+
+ return ReturnValue;
+}
diff --git a/tools/llvm-vtabledump/llvm-vtabledump.h b/tools/llvm-vtabledump/llvm-vtabledump.h
new file mode 100644
index 000000000000..62f755739c39
--- /dev/null
+++ b/tools/llvm-vtabledump/llvm-vtabledump.h
@@ -0,0 +1,23 @@
+//===-- llvm-vtabledump.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_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H
+#define LLVM_TOOLS_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H
+
+#include "llvm/Support/CommandLine.h"
+#include <string>
+
+namespace opts {
+extern llvm::cl::list<std::string> InputFilenames;
+} // namespace opts
+
+#define LLVM_VTABLEDUMP_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+#endif
diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt
index 71391b7cf5f4..87f42e87cb41 100644
--- a/tools/lto/CMakeLists.txt
+++ b/tools/lto/CMakeLists.txt
@@ -7,8 +7,6 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" )
-
set(SOURCES
LTODisassembler.cpp
lto.cpp
diff --git a/tools/lto/Makefile b/tools/lto/Makefile
index a4fe9ac77c17..530c05a47318 100644
--- a/tools/lto/Makefile
+++ b/tools/lto/Makefile
@@ -17,10 +17,6 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/lto.exports
include $(LEVEL)/Makefile.common
-ifdef LLVM_VERSION_INFO
-CXX.Flags += -DLLVM_VERSION_INFO='"$(LLVM_VERSION_INFO)"'
-endif
-
ifeq ($(HOST_OS),Darwin)
# Special hack to allow libLTO to have an offset version number.
ifdef LLVM_LTO_VERSION_OFFSET
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index 5732996a1606..ec0372ea5607 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -14,6 +14,7 @@
#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"
@@ -32,6 +33,10 @@ static cl::opt<bool>
DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false),
cl::desc("Do not run the GVN load PRE pass"));
+static cl::opt<bool>
+DisableLTOVectorization("disable-lto-vectorization", cl::init(false),
+ cl::desc("Do not run loop or slp vectorization during LTO"));
+
// Holds most recent error string.
// *** Not thread safe ***
static std::string sLastErrorString;
@@ -146,6 +151,24 @@ lto_module_t lto_module_create_from_memory_with_path(const void* mem,
LTOModule::createFromBuffer(mem, length, Options, sLastErrorString, path));
}
+lto_module_t lto_module_create_in_local_context(const void *mem, size_t length,
+ const char *path) {
+ lto_initialize();
+ llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ return wrap(LTOModule::createInLocalContext(mem, length, Options,
+ sLastErrorString, path));
+}
+
+lto_module_t lto_module_create_in_codegen_context(const void *mem,
+ size_t length,
+ const char *path,
+ lto_code_gen_t cg) {
+ lto_initialize();
+ llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ return wrap(LTOModule::createInContext(mem, length, Options, sLastErrorString,
+ path, &unwrap(cg)->getContext()));
+}
+
void lto_module_dispose(lto_module_t mod) { delete unwrap(mod); }
const char* lto_module_get_target_triple(lto_module_t mod) {
@@ -191,21 +214,31 @@ 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), sLastErrorString);
+ return !unwrap(cg)->addModule(unwrap(mod));
}
bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) {
@@ -252,7 +285,8 @@ const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
parsedOptions = true;
}
return unwrap(cg)->compile(length, DisableOpt, DisableInline,
- DisableGVNLoadPRE, sLastErrorString);
+ DisableGVNLoadPRE, DisableLTOVectorization,
+ sLastErrorString);
}
bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
@@ -261,8 +295,9 @@ bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
lto_add_attrs(cg);
parsedOptions = true;
}
- return !unwrap(cg)->compile_to_file(name, DisableOpt, DisableInline,
- DisableGVNLoadPRE, sLastErrorString);
+ return !unwrap(cg)->compile_to_file(
+ name, DisableOpt, DisableInline, DisableGVNLoadPRE,
+ DisableLTOVectorization, sLastErrorString);
}
void lto_codegen_debug_options(lto_code_gen_t cg, const char *opt) {
diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports
index b10ab1a3e6c0..f6ceaac74d18 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
@@ -25,6 +27,7 @@ lto_codegen_add_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
diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp
index 760097974dbd..604f93adfbbf 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');
@@ -324,7 +324,7 @@ DumpVersionMin(const MachOObjectFile &Obj,
const MachOObjectFile::LoadCommandInfo &LCI) {
MachO::version_min_command VMLC = Obj.getVersionMinLoadCommand(LCI);
outs() << " ('version, " << VMLC.version << ")\n"
- << " ('reserved, " << VMLC.reserved << ")\n";
+ << " ('sdk, " << VMLC.sdk << ")\n";
return 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:
@@ -403,12 +403,12 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n");
- ErrorOr<Binary *> BinaryOrErr = createBinary(InputFile);
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFile);
if (std::error_code EC = BinaryOrErr.getError())
return Error("unable to read input: '" + EC.message() + "'");
- std::unique_ptr<Binary> Binary(BinaryOrErr.get());
+ Binary &Binary = *BinaryOrErr.get().getBinary();
- const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(Binary.get());
+ const MachOObjectFile *InputObject = dyn_cast<MachOObjectFile>(&Binary);
if (!InputObject)
return Error("Not a MachO object");
diff --git a/tools/msbuild/CMakeLists.txt b/tools/msbuild/CMakeLists.txt
index b7be71d2a880..4f471e5408ba 100644
--- a/tools/msbuild/CMakeLists.txt
+++ b/tools/msbuild/CMakeLists.txt
@@ -10,6 +10,8 @@ if (WIN32)
set(prop_file_v110_xp "Microsoft.Cpp.${platform}.LLVM-vs2012_xp.props")
set(prop_file_v120 "toolset-vs2013.props")
set(prop_file_v120_xp "toolset-vs2013_xp.props")
+ set(prop_file_v140 "toolset-vs2014.props")
+ set(prop_file_v140_xp "toolset-vs2014_xp.props")
if (platform STREQUAL "Win32")
set(mflag "m32")
@@ -29,6 +31,11 @@ if (WIN32)
configure_file(${prop_file_in} ${platform}/${prop_file_v120})
set(VS_VERSION "v120_xp")
configure_file(${prop_file_in} ${platform}/${prop_file_v120_xp})
+ set(VS_VERSION "v140")
+ set(MSC_VERSION "1900")
+ configure_file(${prop_file_in} ${platform}/${prop_file_v140})
+ set(VS_VERSION "v140_xp")
+ configure_file(${prop_file_in} ${platform}/${prop_file_v140_xp})
set(VS_VERSION)
set(MSC_VERSION)
set(mflag)
@@ -38,12 +45,16 @@ if (WIN32)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v110_xp}" DESTINATION tools/msbuild/${platform})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v120}" DESTINATION tools/msbuild/${platform})
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v120_xp}" DESTINATION tools/msbuild/${platform})
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v140}" DESTINATION tools/msbuild/${platform})
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${platform}/${prop_file_v140_xp}" DESTINATION tools/msbuild/${platform})
install(FILES "Microsoft.Cpp.Win32.LLVM-vs2010.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2010.targets")
install(FILES "Microsoft.Cpp.Win32.LLVM-vs2012.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2012.targets")
install(FILES "Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets" DESTINATION "tools/msbuild/${platform}" RENAME "Microsoft.Cpp.${platform}.LLVM-vs2012_xp.targets")
install(FILES "toolset-vs2013.targets" DESTINATION "tools/msbuild/${platform}")
install(FILES "toolset-vs2013_xp.targets" DESTINATION "tools/msbuild/${platform}")
+ install(FILES "toolset-vs2014.targets" DESTINATION "tools/msbuild/${platform}")
+ install(FILES "toolset-vs2014_xp.targets" DESTINATION "tools/msbuild/${platform}")
endforeach()
set(LIB_PATH_VERSION)
diff --git a/tools/msbuild/install.bat b/tools/msbuild/install.bat
index 9880fb27e9b2..6e321e3f5801 100644
--- a/tools/msbuild/install.bat
+++ b/tools/msbuild/install.bat
@@ -6,13 +6,15 @@ set SUCCESS=0
REM Change to the directory of this batch file.
cd /d %~dp0
+REM Loop over the two platforms in awkward batch file fashion.
set PLATFORM=None
-:START
-IF %PLATFORM% == x64 GOTO LOOPEND
+:PLATFORMLOOPHEAD
+IF %PLATFORM% == x64 GOTO PLATFORMLOOPEND
IF %PLATFORM% == Win32 SET PLATFORM=x64
IF %PLATFORM% == None SET PLATFORM=Win32
REM Search for the MSBuild toolsets directory.
+
SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V100
SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\%PLATFORM%\PlatformToolsets"
@@ -30,13 +32,24 @@ IF EXIST %D% GOTO FOUND_V120
SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\%PLATFORM%\PlatformToolsets"
IF EXIST %D% GOTO FOUND_V120
-:LOOPEND
+:TRY_V140
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V140\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V140
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V140\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V140
+
+:TRY_V150
+
+GOTO PLATFORMLOOPHEAD
+
+:PLATFORMLOOPEND
IF %SUCCESS% == 1 goto DONE
echo Failed to find MSBuild toolsets directory.
goto FAILED
:FOUND_V100
+REM Routine for installing v100 toolchain.
IF NOT EXIST %D%\LLVM-vs2010 mkdir %D%\LLVM-vs2010
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2010.props %D%\LLVM-vs2010
@@ -47,6 +60,7 @@ set SUCCESS=1
GOTO TRY_V110
:FOUND_V110
+REM Routine for installing v110 toolchain.
IF NOT EXIST %D%\LLVM-vs2012 mkdir %D%\LLVM-vs2012
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
copy %PLATFORM%\Microsoft.Cpp.%PLATFORM%.LLVM-vs2012.props %D%\LLVM-vs2012
@@ -63,6 +77,7 @@ set SUCCESS=1
GOTO TRY_V120
:FOUND_V120
+REM Routine for installing v120 toolchain.
IF NOT EXIST %D%\LLVM-vs2013 mkdir %D%\LLVM-vs2013
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
copy %PLATFORM%\toolset-vs2013.props %D%\LLVM-vs2013\toolset.props
@@ -76,7 +91,24 @@ IF NOT %ERRORLEVEL% == 0 GOTO FAILED
copy %PLATFORM%\toolset-vs2013_xp.targets %D%\LLVM-vs2013_xp\toolset.targets
IF NOT %ERRORLEVEL% == 0 GOTO FAILED
set SUCCESS=1
-GOTO START
+GOTO TRY_V140
+
+:FOUND_V140
+REM Routine for installing v140 toolchain.
+IF NOT EXIST %D%\LLVM-vs2014 mkdir %D%\LLVM-vs2014
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy %PLATFORM%\toolset-vs2014.props %D%\LLVM-vs2014\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy %PLATFORM%\toolset-vs2014.targets %D%\LLVM-vs2014\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+IF NOT EXIST %D%\LLVM-vs2014_xp mkdir %D%\LLVM-vs2014_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy %PLATFORM%\toolset-vs2014_xp.props %D%\LLVM-vs2014_xp\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy %PLATFORM%\toolset-vs2014_xp.targets %D%\LLVM-vs2014_xp\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO TRY_V150
:DONE
diff --git a/tools/msbuild/toolset-vs2014.targets b/tools/msbuild/toolset-vs2014.targets
new file mode 100644
index 000000000000..05b59a2d84f0
--- /dev/null
+++ b/tools/msbuild/toolset-vs2014.targets
@@ -0,0 +1,3 @@
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+</Project>
diff --git a/tools/msbuild/toolset-vs2014_xp.targets b/tools/msbuild/toolset-vs2014_xp.targets
new file mode 100644
index 000000000000..eec4f18daa4f
--- /dev/null
+++ b/tools/msbuild/toolset-vs2014_xp.targets
@@ -0,0 +1,21 @@
+<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <!-- Force TargetFrameworkVersion to v4.0 to support XP-->
+ <PropertyGroup>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <BeforeClCompileTargets>NoSupportCodeAnalysisXP;$(BeforeClCompileTargets)</BeforeClCompileTargets>
+ </PropertyGroup>
+
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+
+ <Target Name="NoSupportCodeAnalysisXP" Condition="'$(ErrorNoSupportCodeAnalysisXP)' != 'false'">
+ <VCMessage Condition="'$(DesignTimeBuild)' != 'true' and '@(ClCompile->AnyHaveMetadataValue('EnablePREfast', 'true'))'=='true'" Code="MSB8026" Type="Error"/>
+ </Target>
+
+ <PropertyGroup>
+ <PrepareForBuildDependsOn>CheckWindowsSDK71A;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn>
+ </PropertyGroup>
+
+ <Target Name="CheckWindowsSDK71A">
+ <VCMessage Code="MSB8003" Type="Warning" Arguments="WindowsSdkDir_71A" Condition="'$(WindowsSdkDir_71A)'=='' and '$(UseEnv)' != 'true'" />
+ </Target>
+</Project>
diff --git a/tools/msbuild/uninstall.bat b/tools/msbuild/uninstall.bat
index b0bc943daf1f..c1afae2c3c96 100644
--- a/tools/msbuild/uninstall.bat
+++ b/tools/msbuild/uninstall.bat
@@ -6,8 +6,8 @@ REM CD to the directory of this batch file.
cd /d %~dp0
set PLATFORM=None
-:START
-IF %PLATFORM% == x64 GOTO END
+:LOOPHEAD
+IF %PLATFORM% == x64 GOTO LOOPEND
IF %PLATFORM% == Win32 SET PLATFORM=x64
IF %PLATFORM% == None SET PLATFORM=Win32
@@ -51,8 +51,23 @@ IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V140\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2014 del %D%\LLVM-vs2014\toolset.props
+IF EXIST %D%\LLVM-vs2014 del %D%\LLVM-vs2014\toolset.targets
+IF EXIST %D%\LLVM-vs2014 rmdir %D%\LLVM-vs2014
+IF EXIST %D%\LLVM-vs2014_xp del %D%\LLVM-vs2014_xp\toolset.props
+IF EXIST %D%\LLVM-vs2014_xp del %D%\LLVM-vs2014_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2014_xp rmdir %D%\LLVM-vs2014_xp
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V140\Platforms\%PLATFORM%\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2014 del %D%\LLVM-vs2014\toolset.props
+IF EXIST %D%\LLVM-vs2014 del %D%\LLVM-vs2014\toolset.targets
+IF EXIST %D%\LLVM-vs2014 rmdir %D%\LLVM-vs2014
+IF EXIST %D%\LLVM-vs2014_xp del %D%\LLVM-vs2014_xp\toolset.props
+IF EXIST %D%\LLVM-vs2014_xp del %D%\LLVM-vs2014_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2014_xp rmdir %D%\LLVM-vs2014_xp
-GOTO START
-:END
+GOTO LOOPHEAD
+
+:LOOPEND
echo Done!
diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt
index f167ed5f6e87..3cdac5c74875 100644
--- a/tools/obj2yaml/CMakeLists.txt
+++ b/tools/obj2yaml/CMakeLists.txt
@@ -3,6 +3,6 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_llvm_utility(obj2yaml
+add_llvm_tool(obj2yaml
obj2yaml.cpp coff2yaml.cpp elf2yaml.cpp Error.cpp
)
diff --git a/tools/obj2yaml/Error.cpp b/tools/obj2yaml/Error.cpp
index 00741287a649..abef8af58cbf 100644
--- a/tools/obj2yaml/Error.cpp
+++ b/tools/obj2yaml/Error.cpp
@@ -20,7 +20,9 @@ public:
};
} // namespace
-const char *_obj2yaml_error_category::name() const { return "obj2yaml"; }
+const char *_obj2yaml_error_category::name() const LLVM_NOEXCEPT {
+ return "obj2yaml";
+}
std::string _obj2yaml_error_category::message(int ev) const {
switch (static_cast<obj2yaml_error>(ev)) {
diff --git a/tools/obj2yaml/Error.h b/tools/obj2yaml/Error.h
index 4657f0db5282..982f59e236cc 100644
--- a/tools/obj2yaml/Error.h
+++ b/tools/obj2yaml/Error.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_ERROR_H
-#define LLVM_TOOLS_ERROR_H
+#ifndef LLVM_TOOLS_OBJ2YAML_ERROR_H
+#define LLVM_TOOLS_OBJ2YAML_ERROR_H
#include <system_error>
diff --git a/tools/obj2yaml/Makefile b/tools/obj2yaml/Makefile
index 95f393ddd6f4..6cbef6998dc6 100644
--- a/tools/obj2yaml/Makefile
+++ b/tools/obj2yaml/Makefile
@@ -14,7 +14,4 @@ LINK_COMPONENTS := object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-# Don't install this utility
-NO_INSTALL = 1
-
include $(LEVEL)/Makefile.common
diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp
index fed4533a982c..5baa644557cd 100644
--- a/tools/obj2yaml/coff2yaml.cpp
+++ b/tools/obj2yaml/coff2yaml.cpp
@@ -20,7 +20,9 @@ namespace {
class COFFDumper {
const object::COFFObjectFile &Obj;
COFFYAML::Object YAMLObj;
- void dumpHeader(const object::coff_file_header *Header);
+ template <typename T>
+ void dumpOptionalHeader(T OptionalHeader);
+ void dumpHeader();
void dumpSections(unsigned numSections);
void dumpSymbols(unsigned numSymbols);
@@ -31,40 +33,90 @@ public:
}
-static void check(std::error_code ec) {
- if (ec)
- report_fatal_error(ec.message());
+COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {
+ const object::pe32_header *PE32Header = nullptr;
+ Obj.getPE32Header(PE32Header);
+ if (PE32Header) {
+ dumpOptionalHeader(PE32Header);
+ } else {
+ const object::pe32plus_header *PE32PlusHeader = nullptr;
+ Obj.getPE32PlusHeader(PE32PlusHeader);
+ if (PE32PlusHeader) {
+ dumpOptionalHeader(PE32PlusHeader);
+ }
+ }
+ dumpHeader();
+ dumpSections(Obj.getNumberOfSections());
+ dumpSymbols(Obj.getNumberOfSymbols());
}
-COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) {
- const object::coff_file_header *Header;
- check(Obj.getCOFFHeader(Header));
- dumpHeader(Header);
- dumpSections(Header->NumberOfSections);
- dumpSymbols(Header->NumberOfSymbols);
+template <typename T> void COFFDumper::dumpOptionalHeader(T OptionalHeader) {
+ YAMLObj.OptionalHeader = COFFYAML::PEHeader();
+ YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =
+ OptionalHeader->AddressOfEntryPoint;
+ YAMLObj.OptionalHeader->Header.AddressOfEntryPoint =
+ OptionalHeader->AddressOfEntryPoint;
+ YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase;
+ YAMLObj.OptionalHeader->Header.SectionAlignment =
+ OptionalHeader->SectionAlignment;
+ YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment;
+ YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion =
+ OptionalHeader->MajorOperatingSystemVersion;
+ YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion =
+ OptionalHeader->MinorOperatingSystemVersion;
+ YAMLObj.OptionalHeader->Header.MajorImageVersion =
+ OptionalHeader->MajorImageVersion;
+ YAMLObj.OptionalHeader->Header.MinorImageVersion =
+ OptionalHeader->MinorImageVersion;
+ YAMLObj.OptionalHeader->Header.MajorSubsystemVersion =
+ OptionalHeader->MajorSubsystemVersion;
+ YAMLObj.OptionalHeader->Header.MinorSubsystemVersion =
+ OptionalHeader->MinorSubsystemVersion;
+ YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem;
+ YAMLObj.OptionalHeader->Header.DLLCharacteristics =
+ OptionalHeader->DLLCharacteristics;
+ YAMLObj.OptionalHeader->Header.SizeOfStackReserve =
+ OptionalHeader->SizeOfStackReserve;
+ YAMLObj.OptionalHeader->Header.SizeOfStackCommit =
+ OptionalHeader->SizeOfStackCommit;
+ YAMLObj.OptionalHeader->Header.SizeOfHeapReserve =
+ OptionalHeader->SizeOfHeapReserve;
+ YAMLObj.OptionalHeader->Header.SizeOfHeapCommit =
+ OptionalHeader->SizeOfHeapCommit;
+ unsigned I = 0;
+ for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) {
+ const object::data_directory *DD;
+ if (Obj.getDataDirectory(I++, DD))
+ continue;
+ DestDD = COFF::DataDirectory();
+ DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress;
+ DestDD->Size = DD->Size;
+ }
}
-void COFFDumper::dumpHeader(const object::coff_file_header *Header) {
- YAMLObj.Header.Machine = Header->Machine;
- YAMLObj.Header.Characteristics = Header->Characteristics;
+void COFFDumper::dumpHeader() {
+ YAMLObj.Header.Machine = Obj.getMachine();
+ YAMLObj.Header.Characteristics = Obj.getCharacteristics();
}
void COFFDumper::dumpSections(unsigned NumSections) {
- std::vector<COFFYAML::Section> &Sections = YAMLObj.Sections;
- for (const auto &Section : Obj.sections()) {
- const object::coff_section *Sect = Obj.getCOFFSection(Section);
- COFFYAML::Section Sec;
- Sec.Name = Sect->Name; // FIXME: check the null termination!
- uint32_t Characteristics = Sect->Characteristics;
- Sec.Header.Characteristics = Characteristics;
- Sec.Alignment = 1 << (((Characteristics >> 20) & 0xf) - 1);
+ std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections;
+ for (const auto &ObjSection : Obj.sections()) {
+ const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection);
+ COFFYAML::Section NewYAMLSection;
+ ObjSection.getName(NewYAMLSection.Name);
+ NewYAMLSection.Header.Characteristics = COFFSection->Characteristics;
+ NewYAMLSection.Header.VirtualAddress = ObjSection.getAddress();
+ NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize;
+ NewYAMLSection.Alignment = ObjSection.getAlignment();
ArrayRef<uint8_t> sectionData;
- Obj.getSectionContents(Sect, sectionData);
- Sec.SectionData = yaml::BinaryRef(sectionData);
+ if (!ObjSection.isBSS())
+ Obj.getSectionContents(COFFSection, sectionData);
+ NewYAMLSection.SectionData = yaml::BinaryRef(sectionData);
std::vector<COFFYAML::Relocation> Relocations;
- for (const auto &Reloc : Section.relocations()) {
+ for (const auto &Reloc : ObjSection.relocations()) {
const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc);
COFFYAML::Relocation Rel;
object::symbol_iterator Sym = Reloc.getSymbol();
@@ -73,8 +125,8 @@ void COFFDumper::dumpSections(unsigned NumSections) {
Rel.Type = reloc->Type;
Relocations.push_back(Rel);
}
- Sec.Relocations = Relocations;
- Sections.push_back(Sec);
+ NewYAMLSection.Relocations = Relocations;
+ YAMLSections.push_back(NewYAMLSection);
}
}
@@ -111,13 +163,15 @@ static void dumpWeakExternal(COFFYAML::Symbol *Sym,
static void
dumpSectionDefinition(COFFYAML::Symbol *Sym,
- const object::coff_aux_section_definition *ObjSD) {
+ const object::coff_aux_section_definition *ObjSD,
+ bool IsBigObj) {
COFF::AuxiliarySectionDefinition YAMLASD;
+ int32_t AuxNumber = ObjSD->getNumber(IsBigObj);
YAMLASD.Length = ObjSD->Length;
YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations;
YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers;
YAMLASD.CheckSum = ObjSD->CheckSum;
- YAMLASD.Number = ObjSD->Number;
+ YAMLASD.Number = AuxNumber;
YAMLASD.Selection = ObjSD->Selection;
Sym->SectionDefinition = YAMLASD;
@@ -136,63 +190,64 @@ dumpCLRTokenDefinition(COFFYAML::Symbol *Sym,
void COFFDumper::dumpSymbols(unsigned NumSymbols) {
std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
for (const auto &S : Obj.symbols()) {
- const object::coff_symbol *Symbol = Obj.getCOFFSymbol(S);
+ object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S);
COFFYAML::Symbol Sym;
Obj.getSymbolName(Symbol, Sym.Name);
- Sym.SimpleType = COFF::SymbolBaseType(Symbol->getBaseType());
- Sym.ComplexType = COFF::SymbolComplexType(Symbol->getComplexType());
- Sym.Header.StorageClass = Symbol->StorageClass;
- Sym.Header.Value = Symbol->Value;
- Sym.Header.SectionNumber = Symbol->SectionNumber;
- Sym.Header.NumberOfAuxSymbols = Symbol->NumberOfAuxSymbols;
-
- if (Symbol->NumberOfAuxSymbols > 0) {
+ Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType());
+ Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType());
+ Sym.Header.StorageClass = Symbol.getStorageClass();
+ Sym.Header.Value = Symbol.getValue();
+ Sym.Header.SectionNumber = Symbol.getSectionNumber();
+ Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols();
+
+ if (Symbol.getNumberOfAuxSymbols() > 0) {
ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol);
- if (Symbol->isFunctionDefinition()) {
+ if (Symbol.isFunctionDefinition()) {
// This symbol represents a function definition.
- assert(Symbol->NumberOfAuxSymbols == 1 &&
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
"Expected a single aux symbol to describe this function!");
const object::coff_aux_function_definition *ObjFD =
reinterpret_cast<const object::coff_aux_function_definition *>(
AuxData.data());
dumpFunctionDefinition(&Sym, ObjFD);
- } else if (Symbol->isFunctionLineInfo()) {
+ } else if (Symbol.isFunctionLineInfo()) {
// This symbol describes function line number information.
- assert(Symbol->NumberOfAuxSymbols == 1 &&
- "Exepected a single aux symbol to describe this section!");
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this function!");
const object::coff_aux_bf_and_ef_symbol *ObjBES =
reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>(
AuxData.data());
dumpbfAndEfLineInfo(&Sym, ObjBES);
- } else if (Symbol->isWeakExternal()) {
+ } else if (Symbol.isAnyUndefined()) {
// This symbol represents a weak external definition.
- assert(Symbol->NumberOfAuxSymbols == 1 &&
- "Exepected a single aux symbol to describe this section!");
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this weak symbol!");
const object::coff_aux_weak_external *ObjWE =
reinterpret_cast<const object::coff_aux_weak_external *>(
AuxData.data());
dumpWeakExternal(&Sym, ObjWE);
- } else if (Symbol->isFileRecord()) {
+ } else if (Symbol.isFileRecord()) {
// This symbol represents a file record.
Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()),
- Symbol->NumberOfAuxSymbols * COFF::SymbolSize)
+ Symbol.getNumberOfAuxSymbols() *
+ Obj.getSymbolTableEntrySize())
.rtrim(StringRef("\0", /*length=*/1));
- } else if (Symbol->isSectionDefinition()) {
+ } else if (Symbol.isSectionDefinition()) {
// This symbol represents a section definition.
- assert(Symbol->NumberOfAuxSymbols == 1 &&
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
"Expected a single aux symbol to describe this section!");
const object::coff_aux_section_definition *ObjSD =
reinterpret_cast<const object::coff_aux_section_definition *>(
AuxData.data());
- dumpSectionDefinition(&Sym, ObjSD);
- } else if (Symbol->isCLRToken()) {
+ dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj());
+ } else if (Symbol.isCLRToken()) {
// This symbol represents a CLR token definition.
- assert(Symbol->NumberOfAuxSymbols == 1 &&
- "Expected a single aux symbol to describe this CLR Token");
+ assert(Symbol.getNumberOfAuxSymbols() == 1 &&
+ "Expected a single aux symbol to describe this CLR Token!");
const object::coff_aux_clr_token *ObjCLRToken =
reinterpret_cast<const object::coff_aux_clr_token *>(
diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp
index 8b53ee770a62..d770ce1151ea 100644
--- a/tools/obj2yaml/elf2yaml.cpp
+++ b/tools/obj2yaml/elf2yaml.cpp
@@ -133,7 +133,7 @@ std::error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym,
S.Type = Sym->getType();
S.Value = Sym->st_value;
S.Size = Sym->st_size;
- S.Visibility = Sym->st_other & 0x3;
+ S.Other = Sym->st_other;
ErrorOr<StringRef> NameOrErr = Obj.getSymbolName(Sym);
if (std::error_code EC = NameOrErr.getError())
diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp
index 944314a923f7..b64096d75fa4 100644
--- a/tools/obj2yaml/obj2yaml.cpp
+++ b/tools/obj2yaml/obj2yaml.cpp
@@ -32,13 +32,13 @@ static std::error_code dumpInput(StringRef File) {
if (File != "-" && !sys::fs::exists(File))
return obj2yaml_error::file_not_found;
- ErrorOr<Binary *> BinaryOrErr = createBinary(File);
+ ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (std::error_code EC = BinaryOrErr.getError())
return EC;
- std::unique_ptr<Binary> Binary(BinaryOrErr.get());
+ Binary &Binary = *BinaryOrErr.get().getBinary();
// TODO: If this is an archive, then burst it and dump each entry
- if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get()))
+ if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
return dumpObject(*Obj);
return obj2yaml_error::unrecognized_file_format;
diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h
index 6d81110f7a38..643ab7bc434d 100644
--- a/tools/obj2yaml/obj2yaml.h
+++ b/tools/obj2yaml/obj2yaml.h
@@ -10,8 +10,8 @@
// source file, implement it.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_OBJ2YAML_H
-#define LLVM_TOOLS_OBJ2YAML_H
+#ifndef LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H
+#define LLVM_TOOLS_OBJ2YAML_OBJ2YAML_H
#include "llvm/Object/COFF.h"
#include "llvm/Support/raw_ostream.h"
diff --git a/tools/opt/BreakpointPrinter.cpp b/tools/opt/BreakpointPrinter.cpp
index 44f4a11773ef..3cbc0ae50f14 100644
--- a/tools/opt/BreakpointPrinter.cpp
+++ b/tools/opt/BreakpointPrinter.cpp
@@ -62,7 +62,7 @@ struct BreakpointPrinter : public ModulePass {
continue;
getContextName(SP.getContext().resolve(TypeIdentifierMap), Name);
Name = Name + SP.getDisplayName().str();
- if (!Name.empty() && Processed.insert(Name)) {
+ if (!Name.empty() && Processed.insert(Name).second) {
Out << Name << "\n";
}
}
diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp
index 8076ff44872f..f215c77459a8 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"
@@ -31,24 +31,21 @@
using namespace llvm;
using namespace opt_tool;
+static cl::opt<bool>
+ DebugPM("debug-pass-manager", cl::Hidden,
+ cl::desc("Print pass management debugging information"));
+
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;
-
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- MAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-
-#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.
+ registerModuleAnalyses(MAM);
+ registerCGSCCAnalyses(CGAM);
+ registerFunctionAnalyses(FAM);
// Cross register the analysis managers through their proxies.
MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM));
@@ -58,11 +55,11 @@ 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 (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, DebugPM)) {
errs() << Arg0 << ": unable to parse pass pipeline description.\n";
return false;
}
@@ -86,7 +83,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 3661d3e6778a..f977baca7f83 100644
--- a/tools/opt/NewPMDriver.h
+++ b/tools/opt/NewPMDriver.h
@@ -18,8 +18,8 @@
///
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_OPT_NEW_PM_DRIVER_H
-#define LLVM_TOOLS_OPT_NEW_PM_DRIVER_H
+#ifndef LLVM_TOOLS_OPT_NEWPMDRIVER_H
+#define LLVM_TOOLS_OPT_NEWPMDRIVER_H
#include "llvm/ADT/StringRef.h"
diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def
index e1e49004c741..c98de60b5706 100644
--- a/tools/opt/PassRegistry.def
+++ b/tools/opt/PassRegistry.def
@@ -20,32 +20,46 @@
#define MODULE_ANALYSIS(NAME, CREATE_PASS)
#endif
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
+MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
#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("domtree", DominatorTreeAnalysis())
+FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis())
#undef FUNCTION_ANALYSIS
#ifndef FUNCTION_PASS
#define FUNCTION_PASS(NAME, CREATE_PASS)
#endif
+FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
+FUNCTION_PASS("no-op-function", NoOpFunctionPass())
FUNCTION_PASS("print", PrintFunctionPass(dbgs()))
+FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs()))
+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 a171f42691a8..518112a1c88c 100644
--- a/tools/opt/Passes.cpp
+++ b/tools/opt/Passes.cpp
@@ -17,6 +17,7 @@
#include "Passes.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Analysis/LazyCallGraph.h"
+#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
@@ -28,96 +29,167 @@ 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 llvm::registerModuleAnalyses(ModuleAnalysisManager &MAM) {
+#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
+ MAM.registerPass(CREATE_PASS);
+#include "PassRegistry.def"
+}
+void llvm::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) {
+#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
+ CGAM.registerPass(CREATE_PASS);
+#include "PassRegistry.def"
+}
+
+void llvm::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;
- }
-
#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;
- }
-
#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;
- }
-
#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;
@@ -125,15 +197,16 @@ static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) {
static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
StringRef &PipelineText,
- bool VerifyEachPass) {
+ 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] == ')');
@@ -161,16 +234,17 @@ static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
}
static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
- StringRef &PipelineText,
- bool VerifyEachPass) {
+ 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 +253,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] == ')');
@@ -211,15 +286,16 @@ static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
static bool parseModulePassPipeline(ModulePassManager &MPM,
StringRef &PipelineText,
- bool VerifyEachPass) {
+ 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 +304,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 +319,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] == ')');
@@ -277,47 +355,38 @@ static bool parseModulePassPipeline(ModulePassManager &MPM,
// 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 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 3bd675269245..623da9ff4b4a 100644
--- a/tools/opt/Passes.h
+++ b/tools/opt/Passes.h
@@ -17,9 +17,31 @@
#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;
+
+/// \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.
///
@@ -50,8 +72,7 @@ class ModulePassManager;
/// 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 VerifyEachPass = true, bool DebugLogging = false);
}
#endif
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 6ba6340040b3..986758908061 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -109,14 +109,6 @@ DisableOptimizations("disable-opt",
cl::desc("Do not run any optimization passes"));
static cl::opt<bool>
-DisableInternalize("disable-internalize",
- cl::desc("Do not mark all symbols as internal"));
-
-static cl::opt<bool>
-StandardCompileOpts("std-compile-opts",
- cl::desc("Include the standard compile time optimizations"));
-
-static cl::opt<bool>
StandardLinkOpts("std-link-opts",
cl::desc("Include the standard link time optimizations"));
@@ -145,7 +137,7 @@ TargetTriple("mtriple", cl::desc("Override target triple for module"));
static cl::opt<bool>
UnitAtATime("funit-at-a-time",
- cl::desc("Enable IPO. This is same as llvm-gcc's -funit-at-a-time"),
+ cl::desc("Enable IPO. This corresponds to gcc's -funit-at-a-time"),
cl::init(true));
static cl::opt<bool>
@@ -198,9 +190,8 @@ static inline void addPass(PassManagerBase &PM, Pass *P) {
}
}
-/// AddOptimizationPasses - This routine adds optimization passes
-/// based on selected optimization level, OptLevel. This routine
-/// duplicates llvm-gcc behaviour.
+/// This routine adds optimization passes based on selected optimization level,
+/// OptLevel.
///
/// OptLevel - Optimization Level
static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
@@ -238,41 +229,16 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
Builder.populateModulePassManager(MPM);
}
-static void AddStandardCompilePasses(PassManagerBase &PM) {
- PM.add(createVerifierPass()); // Verify that input is correct
-
- // If the -strip-debug command line option was specified, do it.
- if (StripDebug)
- addPass(PM, createStripSymbolsPass(true));
-
- // Verify debug info only after it's (possibly) stripped.
- PM.add(createDebugInfoVerifierPass());
-
- if (DisableOptimizations) return;
-
- // -std-compile-opts adds the same module passes as -O3.
+static void AddStandardLinkPasses(PassManagerBase &PM) {
PassManagerBuilder Builder;
+ Builder.VerifyInput = true;
+ Builder.StripDebug = StripDebug;
+ if (DisableOptimizations)
+ Builder.OptLevel = 0;
+
if (!DisableInline)
Builder.Inliner = createFunctionInliningPass();
- Builder.OptLevel = 3;
- Builder.populateModulePassManager(PM);
-}
-
-static void AddStandardLinkPasses(PassManagerBase &PM) {
- PM.add(createVerifierPass()); // Verify that input is correct
-
- // If the -strip-debug command line option was specified, do it.
- if (StripDebug)
- addPass(PM, createStripSymbolsPass(true));
-
- // Verify debug info only after it's (possibly) stripped.
- PM.add(createDebugInfoVerifierPass());
-
- if (DisableOptimizations) return;
-
- PassManagerBuilder Builder;
- Builder.populateLTOPassManager(PM, /*Internalize=*/ !DisableInternalize,
- /*RunInliner=*/ !DisableInline);
+ Builder.populateLTOPassManager(PM);
}
//===----------------------------------------------------------------------===//
@@ -341,7 +307,6 @@ int main(int argc, char **argv) {
// Initialize passes
PassRegistry &Registry = *PassRegistry::getPassRegistry();
initializeCore(Registry);
- initializeDebugIRPass(Registry);
initializeScalarOpts(Registry);
initializeObjCARCOpts(Registry);
initializeVectorization(Registry);
@@ -355,7 +320,8 @@ int main(int argc, char **argv) {
// For codegen passes, only passes that do IR to IR transformation are
// supported.
initializeCodeGenPreparePass(Registry);
- initializeAtomicExpandLoadLinkedPass(Registry);
+ initializeAtomicExpandPass(Registry);
+ initializeRewriteSymbolsPass(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
@@ -372,10 +338,9 @@ int main(int argc, char **argv) {
SMDiagnostic Err;
// Load the input module...
- std::unique_ptr<Module> M;
- M.reset(ParseIRFile(InputFilename, Err, Context));
+ std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
- if (!M.get()) {
+ if (!M) {
Err.print(argv[0], errs());
return 1;
}
@@ -395,11 +360,10 @@ int main(int argc, char **argv) {
if (OutputFilename.empty())
OutputFilename = "-";
- std::string ErrorInfo;
- Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ std::error_code EC;
+ Out.reset(new tool_output_file(OutputFilename, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
}
@@ -425,7 +389,7 @@ 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,
+ return runPassPipeline(argv[0], Context, *M, Out.get(), PassPipeline,
OK, VK)
? 0
: 1;
@@ -445,14 +409,14 @@ int main(int argc, char **argv) {
Passes.add(TLI);
// 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(M.get()));
+ Passes.add(new DataLayoutPass());
Triple ModuleTriple(M->getTargetTriple());
TargetMachine *Machine = nullptr;
@@ -461,15 +425,15 @@ int main(int argc, char **argv) {
std::unique_ptr<TargetMachine> TM(Machine);
// Add internal analysis passes from the target machine.
- if (TM.get())
+ if (TM)
TM->addAnalysisPasses(Passes);
std::unique_ptr<FunctionPassManager> FPasses;
if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) {
FPasses.reset(new FunctionPassManager(M.get()));
if (DL)
- FPasses->add(new DataLayoutPass(M.get()));
- if (TM.get())
+ FPasses->add(new DataLayoutPass());
+ if (TM)
TM->addAnalysisPasses(*FPasses);
}
@@ -480,11 +444,11 @@ int main(int argc, char **argv) {
if (OutputFilename.empty())
OutputFilename = "-";
- std::string ErrorInfo;
- Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo,
- sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ std::error_code EC;
+ Out = llvm::make_unique<tool_output_file>(OutputFilename, EC,
+ sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
}
@@ -492,21 +456,12 @@ int main(int argc, char **argv) {
NoOutput = true;
}
- // If the -strip-debug command line option was specified, add it. If
- // -std-compile-opts was also specified, it will handle StripDebug.
- if (StripDebug && !StandardCompileOpts)
+ // If the -strip-debug command line option was specified, add it.
+ if (StripDebug)
addPass(Passes, createStripSymbolsPass(true));
// Create a new optimization pass for each one specified on the command line
for (unsigned i = 0; i < PassList.size(); ++i) {
- // Check to see if -std-compile-opts was specified before this option. If
- // so, handle it.
- if (StandardCompileOpts &&
- StandardCompileOpts.getPosition() < PassList.getPosition(i)) {
- AddStandardCompilePasses(Passes);
- StandardCompileOpts = false;
- }
-
if (StandardLinkOpts &&
StandardLinkOpts.getPosition() < PassList.getPosition(i)) {
AddStandardLinkPasses(Passes);
@@ -579,12 +534,6 @@ int main(int argc, char **argv) {
Passes.add(createPrintModulePass(errs()));
}
- // If -std-compile-opts was specified at the end of the pass list, add them.
- if (StandardCompileOpts) {
- AddStandardCompilePasses(Passes);
- StandardCompileOpts = false;
- }
-
if (StandardLinkOpts) {
AddStandardLinkPasses(Passes);
StandardLinkOpts = false;
@@ -607,8 +556,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();
}
@@ -630,7 +579,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/CMakeLists.txt b/tools/verify-uselistorder/CMakeLists.txt
new file mode 100644
index 000000000000..260a95adb6a6
--- /dev/null
+++ b/tools/verify-uselistorder/CMakeLists.txt
@@ -0,0 +1,12 @@
+set(LLVM_LINK_COMPONENTS
+ AsmParser
+ BitReader
+ BitWriter
+ Core
+ IRReader
+ Support
+ )
+
+add_llvm_tool(verify-uselistorder
+ verify-uselistorder.cpp
+ )
diff --git a/tools/verify-uselistorder/LLVMBuild.txt b/tools/verify-uselistorder/LLVMBuild.txt
new file mode 100644
index 000000000000..23957c189c8a
--- /dev/null
+++ b/tools/verify-uselistorder/LLVMBuild.txt
@@ -0,0 +1,22 @@
+;===- ./tools/verify-uselistorder/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 = verify-uselistorder
+parent = Tools
+required_libraries = IRReader BitWriter Support
diff --git a/tools/verify-uselistorder/Makefile b/tools/verify-uselistorder/Makefile
new file mode 100644
index 000000000000..90d2aa89128b
--- /dev/null
+++ b/tools/verify-uselistorder/Makefile
@@ -0,0 +1,17 @@
+##===- tools/verify-uselistorder/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 := verify-uselistorder
+LINK_COMPONENTS := AsmParser BitReader BitWriter Core IRReader Support
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp
new file mode 100644
index 000000000000..a6536083e880
--- /dev/null
+++ b/tools/verify-uselistorder/verify-uselistorder.cpp
@@ -0,0 +1,568 @@
+//===- verify-uselistorder.cpp - The LLVM Modular Optimizer ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Verify that use-list order can be serialized correctly. After reading the
+// provided IR, this tool shuffles the use-lists and then writes and reads to a
+// separate Module whose use-list orders are compared to the original.
+//
+// The shuffles are deterministic, but guarantee that use-lists will change.
+// The algorithm per iteration is as follows:
+//
+// 1. Seed the random number generator. The seed is different for each
+// shuffle. Shuffle 0 uses default+0, shuffle 1 uses default+1, and so on.
+//
+// 2. Visit every Value in a deterministic order.
+//
+// 3. Assign a random number to each Use in the Value's use-list in order.
+//
+// 4. If the numbers are already in order, reassign numbers until they aren't.
+//
+// 5. Sort the use-list using Value::sortUseList(), which is a stable sort.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/AsmParser/Parser.h"
+#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/UseListOrder.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/IRReader/IRReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/SystemUtils.h"
+#include <random>
+#include <vector>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "use-list-order"
+
+static cl::opt<std::string> InputFilename(cl::Positional,
+ cl::desc("<input bitcode file>"),
+ cl::init("-"),
+ cl::value_desc("filename"));
+
+static cl::opt<bool> SaveTemps("save-temps", cl::desc("Save temp files"),
+ cl::init(false));
+
+static cl::opt<unsigned>
+ NumShuffles("num-shuffles",
+ cl::desc("Number of times to shuffle and verify use-lists"),
+ cl::init(1));
+
+namespace {
+
+struct TempFile {
+ std::string Filename;
+ FileRemover Remover;
+ bool init(const std::string &Ext);
+ bool writeBitcode(const Module &M) const;
+ bool writeAssembly(const Module &M) const;
+ std::unique_ptr<Module> readBitcode(LLVMContext &Context) const;
+ std::unique_ptr<Module> readAssembly(LLVMContext &Context) const;
+};
+
+struct ValueMapping {
+ DenseMap<const Value *, unsigned> IDs;
+ std::vector<const Value *> Values;
+
+ /// \brief Construct a value mapping for module.
+ ///
+ /// Creates mapping from every value in \c M to an ID. This mapping includes
+ /// un-referencable values.
+ ///
+ /// Every \a Value that gets serialized in some way should be represented
+ /// here. The order needs to be deterministic, but it's unnecessary to match
+ /// the value-ids in the bitcode writer.
+ ///
+ /// All constants that are referenced by other values are included in the
+ /// mapping, but others -- which wouldn't be serialized -- are not.
+ ValueMapping(const Module &M);
+
+ /// \brief Map a value.
+ ///
+ /// Maps a value. If it's a constant, maps all of its operands first.
+ void map(const Value *V);
+ unsigned lookup(const Value *V) const { return IDs.lookup(V); }
+};
+
+} // end namespace
+
+bool TempFile::init(const std::string &Ext) {
+ SmallVector<char, 64> Vector;
+ DEBUG(dbgs() << " - create-temp-file\n");
+ if (auto EC = sys::fs::createTemporaryFile("use-list-order", Ext, Vector)) {
+ (void)EC;
+ DEBUG(dbgs() << "error: " << EC.message() << "\n");
+ return true;
+ }
+ assert(!Vector.empty());
+
+ Filename.assign(Vector.data(), Vector.data() + Vector.size());
+ Remover.setFile(Filename, !SaveTemps);
+ DEBUG(dbgs() << " - filename = " << Filename << "\n");
+ return false;
+}
+
+bool TempFile::writeBitcode(const Module &M) const {
+ DEBUG(dbgs() << " - write bitcode\n");
+ std::error_code EC;
+ raw_fd_ostream OS(Filename, EC, sys::fs::F_None);
+ if (EC) {
+ DEBUG(dbgs() << "error: " << EC.message() << "\n");
+ return true;
+ }
+
+ WriteBitcodeToFile(&M, OS);
+ return false;
+}
+
+bool TempFile::writeAssembly(const Module &M) const {
+ DEBUG(dbgs() << " - write assembly\n");
+ std::error_code EC;
+ raw_fd_ostream OS(Filename, EC, sys::fs::F_Text);
+ if (EC) {
+ DEBUG(dbgs() << "error: " << EC.message() << "\n");
+ return true;
+ }
+
+ OS << M;
+ return false;
+}
+
+std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
+ DEBUG(dbgs() << " - read bitcode\n");
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
+ MemoryBuffer::getFile(Filename);
+ if (!BufferOr) {
+ DEBUG(dbgs() << "error: " << BufferOr.getError().message() << "\n");
+ return nullptr;
+ }
+
+ MemoryBuffer *Buffer = BufferOr.get().get();
+ ErrorOr<Module *> ModuleOr =
+ parseBitcodeFile(Buffer->getMemBufferRef(), Context);
+ if (!ModuleOr) {
+ DEBUG(dbgs() << "error: " << ModuleOr.getError().message() << "\n");
+ return nullptr;
+ }
+ return std::unique_ptr<Module>(ModuleOr.get());
+}
+
+std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
+ DEBUG(dbgs() << " - read assembly\n");
+ SMDiagnostic Err;
+ std::unique_ptr<Module> M = parseAssemblyFile(Filename, Err, Context);
+ if (!M.get())
+ DEBUG(dbgs() << "error: "; Err.print("verify-use-list-order", dbgs()));
+ return M;
+}
+
+ValueMapping::ValueMapping(const Module &M) {
+ // Every value should be mapped, including things like void instructions and
+ // basic blocks that are kept out of the ValueEnumerator.
+ //
+ // The current mapping order makes it easier to debug the tables. It happens
+ // to be similar to the ID mapping when writing ValueEnumerator, but they
+ // aren't (and needn't be) in sync.
+
+ // Globals.
+ for (const GlobalVariable &G : M.globals())
+ map(&G);
+ for (const GlobalAlias &A : M.aliases())
+ map(&A);
+ for (const Function &F : M)
+ map(&F);
+
+ // Constants used by globals.
+ for (const GlobalVariable &G : M.globals())
+ if (G.hasInitializer())
+ map(G.getInitializer());
+ for (const GlobalAlias &A : M.aliases())
+ map(A.getAliasee());
+ for (const Function &F : M) {
+ if (F.hasPrefixData())
+ map(F.getPrefixData());
+ if (F.hasPrologueData())
+ map(F.getPrologueData());
+ }
+
+ // Function bodies.
+ for (const Function &F : M) {
+ for (const Argument &A : F.args())
+ map(&A);
+ for (const BasicBlock &BB : F)
+ map(&BB);
+ for (const BasicBlock &BB : F)
+ for (const Instruction &I : BB)
+ map(&I);
+
+ // Constants used by instructions.
+ for (const BasicBlock &BB : F)
+ for (const Instruction &I : BB)
+ for (const Value *Op : I.operands())
+ if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
+ isa<InlineAsm>(Op))
+ map(Op);
+ }
+}
+
+void ValueMapping::map(const Value *V) {
+ if (IDs.lookup(V))
+ return;
+
+ if (auto *C = dyn_cast<Constant>(V))
+ if (!isa<GlobalValue>(C))
+ for (const Value *Op : C->operands())
+ map(Op);
+
+ Values.push_back(V);
+ IDs[V] = Values.size();
+}
+
+#ifndef NDEBUG
+static void dumpMapping(const ValueMapping &VM) {
+ dbgs() << "value-mapping (size = " << VM.Values.size() << "):\n";
+ for (unsigned I = 0, E = VM.Values.size(); I != E; ++I) {
+ dbgs() << " - id = " << I << ", value = ";
+ VM.Values[I]->dump();
+ }
+}
+
+static void debugValue(const ValueMapping &M, unsigned I, StringRef Desc) {
+ const Value *V = M.Values[I];
+ dbgs() << " - " << Desc << " value = ";
+ V->dump();
+ for (const Use &U : V->uses()) {
+ dbgs() << " => use: op = " << U.getOperandNo()
+ << ", user-id = " << M.IDs.lookup(U.getUser()) << ", user = ";
+ U.getUser()->dump();
+ }
+}
+
+static void debugUserMismatch(const ValueMapping &L, const ValueMapping &R,
+ unsigned I) {
+ dbgs() << " - fail: user mismatch: ID = " << I << "\n";
+ debugValue(L, I, "LHS");
+ debugValue(R, I, "RHS");
+
+ dbgs() << "\nlhs-";
+ dumpMapping(L);
+ dbgs() << "\nrhs-";
+ dumpMapping(R);
+}
+
+static void debugSizeMismatch(const ValueMapping &L, const ValueMapping &R) {
+ dbgs() << " - fail: map size: " << L.Values.size()
+ << " != " << R.Values.size() << "\n";
+ dbgs() << "\nlhs-";
+ dumpMapping(L);
+ dbgs() << "\nrhs-";
+ dumpMapping(R);
+}
+#endif
+
+static bool matches(const ValueMapping &LM, const ValueMapping &RM) {
+ DEBUG(dbgs() << "compare value maps\n");
+ if (LM.Values.size() != RM.Values.size()) {
+ DEBUG(debugSizeMismatch(LM, RM));
+ return false;
+ }
+
+ // This mapping doesn't include dangling constant users, since those don't
+ // get serialized. However, checking if users are constant and calling
+ // isConstantUsed() on every one is very expensive. Instead, just check if
+ // the user is mapped.
+ auto skipUnmappedUsers =
+ [&](Value::const_use_iterator &U, Value::const_use_iterator E,
+ const ValueMapping &M) {
+ while (U != E && !M.lookup(U->getUser()))
+ ++U;
+ };
+
+ // Iterate through all values, and check that both mappings have the same
+ // users.
+ for (unsigned I = 0, E = LM.Values.size(); I != E; ++I) {
+ const Value *L = LM.Values[I];
+ const Value *R = RM.Values[I];
+ auto LU = L->use_begin(), LE = L->use_end();
+ auto RU = R->use_begin(), RE = R->use_end();
+ skipUnmappedUsers(LU, LE, LM);
+ skipUnmappedUsers(RU, RE, RM);
+
+ while (LU != LE) {
+ if (RU == RE) {
+ DEBUG(debugUserMismatch(LM, RM, I));
+ return false;
+ }
+ if (LM.lookup(LU->getUser()) != RM.lookup(RU->getUser())) {
+ DEBUG(debugUserMismatch(LM, RM, I));
+ return false;
+ }
+ if (LU->getOperandNo() != RU->getOperandNo()) {
+ DEBUG(debugUserMismatch(LM, RM, I));
+ return false;
+ }
+ skipUnmappedUsers(++LU, LE, LM);
+ skipUnmappedUsers(++RU, RE, RM);
+ }
+ if (RU != RE) {
+ DEBUG(debugUserMismatch(LM, RM, I));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void verifyAfterRoundTrip(const Module &M,
+ std::unique_ptr<Module> OtherM) {
+ if (!OtherM)
+ report_fatal_error("parsing failed");
+ if (verifyModule(*OtherM, &errs()))
+ report_fatal_error("verification failed");
+ if (!matches(ValueMapping(M), ValueMapping(*OtherM)))
+ report_fatal_error("use-list order changed");
+}
+static void verifyBitcodeUseListOrder(const Module &M) {
+ errs() << "*** verify-use-list-order: bitcode ***\n";
+ TempFile F;
+ if (F.init("bc"))
+ report_fatal_error("failed to initialize bitcode file");
+
+ if (F.writeBitcode(M))
+ report_fatal_error("failed to write bitcode");
+
+ LLVMContext Context;
+ verifyAfterRoundTrip(M, F.readBitcode(Context));
+}
+
+static void verifyAssemblyUseListOrder(const Module &M) {
+ errs() << "*** verify-use-list-order: assembly ***\n";
+ TempFile F;
+ if (F.init("ll"))
+ report_fatal_error("failed to initialize assembly file");
+
+ if (F.writeAssembly(M))
+ report_fatal_error("failed to write assembly");
+
+ LLVMContext Context;
+ verifyAfterRoundTrip(M, F.readAssembly(Context));
+}
+
+static void verifyUseListOrder(const Module &M) {
+ verifyBitcodeUseListOrder(M);
+ verifyAssemblyUseListOrder(M);
+}
+
+static void shuffleValueUseLists(Value *V, std::minstd_rand0 &Gen,
+ DenseSet<Value *> &Seen) {
+ if (!Seen.insert(V).second)
+ return;
+
+ if (auto *C = dyn_cast<Constant>(V))
+ if (!isa<GlobalValue>(C))
+ for (Value *Op : C->operands())
+ shuffleValueUseLists(Op, Gen, Seen);
+
+ if (V->use_empty() || std::next(V->use_begin()) == V->use_end())
+ // Nothing to shuffle for 0 or 1 users.
+ return;
+
+ // Generate random numbers between 10 and 99, which will line up nicely in
+ // debug output. We're not worried about collisons here.
+ DEBUG(dbgs() << "V = "; V->dump());
+ std::uniform_int_distribution<short> Dist(10, 99);
+ SmallDenseMap<const Use *, short, 16> Order;
+ auto compareUses =
+ [&Order](const Use &L, const Use &R) { return Order[&L] < Order[&R]; };
+ do {
+ for (const Use &U : V->uses()) {
+ auto I = Dist(Gen);
+ Order[&U] = I;
+ DEBUG(dbgs() << " - order: " << I << ", op = " << U.getOperandNo()
+ << ", U = ";
+ U.getUser()->dump());
+ }
+ } while (std::is_sorted(V->use_begin(), V->use_end(), compareUses));
+
+ DEBUG(dbgs() << " => shuffle\n");
+ V->sortUseList(compareUses);
+
+ DEBUG({
+ for (const Use &U : V->uses()) {
+ dbgs() << " - order: " << Order.lookup(&U)
+ << ", op = " << U.getOperandNo() << ", U = ";
+ U.getUser()->dump();
+ }
+ });
+}
+
+static void reverseValueUseLists(Value *V, DenseSet<Value *> &Seen) {
+ if (!Seen.insert(V).second)
+ return;
+
+ if (auto *C = dyn_cast<Constant>(V))
+ if (!isa<GlobalValue>(C))
+ for (Value *Op : C->operands())
+ reverseValueUseLists(Op, Seen);
+
+ if (V->use_empty() || std::next(V->use_begin()) == V->use_end())
+ // Nothing to shuffle for 0 or 1 users.
+ return;
+
+ DEBUG({
+ dbgs() << "V = ";
+ V->dump();
+ for (const Use &U : V->uses()) {
+ dbgs() << " - order: op = " << U.getOperandNo() << ", U = ";
+ U.getUser()->dump();
+ }
+ dbgs() << " => reverse\n";
+ });
+
+ V->reverseUseList();
+
+ DEBUG({
+ for (const Use &U : V->uses()) {
+ dbgs() << " - order: op = " << U.getOperandNo() << ", U = ";
+ U.getUser()->dump();
+ }
+ });
+}
+
+template <class Changer>
+static void changeUseLists(Module &M, Changer changeValueUseList) {
+ // Visit every value that would be serialized to an IR file.
+ //
+ // Globals.
+ for (GlobalVariable &G : M.globals())
+ changeValueUseList(&G);
+ for (GlobalAlias &A : M.aliases())
+ changeValueUseList(&A);
+ for (Function &F : M)
+ changeValueUseList(&F);
+
+ // Constants used by globals.
+ for (GlobalVariable &G : M.globals())
+ if (G.hasInitializer())
+ changeValueUseList(G.getInitializer());
+ for (GlobalAlias &A : M.aliases())
+ changeValueUseList(A.getAliasee());
+ for (Function &F : M) {
+ if (F.hasPrefixData())
+ changeValueUseList(F.getPrefixData());
+ if (F.hasPrologueData())
+ changeValueUseList(F.getPrologueData());
+ }
+
+ // Function bodies.
+ for (Function &F : M) {
+ for (Argument &A : F.args())
+ changeValueUseList(&A);
+ for (BasicBlock &BB : F)
+ changeValueUseList(&BB);
+ for (BasicBlock &BB : F)
+ for (Instruction &I : BB)
+ changeValueUseList(&I);
+
+ // Constants used by instructions.
+ for (BasicBlock &BB : F)
+ for (Instruction &I : BB)
+ for (Value *Op : I.operands())
+ if ((isa<Constant>(Op) && !isa<GlobalValue>(*Op)) ||
+ isa<InlineAsm>(Op))
+ changeValueUseList(Op);
+ }
+
+ if (verifyModule(M, &errs()))
+ report_fatal_error("verification failed");
+}
+
+static void shuffleUseLists(Module &M, unsigned SeedOffset) {
+ errs() << "*** shuffle-use-lists ***\n";
+ std::minstd_rand0 Gen(std::minstd_rand0::default_seed + SeedOffset);
+ DenseSet<Value *> Seen;
+ changeUseLists(M, [&](Value *V) { shuffleValueUseLists(V, Gen, Seen); });
+ DEBUG(dbgs() << "\n");
+}
+
+static void reverseUseLists(Module &M) {
+ errs() << "*** reverse-use-lists ***\n";
+ DenseSet<Value *> Seen;
+ changeUseLists(M, [&](Value *V) { reverseValueUseLists(V, Seen); });
+ DEBUG(dbgs() << "\n");
+}
+
+int main(int argc, char **argv) {
+ sys::PrintStackTraceOnErrorSignal();
+ llvm::PrettyStackTraceProgram X(argc, argv);
+
+ // Enable debug stream buffering.
+ EnableDebugBuffering = true;
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ LLVMContext &Context = getGlobalContext();
+
+ cl::ParseCommandLineOptions(argc, argv,
+ "llvm tool to verify use-list order\n");
+
+ SMDiagnostic Err;
+
+ // Load the input module...
+ std::unique_ptr<Module> M = parseIRFile(InputFilename, Err, Context);
+
+ if (!M.get()) {
+ Err.print(argv[0], errs());
+ return 1;
+ }
+ if (verifyModule(*M, &errs()))
+ report_fatal_error("verification failed");
+
+ errs() << "*** verify-use-list-order ***\n";
+ // Can't verify if order isn't preserved.
+ if (!shouldPreserveBitcodeUseListOrder()) {
+ errs() << "warning: forcing -preserve-bc-use-list-order\n";
+ setPreserveBitcodeUseListOrder(true);
+ }
+ if (!shouldPreserveAssemblyUseListOrder()) {
+ errs() << "warning: forcing -preserve-ll-use-list-order\n";
+ setPreserveAssemblyUseListOrder(true);
+ }
+
+ // Verify the use lists now and after reversing them.
+ verifyUseListOrder(*M);
+ reverseUseLists(*M);
+ verifyUseListOrder(*M);
+
+ for (unsigned I = 0, E = NumShuffles; I != E; ++I) {
+ errs() << "*** shuffle iteration: " << I + 1 << " of " << E << " ***\n";
+
+ // Shuffle with a different (deterministic) seed each time.
+ shuffleUseLists(*M, I);
+
+ // Verify again before and after reversing.
+ verifyUseListOrder(*M);
+ reverseUseLists(*M);
+ verifyUseListOrder(*M);
+ }
+
+ return 0;
+}
diff --git a/tools/yaml2obj/CMakeLists.txt b/tools/yaml2obj/CMakeLists.txt
index 78e92a0680fe..52e9df4d766a 100644
--- a/tools/yaml2obj/CMakeLists.txt
+++ b/tools/yaml2obj/CMakeLists.txt
@@ -4,7 +4,7 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_llvm_utility(yaml2obj
+add_llvm_tool(yaml2obj
yaml2obj.cpp
yaml2coff.cpp
yaml2elf.cpp
diff --git a/tools/yaml2obj/Makefile b/tools/yaml2obj/Makefile
index 88017954087a..912f0e31ae7c 100644
--- a/tools/yaml2obj/Makefile
+++ b/tools/yaml2obj/Makefile
@@ -14,7 +14,4 @@ LINK_COMPONENTS := object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS = 1
-# Don't install this utility
-NO_INSTALL = 1
-
include $(LEVEL)/Makefile.common
diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp
index c772db9a8e80..8322b2ff0a0d 100644
--- a/tools/yaml2obj/yaml2coff.cpp
+++ b/tools/yaml2obj/yaml2coff.cpp
@@ -13,11 +13,12 @@
//===----------------------------------------------------------------------===//
#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/COFF.h"
#include "llvm/Object/COFFYAML.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MemoryBuffer.h"
@@ -30,12 +31,35 @@ using namespace llvm;
/// This parses a yaml stream that represents a COFF object file.
/// See docs/yaml2obj for the yaml scheema.
struct COFFParser {
- COFFParser(COFFYAML::Object &Obj) : Obj(Obj) {
+ COFFParser(COFFYAML::Object &Obj)
+ : Obj(Obj), SectionTableStart(0), SectionTableSize(0) {
// A COFF string table always starts with a 4 byte size field. Offsets into
// it include this size, so allocate it now.
StringTable.append(4, char(0));
}
+ bool useBigObj() const {
+ return static_cast<int32_t>(Obj.Sections.size()) >
+ COFF::MaxNumberOfSections16;
+ }
+
+ bool isPE() const { return Obj.OptionalHeader.hasValue(); }
+ bool is64Bit() const {
+ return Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64;
+ }
+
+ uint32_t getFileAlignment() const {
+ return Obj.OptionalHeader->Header.FileAlignment;
+ }
+
+ unsigned getHeaderSize() const {
+ return useBigObj() ? COFF::Header32Size : COFF::Header16Size;
+ }
+
+ unsigned getSymbolSize() const {
+ return useBigObj() ? COFF::Symbol32Size : COFF::Symbol16Size;
+ }
+
bool parseSections() {
for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(),
e = Obj.Sections.end(); i != e; ++i) {
@@ -111,39 +135,61 @@ struct COFFParser {
StringMap<unsigned> StringTableMap;
std::string StringTable;
+ uint32_t SectionTableStart;
+ uint32_t SectionTableSize;
};
// Take a CP and assign addresses and sizes to everything. Returns false if the
// layout is not valid to do.
-static bool layoutCOFF(COFFParser &CP) {
- uint32_t SectionTableStart = 0;
- uint32_t SectionTableSize = 0;
+static bool layoutOptionalHeader(COFFParser &CP) {
+ if (!CP.isPE())
+ return true;
+ unsigned PEHeaderSize = CP.is64Bit() ? sizeof(object::pe32plus_header)
+ : sizeof(object::pe32_header);
+ CP.Obj.Header.SizeOfOptionalHeader =
+ PEHeaderSize +
+ sizeof(object::data_directory) * (COFF::NUM_DATA_DIRECTORIES + 1);
+ return true;
+}
+
+namespace {
+enum { DOSStubSize = 128 };
+}
+// Take a CP and assign addresses and sizes to everything. Returns false if the
+// layout is not valid to do.
+static bool layoutCOFF(COFFParser &CP) {
// The section table starts immediately after the header, including the
// optional header.
- SectionTableStart = sizeof(COFF::header) + CP.Obj.Header.SizeOfOptionalHeader;
- SectionTableSize = sizeof(COFF::section) * CP.Obj.Sections.size();
+ CP.SectionTableStart =
+ CP.getHeaderSize() + CP.Obj.Header.SizeOfOptionalHeader;
+ if (CP.isPE())
+ CP.SectionTableStart += DOSStubSize + sizeof(COFF::PEMagic);
+ CP.SectionTableSize = COFF::SectionSize * CP.Obj.Sections.size();
- uint32_t CurrentSectionDataOffset = SectionTableStart + SectionTableSize;
+ uint32_t CurrentSectionDataOffset =
+ CP.SectionTableStart + CP.SectionTableSize;
// Assign each section data address consecutively.
- for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
- e = CP.Obj.Sections.end();
- i != e; ++i) {
- if (i->SectionData.binary_size() > 0) {
- i->Header.SizeOfRawData = i->SectionData.binary_size();
- i->Header.PointerToRawData = CurrentSectionDataOffset;
- CurrentSectionDataOffset += i->Header.SizeOfRawData;
- if (!i->Relocations.empty()) {
- i->Header.PointerToRelocations = CurrentSectionDataOffset;
- i->Header.NumberOfRelocations = i->Relocations.size();
- CurrentSectionDataOffset += i->Header.NumberOfRelocations *
- COFF::RelocationSize;
+ for (COFFYAML::Section &S : CP.Obj.Sections) {
+ if (S.SectionData.binary_size() > 0) {
+ CurrentSectionDataOffset = RoundUpToAlignment(
+ CurrentSectionDataOffset, CP.isPE() ? CP.getFileAlignment() : 4);
+ S.Header.SizeOfRawData = S.SectionData.binary_size();
+ if (CP.isPE())
+ S.Header.SizeOfRawData =
+ RoundUpToAlignment(S.Header.SizeOfRawData, CP.getFileAlignment());
+ S.Header.PointerToRawData = CurrentSectionDataOffset;
+ CurrentSectionDataOffset += S.Header.SizeOfRawData;
+ if (!S.Relocations.empty()) {
+ S.Header.PointerToRelocations = CurrentSectionDataOffset;
+ S.Header.NumberOfRelocations = S.Relocations.size();
+ CurrentSectionDataOffset +=
+ S.Header.NumberOfRelocations * COFF::RelocationSize;
}
- // TODO: Handle alignment.
} else {
- i->Header.SizeOfRawData = 0;
- i->Header.PointerToRawData = 0;
+ S.Header.SizeOfRawData = 0;
+ S.Header.PointerToRawData = 0;
}
}
@@ -163,7 +209,7 @@ static bool layoutCOFF(COFFParser &CP) {
NumberOfAuxSymbols += 1;
if (!i->File.empty())
NumberOfAuxSymbols +=
- (i->File.size() + COFF::SymbolSize - 1) / COFF::SymbolSize;
+ (i->File.size() + CP.getSymbolSize() - 1) / CP.getSymbolSize();
if (i->SectionDefinition)
NumberOfAuxSymbols += 1;
if (i->CLRToken)
@@ -175,7 +221,10 @@ static bool layoutCOFF(COFFParser &CP) {
// Store all the allocated start addresses in the header.
CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size();
CP.Obj.Header.NumberOfSymbols = NumberOfSymbols;
- CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
+ if (NumberOfSymbols > 0 || CP.StringTable.size() > 4)
+ CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
+ else
+ CP.Obj.Header.PointerToSymbolTable = 0;
*reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0])
= CP.StringTable.size();
@@ -222,15 +271,153 @@ zeros_impl<sizeof(T)> zeros(const T &) {
return zeros_impl<sizeof(T)>();
}
-bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
- OS << binary_le(CP.Obj.Header.Machine)
- << binary_le(CP.Obj.Header.NumberOfSections)
- << binary_le(CP.Obj.Header.TimeDateStamp)
- << binary_le(CP.Obj.Header.PointerToSymbolTable)
- << binary_le(CP.Obj.Header.NumberOfSymbols)
- << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
- << binary_le(CP.Obj.Header.Characteristics);
+struct num_zeros_impl {
+ size_t N;
+ num_zeros_impl(size_t N) : N(N) {}
+};
+
+raw_ostream &operator<<(raw_ostream &OS, const num_zeros_impl &NZI) {
+ for (size_t I = 0; I != NZI.N; ++I)
+ OS.write(0);
+ return OS;
+}
+
+num_zeros_impl num_zeros(size_t N) {
+ num_zeros_impl NZI(N);
+ return NZI;
+}
+
+template <typename T>
+static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header) {
+ memset(Header, 0, sizeof(*Header));
+ Header->Magic = Magic;
+ Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment;
+ Header->FileAlignment = CP.Obj.OptionalHeader->Header.FileAlignment;
+ uint32_t SizeOfCode = 0, SizeOfInitializedData = 0,
+ SizeOfUninitializedData = 0;
+ uint32_t SizeOfHeaders = RoundUpToAlignment(
+ CP.SectionTableStart + CP.SectionTableSize, Header->FileAlignment);
+ uint32_t SizeOfImage =
+ RoundUpToAlignment(SizeOfHeaders, Header->SectionAlignment);
+ uint32_t BaseOfData = 0;
+ for (const COFFYAML::Section &S : CP.Obj.Sections) {
+ if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_CODE)
+ SizeOfCode += S.Header.SizeOfRawData;
+ if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ SizeOfInitializedData += S.Header.SizeOfRawData;
+ if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ SizeOfUninitializedData += S.Header.SizeOfRawData;
+ if (S.Name.equals(".text"))
+ Header->BaseOfCode = S.Header.VirtualAddress; // RVA
+ else if (S.Name.equals(".data"))
+ BaseOfData = S.Header.VirtualAddress; // RVA
+ if (S.Header.VirtualAddress)
+ SizeOfImage +=
+ RoundUpToAlignment(S.Header.VirtualSize, Header->SectionAlignment);
+ }
+ Header->SizeOfCode = SizeOfCode;
+ Header->SizeOfInitializedData = SizeOfInitializedData;
+ Header->SizeOfUninitializedData = SizeOfUninitializedData;
+ Header->AddressOfEntryPoint =
+ CP.Obj.OptionalHeader->Header.AddressOfEntryPoint; // RVA
+ Header->ImageBase = CP.Obj.OptionalHeader->Header.ImageBase;
+ Header->MajorOperatingSystemVersion =
+ CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion;
+ Header->MinorOperatingSystemVersion =
+ CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion;
+ Header->MajorImageVersion =
+ CP.Obj.OptionalHeader->Header.MajorImageVersion;
+ Header->MinorImageVersion =
+ CP.Obj.OptionalHeader->Header.MinorImageVersion;
+ Header->MajorSubsystemVersion =
+ CP.Obj.OptionalHeader->Header.MajorSubsystemVersion;
+ Header->MinorSubsystemVersion =
+ CP.Obj.OptionalHeader->Header.MinorSubsystemVersion;
+ Header->SizeOfImage = SizeOfImage;
+ Header->SizeOfHeaders = SizeOfHeaders;
+ Header->Subsystem = CP.Obj.OptionalHeader->Header.Subsystem;
+ Header->DLLCharacteristics = CP.Obj.OptionalHeader->Header.DLLCharacteristics;
+ Header->SizeOfStackReserve = CP.Obj.OptionalHeader->Header.SizeOfStackReserve;
+ Header->SizeOfStackCommit = CP.Obj.OptionalHeader->Header.SizeOfStackCommit;
+ Header->SizeOfHeapReserve = CP.Obj.OptionalHeader->Header.SizeOfHeapReserve;
+ Header->SizeOfHeapCommit = CP.Obj.OptionalHeader->Header.SizeOfHeapCommit;
+ Header->NumberOfRvaAndSize = COFF::NUM_DATA_DIRECTORIES + 1;
+ return BaseOfData;
+}
+
+static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
+ if (CP.isPE()) {
+ // PE files start with a DOS stub.
+ object::dos_header DH;
+ memset(&DH, 0, sizeof(DH));
+
+ // DOS EXEs start with "MZ" magic.
+ DH.Magic[0] = 'M';
+ DH.Magic[1] = 'Z';
+ // Initializing the AddressOfRelocationTable is strictly optional but
+ // mollifies certain tools which expect it to have a value greater than
+ // 0x40.
+ DH.AddressOfRelocationTable = sizeof(DH);
+ // This is the address of the PE signature.
+ DH.AddressOfNewExeHeader = DOSStubSize;
+
+ // Write out our DOS stub.
+ OS.write(reinterpret_cast<char *>(&DH), sizeof(DH));
+ // Write padding until we reach the position of where our PE signature
+ // should live.
+ OS << num_zeros(DOSStubSize - sizeof(DH));
+ // Write out the PE signature.
+ OS.write(COFF::PEMagic, sizeof(COFF::PEMagic));
+ }
+ if (CP.useBigObj()) {
+ OS << binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN))
+ << binary_le(static_cast<uint16_t>(0xffff))
+ << binary_le(static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion))
+ << binary_le(CP.Obj.Header.Machine)
+ << binary_le(CP.Obj.Header.TimeDateStamp);
+ OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
+ OS << zeros(uint32_t(0))
+ << zeros(uint32_t(0))
+ << zeros(uint32_t(0))
+ << zeros(uint32_t(0))
+ << binary_le(CP.Obj.Header.NumberOfSections)
+ << binary_le(CP.Obj.Header.PointerToSymbolTable)
+ << binary_le(CP.Obj.Header.NumberOfSymbols);
+ } else {
+ OS << binary_le(CP.Obj.Header.Machine)
+ << binary_le(static_cast<int16_t>(CP.Obj.Header.NumberOfSections))
+ << binary_le(CP.Obj.Header.TimeDateStamp)
+ << binary_le(CP.Obj.Header.PointerToSymbolTable)
+ << binary_le(CP.Obj.Header.NumberOfSymbols)
+ << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
+ << binary_le(CP.Obj.Header.Characteristics);
+ }
+ if (CP.isPE()) {
+ if (CP.is64Bit()) {
+ object::pe32plus_header PEH;
+ initializeOptionalHeader(CP, COFF::PE32Header::PE32_PLUS, &PEH);
+ OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
+ } else {
+ object::pe32_header PEH;
+ uint32_t BaseOfData = initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH);
+ PEH.BaseOfData = BaseOfData;
+ OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
+ }
+ for (const Optional<COFF::DataDirectory> &DD :
+ CP.Obj.OptionalHeader->DataDirectories) {
+ if (!DD.hasValue()) {
+ OS << zeros(uint32_t(0));
+ OS << zeros(uint32_t(0));
+ } else {
+ OS << binary_le(DD->RelativeVirtualAddress);
+ OS << binary_le(DD->Size);
+ }
+ }
+ OS << zeros(uint32_t(0));
+ OS << zeros(uint32_t(0));
+ }
+ assert(OS.tell() == CP.SectionTableStart);
// Output section table.
for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
e = CP.Obj.Sections.end();
@@ -246,6 +433,7 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
<< binary_le(i->Header.NumberOfLineNumbers)
<< binary_le(i->Header.Characteristics);
}
+ assert(OS.tell() == CP.SectionTableStart + CP.SectionTableSize);
unsigned CurSymbol = 0;
StringMap<unsigned> SymbolTableIndexMap;
@@ -257,12 +445,15 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
}
// Output section data.
- for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
- e = CP.Obj.Sections.end();
- i != e; ++i) {
- i->SectionData.writeAsBinary(OS);
- for (unsigned I2 = 0, E2 = i->Relocations.size(); I2 != E2; ++I2) {
- const COFFYAML::Relocation &R = i->Relocations[I2];
+ for (const COFFYAML::Section &S : CP.Obj.Sections) {
+ if (!S.Header.SizeOfRawData)
+ continue;
+ assert(S.Header.PointerToRawData >= OS.tell());
+ OS << num_zeros(S.Header.PointerToRawData - OS.tell());
+ S.SectionData.writeAsBinary(OS);
+ assert(S.Header.SizeOfRawData >= S.SectionData.binary_size());
+ OS << num_zeros(S.Header.SizeOfRawData - S.SectionData.binary_size());
+ for (const COFFYAML::Relocation &R : S.Relocations) {
uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
OS << binary_le(R.VirtualAddress)
<< binary_le(SymbolTableIndex)
@@ -276,9 +467,12 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
e = CP.Obj.Symbols.end();
i != e; ++i) {
OS.write(i->Header.Name, COFF::NameSize);
- OS << binary_le(i->Header.Value)
- << binary_le(i->Header.SectionNumber)
- << binary_le(i->Header.Type)
+ OS << binary_le(i->Header.Value);
+ if (CP.useBigObj())
+ OS << binary_le(i->Header.SectionNumber);
+ else
+ OS << binary_le(static_cast<int16_t>(i->Header.SectionNumber));
+ OS << binary_le(i->Header.Type)
<< binary_le(i->Header.StorageClass)
<< binary_le(i->Header.NumberOfAuxSymbols);
@@ -287,43 +481,50 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
<< binary_le(i->FunctionDefinition->TotalSize)
<< binary_le(i->FunctionDefinition->PointerToLinenumber)
<< binary_le(i->FunctionDefinition->PointerToNextFunction)
- << zeros(i->FunctionDefinition->unused);
+ << zeros(i->FunctionDefinition->unused)
+ << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
if (i->bfAndefSymbol)
OS << zeros(i->bfAndefSymbol->unused1)
<< binary_le(i->bfAndefSymbol->Linenumber)
<< zeros(i->bfAndefSymbol->unused2)
<< binary_le(i->bfAndefSymbol->PointerToNextFunction)
- << zeros(i->bfAndefSymbol->unused3);
+ << zeros(i->bfAndefSymbol->unused3)
+ << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
if (i->WeakExternal)
OS << binary_le(i->WeakExternal->TagIndex)
<< binary_le(i->WeakExternal->Characteristics)
- << zeros(i->WeakExternal->unused);
+ << zeros(i->WeakExternal->unused)
+ << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
if (!i->File.empty()) {
+ unsigned SymbolSize = CP.getSymbolSize();
uint32_t NumberOfAuxRecords =
- (i->File.size() + COFF::SymbolSize - 1) / COFF::SymbolSize;
- uint32_t NumberOfAuxBytes = NumberOfAuxRecords * COFF::SymbolSize;
+ (i->File.size() + SymbolSize - 1) / SymbolSize;
+ uint32_t NumberOfAuxBytes = NumberOfAuxRecords * SymbolSize;
uint32_t NumZeros = NumberOfAuxBytes - i->File.size();
OS.write(i->File.data(), i->File.size());
- for (uint32_t Padding = 0; Padding < NumZeros; ++Padding)
- OS.write(0);
+ OS << num_zeros(NumZeros);
}
if (i->SectionDefinition)
OS << binary_le(i->SectionDefinition->Length)
<< binary_le(i->SectionDefinition->NumberOfRelocations)
<< binary_le(i->SectionDefinition->NumberOfLinenumbers)
<< binary_le(i->SectionDefinition->CheckSum)
- << binary_le(i->SectionDefinition->Number)
+ << binary_le(static_cast<int16_t>(i->SectionDefinition->Number))
<< binary_le(i->SectionDefinition->Selection)
- << zeros(i->SectionDefinition->unused);
+ << zeros(i->SectionDefinition->unused)
+ << binary_le(static_cast<int16_t>(i->SectionDefinition->Number >> 16))
+ << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
if (i->CLRToken)
OS << binary_le(i->CLRToken->AuxType)
<< zeros(i->CLRToken->unused1)
<< binary_le(i->CLRToken->SymbolTableIndex)
- << zeros(i->CLRToken->unused2);
+ << zeros(i->CLRToken->unused2)
+ << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
}
// Output string table.
- OS.write(&CP.StringTable[0], CP.StringTable.size());
+ if (CP.Obj.Header.PointerToSymbolTable)
+ OS.write(&CP.StringTable[0], CP.StringTable.size());
return true;
}
@@ -341,6 +542,10 @@ int yaml2coff(yaml::Input &YIn, raw_ostream &Out) {
return 1;
}
+ if (!layoutOptionalHeader(CP)) {
+ errs() << "yaml2obj: Failed to layout optional header for COFF file!\n";
+ return 1;
+ }
if (!layoutCOFF(CP)) {
errs() << "yaml2obj: Failed to layout COFF file!\n";
return 1;
diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp
index 6eeecaedcabd..44c8c12da89d 100644
--- a/tools/yaml2obj/yaml2elf.cpp
+++ b/tools/yaml2obj/yaml2elf.cpp
@@ -62,11 +62,7 @@ class NameToIdxMap {
public:
/// \returns true if name is already present in the map.
bool addName(StringRef Name, unsigned i) {
- StringMapEntry<int> &Entry = Map.GetOrCreateValue(Name, -1);
- if (Entry.getValue() != -1)
- return true;
- Entry.setValue((int)i);
- return false;
+ return !Map.insert(std::make_pair(Name, (int)i)).second;
}
/// \returns true if name is not present in the map
bool lookup(StringRef Name, unsigned &Idx) const {
@@ -190,7 +186,7 @@ bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
for (const auto &Sec : Doc.Sections)
DotShStrtab.add(Sec->Name);
- DotShStrtab.finalize();
+ DotShStrtab.finalize(StringTableBuilder::ELF);
for (const auto &Sec : Doc.Sections) {
zero(SHeader);
@@ -261,7 +257,7 @@ void ELFState<ELFT>::initSymtabSectionHeader(Elf_Shdr &SHeader,
DotStrtab.add(Sym.Name);
for (const auto &Sym : Doc.Symbols.Weak)
DotStrtab.add(Sym.Name);
- DotStrtab.finalize();
+ DotStrtab.finalize(StringTableBuilder::ELF);
addSymbols(Doc.Symbols.Local, Syms, ELF::STB_LOCAL);
addSymbols(Doc.Symbols.Global, Syms, ELF::STB_GLOBAL);
@@ -304,7 +300,7 @@ void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
Symbol.st_shndx = Index;
} // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier.
Symbol.st_value = Sym.Value;
- Symbol.st_other = Sym.Visibility;
+ Symbol.st_other = Sym.Other;
Symbol.st_size = Sym.Size;
Syms.push_back(Symbol);
}
diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
index 945fad1384aa..375cd89849c3 100644
--- a/tools/yaml2obj/yaml2obj.cpp
+++ b/tools/yaml2obj/yaml2obj.cpp
@@ -83,11 +83,11 @@ int main(int argc, char **argv) {
if (OutputFilename.empty())
OutputFilename = "-";
- std::string ErrorInfo;
+ std::error_code EC;
std::unique_ptr<tool_output_file> Out(
- new tool_output_file(OutputFilename.c_str(), ErrorInfo, sys::fs::F_None));
- if (!ErrorInfo.empty()) {
- errs() << ErrorInfo << '\n';
+ new tool_output_file(OutputFilename, EC, sys::fs::F_None));
+ if (EC) {
+ errs() << EC.message() << '\n';
return 1;
}
diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h
index 086f6413aa78..7290a9af2c64 100644
--- a/tools/yaml2obj/yaml2obj.h
+++ b/tools/yaml2obj/yaml2obj.h
@@ -9,8 +9,8 @@
/// \file
/// \brief Common declarations for yaml2obj
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_YAML2OBJ_H
-#define LLVM_TOOLS_YAML2OBJ_H
+#ifndef LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H
+#define LLVM_TOOLS_YAML2OBJ_YAML2OBJ_H
namespace llvm {
class raw_ostream;