aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorStephen Hines <srhines@google.com>2014-12-01 14:51:49 -0800
committerStephen Hines <srhines@google.com>2014-12-02 16:08:10 -0800
commit37ed9c199ca639565f6ce88105f9e39e898d82d0 (patch)
tree8fb36d3910e3ee4c4e1b7422f4f017108efc52f5 /tools
parentd2327b22152ced7bc46dc629fc908959e8a52d03 (diff)
downloadexternal_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.zip
external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.gz
external_llvm-37ed9c199ca639565f6ce88105f9e39e898d82d0.tar.bz2
Update aosp/master LLVM for rebase to r222494.
Change-Id: Ic787f5e0124df789bd26f3f24680f45e678eef2d
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt11
-rw-r--r--tools/LLVMBuild.txt2
-rw-r--r--tools/Makefile10
-rw-r--r--tools/bugpoint-passes/CMakeLists.txt4
-rw-r--r--tools/bugpoint/Android.mk1
-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.cpp33
-rw-r--r--tools/bugpoint/ToolRunner.h4
-rw-r--r--tools/bugpoint/bugpoint.cpp14
-rw-r--r--tools/gold/CMakeLists.txt4
-rw-r--r--tools/gold/Makefile2
-rw-r--r--tools/gold/gold-plugin.cpp782
-rw-r--r--tools/llc/Android.mk1
-rw-r--r--tools/llc/llc.cpp40
-rw-r--r--tools/lli/Android.mk1
-rw-r--r--tools/lli/CMakeLists.txt3
-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.cpp33
-rw-r--r--tools/lli/RemoteMemoryManager.h24
-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.cpp106
-rw-r--r--tools/llvm-ar/CMakeLists.txt1
-rw-r--r--tools/llvm-ar/llvm-ar.cpp338
-rw-r--r--tools/llvm-as/llvm-as.cpp10
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp106
-rw-r--r--tools/llvm-c-test/CMakeLists.txt9
-rw-r--r--tools/llvm-c-test/disassemble.c20
-rw-r--r--tools/llvm-config/CMakeLists.txt15
-rw-r--r--tools/llvm-cov/Android.mk15
-rw-r--r--tools/llvm-cov/CMakeLists.txt10
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp484
-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.cpp91
-rw-r--r--tools/llvm-cov/gcov.cpp153
-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.cpp8
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp20
-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.go261
-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.cpp21
-rw-r--r--tools/llvm-link/llvm-link.cpp69
-rw-r--r--tools/llvm-lto/CMakeLists.txt1
-rw-r--r--tools/llvm-lto/llvm-lto.cpp52
-rw-r--r--tools/llvm-mc/Android.mk3
-rw-r--r--tools/llvm-mc/Disassembler.cpp70
-rw-r--r--tools/llvm-mc/Disassembler.h4
-rw-r--r--tools/llvm-mc/llvm-mc.cpp19
-rw-r--r--tools/llvm-mcmarkup/llvm-mcmarkup.cpp7
-rw-r--r--tools/llvm-nm/Android.mk6
-rw-r--r--tools/llvm-nm/CMakeLists.txt1
-rw-r--r--tools/llvm-nm/llvm-nm.cpp463
-rw-r--r--tools/llvm-objdump/Android.mk4
-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.cpp3645
-rw-r--r--tools/llvm-objdump/Makefile2
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp372
-rw-r--r--tools/llvm-objdump/llvm-objdump.h16
-rw-r--r--tools/llvm-profdata/CMakeLists.txt6
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp180
-rw-r--r--tools/llvm-readobj/ARMAttributeParser.h4
-rw-r--r--tools/llvm-readobj/ARMEHABIPrinter.h4
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp61
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.h52
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp407
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp6
-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.h9
-rw-r--r--tools/llvm-readobj/StreamWriter.h20
-rw-r--r--tools/llvm-readobj/Win64EHDumper.h4
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp46
-rw-r--r--tools/llvm-readobj/llvm-readobj.h4
-rw-r--r--tools/llvm-rtdyld/Android.mk2
-rw-r--r--tools/llvm-rtdyld/LLVMBuild.txt2
-rw-r--r--tools/llvm-rtdyld/Makefile2
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp188
-rw-r--r--tools/llvm-shlib/CMakeLists.txt100
-rw-r--r--tools/llvm-shlib/libllvm.cpp13
-rw-r--r--tools/llvm-size/llvm-size.cpp48
-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.txt3
-rw-r--r--tools/lto/Makefile4
-rw-r--r--tools/lto/lto.cpp36
-rw-r--r--tools/macho-dump/macho-dump.cpp8
-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/Android.mk1
-rw-r--r--tools/opt/BreakpointPrinter.cpp2
-rw-r--r--tools/opt/NewPMDriver.h4
-rw-r--r--tools/opt/opt.cpp101
-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.cpp562
-rw-r--r--tools/yaml2obj/CMakeLists.txt3
-rw-r--r--tools/yaml2obj/Makefile3
-rw-r--r--tools/yaml2obj/yaml2coff.cpp309
-rw-r--r--tools/yaml2obj/yaml2elf.cpp12
-rw-r--r--tools/yaml2obj/yaml2obj.cpp8
-rw-r--r--tools/yaml2obj/yaml2obj.h4
156 files changed, 10837 insertions, 2123 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 846ad1e..fd761ec 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,7 @@ add_llvm_tool_subdirectory(llvm-objdump)
add_llvm_tool_subdirectory(llvm-readobj)
add_llvm_tool_subdirectory(llvm-rtdyld)
add_llvm_tool_subdirectory(llvm-dwarfdump)
+add_llvm_tool_subdirectory(llvm-vtabledump)
if( LLVM_USE_INTEL_JITEVENTS )
add_llvm_tool_subdirectory(llvm-jitlistener)
else()
@@ -42,6 +49,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 +58,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)
diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt
index 1b537a3..13a08b2 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
[component_0]
type = Group
diff --git a/tools/Makefile b/tools/Makefile
index 97ad99a..4b8923a 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
# 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-passes/CMakeLists.txt b/tools/bugpoint-passes/CMakeLists.txt
index b7ee626..de68bb5 100644
--- a/tools/bugpoint-passes/CMakeLists.txt
+++ b/tools/bugpoint-passes/CMakeLists.txt
@@ -10,6 +10,10 @@ if( NOT LLVM_REQUIRES_RTTI )
endif()
endif()
+if(WIN32 OR CYGWIN)
+ set(LLVM_LINK_COMPONENTS Core)
+endif()
+
add_llvm_loadable_module( BugpointPasses
TestPasses.cpp
)
diff --git a/tools/bugpoint/Android.mk b/tools/bugpoint/Android.mk
index 78f3eff..512a91f 100644
--- a/tools/bugpoint/Android.mk
+++ b/tools/bugpoint/Android.mk
@@ -35,6 +35,7 @@ bugpoint_STATIC_LIBRARIES := \
libLLVMTarget \
libLLVMCore \
libLLVMMC \
+ libLLVMProfileData \
libLLVMTransformUtils \
libLLVMVectorize \
libLLVMSupport \
diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp
index cecccbe..b8be17e 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 3169d29..5797812 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 8bd61b3..bac948a 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 4fb6856..34fe53c 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 8083e2d..a0bb570 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 3f1f84e..8cb4583 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 d452fd9..f197cc5 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 4a2401b..51091e2 100644
--- a/tools/bugpoint/ToolRunner.cpp
+++ b/tools/bugpoint/ToolRunner.cpp
@@ -141,13 +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);
}
+
RunProgramWithTimeout(ProgPath, Args, "", ErrorFilename.str(),
ErrorFilename.str(), Timeout, MemoryLimit);
// FIXME: check return code ?
@@ -427,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";
}
@@ -907,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 6e7b95c..454724a 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 c7dae0f..d0bade5 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/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt
index 3864e15..3033010 100644
--- a/tools/gold/CMakeLists.txt
+++ b/tools/gold/CMakeLists.txt
@@ -16,7 +16,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 593d8ea..aa006b0 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 b908510..cfda6d2 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -13,33 +13,35 @@
//===----------------------------------------------------------------------===//
#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/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/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 +63,24 @@ 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 generate_bc { BC_NO, BC_ONLY, BC_SAVE_TEMPS };
static bool generate_api_file = false;
static generate_bc generate_bc_file = BC_NO;
- static std::string bc_path;
static std::string obj_path;
static std::string extra_library_path;
static std::string triple;
@@ -89,11 +90,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_;
@@ -109,20 +110,16 @@ namespace options {
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;
- }
+ } else if (opt == "save-temps") {
+ generate_bc_file = BC_SAVE_TEMPS;
} 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 +156,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 +173,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 +182,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 +191,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 +224,50 @@ 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);
+}
+
/// 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 +279,567 @@ 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))
+ ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
+ object::IRObjectFile::createIRObjectFile(BufferRef, Context);
+ std::error_code EC = ObjOrErr.getError();
+ if (EC == BitcodeError::InvalidBitcodeSignature ||
+ 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 (!(Symflags & object::BasicSymbolRef::SF_Global))
+ continue;
+
+ if (Symflags & object::BasicSymbolRef::SF_FormatSpecific)
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");
+}
- assert(CodeGen);
+static GlobalObject *makeInternalReplacement(GlobalObject *GO) {
+ Module *M = GO->getParent();
+ GlobalObject *Ret;
+ if (auto *F = dyn_cast<Function>(GO)) {
+ if (F->materialize())
+ message(LDPL_FATAL, "LLVM gold plugin has failed to read a function");
+
+ auto *NewF = Function::Create(F->getFunctionType(), F->getLinkage(),
+ F->getName(), M);
+
+ ValueToValueMapTy VM;
+ Function::arg_iterator NewI = NewF->arg_begin();
+ for (auto &Arg : F->args()) {
+ NewI->setName(Arg.getName());
+ VM[&Arg] = NewI;
+ ++NewI;
+ }
- 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());
+ NewF->getBasicBlockList().splice(NewF->end(), F->getBasicBlockList());
+ for (auto &BB : *NewF) {
+ for (auto &Inst : BB)
+ RemapInstruction(&Inst, VM, RF_IgnoreMissingEntries);
+ }
+
+ Ret = NewF;
+ F->deleteBody();
+ } else {
+ auto *Var = cast<GlobalVariable>(GO);
+ Ret = new GlobalVariable(
+ *M, Var->getType()->getElementType(), Var->isConstant(),
+ Var->getLinkage(), Var->getInitializer(), Var->getName(),
+ nullptr, Var->getThreadLocalMode(), Var->getType()->getAddressSpace(),
+ Var->isExternallyInitialized());
+ Var->setInitializer(nullptr);
}
+ Ret->copyAttributesFrom(GO);
+ Ret->setLinkage(GlobalValue::InternalLinkage);
+ Ret->setComdat(GO->getComdat());
+
+ return Ret;
+}
+
+namespace {
+class LocalValueMaterializer : public ValueMaterializer {
+ DenseSet<GlobalValue *> &Dropped;
+
+public:
+ LocalValueMaterializer(DenseSet<GlobalValue *> &Dropped) : Dropped(Dropped) {}
+ Value *materializeValueFor(Value *V) override;
+};
+}
+
+Value *LocalValueMaterializer::materializeValueFor(Value *V) {
+ auto *GV = dyn_cast<GlobalValue>(V);
+ if (!GV)
+ return nullptr;
+ if (!Dropped.count(GV))
+ return nullptr;
+ assert(!isa<GlobalAlias>(GV) && "Found alias point to weak alias.");
+ return makeInternalReplacement(cast<GlobalObject>(GV));
+}
+
+static Constant *mapConstantToLocalCopy(Constant *C, ValueToValueMapTy &VM,
+ LocalValueMaterializer *Materializer) {
+ return MapValue(C, VM, RF_IgnoreMissingEntries, nullptr, Materializer);
+}
+
+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");
- for (std::list<claimed_file>::iterator I = Modules.begin(),
- E = Modules.end(); I != E; ++I) {
- if (I->syms.empty())
+ const void *View;
+ if (get_view(F.handle, &View) != LDPS_OK)
+ message(LDPL_FATAL, "Failed to get a view of file");
+
+ llvm::ErrorOr<MemoryBufferRef> MBOrErr =
+ object::IRObjectFile::findBitcodeInMemBuffer(
+ MemoryBufferRef(StringRef((const char *)View, File.filesize), ""));
+ if (std::error_code EC = MBOrErr.getError())
+ message(LDPL_FATAL, "Could not read bitcode from file : %s",
+ EC.message().c_str());
+
+ std::unique_ptr<MemoryBuffer> Buffer =
+ MemoryBuffer::getMemBuffer(MBOrErr->getBuffer(), "", false);
+
+ if (release_input_file(F.handle) != LDPS_OK)
+ message(LDPL_FATAL, "Failed to release file information");
+
+ ErrorOr<Module *> MOrErr = getLazyBitcodeModule(std::move(Buffer), Context);
+
+ if (std::error_code EC = MOrErr.getError())
+ message(LDPL_FATAL, "Could not read bitcode from file : %s",
+ EC.message().c_str());
+
+ std::unique_ptr<Module> M(MOrErr.get());
+
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
+
+ DenseSet<GlobalValue *> Drop;
+ std::vector<GlobalAlias *> KeptAliases;
+ for (ld_plugin_symbol &Sym : F.syms) {
+ ld_plugin_symbol_resolution Resolution =
+ (ld_plugin_symbol_resolution)Sym.resolution;
+
+ if (options::generate_api_file)
+ *ApiFile << Sym.name << ' ' << getResolutionName(Resolution) << '\n';
+
+ GlobalValue *GV = M->getNamedValue(Sym.name);
+ if (!GV)
+ 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.
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:
+ case LDPR_UNDEF:
+ assert(GV->isDeclarationForLinker());
+ break;
+
+ case LDPR_PREVAILING_DEF_IRONLY: {
+ keepGlobalValue(*GV, KeptAliases);
+ if (!Used.count(GV)) {
+ // Since we use the regular lib/Linker, we cannot just internalize GV
+ // now or it will not be copied to the merged module. Instead we force
+ // it to be copied and then internalize it.
+ Internalize.insert(Sym.name);
}
+ 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(Sym.name);
+
+ // 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(Sym.name);
+ keepGlobalValue(*GV, KeptAliases);
+ break;
+ }
}
+
+ free(Sym.name);
+ free(Sym.comdat_key);
+ Sym.name = nullptr;
+ Sym.comdat_key = nullptr;
}
- 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);
+ if (Aliasee != Replacement)
+ 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 M;
+}
+
+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::generate_bc_file == options::BC_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::generate_bc_file != options::BC_NO) {
+ std::string path;
+ if (options::generate_bc_file == options::BC_ONLY)
+ path = output_name;
+ else
+ path = output_name + ".bc";
+ saveBCFile(path, *L.getModule());
+ if (options::generate_bc_file == options::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);
+ }
+
+ if (options::generate_bc_file == options::BC_ONLY)
+ 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/Android.mk b/tools/llc/Android.mk
index a25cf5c..a98cd8b 100644
--- a/tools/llc/Android.mk
+++ b/tools/llc/Android.mk
@@ -48,6 +48,7 @@ llvm_llc_STATIC_LIBRARIES := \
libLLVMipo \
libLLVMipa \
libLLVMLinker \
+ libLLVMMCDisassembler \
libLLVMMC \
libLLVMMCParser \
libLLVMScalarOpts \
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index 09ff461..fe4d9ac 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,23 +95,6 @@ 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) {
@@ -119,7 +103,12 @@ static tool_output_file *GetOutputStream(const char *TargetName,
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,14 +147,13 @@ 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';
+ tool_output_file *FDOut = new tool_output_file(OutputFilename, EC, OpenFlags);
+ if (EC) {
+ errs() << EC.message() << '\n';
delete FDOut;
return nullptr;
}
@@ -231,7 +219,7 @@ 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));
+ M = parseIRFile(InputFilename, Err, Context);
mod = M.get();
if (mod == nullptr) {
Err.print(argv[0], errs());
@@ -317,9 +305,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())
+ if (const DataLayout *DL = Target.getSubtargetImpl()->getDataLayout())
mod->setDataLayout(DL);
- PM.add(new DataLayoutPass(mod));
+ PM.add(new DataLayoutPass());
if (RelaxAll.getNumOccurrences() > 0 &&
FileType != TargetMachine::CGFT_ObjectFile)
diff --git a/tools/lli/Android.mk b/tools/lli/Android.mk
index f550f93..1b09102 100644
--- a/tools/lli/Android.mk
+++ b/tools/lli/Android.mk
@@ -44,7 +44,6 @@ lli_STATIC_LIBRARIES := \
libLLVMX86Disassembler \
libLLVMAsmPrinter \
libLLVMSelectionDAG \
- libLLVMJIT \
libLLVMCodeGen \
libLLVMInstrumentation \
libLLVMExecutionEngine \
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 731b61a..3610d76 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -7,8 +7,9 @@ set(LLVM_LINK_COMPONENTS
IRReader
Instrumentation
Interpreter
- JIT
+ MC
MCJIT
+ Object
SelectionDAG
Support
native
diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt
index aab2a20..4c14c47 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 eca5d83..94d6f06 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 2d8c708..ebd3c65 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 4816517..5a135ea 100644
--- a/tools/lli/RemoteMemoryManager.cpp
+++ b/tools/lli/RemoteMemoryManager.cpp
@@ -172,36 +172,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 cf5d7c6..0bdb4e2 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 {
@@ -93,22 +93,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 73e8ae2..ee758a2 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 f87fc61..bb621f5 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 cb934a1..c210e4b 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 48828c1..276740b 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,10 +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));
@@ -263,23 +257,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 +339,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 +347,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 +363,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 +392,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.
@@ -423,18 +415,12 @@ 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 +437,16 @@ 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());
+ } else if (RemoteMCJIT) {
+ errs() << "error: Remote process execution does not work with the "
+ "interpreter.\n";
+ exit(1);
}
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
@@ -511,46 +493,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 +596,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 0e809a7..5193def 100644
--- a/tools/llvm-ar/CMakeLists.txt
+++ b/tools/llvm-ar/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ Core
Object
Support
)
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index f638e55..8ee66f6 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,20 +412,20 @@ class NewArchiveIterator {
object::Archive::child_iterator OldI;
- std::string NewFilename;
+ StringRef NewFilename;
mutable int NewFD;
mutable sys::fs::file_status NewStatus;
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;
+ StringRef getNew() const;
int getFD() const;
const sys::fs::file_status &getStatus() const;
};
@@ -426,8 +437,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), NewFD(-1) {}
StringRef NewArchiveIterator::getName() const { return Name; }
@@ -438,9 +449,9 @@ 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 {
@@ -485,16 +496,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 +554,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 +567,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 +605,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;
@@ -686,7 +696,7 @@ static void writeStringTable(raw_fd_ostream &Out,
static void
writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
- MutableArrayRef<std::unique_ptr<MemoryBuffer>> Buffers,
+ ArrayRef<MemoryBufferRef> Buffers,
std::vector<std::pair<unsigned, unsigned>> &MemberOffsetRefs) {
unsigned StartOffset = 0;
unsigned MemberNum = 0;
@@ -697,13 +707,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 +721,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;
@@ -725,7 +735,6 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum));
print32BE(Out, 0);
}
- MemberBuffer.reset(Obj->releaseBuffer());
}
Out << NameOS.str();
@@ -743,8 +752,9 @@ writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members,
Out.seek(Pos);
}
-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,38 +764,36 @@ 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<std::unique_ptr<MemoryBuffer>> MemberBuffers;
- MemberBuffers.resize(NewMembers.size());
+ std::vector<std::unique_ptr<MemoryBuffer>> Buffers;
+ std::vector<MemoryBufferRef> Members;
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();
+ StringRef Filename = Member.getNew();
int FD = Member.getFD();
const sys::fs::file_status &Status = Member.getStatus();
ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false);
failIfError(MemberBufferOrErr.getError(), Filename);
- MemberBuffer = std::move(MemberBufferOrErr.get());
+ 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);
}
if (Symtab) {
- writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs);
+ writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs);
}
std::vector<unsigned> StringMapIndexes;
@@ -809,9 +817,9 @@ static void performWriteOperation(ArchiveOperation Operation,
}
Out.seek(Pos);
- const MemoryBuffer *File = MemberBuffers[MemberNum].get();
+ MemoryBufferRef File = Members[MemberNum];
if (I->isNewMember()) {
- const char *FileName = I->getNew();
+ StringRef FileName = I->getNew();
const sys::fs::file_status &Status = I->getStatus();
StringRef Name = sys::path::filename(FileName);
@@ -839,7 +847,7 @@ static void performWriteOperation(ArchiveOperation Operation,
OldMember->getSize());
}
- Out << File->getBuffer();
+ Out << File.getBuffer();
if (Out.tell() % 2)
Out << '\n';
@@ -851,6 +859,18 @@ static void performWriteOperation(ArchiveOperation Operation,
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 +881,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 +898,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 +907,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 +920,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 +942,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 007241c..5ccf505 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 15567cf..f95b272 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -31,6 +31,7 @@
#include "llvm/Bitcode/LLVMBitCodes.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
@@ -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) {
@@ -271,7 +273,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
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 +318,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 +351,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 +394,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 +435,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 +480,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 +504,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 +524,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 +576,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 +602,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 +661,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 34fea3d..989678b 100644
--- a/tools/llvm-c-test/CMakeLists.txt
+++ b/tools/llvm-c-test/CMakeLists.txt
@@ -7,6 +7,10 @@ set(LLVM_LINK_COMPONENTS
Target
)
+if(TARGET LLVM)
+ 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 +25,8 @@ add_llvm_tool(llvm-c-test
object.c
targets.c
)
+
+# Use libLLVM.so if it is available.
+if(TARGET LLVM)
+ 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 eb40bf3..05a9218 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/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt
index 8d83762..50c84e6 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-cov/Android.mk b/tools/llvm-cov/Android.mk
index dae211f..d76c940 100644
--- a/tools/llvm-cov/Android.mk
+++ b/tools/llvm-cov/Android.mk
@@ -8,9 +8,22 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../..
#===---------------------------------------------------------------===
llvm_cov_SRC_FILES := \
- llvm-cov.cpp
+ CodeCoverage.cpp \
+ CoverageFilters.cpp \
+ CoverageReport.cpp \
+ CoverageSummary.cpp \
+ CoverageSummaryInfo.cpp \
+ gcov.cpp \
+ llvm-cov.cpp \
+ SourceCoverageView.cpp \
+ TestingSupport.cpp
llvm_cov_STATIC_LIBRARIES := \
+ libLLVMObject \
+ libLLVMProfileData \
+ libLLVMMC \
+ libLLVMMCParser \
+ libLLVMBitReader \
libLLVMCore \
libLLVMSupport \
diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt
index 67cea71..b2d2b89 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 0000000..093525e
--- /dev/null
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -0,0 +1,484 @@
+//===- 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 "CoverageViewOptions.h"
+#include "CoverageFilters.h"
+#include "SourceCoverageView.h"
+#include "CoverageSummary.h"
+#include "CoverageReport.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/CoverageMapping.h"
+#include "llvm/ProfileData/CoverageMappingReader.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/PrettyStackTrace.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 0000000..325dd72
--- /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 0000000..e543005
--- /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 <vector>
+#include <memory>
+
+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 0000000..7ac9355
--- /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/Format.h"
+#include "llvm/Support/FileSystem.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 0000000..e8d34f2
--- /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 "CoverageViewOptions.h"
+#include "CoverageSummary.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 0000000..059c8c8
--- /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 0000000..9dbebde
--- /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 0000000..dd78ace
--- /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 0000000..0036032
--- /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 0000000..94b55fe
--- /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 87e00d1..d6eb74d 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 efed6cc..6e32b4d 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 0000000..0271329
--- /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 0000000..015099c
--- /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 0000000..d92a748
--- /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 0000000..537f133
--- /dev/null
+++ b/tools/llvm-cov/TestingSupport.cpp
@@ -0,0 +1,91 @@
+//===- 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/raw_ostream.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include <system_error>
+#include <functional>
+
+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 0000000..4c9195a
--- /dev/null
+++ b/tools/llvm-cov/gcov.cpp
@@ -0,0 +1,153 @@
+//===- 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/MemoryObject.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 18cc1b1..a67859e 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/raw_ostream.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 <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 ac13a5e..855f688 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 43e318a..8eb53ff 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 4470968..f0d8311 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 f70219e..ae58f5c 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 3b0f838..fb73717 100644
--- a/tools/llvm-dis/llvm-dis.cpp
+++ b/tools/llvm-dis/llvm-dis.cpp
@@ -171,11 +171,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 f44b0e3..1c540c9 100644
--- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -45,6 +45,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 +69,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 0f70868..53b2f0d 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 0000000..20393f7
--- /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 0000000..4465b2a
--- /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 0000000..47f9481
--- /dev/null
+++ b/tools/llvm-go/llvm-go.go
@@ -0,0 +1,261 @@
+//===-- 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"},
+}
+
+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, 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())
+ }
+ }
+
+ 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,
+ }
+ 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=") {
+ 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")
+
+ 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], "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, 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 c9704fb..68a4303 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 1ce78ac..e6ed20b 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 b132227..6d72427 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 c159aa5..0bb6e8b 100644
--- a/tools/llvm-jitlistener/llvm-jitlistener.cpp
+++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp
@@ -17,7 +17,7 @@
#include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
-#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectImage.h"
#include "llvm/IR/Module.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(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 ed8c06e..828b9bb 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/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt
index 485b03d..9adf629 100644
--- a/tools/llvm-lto/CMakeLists.txt
+++ b/tools/llvm-lto/CMakeLists.txt
@@ -1,6 +1,5 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
- Core
LTO
MC
Support
diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp
index 8b39f12..3c950ba 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>"));
@@ -63,6 +71,25 @@ struct ModuleInfo {
};
}
+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";
+}
+
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
@@ -84,6 +111,9 @@ int main(int argc, char **argv) {
LTOCodeGenerator CodeGen;
+ if (UseDiagnosticHandler)
+ CodeGen.setDiagnosticHandler(handleDiagnostics, nullptr);
+
switch (RelocModel) {
case Reloc::Static:
CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_STATIC);
@@ -117,12 +147,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 +183,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 +205,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/Android.mk b/tools/llvm-mc/Android.mk
index d794c8a..e6de9eb 100644
--- a/tools/llvm-mc/Android.mk
+++ b/tools/llvm-mc/Android.mk
@@ -34,7 +34,10 @@ llvm_mc_STATIC_LIBRARIES := \
libLLVMX86AsmPrinter \
libLLVMX86Utils \
libLLVMX86Disassembler \
+ libLLVMX86CodeGen \
libLLVMAsmPrinter \
+ libLLVMCodeGen \
+ libLLVMAnalysis \
libLLVMTarget \
libLLVMMC \
libLLVMObject \
diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp
index 9367590..95d146a 100644
--- a/tools/llvm-mc/Disassembler.cpp
+++ b/tools/llvm-mc/Disassembler.cpp
@@ -22,33 +22,14 @@
#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,
@@ -56,21 +37,21 @@ static bool PrintInsts(const MCDisassembler &DisAsm,
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 +64,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 +79,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 +118,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 +162,7 @@ int Disassembler::disassemble(const Target &T,
}
// Set up initial section manually here
- Streamer.InitSections();
+ Streamer.InitSections(false);
bool ErrorOccurred = false;
@@ -195,7 +172,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 +198,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 5615da8..1f18ac0 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 4c5b230..5da9e86 100644
--- a/tools/llvm-mc/llvm-mc.cpp
+++ b/tools/llvm-mc/llvm-mc.cpp
@@ -208,11 +208,11 @@ static tool_output_file *GetOutputStream() {
if (OutputFilename == "")
OutputFilename = "-";
- std::string Err;
+ std::error_code EC;
tool_output_file *Out =
- new tool_output_file(OutputFilename.c_str(), Err, sys::fs::F_None);
- if (!Err.empty()) {
- errs() << Err << '\n';
+ new tool_output_file(OutputFilename, EC, sys::fs::F_None);
+ if (EC) {
+ errs() << EC.message() << '\n';
delete Out;
return nullptr;
}
@@ -373,12 +373,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.
@@ -471,9 +471,10 @@ 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;
diff --git a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp
index a878f11..5654313 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/Android.mk b/tools/llvm-nm/Android.mk
index 98e7ba9..a17ca4d 100644
--- a/tools/llvm-nm/Android.mk
+++ b/tools/llvm-nm/Android.mk
@@ -30,19 +30,23 @@ llvm_nm_STATIC_LIBRARIES := \
libLLVMMipsDesc \
libLLVMMipsAsmPrinter \
libLLVMMipsDisassembler \
- libLLVMX86CodeGen \
libLLVMX86Info \
libLLVMX86Desc \
libLLVMX86AsmPrinter \
libLLVMX86AsmParser \
+ libLLVMX86CodeGen \
libLLVMX86Utils \
libLLVMX86Disassembler \
+ libLLVMCodeGen \
+ libLLVMAnalysis \
+ libLLVMTarget \
libLLVMObject \
libLLVMBitReader \
libLLVMMC \
libLLVMMCParser \
libLLVMCore \
libLLVMSupport \
+ libLLVMMCDisassembler \
include $(CLEAR_VARS)
diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt
index 1fe4a2d..20293bb 100644
--- a/tools/llvm-nm/CMakeLists.txt
+++ b/tools/llvm-nm/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ Core
Object
Support
)
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index 3bd9ef9..be2c4fa 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -87,8 +87,8 @@ cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix"));
cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin"));
static cl::list<std::string>
-ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
- cl::ZeroOrMore);
+ ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
+ cl::ZeroOrMore);
bool ArchAll = false;
cl::opt<bool> PrintFileName(
@@ -136,6 +136,22 @@ cl::opt<bool> JustSymbolName("just-symbol-name",
cl::desc("Print just the symbol's name"));
cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"),
cl::aliasopt(JustSymbolName));
+
+// FIXME: This option takes exactly two strings and should be allowed anywhere
+// on the command line. Such that "llvm-nm -s __TEXT __text foo.o" would work.
+// But that does not as the CommandLine Library does not have a way to make
+// this work. For now the "-s __TEXT __text" has to be last on the command
+// line.
+cl::list<std::string> SegSect("s", cl::Positional, cl::ZeroOrMore,
+ cl::desc("Dump only symbols from this segment "
+ "and section name, Mach-O only"));
+
+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;
@@ -234,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;
@@ -258,8 +274,10 @@ typedef std::vector<NMSymbol> SymbolListT;
static SymbolListT SymbolList;
// darwinPrintSymbol() is used to print a symbol from a Mach-O file when the
-// the OutputFormat is darwin. It produces the same output as darwin's nm(1) -m
-// output.
+// the OutputFormat is darwin or we are printing Mach-O symbols in hex. For
+// the darwin format it produces the same output as darwin's nm(1) -m output
+// and when printing Mach-O symbols in hex it produces the same output as
+// darwin's nm(1) -x format.
static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I,
char *SymbolAddrStr, const char *printBlanks) {
MachO::mach_header H;
@@ -268,7 +286,9 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I,
MachO::nlist_64 STE_64;
MachO::nlist STE;
uint8_t NType;
+ uint8_t NSect;
uint16_t NDesc;
+ uint32_t NStrx;
uint64_t NValue;
if (MachO->is64Bit()) {
H_64 = MachO->MachOObjectFile::getHeader64();
@@ -276,7 +296,9 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I,
Flags = H_64.flags;
STE_64 = MachO->getSymbol64TableEntry(I->Symb);
NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
NDesc = STE_64.n_desc;
+ NStrx = STE_64.n_strx;
NValue = STE_64.n_value;
} else {
H = MachO->MachOObjectFile::getHeader();
@@ -284,10 +306,34 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I,
Flags = H.flags;
STE = MachO->getSymbolTableEntry(I->Symb);
NType = STE.n_type;
+ NSect = STE.n_sect;
NDesc = STE.n_desc;
+ NStrx = STE.n_strx;
NValue = STE.n_value;
}
+ // If we are printing Mach-O symbols in hex do that and return.
+ if (FormatMachOasHex) {
+ char Str[18] = "";
+ const char *printFormat;
+ if (MachO->is64Bit())
+ printFormat = "%016" PRIx64;
+ else
+ printFormat = "%08" PRIx64;
+ format(printFormat, NValue).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ format("%02x", NType).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ format("%02x", NSect).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ format("%04x", NDesc).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ format("%08x", NStrx).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ outs() << I->Name << "\n";
+ return;
+ }
+
if (PrintAddress) {
if ((NType & MachO::N_TYPE) == MachO::N_INDR)
strcpy(SymbolAddrStr, printBlanks);
@@ -414,7 +460,87 @@ static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I,
outs() << "\n";
}
-static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
+// Table that maps Darwin's Mach-O stab constants to strings to allow printing.
+struct DarwinStabName {
+ uint8_t NType;
+ const char *Name;
+};
+static const struct DarwinStabName DarwinStabNames[] = {
+ {MachO::N_GSYM, "GSYM"},
+ {MachO::N_FNAME, "FNAME"},
+ {MachO::N_FUN, "FUN"},
+ {MachO::N_STSYM, "STSYM"},
+ {MachO::N_LCSYM, "LCSYM"},
+ {MachO::N_BNSYM, "BNSYM"},
+ {MachO::N_PC, "PC"},
+ {MachO::N_AST, "AST"},
+ {MachO::N_OPT, "OPT"},
+ {MachO::N_RSYM, "RSYM"},
+ {MachO::N_SLINE, "SLINE"},
+ {MachO::N_ENSYM, "ENSYM"},
+ {MachO::N_SSYM, "SSYM"},
+ {MachO::N_SO, "SO"},
+ {MachO::N_OSO, "OSO"},
+ {MachO::N_LSYM, "LSYM"},
+ {MachO::N_BINCL, "BINCL"},
+ {MachO::N_SOL, "SOL"},
+ {MachO::N_PARAMS, "PARAM"},
+ {MachO::N_VERSION, "VERS"},
+ {MachO::N_OLEVEL, "OLEV"},
+ {MachO::N_PSYM, "PSYM"},
+ {MachO::N_EINCL, "EINCL"},
+ {MachO::N_ENTRY, "ENTRY"},
+ {MachO::N_LBRAC, "LBRAC"},
+ {MachO::N_EXCL, "EXCL"},
+ {MachO::N_RBRAC, "RBRAC"},
+ {MachO::N_BCOMM, "BCOMM"},
+ {MachO::N_ECOMM, "ECOMM"},
+ {MachO::N_ECOML, "ECOML"},
+ {MachO::N_LENG, "LENG"},
+ {0, 0}};
+static const char *getDarwinStabString(uint8_t NType) {
+ for (unsigned i = 0; DarwinStabNames[i].Name; i++) {
+ if (DarwinStabNames[i].NType == NType)
+ return DarwinStabNames[i].Name;
+ }
+ return 0;
+}
+
+// darwinPrintStab() prints the n_sect, n_desc along with a symbolic name of
+// a stab n_type value in a Mach-O file.
+static void darwinPrintStab(MachOObjectFile *MachO, SymbolListT::iterator I) {
+ MachO::nlist_64 STE_64;
+ MachO::nlist STE;
+ uint8_t NType;
+ uint8_t NSect;
+ uint16_t NDesc;
+ if (MachO->is64Bit()) {
+ STE_64 = MachO->getSymbol64TableEntry(I->Symb);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ } else {
+ STE = MachO->getSymbolTableEntry(I->Symb);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ }
+
+ char Str[18] = "";
+ format("%02x", NSect).print(Str, sizeof(Str));
+ outs() << ' ' << Str << ' ';
+ format("%04x", NDesc).print(Str, sizeof(Str));
+ outs() << Str << ' ';
+ if (const char *stabString = getDarwinStabString(NType))
+ format("%5.5s", stabString).print(Str, sizeof(Str));
+ else
+ format(" %02x", NType).print(Str, sizeof(Str));
+ outs() << Str;
+}
+
+static void sortAndPrintSymbolList(SymbolicFile &Obj, bool printName,
+ std::string ArchiveName,
+ std::string ArchitectureName) {
if (!NoSort) {
if (NumericSort)
std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolAddress);
@@ -424,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;
@@ -451,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;
}
@@ -470,11 +605,13 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
if (I->Size != UnknownAddressOrSize)
format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr));
- // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's
- // nm(1) -m output, else if OutputFormat is darwin and not a Mach-O object
- // fall back to OutputFormat bsd (see below).
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj);
- if (OutputFormat == darwin && MachO) {
+ // If OutputFormat is darwin or we are printing Mach-O symbols in hex and
+ // we have a MachOObjectFile, call darwinPrintSymbol to print as darwin's
+ // 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);
+ if ((OutputFormat == darwin || FormatMachOasHex) && MachO) {
darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks);
} else if (OutputFormat == posix) {
outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr
@@ -487,7 +624,10 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) {
if (I->Size != UnknownAddressOrSize)
outs() << ' ';
}
- outs() << I->TypeChar << " " << I->Name << "\n";
+ outs() << I->TypeChar;
+ if (I->TypeChar == '-' && MachO)
+ darwinPrintStab(MachO, I);
+ outs() << " " << I->Name << "\n";
} else if (OutputFormat == sysv) {
std::string PaddedName(I->Name);
while (PaddedName.length() < 20)
@@ -549,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);
@@ -566,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 '?';
@@ -574,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';
}
@@ -612,6 +748,9 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) {
DataRefImpl Symb = I->getRawDataRefImpl();
uint8_t NType = getNType(Obj, Symb);
+ if (NType & MachO::N_STAB)
+ return '-';
+
switch (NType & MachO::N_TYPE) {
case MachO::N_ABS:
return 's';
@@ -654,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();
@@ -663,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';
@@ -693,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);
@@ -714,32 +853,90 @@ static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) {
return Ret;
}
-static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) {
- basic_symbol_iterator IBegin = Obj->symbol_begin();
- basic_symbol_iterator IEnd = Obj->symbol_end();
+// getNsectForSegSect() is used to implement the Mach-O "-s segname sectname"
+// option to dump only those symbols from that section in a Mach-O file.
+// It is called once for each Mach-O file from dumpSymbolNamesFromObject()
+// to get the section number for that named section from the command line
+// arguments. It returns the section number for that section in the Mach-O
+// file or zero it is not present.
+static unsigned getNsectForSegSect(MachOObjectFile *Obj) {
+ unsigned Nsect = 1;
+ for (section_iterator I = Obj->section_begin(), E = Obj->section_end();
+ I != E; ++I) {
+ DataRefImpl Ref = I->getRawDataRefImpl();
+ StringRef SectionName;
+ Obj->getSectionName(Ref, SectionName);
+ StringRef SegmentName = Obj->getSectionFinalSegmentName(Ref);
+ if (SegmentName == SegSect[0] && SectionName == SegSect[1])
+ return Nsect;
+ Nsect++;
+ }
+ return 0;
+}
+
+// getNsectInMachO() is used to implement the Mach-O "-s segname sectname"
+// option to dump only those symbols from that section in a Mach-O file.
+// It is called once for each symbol in a Mach-O file from
+// dumpSymbolNamesFromObject() and returns the section number for that symbol
+// if it is in a section, else it returns 0.
+static unsigned getNsectInMachO(MachOObjectFile &Obj, basic_symbol_iterator I) {
+ DataRefImpl Symb = I->getRawDataRefImpl();
+ if (Obj.is64Bit()) {
+ MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb);
+ if ((STE.n_type & MachO::N_TYPE) == MachO::N_SECT)
+ return STE.n_sect;
+ return 0;
+ }
+ MachO::nlist STE = Obj.getSymbolTableEntry(Symb);
+ if ((STE.n_type & MachO::N_TYPE) == MachO::N_SECT)
+ return STE.n_sect;
+ return 0;
+}
+
+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;
}
std::string NameBuffer;
raw_string_ostream OS(NameBuffer);
+ // 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);
+ if (SegSect.size() != 0 && MachO) {
+ Nsect = getNsectForSegSect(MachO);
+ // If this section is not in the object file no symbols are printed.
+ if (Nsect == 0)
+ return;
+ }
for (basic_symbol_iterator I = IBegin; I != IEnd; ++I) {
uint32_t SymFlags = I->getFlags();
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;
}
}
+ // If a "-s segname sectname" option was specified and this is a Mach-O
+ // file and this section appears in this file, Nsect will be non-zero then
+ // see if this symbol is a symbol from that section and if not skip it.
+ if (Nsect && Nsect != getNsectInMachO(*MachO, I))
+ continue;
NMSymbol S;
S.Size = UnknownAddressOrSize;
S.Address = UnknownAddressOrSize;
@@ -766,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
@@ -809,16 +1006,15 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
MemoryBuffer::getFileOrSTDIN(Filename);
if (error(BufferOrErr.getError(), Filename))
return;
- std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get());
LLVMContext &Context = getGlobalContext();
- ErrorOr<Binary *> BinaryOrErr = createBinary(Buffer, &Context);
+ ErrorOr<std::unique_ptr<Binary>> BinaryOrErr = createBinary(
+ BufferOrErr.get()->getMemBufferRef(), NoLLVMBitcode ? nullptr : &Context);
if (error(BinaryOrErr.getError(), Filename))
return;
- Buffer.release();
- 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();
@@ -846,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.
@@ -872,14 +1070,22 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
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);
+ dumpSymbolNamesFromObject(Obj, false, ArchiveName,
+ ArchitectureName);
} else if (!I->getAsArchive(A)) {
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
@@ -890,14 +1096,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);
}
}
}
@@ -921,9 +1134,11 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
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);
+ ObjectFile &Obj = *ObjOrErr.get();
+ dumpSymbolNamesFromObject(Obj, false);
} else if (!I->getAsArchive(A)) {
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
@@ -934,10 +1149,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);
}
}
}
@@ -953,15 +1171,24 @@ static void dumpSymbolNamesFromFile(std::string &Filename) {
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);
+ 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 (!I->getAsArchive(A)) {
for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
AI != AE; ++AI) {
@@ -970,25 +1197,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);
@@ -1040,13 +1274,16 @@ 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");
}
}
+ if (SegSect.size() != 0 && SegSect.size() != 2)
+ error("bad number of arguments (must be two arguments)",
+ "for the -s option");
+
std::for_each(InputFilenames.begin(), InputFilenames.end(),
dumpSymbolNamesFromFile);
diff --git a/tools/llvm-objdump/Android.mk b/tools/llvm-objdump/Android.mk
index 8105ebf..077e0ee 100644
--- a/tools/llvm-objdump/Android.mk
+++ b/tools/llvm-objdump/Android.mk
@@ -34,14 +34,16 @@ llvm_objdump_STATIC_LIBRARIES := \
libLLVMX86Info \
libLLVMX86Desc \
libLLVMX86AsmParser \
+ libLLVMX86CodeGen \
libLLVMX86AsmPrinter \
libLLVMX86Utils \
libLLVMX86Disassembler \
libLLVMAsmPrinter \
+ libLLVMCodeGen \
+ libLLVMAnalysis \
libLLVMTarget \
libLLVMObject \
libLLVMMCParser \
- libLLVMMCAnalysis \
libLLVMMC \
libLLVMMCDisassembler \
libLLVMBitReader \
diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt
index d63602b..61bf3b3 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 39d8e8e..4a20b91 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 d9c09b6..d16c501 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 4b46ac4..3a28703 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -12,16 +12,17 @@
//===----------------------------------------------------------------------===//
#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"
@@ -30,41 +31,70 @@
#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/GraphWriter.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#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<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 const Target *GetTarget(const MachOObjectFile *MachOObj) {
+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 +123,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,
@@ -165,20 +217,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;
}
@@ -195,29 +245,1371 @@ static void DisassembleInputMachO2(StringRef Filename,
MachOObjectFile *MachOOF);
void llvm::DisassembleInputMachO(StringRef Filename) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buff =
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
MemoryBuffer::getFileOrSTDIN(Filename);
- if (std::error_code EC = Buff.getError()) {
+ if (std::error_code EC = BuffOrErr.getError()) {
errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n";
return;
}
+ std::unique_ptr<MemoryBuffer> Buff = std::move(BuffOrErr.get());
- std::unique_ptr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile *>(
- ObjectFile::createMachOObjectFile(Buff.get()).get()));
+ std::unique_ptr<MachOObjectFile> MachOOF = std::move(
+ ObjectFile::createMachOObjectFile(Buff.get()->getMemBufferRef()).get());
DisassembleInputMachO2(Filename, MachOOF.get());
}
+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;
+
+ 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);
+
+ return name;
+}
+
+// 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 DisassembleInputMachO2(StringRef Filename,
MachOObjectFile *MachOOF) {
- const Target *TheTarget = GetTarget(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 +1617,80 @@ 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);
- if (!InstrAnalysis || !AsmInfo || !STI || !DisAsm || !IP) {
+ if (!AsmInfo || !STI || !DisAsm || !IP) {
errs() << "error: couldn't initialize disassembler for target "
<< TripleName << '\n';
return;
}
+ // 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;
+ }
+
outs() << '\n' << Filename << ":\n\n";
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 +1709,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 +1734,30 @@ 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));
}
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 +1766,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 +1788,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 +1841,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 +1855,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 +1869,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 +1952,1924 @@ 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
+ }
}
}
}
+ 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";
+ case MachO::CPU_SUBTYPE_X86_64_ALL:
+ outs() << " ALL";
+ break;
+ case MachO::CPU_SUBTYPE_X86_64_H:
+ outs() << " Haswell";
+ outs() << format(" %10d", cpusubtype & ~MachO::CPU_SUBTYPE_MASK);
+ 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" PRIx32, vmaddr) << "\n";
+ outs() << " vmsize " << format("0x%08" PRIx32, 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" PRIx32, addr) << "\n";
+ outs() << " size " << format("0x%08" PRIx32, 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 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\n";
+ 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 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) {
+ 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_64 S = Obj->getSection64(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_VERSION_MIN_MACOSX) {
+ 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_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 c3601eb..4616b78 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 309bf23..8903bff 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"
@@ -85,6 +79,21 @@ static cl::opt<bool>
SymbolTable("t", cl::desc("Display the symbol table"));
static cl::opt<bool>
+ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
+
+static cl::opt<bool>
+Rebase("rebase", cl::desc("Display mach-o rebasing info"));
+
+static cl::opt<bool>
+Bind("bind", cl::desc("Display mach-o binding info"));
+
+static cl::opt<bool>
+LazyBind("lazy-bind", cl::desc("Display mach-o lazy binding info"));
+
+static cl::opt<bool>
+WeakBind("weak-bind", cl::desc("Display mach-o weak binding info"));
+
+static cl::opt<bool>
MachOOpt("macho", cl::desc("Use MachO specific object file parser"));
static cl::alias
MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt));
@@ -94,6 +103,12 @@ llvm::TripleName("triple", cl::desc("Target triple to disassemble for, "
"see -version for available targets"));
cl::opt<std::string>
+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", cl::desc("Target arch to disassemble for, "
"see -version for available targets"));
@@ -107,15 +122,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"));
@@ -132,20 +148,6 @@ 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;
bool llvm::error(std::error_code EC) {
@@ -191,53 +193,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 +258,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 +281,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 +293,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 +307,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 +373,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 +386,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 +405,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 +455,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 +497,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,25 +515,24 @@ 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.getContents(Contents)))
- 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) {
+ if (Section.isBSS()) {
outs() << format("<skipping contents of bss section at [%04" PRIx64
- ", %04" PRIx64 ")>\n", BaseAddr,
- BaseAddr + Contents.size());
+ ", %04" PRIx64 ")>\n",
+ BaseAddr, BaseAddr + Size);
continue;
}
+ if (error(Section.getContents(Contents)))
+ continue;
+
// Dump out the content as hex and printable ascii characters.
for (std::size_t addr = 0, end = Contents.size(); addr < end; addr += 16) {
outs() << format(" %04" PRIx64 " ", BaseAddr + addr);
@@ -670,34 +560,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)
@@ -705,18 +593,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";
@@ -809,10 +697,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;
+ }
+}
+
+static void 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;
+ }
+}
+
+static void 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;
+ }
+}
+
+static void 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;
+ }
+}
+
+static void 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;
+ }
+}
+
+static void 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;
}
}
@@ -822,6 +767,8 @@ static void printPrivateFileHeader(const ObjectFile *o) {
printELFFileHeader(o);
} else if (o->isCOFF()) {
printCOFFFileHeader(o);
+ } else if (o->isMachO()) {
+ printMachOFileHeader(o);
}
}
@@ -844,6 +791,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;
@@ -880,16 +837,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()) {
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";
@@ -925,7 +882,12 @@ int main(int argc, char **argv) {
&& !SectionContents
&& !SymbolTable
&& !UnwindInfo
- && !PrivateHeaders) {
+ && !PrivateHeaders
+ && !ExportsTrie
+ && !Rebase
+ && !Bind
+ && !LazyBind
+ && !WeakBind) {
cl::PrintHelpMessage();
return 2;
}
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index 80f8f58..ef1509f 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -7,23 +7,26 @@
//
//===----------------------------------------------------------------------===//
-#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> NoShowRawInsn;
// Various helper functions.
bool error(std::error_code ec);
@@ -31,8 +34,15 @@ bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b);
void DumpBytes(StringRef bytes);
void DisassembleInputMachO(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);
} // end namespace llvm
diff --git a/tools/llvm-profdata/CMakeLists.txt b/tools/llvm-profdata/CMakeLists.txt
index 3529114..0e330fd 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 ba88aad..e977799 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -14,6 +14,9 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/ProfileData/InstrProfWriter.h"
+#include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ProfileData/SampleProfWriter.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -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::desc("Output file"));
- cl::alias OutputFilenameA("o", cl::desc("Alias for --output"), cl::Required,
- 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.h b/tools/llvm-readobj/ARMAttributeParser.h
index c286251..f924c83 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 7608cfb..b15421d 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 b486e4a..ede36d1 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -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 740c8b5..274ef11 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 7842cd4..5276428 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,49 @@ 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 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 +328,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 +358,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 +388,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 +439,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 +475,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 +508,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 +539,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 +592,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 +601,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 +630,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 +739,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 +749,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 +794,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 +801,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 +827,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 +861,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 +887,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 +905,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 +967,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 +975,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 +995,113 @@ 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::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 5df51e2..d68c786 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -407,6 +407,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) {
switch (Type) {
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
+ LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
}
}
@@ -603,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()));
@@ -675,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 a078f5c..7e6f780 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 81ce408..f3e24bb 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 a5e5cf8..7e8fdad 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 f80a28b..a34e091 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,11 @@ public:
// Only implemented for MIPS ELF at this time.
virtual void printMipsPLTGOT() { }
+ // Only implemented for PE/COFF.
+ virtual void printCOFFImports() { }
+ virtual void printCOFFDirectives() { }
+ virtual void printCOFFBaseReloc() { }
+
protected:
StreamWriter& W;
};
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
index 04b38fb..2fc53ee 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 9ce4d39..a80df9c 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 8d2a997..d08f186 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,20 @@ 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-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 +173,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 +225,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 +254,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 +280,12 @@ static void dumpObject(const ObjectFile *Obj) {
if (isMipsArch(Obj->getArch()) && Obj->isELF())
if (opts::MipsPLTGOT)
Dumper->printMipsPLTGOT();
+ if (opts::COFFImports)
+ Dumper->printCOFFImports();
+ if (opts::COFFDirectives)
+ Dumper->printCOFFDirectives();
+ if (opts::COFFBaseRelocs)
+ Dumper->printCOFFBaseReloc();
}
@@ -287,16 +319,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 0413948..1c33417 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/Android.mk b/tools/llvm-rtdyld/Android.mk
index 6f902d3..4f4fb4c 100644
--- a/tools/llvm-rtdyld/Android.mk
+++ b/tools/llvm-rtdyld/Android.mk
@@ -39,6 +39,7 @@ llvm_rtdyld_STATIC_LIBRARIES := \
libLLVMX86Disassembler \
libLLVMDebugInfo \
libLLVMExecutionEngine \
+ libLLVMCodeGen \
libLLVMObject \
libLLVMMC \
libLLVMMCParser \
@@ -46,6 +47,7 @@ llvm_rtdyld_STATIC_LIBRARIES := \
libLLVMBitReader \
libLLVMCore \
libLLVMSupport \
+ libLLVMMCDisassembler \
include $(CLEAR_VARS)
diff --git a/tools/llvm-rtdyld/LLVMBuild.txt b/tools/llvm-rtdyld/LLVMBuild.txt
index b36d13c..c4ed49b 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 fabdd68..9de753e 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 45734f4..87d381e 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -34,6 +34,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
+#include <list>
#include <system_error>
using namespace llvm;
@@ -78,6 +79,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
@@ -183,8 +209,8 @@ static int printLineInfoForInput() {
std::unique_ptr<ObjectImage> LoadedObject;
// Load the object file
- LoadedObject.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
+ LoadedObject = Dyld.loadObject(
+ llvm::make_unique<ObjectBuffer>(std::move(*InputBuffer)));
if (!LoadedObject) {
return Error(Dyld.getErrorString());
}
@@ -193,7 +219,7 @@ static int printLineInfoForInput() {
Dyld.resolveRelocations();
std::unique_ptr<DIContext> Context(
- DIContext::getDWARFContext(LoadedObject->getObjectFile()));
+ DIContext::getDWARFContext(*LoadedObject->getObjectFile()));
// Use symbol info to iterate functions in the object.
for (object::symbol_iterator I = LoadedObject->begin_symbols(),
@@ -244,8 +270,8 @@ static int executeInput() {
return Error("unable to read input: '" + EC.message() + "'");
std::unique_ptr<ObjectImage> LoadedObject;
// Load the object file
- LoadedObject.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
+ LoadedObject = Dyld.loadObject(
+ llvm::make_unique<ObjectBuffer>(std::move(*InputBuffer)));
if (!LoadedObject) {
return Error(Dyld.getErrorString());
}
@@ -300,6 +326,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 +501,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())
@@ -360,19 +517,30 @@ static int linkAndVerify() {
std::unique_ptr<ObjectImage> LoadedObject;
// Load the object file
- LoadedObject.reset(
- Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release())));
+ LoadedObject = Dyld.loadObject(
+ llvm::make_unique<ObjectBuffer>(std::move(*InputBuffer)));
if (!LoadedObject) {
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 0000000..100c184
--- /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)
+ 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 0000000..40b4f66
--- /dev/null
+++ b/tools/llvm-shlib/libllvm.cpp
@@ -0,0 +1,13 @@
+//===-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.
+//
+//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp
index 50b5220..59a5f20 100644
--- a/tools/llvm-size/llvm-size.cpp
+++ b/tools/llvm-size/llvm-size.cpp
@@ -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.
@@ -692,7 +675,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 +714,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 23d3b63..21a79e3 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 c1d39ef..36061d7 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 45febe0..ff848fc 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 29db172..d554022 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 0000000..4fe205b
--- /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 0000000..c5de895
--- /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 0000000..fd8bb18
--- /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 0000000..6a3cbff
--- /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 0000000..596c64c
--- /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 0000000..a21acae
--- /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 0000000..62f7557
--- /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 71391b7..559b22b 100644
--- a/tools/lto/CMakeLists.txt
+++ b/tools/lto/CMakeLists.txt
@@ -1,14 +1,11 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
- Core
LTO
MC
MCDisassembler
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 a4fe9ac..530c05a 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 b401f9a..ef37c90 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -32,6 +32,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 +150,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) {
@@ -205,7 +227,7 @@ lto_code_gen_t lto_codegen_create(void) {
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) {
@@ -222,10 +244,6 @@ void lto_codegen_set_cpu(lto_code_gen_t cg, const char *cpu) {
return unwrap(cg)->setCpu(cpu);
}
-void lto_codegen_set_attr(lto_code_gen_t cg, const char *attr) {
- return unwrap(cg)->setAttr(attr);
-}
-
void lto_codegen_set_assembler_path(lto_code_gen_t cg, const char *path) {
// In here only for backwards compatibility. We use MC now.
}
@@ -256,7 +274,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) {
@@ -265,8 +284,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/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp
index 7600979..aac720d 100644
--- a/tools/macho-dump/macho-dump.cpp
+++ b/tools/macho-dump/macho-dump.cpp
@@ -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;
}
@@ -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 b7be71d..4f471e5 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 9880fb2..6e321e3 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 0000000..05b59a2
--- /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 0000000..eec4f18
--- /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 b0bc943..c1afae2 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 f167ed5..3cdac5c 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 0074128..abef8af 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 4657f0d..982f59e 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 95f393d..6cbef69 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 fed4533..5baa644 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 8b53ee7..d770ce1 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 944314a..b64096d 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 6d81110..643ab7b 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/Android.mk b/tools/opt/Android.mk
index 6f3f48d..fc3c8d0 100644
--- a/tools/opt/Android.mk
+++ b/tools/opt/Android.mk
@@ -60,6 +60,7 @@ llvm_opt_STATIC_LIBRARIES := \
libLLVMMC \
libLLVMMCParser \
libLLVMObject \
+ libLLVMProfileData \
libLLVMCore \
libLLVMAsmParser \
libLLVMOption \
diff --git a/tools/opt/BreakpointPrinter.cpp b/tools/opt/BreakpointPrinter.cpp
index 44f4a11..3cbc0ae 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.h b/tools/opt/NewPMDriver.h
index 3661d3e..f977bac 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/opt.cpp b/tools/opt/opt.cpp
index 6ba6340..cdd22e4 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);
}
//===----------------------------------------------------------------------===//
@@ -355,7 +321,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,8 +339,7 @@ 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()) {
Err.print(argv[0], errs());
@@ -395,11 +361,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;
}
}
@@ -452,7 +417,7 @@ int main(int argc, char **argv) {
}
if (DL)
- Passes.add(new DataLayoutPass(M.get()));
+ Passes.add(new DataLayoutPass());
Triple ModuleTriple(M->getTargetTriple());
TargetMachine *Machine = nullptr;
@@ -468,7 +433,7 @@ int main(int argc, char **argv) {
if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) {
FPasses.reset(new FunctionPassManager(M.get()));
if (DL)
- FPasses->add(new DataLayoutPass(M.get()));
+ FPasses->add(new DataLayoutPass());
if (TM.get())
TM->addAnalysisPasses(*FPasses);
@@ -480,11 +445,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;
}
}
@@ -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;
diff --git a/tools/verify-uselistorder/CMakeLists.txt b/tools/verify-uselistorder/CMakeLists.txt
new file mode 100644
index 0000000..260a95a
--- /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 0000000..23957c1
--- /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 0000000..90d2aa8
--- /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 0000000..992a5b0
--- /dev/null
+++ b/tools/verify-uselistorder/verify-uselistorder.cpp
@@ -0,0 +1,562 @@
+//===- 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());
+
+ // 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());
+
+ // 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 5e63dfb..52e9df4 100644
--- a/tools/yaml2obj/CMakeLists.txt
+++ b/tools/yaml2obj/CMakeLists.txt
@@ -1,9 +1,10 @@
set(LLVM_LINK_COMPONENTS
+ MC
Object
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 8801795..912f0e3 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 c772db9..6983e9d 100644
--- a/tools/yaml2obj/yaml2coff.cpp
+++ b/tools/yaml2obj/yaml2coff.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Object/COFFYAML.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SourceMgr.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 6eeecae..44c8c12 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 945fad1..375cd89 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 086f641..7290a9a 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;