aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-05-27 18:44:32 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-05-27 18:44:32 +0000
commit5a5ac124e1efaf208671f01c46edb15f29ed2a0b (patch)
treea6140557876943cdd800ee997c9317283394b22c /tools
parentf03b5bed27d0d2eafd68562ce14f8b5e3f1f0801 (diff)
downloadsrc-5a5ac124e1efaf208671f01c46edb15f29ed2a0b.tar.gz
src-5a5ac124e1efaf208671f01c46edb15f29ed2a0b.zip
Vendor import of llvm trunk r238337:vendor/llvm/llvm-trunk-r238337
Notes
Notes: svn path=/vendor/llvm/dist/; revision=283625 svn path=/vendor/llvm/llvm-trunk-r238337/; revision=283626; tag=vendor/llvm/llvm-trunk-r238337
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt4
-rw-r--r--tools/LLVMBuild.txt5
-rw-r--r--tools/Makefile2
-rw-r--r--tools/bugpoint-passes/TestPasses.cpp26
-rw-r--r--tools/bugpoint/BugDriver.cpp26
-rw-r--r--tools/bugpoint/CMakeLists.txt2
-rw-r--r--tools/bugpoint/CrashDebugger.cpp91
-rw-r--r--tools/bugpoint/ExtractFunction.cpp6
-rw-r--r--tools/bugpoint/Miscompilation.cpp17
-rw-r--r--tools/bugpoint/OptimizerDriver.cpp11
-rw-r--r--tools/bugpoint/ToolRunner.h2
-rw-r--r--tools/bugpoint/bugpoint.cpp8
-rw-r--r--tools/dsymutil/CMakeLists.txt4
-rw-r--r--tools/dsymutil/DebugMap.cpp26
-rw-r--r--tools/dsymutil/DebugMap.h28
-rw-r--r--tools/dsymutil/DwarfLinker.cpp2526
-rw-r--r--tools/dsymutil/LLVMBuild.txt2
-rw-r--r--tools/dsymutil/MachODebugMapParser.cpp37
-rw-r--r--tools/dsymutil/Makefile2
-rw-r--r--tools/dsymutil/dsymutil.cpp32
-rw-r--r--tools/dsymutil/dsymutil.h10
-rw-r--r--tools/gold/CMakeLists.txt3
-rw-r--r--tools/gold/gold-plugin.cpp97
-rw-r--r--tools/llc/CMakeLists.txt4
-rw-r--r--tools/llc/llc.cpp68
-rw-r--r--tools/lli/CMakeLists.txt7
-rw-r--r--tools/lli/LLVMBuild.txt2
-rw-r--r--tools/lli/Makefile4
-rw-r--r--tools/lli/OrcLazyJIT.cpp148
-rw-r--r--tools/lli/OrcLazyJIT.h164
-rw-r--r--tools/lli/RemoteMemoryManager.cpp1
-rw-r--r--tools/lli/RemoteMemoryManager.h2
-rw-r--r--tools/lli/RemoteTargetExternal.h2
-rw-r--r--tools/lli/lli.cpp56
-rw-r--r--tools/llvm-ar/llvm-ar.cpp2
-rw-r--r--tools/llvm-as/llvm-as.cpp17
-rw-r--r--tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp39
-rw-r--r--tools/llvm-config/CMakeLists.txt2
-rw-r--r--tools/llvm-config/llvm-config.cpp8
-rw-r--r--tools/llvm-cov/CMakeLists.txt1
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp73
-rw-r--r--tools/llvm-cov/CoverageReport.cpp40
-rw-r--r--tools/llvm-cov/CoverageReport.h11
-rw-r--r--tools/llvm-cov/CoverageSummary.cpp64
-rw-r--r--tools/llvm-cov/CoverageSummary.h45
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.cpp25
-rw-r--r--tools/llvm-cov/CoverageSummaryInfo.h53
-rw-r--r--tools/llvm-cov/RenderingSupport.h2
-rw-r--r--tools/llvm-cov/SourceCoverageView.cpp46
-rw-r--r--tools/llvm-cov/SourceCoverageView.h7
-rw-r--r--tools/llvm-cov/gcov.cpp9
-rw-r--r--tools/llvm-cov/llvm-cov.cpp34
-rw-r--r--tools/llvm-cxxdump/CMakeLists.txt (renamed from tools/llvm-vtabledump/CMakeLists.txt)4
-rw-r--r--tools/llvm-cxxdump/Error.cpp (renamed from tools/llvm-vtabledump/Error.cpp)22
-rw-r--r--tools/llvm-cxxdump/Error.h (renamed from tools/llvm-vtabledump/Error.h)18
-rw-r--r--tools/llvm-cxxdump/LLVMBuild.txt (renamed from tools/llvm-vtabledump/LLVMBuild.txt)4
-rw-r--r--tools/llvm-cxxdump/Makefile (renamed from tools/llvm-vtabledump/Makefile)4
-rw-r--r--tools/llvm-cxxdump/llvm-cxxdump.cpp (renamed from tools/llvm-vtabledump/llvm-vtabledump.cpp)161
-rw-r--r--tools/llvm-cxxdump/llvm-cxxdump.h (renamed from tools/llvm-vtabledump/llvm-vtabledump.h)8
-rw-r--r--tools/llvm-dis/llvm-dis.cpp54
-rw-r--r--tools/llvm-dwarfdump/CMakeLists.txt2
-rw-r--r--tools/llvm-dwarfdump/LLVMBuild.txt2
-rw-r--r--tools/llvm-dwarfdump/Makefile2
-rw-r--r--tools/llvm-dwarfdump/llvm-dwarfdump.cpp3
-rw-r--r--tools/llvm-extract/llvm-extract.cpp20
-rw-r--r--tools/llvm-go/llvm-go.go39
-rw-r--r--tools/llvm-jitlistener/Makefile54
-rw-r--r--tools/llvm-jitlistener/llvm-jitlistener.cpp3
-rw-r--r--tools/llvm-link/llvm-link.cpp70
-rw-r--r--tools/llvm-lto/llvm-lto.cpp51
-rw-r--r--tools/llvm-mc/CMakeLists.txt6
-rw-r--r--tools/llvm-mc/llvm-mc.cpp32
-rw-r--r--tools/llvm-nm/llvm-nm.cpp132
-rw-r--r--tools/llvm-objdump/CMakeLists.txt2
-rw-r--r--tools/llvm-objdump/LLVMBuild.txt2
-rw-r--r--tools/llvm-objdump/MachODump.cpp4542
-rw-r--r--tools/llvm-objdump/Makefile2
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp97
-rw-r--r--tools/llvm-objdump/llvm-objdump.h24
-rw-r--r--tools/llvm-pdbdump/BuiltinDumper.cpp87
-rw-r--r--tools/llvm-pdbdump/BuiltinDumper.h30
-rw-r--r--tools/llvm-pdbdump/CMakeLists.txt18
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.cpp190
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.h62
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.cpp140
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.h39
-rw-r--r--tools/llvm-pdbdump/EnumDumper.cpp52
-rw-r--r--tools/llvm-pdbdump/EnumDumper.h30
-rw-r--r--tools/llvm-pdbdump/ExternalSymbolDumper.cpp40
-rw-r--r--tools/llvm-pdbdump/ExternalSymbolDumper.h32
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.cpp254
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.h42
-rw-r--r--tools/llvm-pdbdump/LLVMBuild.txt23
-rw-r--r--tools/llvm-pdbdump/LinePrinter.cpp124
-rw-r--r--tools/llvm-pdbdump/LinePrinter.h89
-rw-r--r--tools/llvm-pdbdump/Makefile17
-rw-r--r--tools/llvm-pdbdump/TypeDumper.cpp97
-rw-r--r--tools/llvm-pdbdump/TypeDumper.h34
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.cpp79
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.h37
-rw-r--r--tools/llvm-pdbdump/VariableDumper.cpp170
-rw-r--r--tools/llvm-pdbdump/VariableDumper.h41
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.cpp284
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.h32
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp25
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp34
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp190
-rw-r--r--tools/llvm-readobj/MachODumper.cpp25
-rw-r--r--tools/llvm-readobj/ObjDumper.h1
-rw-r--r--tools/llvm-readobj/StreamWriter.h14
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp36
-rw-r--r--tools/llvm-readobj/llvm-readobj.h3
-rw-r--r--tools/llvm-rtdyld/CMakeLists.txt2
-rw-r--r--tools/llvm-rtdyld/Makefile2
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp90
-rw-r--r--tools/llvm-shlib/CMakeLists.txt67
-rw-r--r--tools/llvm-size/llvm-size.cpp2
-rw-r--r--tools/llvm-stress/CMakeLists.txt2
-rw-r--r--tools/llvm-stress/llvm-stress.cpp5
-rw-r--r--tools/llvm-symbolizer/CMakeLists.txt3
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.cpp36
-rw-r--r--tools/llvm-symbolizer/LLVMSymbolize.h15
-rw-r--r--tools/llvm-symbolizer/Makefile2
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp19
-rw-r--r--tools/lto/lto.cpp72
-rw-r--r--tools/lto/lto.exports5
-rw-r--r--tools/obj2yaml/elf2yaml.cpp83
-rw-r--r--tools/opt/BreakpointPrinter.cpp28
-rw-r--r--tools/opt/CMakeLists.txt4
-rw-r--r--tools/opt/LLVMBuild.txt2
-rw-r--r--tools/opt/Makefile2
-rw-r--r--tools/opt/NewPMDriver.cpp27
-rw-r--r--tools/opt/NewPMDriver.h8
-rw-r--r--tools/opt/PassRegistry.def65
-rw-r--r--tools/opt/Passes.cpp397
-rw-r--r--tools/opt/Passes.h78
-rw-r--r--tools/opt/opt.cpp139
-rw-r--r--tools/verify-uselistorder/verify-uselistorder.cpp55
-rw-r--r--tools/yaml2obj/yaml2coff.cpp7
-rw-r--r--tools/yaml2obj/yaml2elf.cpp106
-rw-r--r--tools/yaml2obj/yaml2obj.cpp3
141 files changed, 11092 insertions, 1868 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 7e9938119f5d..7859b49c9de7 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -37,7 +37,7 @@ add_llvm_tool_subdirectory(llvm-readobj)
add_llvm_tool_subdirectory(llvm-rtdyld)
add_llvm_tool_subdirectory(llvm-dwarfdump)
add_llvm_tool_subdirectory(dsymutil)
-add_llvm_tool_subdirectory(llvm-vtabledump)
+add_llvm_tool_subdirectory(llvm-cxxdump)
if( LLVM_USE_INTEL_JITEVENTS )
add_llvm_tool_subdirectory(llvm-jitlistener)
else()
@@ -61,6 +61,8 @@ add_llvm_tool_subdirectory(yaml2obj)
add_llvm_tool_subdirectory(llvm-go)
+add_llvm_tool_subdirectory(llvm-pdbdump)
+
if(NOT CYGWIN AND LLVM_ENABLE_PIC)
add_llvm_tool_subdirectory(lto)
add_llvm_tool_subdirectory(llvm-lto)
diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt
index 53d4ffc28dc1..6a838b72ecff 100644
--- a/tools/LLVMBuild.txt
+++ b/tools/LLVMBuild.txt
@@ -16,7 +16,10 @@
;===------------------------------------------------------------------------===;
[common]
-subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-profdata llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
+subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov
+ llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link
+ llvm-lto llvm-mc llvm-nm llvm-objdump llvm-pdbdump llvm-profdata llvm-rtdyld
+ llvm-size macho-dump opt llvm-mcmarkup verify-uselistorder dsymutil
[component_0]
type = Group
diff --git a/tools/Makefile b/tools/Makefile
index b559edacd52d..d8534866c3d3 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -33,7 +33,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \
macho-dump llvm-objdump llvm-readobj llvm-rtdyld \
llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \
llvm-profdata llvm-symbolizer obj2yaml yaml2obj llvm-c-test \
- llvm-vtabledump verify-uselistorder dsymutil
+ llvm-cxxdump verify-uselistorder dsymutil llvm-pdbdump
# If Intel JIT Events support is configured, build an extra tool to test it.
ifeq ($(USE_INTEL_JITEVENTS), 1)
diff --git a/tools/bugpoint-passes/TestPasses.cpp b/tools/bugpoint-passes/TestPasses.cpp
index ed54e9f8dfc7..6979d0345ee6 100644
--- a/tools/bugpoint-passes/TestPasses.cpp
+++ b/tools/bugpoint-passes/TestPasses.cpp
@@ -68,8 +68,32 @@ namespace {
}
};
}
-
+
char DeleteCalls::ID = 0;
static RegisterPass<DeleteCalls>
Y("bugpoint-deletecalls",
"BugPoint Test Pass - Intentionally 'misoptimize' CallInsts");
+
+namespace {
+ /// CrashOnDeclFunc - This pass is used to test bugpoint. It intentionally
+ /// crash if the module has an undefined function (ie a function that is
+ /// defined in an external module).
+ class CrashOnDeclFunc : public ModulePass {
+ public:
+ static char ID; // Pass ID, replacement for typeid
+ CrashOnDeclFunc() : ModulePass(ID) {}
+ private:
+ bool runOnModule(Module &M) override {
+ for (auto &F : M.functions()) {
+ if (F.isDeclaration())
+ abort();
+ }
+ return false;
+ }
+ };
+}
+
+char CrashOnDeclFunc::ID = 0;
+static RegisterPass<CrashOnDeclFunc>
+ Z("bugpoint-crash-decl-funcs",
+ "BugPoint Test Pass - Intentionally crash on declared functions");
diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp
index b8be17e44dd2..43f4c2963fc3 100644
--- a/tools/bugpoint/BugDriver.cpp
+++ b/tools/bugpoint/BugDriver.cpp
@@ -16,6 +16,7 @@
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Pass.h"
@@ -86,23 +87,28 @@ std::unique_ptr<Module> llvm::parseInputFile(StringRef Filename,
LLVMContext &Ctxt) {
SMDiagnostic Err;
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
- if (!Result)
+ if (!Result) {
Err.print("bugpoint", errs());
+ return Result;
+ }
+
+ if (verifyModule(*Result, &errs())) {
+ errs() << "bugpoint: " << Filename << ": error: input module is broken!\n";
+ return std::unique_ptr<Module>();
+ }
// If we don't have an override triple, use the first one to configure
// bugpoint, or use the host triple if none provided.
- if (Result) {
- if (TargetTriple.getTriple().empty()) {
- Triple TheTriple(Result->getTargetTriple());
+ if (TargetTriple.getTriple().empty()) {
+ Triple TheTriple(Result->getTargetTriple());
- if (TheTriple.getTriple().empty())
- TheTriple.setTriple(sys::getDefaultTargetTriple());
+ if (TheTriple.getTriple().empty())
+ TheTriple.setTriple(sys::getDefaultTargetTriple());
- TargetTriple.setTriple(TheTriple.getTriple());
- }
-
- Result->setTargetTriple(TargetTriple.getTriple()); // override the triple
+ TargetTriple.setTriple(TheTriple.getTriple());
}
+
+ Result->setTargetTriple(TargetTriple.getTriple()); // override the triple
return Result;
}
diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt
index d71e097918c4..daf502e16ccd 100644
--- a/tools/bugpoint/CMakeLists.txt
+++ b/tools/bugpoint/CMakeLists.txt
@@ -31,7 +31,7 @@ add_llvm_tool(bugpoint
ToolRunner.cpp
bugpoint.cpp
)
-set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1)
+export_executable_symbols(bugpoint)
if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
target_link_libraries(bugpoint Polly)
diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp
index bac948aaf3ab..6f41d3030d00 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -19,11 +19,11 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ValueSymbolTable.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileUtilities.h"
#include "llvm/Transforms/Scalar.h"
@@ -40,6 +40,15 @@ namespace {
NoGlobalRM ("disable-global-remove",
cl::desc("Do not remove global variables"),
cl::init(false));
+
+ cl::opt<bool>
+ ReplaceFuncsWithNull("replace-funcs-with-null",
+ cl::desc("When stubbing functions, replace all uses will null"),
+ cl::init(false));
+ cl::opt<bool>
+ DontReducePassList("disable-pass-list-reduction",
+ cl::desc("Skip pass list reduction steps"),
+ cl::init(false));
}
namespace llvm {
@@ -194,6 +203,29 @@ namespace {
};
}
+static void RemoveFunctionReferences(Module *M, const char* Name) {
+ auto *UsedVar = M->getGlobalVariable(Name, true);
+ if (!UsedVar || !UsedVar->hasInitializer()) return;
+ if (isa<ConstantAggregateZero>(UsedVar->getInitializer())) {
+ assert(UsedVar->use_empty());
+ UsedVar->eraseFromParent();
+ return;
+ }
+ auto *OldUsedVal = cast<ConstantArray>(UsedVar->getInitializer());
+ std::vector<Constant*> Used;
+ for(Value *V : OldUsedVal->operand_values()) {
+ Constant *Op = cast<Constant>(V->stripPointerCasts());
+ if(!Op->isNullValue()) {
+ Used.push_back(cast<Constant>(V));
+ }
+ }
+ auto *NewValElemTy = OldUsedVal->getType()->getElementType();
+ auto *NewValTy = ArrayType::get(NewValElemTy, Used.size());
+ auto *NewUsedVal = ConstantArray::get(NewValTy, Used);
+ UsedVar->mutateType(NewUsedVal->getType()->getPointerTo());
+ UsedVar->setInitializer(NewUsedVal);
+}
+
bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
// If main isn't present, claim there is no problem.
if (KeepMain && std::find(Funcs.begin(), Funcs.end(),
@@ -218,13 +250,53 @@ bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) {
outs() << "Checking for crash with only these functions: ";
PrintFunctionList(Funcs);
outs() << ": ";
+ if (!ReplaceFuncsWithNull) {
+ // Loop over and delete any functions which we aren't supposed to be playing
+ // with...
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
+ if (!I->isDeclaration() && !Functions.count(I))
+ DeleteFunctionBody(I);
+ } else {
+ std::vector<GlobalValue*> ToRemove;
+ // First, remove aliases to functions we're about to purge.
+ for (GlobalAlias &Alias : M->aliases()) {
+ Constant *Root = Alias.getAliasee()->stripPointerCasts();
+ Function *F = dyn_cast<Function>(Root);
+ if (F) {
+ if (Functions.count(F))
+ // We're keeping this function.
+ continue;
+ } else if (Root->isNullValue()) {
+ // This referenced a globalalias that we've already replaced,
+ // so we still need to replace this alias.
+ } else if (!F) {
+ // Not a function, therefore not something we mess with.
+ continue;
+ }
- // Loop over and delete any functions which we aren't supposed to be playing
- // with...
- for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
- if (!I->isDeclaration() && !Functions.count(I))
- DeleteFunctionBody(I);
+ PointerType *Ty = cast<PointerType>(Alias.getType());
+ Constant *Replacement = ConstantPointerNull::get(Ty);
+ Alias.replaceAllUsesWith(Replacement);
+ ToRemove.push_back(&Alias);
+ }
+
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
+ if (!I->isDeclaration() && !Functions.count(I)) {
+ PointerType *Ty = cast<PointerType>(I->getType());
+ Constant *Replacement = ConstantPointerNull::get(Ty);
+ I->replaceAllUsesWith(Replacement);
+ ToRemove.push_back(I);
+ }
+ }
+ for (auto *F : ToRemove) {
+ F->eraseFromParent();
+ }
+
+ // Finally, remove any null members from any global intrinsic.
+ RemoveFunctionReferences(M, "llvm.used");
+ RemoveFunctionReferences(M, "llvm.compiler.used");
+ }
// Try running the hacked up program...
if (TestFn(BD, M)) {
BD.setNewProgram(M); // It crashed, keep the trimmed version...
@@ -296,7 +368,7 @@ bool ReduceCrashingBlocks::TestBlocks(std::vector<const BasicBlock*> &BBs) {
(*SI)->removePredecessor(BB);
TerminatorInst *BBTerm = BB->getTerminator();
-
+
if (!BB->getTerminator()->getType()->isVoidTy())
BBTerm->replaceAllUsesWith(Constant::getNullValue(BBTerm->getType()));
@@ -407,9 +479,8 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
}
// Verify that this is still valid.
- PassManager Passes;
+ legacy::PassManager Passes;
Passes.add(createVerifierPass());
- Passes.add(createDebugInfoVerifierPass());
Passes.run(*M);
// Try running on the hacked up program...
@@ -630,7 +701,7 @@ bool BugDriver::debugOptimizerCrash(const std::string &ID) {
std::string Error;
// Reduce the list of passes which causes the optimizer to crash...
- if (!BugpointIsInterrupted)
+ if (!BugpointIsInterrupted && !DontReducePassList)
ReducePassList(*this).reduceList(PassesToRun, Error);
assert(Error.empty());
diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp
index 34fe53c08112..238cbbc70a03 100644
--- a/tools/bugpoint/ExtractFunction.cpp
+++ b/tools/bugpoint/ExtractFunction.cpp
@@ -17,10 +17,10 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Pass.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
@@ -195,9 +195,9 @@ static Constant *GetTorInit(std::vector<std::pair<Function*, int> > &TorList) {
assert(!TorList.empty() && "Don't create empty tor list!");
std::vector<Constant*> ArrayElts;
Type *Int32Ty = Type::getInt32Ty(TorList[0].first->getContext());
-
+
StructType *STy =
- StructType::get(Int32Ty, TorList[0].first->getType(), NULL);
+ StructType::get(Int32Ty, TorList[0].first->getType(), nullptr);
for (unsigned i = 0, e = TorList.size(); i != e; ++i) {
Constant *Elts[] = {
ConstantInt::get(Int32Ty, TorList[i].second),
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index 8cb45838773a..53631d25c390 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -852,7 +852,8 @@ static void CleanupAndPrepareModules(BugDriver &BD, Module *&Test,
// GetElementPtr *funcName, ulong 0, ulong 0
std::vector<Constant*> GEPargs(2,
Constant::getNullValue(Type::getInt32Ty(F->getContext())));
- Value *GEP = ConstantExpr::getGetElementPtr(funcName, GEPargs);
+ Value *GEP = ConstantExpr::getGetElementPtr(InitArray->getType(),
+ funcName, GEPargs);
std::vector<Value*> ResolverArgs;
ResolverArgs.push_back(GEP);
@@ -975,7 +976,7 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe,
}
if (BD.writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, Safe)) {
- errs() << "Error writing bitcode to `" << SafeModuleBC.str()
+ errs() << "Error writing bitcode to `" << SafeModuleBC
<< "'\nExiting.";
exit(1);
}
@@ -1050,7 +1051,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
}
if (writeProgramToFile(TestModuleBC.str(), TestModuleFD, ToCodeGen)) {
- errs() << "Error writing bitcode to `" << TestModuleBC.str()
+ errs() << "Error writing bitcode to `" << TestModuleBC
<< "'\nExiting.";
exit(1);
}
@@ -1068,7 +1069,7 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
}
if (writeProgramToFile(SafeModuleBC.str(), SafeModuleFD, ToNotCodeGen)) {
- errs() << "Error writing bitcode to `" << SafeModuleBC.str()
+ errs() << "Error writing bitcode to `" << SafeModuleBC
<< "'\nExiting.";
exit(1);
}
@@ -1079,17 +1080,17 @@ bool BugDriver::debugCodeGenerator(std::string *Error) {
outs() << "You can reproduce the problem with the command line: \n";
if (isExecutingJIT()) {
- outs() << " lli -load " << SharedObject << " " << TestModuleBC.str();
+ outs() << " lli -load " << SharedObject << " " << TestModuleBC;
} else {
- outs() << " llc " << TestModuleBC.str() << " -o " << TestModuleBC.str()
+ outs() << " llc " << TestModuleBC << " -o " << TestModuleBC
<< ".s\n";
outs() << " gcc " << SharedObject << " " << TestModuleBC.str()
- << ".s -o " << TestModuleBC.str() << ".exe";
+ << ".s -o " << TestModuleBC << ".exe";
#if defined (HAVE_LINK_R)
outs() << " -Wl,-R.";
#endif
outs() << "\n";
- outs() << " " << TestModuleBC.str() << ".exe";
+ outs() << " " << TestModuleBC << ".exe";
}
for (unsigned i = 0, e = InputArgv.size(); i != e; ++i)
outs() << " " << InputArgv[i];
diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp
index f197cc53926a..344e7b588fb8 100644
--- a/tools/bugpoint/OptimizerDriver.cpp
+++ b/tools/bugpoint/OptimizerDriver.cpp
@@ -18,9 +18,9 @@
#include "BugDriver.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileUtilities.h"
@@ -42,6 +42,11 @@ namespace llvm {
extern cl::opt<std::string> OutputPrefix;
}
+static cl::opt<bool> PreserveBitcodeUseListOrder(
+ "preserve-bc-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM bitcode."),
+ cl::init(true), cl::Hidden);
+
namespace {
// ChildOutput - This option captures the name of the child output file that
// is set up by the parent bugpoint process
@@ -55,7 +60,7 @@ namespace {
/// file. If an error occurs, true is returned.
///
static bool writeProgramToFileAux(tool_output_file &Out, const Module *M) {
- WriteBitcodeToFile(M, Out.os());
+ WriteBitcodeToFile(M, Out.os(), PreserveBitcodeUseListOrder);
Out.os().close();
if (!Out.os().has_error()) {
Out.keep();
@@ -151,7 +156,7 @@ bool BugDriver::runPasses(Module *Program,
tool_output_file InFile(InputFilename, InputFD);
- WriteBitcodeToFile(Program, InFile.os());
+ WriteBitcodeToFile(Program, InFile.os(), PreserveBitcodeUseListOrder);
InFile.os().close();
if (InFile.os().has_error()) {
errs() << "Error writing bitcode file: " << InputFilename << "\n";
diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h
index 454724ace5ce..5d67a9426870 100644
--- a/tools/bugpoint/ToolRunner.h
+++ b/tools/bugpoint/ToolRunner.h
@@ -165,7 +165,7 @@ public:
ToolArgs.clear();
if (Args) ToolArgs = *Args;
}
- ~LLC() { delete gcc; }
+ ~LLC() override { delete gcc; }
/// compileProgram - Compile the specified program from bitcode to executable
/// code. This does not produce any output, it is only used when debugging
diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp
index d0bade507d2a..af6d9fccf291 100644
--- a/tools/bugpoint/bugpoint.cpp
+++ b/tools/bugpoint/bugpoint.cpp
@@ -16,10 +16,10 @@
#include "BugDriver.h"
#include "ToolRunner.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
@@ -50,7 +50,7 @@ TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"),
static cl::opt<int>
MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"),
cl::desc("Maximum amount of memory to use. 0 disables check."
- " Defaults to 300MB (800MB under valgrind)."));
+ " Defaults to 400MB (800MB under valgrind)."));
static cl::opt<bool>
UseValgrind("enable-valgrind",
@@ -92,7 +92,7 @@ static void BugpointInterruptFunction() {
// Hack to capture a pass list.
namespace {
- class AddToDriver : public FunctionPassManager {
+ class AddToDriver : public legacy::FunctionPassManager {
BugDriver &D;
public:
AddToDriver(BugDriver &_D) : FunctionPassManager(nullptr), D(_D) {}
@@ -158,7 +158,7 @@ int main(int argc, char **argv) {
if (sys::RunningOnValgrind() || UseValgrind)
MemoryLimit = 800;
else
- MemoryLimit = 300;
+ MemoryLimit = 400;
}
BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit,
diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt
index bfe7c706391a..59b37a9b2900 100644
--- a/tools/dsymutil/CMakeLists.txt
+++ b/tools/dsymutil/CMakeLists.txt
@@ -1,4 +1,8 @@
set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
+ AsmPrinter
+ DebugInfoDWARF
+ MC
Object
Support
)
diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp
index 7898160ae6b9..9fa3f788a89f 100644
--- a/tools/dsymutil/DebugMap.cpp
+++ b/tools/dsymutil/DebugMap.cpp
@@ -23,9 +23,12 @@ DebugMapObject::DebugMapObject(StringRef ObjectFilename)
: Filename(ObjectFilename) {}
bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress,
- uint64_t LinkedAddress) {
+ uint64_t LinkedAddress, uint32_t Size) {
auto InsertResult = Symbols.insert(
- std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress)));
+ std::make_pair(Name, SymbolMapping(ObjectAddress, LinkedAddress, Size)));
+
+ if (InsertResult.second)
+ AddressToMapping[ObjectAddress] = &*InsertResult.first;
return InsertResult.second;
}
@@ -42,9 +45,9 @@ void DebugMapObject::print(raw_ostream &OS) const {
Entries.begin(), Entries.end(),
[](const Entry &LHS, const Entry &RHS) { return LHS.first < RHS.first; });
for (const auto &Sym : Entries) {
- OS << format("\t%016" PRIx64 " => %016" PRIx64 "\t%s\n",
+ OS << format("\t%016" PRIx64 " => %016" PRIx64 "+0x%x\t%s\n",
Sym.second.ObjectAddress, Sym.second.BinaryAddress,
- Sym.first.data());
+ Sym.second.Size, Sym.first.data());
}
OS << '\n';
}
@@ -58,16 +61,25 @@ DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath) {
return *Objects.back();
}
-const DebugMapObject::SymbolMapping *
+const DebugMapObject::DebugMapEntry *
DebugMapObject::lookupSymbol(StringRef SymbolName) const {
StringMap<SymbolMapping>::const_iterator Sym = Symbols.find(SymbolName);
if (Sym == Symbols.end())
return nullptr;
- return &Sym->getValue();
+ return &*Sym;
+}
+
+const DebugMapObject::DebugMapEntry *
+DebugMapObject::lookupObjectAddress(uint64_t Address) const {
+ auto Mapping = AddressToMapping.find(Address);
+ if (Mapping == AddressToMapping.end())
+ return nullptr;
+ return Mapping->getSecond();
}
void DebugMap::print(raw_ostream &OS) const {
- OS << "DEBUG MAP: object addr => executable addr\tsymbol name\n";
+ OS << "DEBUG MAP: " << BinaryTriple.getTriple()
+ << "\n\tobject addr => executable addr\tsymbol name\n";
for (const auto &Obj : objects())
Obj->print(OS);
OS << "END DEBUG MAP\n";
diff --git a/tools/dsymutil/DebugMap.h b/tools/dsymutil/DebugMap.h
index 54bff3272080..ee48b093d4fd 100644
--- a/tools/dsymutil/DebugMap.h
+++ b/tools/dsymutil/DebugMap.h
@@ -21,7 +21,9 @@
#ifndef LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
#define LLVM_TOOLS_DSYMUTIL_DEBUGMAP_H
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/ErrorOr.h"
@@ -60,10 +62,13 @@ class DebugMapObject;
/// }
/// }
class DebugMap {
+ Triple BinaryTriple;
typedef std::vector<std::unique_ptr<DebugMapObject>> ObjectContainer;
ObjectContainer Objects;
public:
+ DebugMap(const Triple &BinaryTriple) : BinaryTriple(BinaryTriple) {}
+
typedef ObjectContainer::const_iterator const_iterator;
iterator_range<const_iterator> objects() const {
@@ -78,6 +83,8 @@ public:
/// debug map.
DebugMapObject &addDebugMapObject(StringRef ObjectFilePath);
+ const Triple &getTriple() const { return BinaryTriple; }
+
void print(raw_ostream &OS) const;
#ifndef NDEBUG
@@ -94,22 +101,34 @@ public:
struct SymbolMapping {
uint64_t ObjectAddress;
uint64_t BinaryAddress;
- SymbolMapping(uint64_t ObjectAddress, uint64_t BinaryAddress)
- : ObjectAddress(ObjectAddress), BinaryAddress(BinaryAddress) {}
+ uint32_t Size;
+ SymbolMapping(uint64_t ObjectAddress, uint64_t BinaryAddress, uint32_t Size)
+ : ObjectAddress(ObjectAddress), BinaryAddress(BinaryAddress),
+ Size(Size) {}
};
+ typedef StringMapEntry<SymbolMapping> DebugMapEntry;
+
/// \brief Adds a symbol mapping to this DebugMapObject.
/// \returns false if the symbol was already registered. The request
/// is discarded in this case.
bool addSymbol(llvm::StringRef SymName, uint64_t ObjectAddress,
- uint64_t LinkedAddress);
+ uint64_t LinkedAddress, uint32_t Size);
/// \brief Lookup a symbol mapping.
/// \returns null if the symbol isn't found.
- const SymbolMapping *lookupSymbol(StringRef SymbolName) const;
+ const DebugMapEntry *lookupSymbol(StringRef SymbolName) const;
+
+ /// \brief Lookup an objectfile address.
+ /// \returns null if the address isn't found.
+ const DebugMapEntry *lookupObjectAddress(uint64_t Address) const;
llvm::StringRef getObjectFilename() const { return Filename; }
+ iterator_range<StringMap<SymbolMapping>::const_iterator> symbols() const {
+ return make_range(Symbols.begin(), Symbols.end());
+ }
+
void print(raw_ostream &OS) const;
#ifndef NDEBUG
void dump() const;
@@ -121,6 +140,7 @@ private:
std::string Filename;
StringMap<SymbolMapping> Symbols;
+ DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
};
}
}
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
index ad471055bd9c..a6e62a838945 100644
--- a/tools/dsymutil/DwarfLinker.cpp
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -7,14 +7,2536 @@
//
//===----------------------------------------------------------------------===//
#include "DebugMap.h"
+#include "BinaryHolder.h"
+#include "DebugMap.h"
#include "dsymutil.h"
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/DIE.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include <string>
+#include <tuple>
namespace llvm {
namespace dsymutil {
-bool linkDwarf(StringRef OutputFilename, const DebugMap &DM, bool Verbose) {
- // Do nothing for now.
+namespace {
+
+void warn(const Twine &Warning, const Twine &Context) {
+ errs() << Twine("while processing ") + Context + ":\n";
+ errs() << Twine("warning: ") + Warning + "\n";
+}
+
+bool error(const Twine &Error, const Twine &Context) {
+ errs() << Twine("while processing ") + Context + ":\n";
+ errs() << Twine("error: ") + Error + "\n";
+ return false;
+}
+
+template <typename KeyT, typename ValT>
+using HalfOpenIntervalMap =
+ IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize,
+ IntervalMapHalfOpenInfo<KeyT>>;
+
+typedef HalfOpenIntervalMap<uint64_t, int64_t> FunctionIntervals;
+
+/// \brief Stores all information relating to a compile unit, be it in
+/// its original instance in the object file to its brand new cloned
+/// and linked DIE tree.
+class CompileUnit {
+public:
+ /// \brief Information gathered about a DIE in the object file.
+ struct DIEInfo {
+ int64_t AddrAdjust; ///< Address offset to apply to the described entity.
+ DIE *Clone; ///< Cloned version of that DIE.
+ uint32_t ParentIdx; ///< The index of this DIE's parent.
+ bool Keep; ///< Is the DIE part of the linked output?
+ bool InDebugMap; ///< Was this DIE's entity found in the map?
+ };
+
+ CompileUnit(DWARFUnit &OrigUnit, unsigned ID)
+ : OrigUnit(OrigUnit), ID(ID), LowPc(UINT64_MAX), HighPc(0), RangeAlloc(),
+ Ranges(RangeAlloc), UnitRangeAttribute(nullptr) {
+ Info.resize(OrigUnit.getNumDIEs());
+ }
+
+ CompileUnit(CompileUnit &&RHS)
+ : OrigUnit(RHS.OrigUnit), Info(std::move(RHS.Info)),
+ CUDie(std::move(RHS.CUDie)), StartOffset(RHS.StartOffset),
+ NextUnitOffset(RHS.NextUnitOffset), RangeAlloc(), Ranges(RangeAlloc) {
+ // The CompileUnit container has been 'reserve()'d with the right
+ // size. We cannot move the IntervalMap anyway.
+ llvm_unreachable("CompileUnits should not be moved.");
+ }
+
+ DWARFUnit &getOrigUnit() const { return OrigUnit; }
+
+ unsigned getUniqueID() const { return ID; }
+
+ DIE *getOutputUnitDIE() const { return CUDie.get(); }
+ void setOutputUnitDIE(DIE *Die) { CUDie.reset(Die); }
+
+ DIEInfo &getInfo(unsigned Idx) { return Info[Idx]; }
+ const DIEInfo &getInfo(unsigned Idx) const { return Info[Idx]; }
+
+ uint64_t getStartOffset() const { return StartOffset; }
+ uint64_t getNextUnitOffset() const { return NextUnitOffset; }
+ void setStartOffset(uint64_t DebugInfoSize) { StartOffset = DebugInfoSize; }
+
+ uint64_t getLowPc() const { return LowPc; }
+ uint64_t getHighPc() const { return HighPc; }
+
+ DIEInteger *getUnitRangesAttribute() const { return UnitRangeAttribute; }
+ const FunctionIntervals &getFunctionRanges() const { return Ranges; }
+ const std::vector<DIEInteger *> &getRangesAttributes() const {
+ return RangeAttributes;
+ }
+
+ const std::vector<std::pair<DIEInteger *, int64_t>> &
+ getLocationAttributes() const {
+ return LocationAttributes;
+ }
+
+ /// \brief Compute the end offset for this unit. Must be
+ /// called after the CU's DIEs have been cloned.
+ /// \returns the next unit offset (which is also the current
+ /// debug_info section size).
+ uint64_t computeNextUnitOffset();
+
+ /// \brief Keep track of a forward reference to DIE \p Die in \p
+ /// RefUnit by \p Attr. The attribute should be fixed up later to
+ /// point to the absolute offset of \p Die in the debug_info section.
+ void noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
+ DIEInteger *Attr);
+
+ /// \brief Apply all fixups recored by noteForwardReference().
+ void fixupForwardReferences();
+
+ /// \brief Add a function range [\p LowPC, \p HighPC) that is
+ /// relocatad by applying offset \p PCOffset.
+ void addFunctionRange(uint64_t LowPC, uint64_t HighPC, int64_t PCOffset);
+
+ /// \brief Keep track of a DW_AT_range attribute that we will need to
+ /// patch up later.
+ void noteRangeAttribute(const DIE &Die, DIEInteger *Attr);
+
+ /// \brief Keep track of a location attribute pointing to a location
+ /// list in the debug_loc section.
+ void noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset);
+
+ /// \brief Add a name accelerator entry for \p Die with \p Name
+ /// which is stored in the string table at \p Offset.
+ void addNameAccelerator(const DIE *Die, const char *Name, uint32_t Offset,
+ bool SkipPubnamesSection = false);
+
+ /// \brief Add a type accelerator entry for \p Die with \p Name
+ /// which is stored in the string table at \p Offset.
+ void addTypeAccelerator(const DIE *Die, const char *Name, uint32_t Offset);
+
+ struct AccelInfo {
+ StringRef Name; ///< Name of the entry.
+ const DIE *Die; ///< DIE this entry describes.
+ uint32_t NameOffset; ///< Offset of Name in the string pool.
+ bool SkipPubSection; ///< Emit this entry only in the apple_* sections.
+
+ AccelInfo(StringRef Name, const DIE *Die, uint32_t NameOffset,
+ bool SkipPubSection = false)
+ : Name(Name), Die(Die), NameOffset(NameOffset),
+ SkipPubSection(SkipPubSection) {}
+ };
+
+ const std::vector<AccelInfo> &getPubnames() const { return Pubnames; }
+ const std::vector<AccelInfo> &getPubtypes() const { return Pubtypes; }
+
+private:
+ DWARFUnit &OrigUnit;
+ unsigned ID;
+ std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
+ std::unique_ptr<DIE> CUDie; ///< Root of the linked DIE tree.
+
+ uint64_t StartOffset;
+ uint64_t NextUnitOffset;
+
+ uint64_t LowPc;
+ uint64_t HighPc;
+
+ /// \brief A list of attributes to fixup with the absolute offset of
+ /// a DIE in the debug_info section.
+ ///
+ /// The offsets for the attributes in this array couldn't be set while
+ /// cloning because for cross-cu forward refences the target DIE's
+ /// offset isn't known you emit the reference attribute.
+ std::vector<std::tuple<DIE *, const CompileUnit *, DIEInteger *>>
+ ForwardDIEReferences;
+
+ FunctionIntervals::Allocator RangeAlloc;
+ /// \brief The ranges in that interval map are the PC ranges for
+ /// functions in this unit, associated with the PC offset to apply
+ /// to the addresses to get the linked address.
+ FunctionIntervals Ranges;
+
+ /// \brief DW_AT_ranges attributes to patch after we have gathered
+ /// all the unit's function addresses.
+ /// @{
+ std::vector<DIEInteger *> RangeAttributes;
+ DIEInteger *UnitRangeAttribute;
+ /// @}
+
+ /// \brief Location attributes that need to be transfered from th
+ /// original debug_loc section to the liked one. They are stored
+ /// along with the PC offset that is to be applied to their
+ /// function's address.
+ std::vector<std::pair<DIEInteger *, int64_t>> LocationAttributes;
+
+ /// \brief Accelerator entries for the unit, both for the pub*
+ /// sections and the apple* ones.
+ /// @{
+ std::vector<AccelInfo> Pubnames;
+ std::vector<AccelInfo> Pubtypes;
+ /// @}
+};
+
+uint64_t CompileUnit::computeNextUnitOffset() {
+ NextUnitOffset = StartOffset + 11 /* Header size */;
+ // The root DIE might be null, meaning that the Unit had nothing to
+ // contribute to the linked output. In that case, we will emit the
+ // unit header without any actual DIE.
+ if (CUDie)
+ NextUnitOffset += CUDie->getSize();
+ return NextUnitOffset;
+}
+
+/// \brief Keep track of a forward cross-cu reference from this unit
+/// to \p Die that lives in \p RefUnit.
+void CompileUnit::noteForwardReference(DIE *Die, const CompileUnit *RefUnit,
+ DIEInteger *Attr) {
+ ForwardDIEReferences.emplace_back(Die, RefUnit, Attr);
+}
+
+/// \brief Apply all fixups recorded by noteForwardReference().
+void CompileUnit::fixupForwardReferences() {
+ for (const auto &Ref : ForwardDIEReferences) {
+ DIE *RefDie;
+ const CompileUnit *RefUnit;
+ DIEInteger *Attr;
+ std::tie(RefDie, RefUnit, Attr) = Ref;
+ Attr->setValue(RefDie->getOffset() + RefUnit->getStartOffset());
+ }
+}
+
+void CompileUnit::addFunctionRange(uint64_t FuncLowPc, uint64_t FuncHighPc,
+ int64_t PcOffset) {
+ Ranges.insert(FuncLowPc, FuncHighPc, PcOffset);
+ this->LowPc = std::min(LowPc, FuncLowPc + PcOffset);
+ this->HighPc = std::max(HighPc, FuncHighPc + PcOffset);
+}
+
+void CompileUnit::noteRangeAttribute(const DIE &Die, DIEInteger *Attr) {
+ if (Die.getTag() != dwarf::DW_TAG_compile_unit)
+ RangeAttributes.push_back(Attr);
+ else
+ UnitRangeAttribute = Attr;
+}
+
+void CompileUnit::noteLocationAttribute(DIEInteger *Attr, int64_t PcOffset) {
+ LocationAttributes.emplace_back(Attr, PcOffset);
+}
+
+/// \brief Add a name accelerator entry for \p Die with \p Name
+/// which is stored in the string table at \p Offset.
+void CompileUnit::addNameAccelerator(const DIE *Die, const char *Name,
+ uint32_t Offset, bool SkipPubSection) {
+ Pubnames.emplace_back(Name, Die, Offset, SkipPubSection);
+}
+
+/// \brief Add a type accelerator entry for \p Die with \p Name
+/// which is stored in the string table at \p Offset.
+void CompileUnit::addTypeAccelerator(const DIE *Die, const char *Name,
+ uint32_t Offset) {
+ Pubtypes.emplace_back(Name, Die, Offset, false);
+}
+
+/// \brief A string table that doesn't need relocations.
+///
+/// We are doing a final link, no need for a string table that
+/// has relocation entries for every reference to it. This class
+/// provides this ablitity by just associating offsets with
+/// strings.
+class NonRelocatableStringpool {
+public:
+ /// \brief Entries are stored into the StringMap and simply linked
+ /// together through the second element of this pair in order to
+ /// keep track of insertion order.
+ typedef StringMap<std::pair<uint32_t, StringMapEntryBase *>, BumpPtrAllocator>
+ MapTy;
+
+ NonRelocatableStringpool()
+ : CurrentEndOffset(0), Sentinel(0), Last(&Sentinel) {
+ // Legacy dsymutil puts an empty string at the start of the line
+ // table.
+ getStringOffset("");
+ }
+
+ /// \brief Get the offset of string \p S in the string table. This
+ /// can insert a new element or return the offset of a preexisitng
+ /// one.
+ uint32_t getStringOffset(StringRef S);
+
+ /// \brief Get permanent storage for \p S (but do not necessarily
+ /// emit \p S in the output section).
+ /// \returns The StringRef that points to permanent storage to use
+ /// in place of \p S.
+ StringRef internString(StringRef S);
+
+ // \brief Return the first entry of the string table.
+ const MapTy::MapEntryTy *getFirstEntry() const {
+ return getNextEntry(&Sentinel);
+ }
+
+ // \brief Get the entry following \p E in the string table or null
+ // if \p E was the last entry.
+ const MapTy::MapEntryTy *getNextEntry(const MapTy::MapEntryTy *E) const {
+ return static_cast<const MapTy::MapEntryTy *>(E->getValue().second);
+ }
+
+ uint64_t getSize() { return CurrentEndOffset; }
+
+private:
+ MapTy Strings;
+ uint32_t CurrentEndOffset;
+ MapTy::MapEntryTy Sentinel, *Last;
+};
+
+/// \brief Get the offset of string \p S in the string table. This
+/// can insert a new element or return the offset of a preexisitng
+/// one.
+uint32_t NonRelocatableStringpool::getStringOffset(StringRef S) {
+ if (S.empty() && !Strings.empty())
+ return 0;
+
+ std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
+ MapTy::iterator It;
+ bool Inserted;
+
+ // A non-empty string can't be at offset 0, so if we have an entry
+ // with a 0 offset, it must be a previously interned string.
+ std::tie(It, Inserted) = Strings.insert(std::make_pair(S, Entry));
+ if (Inserted || It->getValue().first == 0) {
+ // Set offset and chain at the end of the entries list.
+ It->getValue().first = CurrentEndOffset;
+ CurrentEndOffset += S.size() + 1; // +1 for the '\0'.
+ Last->getValue().second = &*It;
+ Last = &*It;
+ }
+ return It->getValue().first;
+}
+
+/// \brief Put \p S into the StringMap so that it gets permanent
+/// storage, but do not actually link it in the chain of elements
+/// that go into the output section. A latter call to
+/// getStringOffset() with the same string will chain it though.
+StringRef NonRelocatableStringpool::internString(StringRef S) {
+ std::pair<uint32_t, StringMapEntryBase *> Entry(0, nullptr);
+ auto InsertResult = Strings.insert(std::make_pair(S, Entry));
+ return InsertResult.first->getKey();
+}
+
+/// \brief The Dwarf streaming logic
+///
+/// All interactions with the MC layer that is used to build the debug
+/// information binary representation are handled in this class.
+class DwarfStreamer {
+ /// \defgroup MCObjects MC layer objects constructed by the streamer
+ /// @{
+ std::unique_ptr<MCRegisterInfo> MRI;
+ std::unique_ptr<MCAsmInfo> MAI;
+ std::unique_ptr<MCObjectFileInfo> MOFI;
+ std::unique_ptr<MCContext> MC;
+ MCAsmBackend *MAB; // Owned by MCStreamer
+ std::unique_ptr<MCInstrInfo> MII;
+ std::unique_ptr<MCSubtargetInfo> MSTI;
+ MCCodeEmitter *MCE; // Owned by MCStreamer
+ MCStreamer *MS; // Owned by AsmPrinter
+ std::unique_ptr<TargetMachine> TM;
+ std::unique_ptr<AsmPrinter> Asm;
+ /// @}
+
+ /// \brief the file we stream the linked Dwarf to.
+ std::unique_ptr<raw_fd_ostream> OutFile;
+
+ uint32_t RangesSectionSize;
+ uint32_t LocSectionSize;
+ uint32_t LineSectionSize;
+
+ /// \brief Emit the pubnames or pubtypes section contribution for \p
+ /// Unit into \p Sec. The data is provided in \p Names.
+ void emitPubSectionForUnit(MCSection *Sec, StringRef Name,
+ const CompileUnit &Unit,
+ const std::vector<CompileUnit::AccelInfo> &Names);
+
+public:
+ /// \brief Actually create the streamer and the ouptut file.
+ ///
+ /// This could be done directly in the constructor, but it feels
+ /// more natural to handle errors through return value.
+ bool init(Triple TheTriple, StringRef OutputFilename);
+
+ /// \brief Dump the file to the disk.
+ bool finish();
+
+ AsmPrinter &getAsmPrinter() const { return *Asm; }
+
+ /// \brief Set the current output section to debug_info and change
+ /// the MC Dwarf version to \p DwarfVersion.
+ void switchToDebugInfoSection(unsigned DwarfVersion);
+
+ /// \brief Emit the compilation unit header for \p Unit in the
+ /// debug_info section.
+ ///
+ /// As a side effect, this also switches the current Dwarf version
+ /// of the MC layer to the one of U.getOrigUnit().
+ void emitCompileUnitHeader(CompileUnit &Unit);
+
+ /// \brief Recursively emit the DIE tree rooted at \p Die.
+ void emitDIE(DIE &Die);
+
+ /// \brief Emit the abbreviation table \p Abbrevs to the
+ /// debug_abbrev section.
+ void emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs);
+
+ /// \brief Emit the string table described by \p Pool.
+ void emitStrings(const NonRelocatableStringpool &Pool);
+
+ /// \brief Emit debug_ranges for \p FuncRange by translating the
+ /// original \p Entries.
+ void emitRangesEntries(
+ int64_t UnitPcOffset, uint64_t OrigLowPc,
+ FunctionIntervals::const_iterator FuncRange,
+ const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
+ unsigned AddressSize);
+
+ /// \brief Emit debug_aranges entries for \p Unit and if \p
+ /// DoRangesSection is true, also emit the debug_ranges entries for
+ /// the DW_TAG_compile_unit's DW_AT_ranges attribute.
+ void emitUnitRangesEntries(CompileUnit &Unit, bool DoRangesSection);
+
+ uint32_t getRangesSectionSize() const { return RangesSectionSize; }
+
+ /// \brief Emit the debug_loc contribution for \p Unit by copying
+ /// the entries from \p Dwarf and offseting them. Update the
+ /// location attributes to point to the new entries.
+ void emitLocationsForUnit(const CompileUnit &Unit, DWARFContext &Dwarf);
+
+ /// \brief Emit the line table described in \p Rows into the
+ /// debug_line section.
+ void emitLineTableForUnit(StringRef PrologueBytes, unsigned MinInstLength,
+ std::vector<DWARFDebugLine::Row> &Rows,
+ unsigned AdddressSize);
+
+ uint32_t getLineSectionSize() const { return LineSectionSize; }
+
+ /// \brief Emit the .debug_pubnames contribution for \p Unit.
+ void emitPubNamesForUnit(const CompileUnit &Unit);
+
+ /// \brief Emit the .debug_pubtypes contribution for \p Unit.
+ void emitPubTypesForUnit(const CompileUnit &Unit);
+};
+
+bool DwarfStreamer::init(Triple TheTriple, StringRef OutputFilename) {
+ std::string ErrorStr;
+ std::string TripleName;
+ StringRef Context = "dwarf streamer init";
+
+ // Get the target.
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TripleName, TheTriple, ErrorStr);
+ if (!TheTarget)
+ return error(ErrorStr, Context);
+ TripleName = TheTriple.getTriple();
+
+ // Create all the MC Objects.
+ MRI.reset(TheTarget->createMCRegInfo(TripleName));
+ if (!MRI)
+ return error(Twine("no register info for target ") + TripleName, Context);
+
+ MAI.reset(TheTarget->createMCAsmInfo(*MRI, TripleName));
+ if (!MAI)
+ return error("no asm info for target " + TripleName, Context);
+
+ MOFI.reset(new MCObjectFileInfo);
+ MC.reset(new MCContext(MAI.get(), MRI.get(), MOFI.get()));
+ MOFI->InitMCObjectFileInfo(TripleName, Reloc::Default, CodeModel::Default,
+ *MC);
+
+ MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, "");
+ if (!MAB)
+ return error("no asm backend for target " + TripleName, Context);
+
+ MII.reset(TheTarget->createMCInstrInfo());
+ if (!MII)
+ return error("no instr info info for target " + TripleName, Context);
+
+ MSTI.reset(TheTarget->createMCSubtargetInfo(TripleName, "", ""));
+ if (!MSTI)
+ return error("no subtarget info for target " + TripleName, Context);
+
+ MCE = TheTarget->createMCCodeEmitter(*MII, *MRI, *MC);
+ if (!MCE)
+ return error("no code emitter for target " + TripleName, Context);
+
+ // Create the output file.
+ std::error_code EC;
+ OutFile =
+ llvm::make_unique<raw_fd_ostream>(OutputFilename, EC, sys::fs::F_None);
+ if (EC)
+ return error(Twine(OutputFilename) + ": " + EC.message(), Context);
+
+ MS = TheTarget->createMCObjectStreamer(TheTriple, *MC, *MAB, *OutFile, MCE,
+ *MSTI, false,
+ /*DWARFMustBeAtTheEnd*/ false);
+ if (!MS)
+ return error("no object streamer for target " + TripleName, Context);
+
+ // Finally create the AsmPrinter we'll use to emit the DIEs.
+ TM.reset(TheTarget->createTargetMachine(TripleName, "", "", TargetOptions()));
+ if (!TM)
+ return error("no target machine for target " + TripleName, Context);
+
+ Asm.reset(TheTarget->createAsmPrinter(*TM, std::unique_ptr<MCStreamer>(MS)));
+ if (!Asm)
+ return error("no asm printer for target " + TripleName, Context);
+
+ RangesSectionSize = 0;
+ LocSectionSize = 0;
+ LineSectionSize = 0;
+
+ return true;
+}
+
+bool DwarfStreamer::finish() {
+ MS->Finish();
return true;
}
+
+/// \brief Set the current output section to debug_info and change
+/// the MC Dwarf version to \p DwarfVersion.
+void DwarfStreamer::switchToDebugInfoSection(unsigned DwarfVersion) {
+ MS->SwitchSection(MOFI->getDwarfInfoSection());
+ MC->setDwarfVersion(DwarfVersion);
+}
+
+/// \brief Emit the compilation unit header for \p Unit in the
+/// debug_info section.
+///
+/// A Dwarf scetion header is encoded as:
+/// uint32_t Unit length (omiting this field)
+/// uint16_t Version
+/// uint32_t Abbreviation table offset
+/// uint8_t Address size
+///
+/// Leading to a total of 11 bytes.
+void DwarfStreamer::emitCompileUnitHeader(CompileUnit &Unit) {
+ unsigned Version = Unit.getOrigUnit().getVersion();
+ switchToDebugInfoSection(Version);
+
+ // Emit size of content not including length itself. The size has
+ // already been computed in CompileUnit::computeOffsets(). Substract
+ // 4 to that size to account for the length field.
+ Asm->EmitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset() - 4);
+ Asm->EmitInt16(Version);
+ // We share one abbreviations table across all units so it's always at the
+ // start of the section.
+ Asm->EmitInt32(0);
+ Asm->EmitInt8(Unit.getOrigUnit().getAddressByteSize());
+}
+
+/// \brief Emit the \p Abbrevs array as the shared abbreviation table
+/// for the linked Dwarf file.
+void DwarfStreamer::emitAbbrevs(const std::vector<DIEAbbrev *> &Abbrevs) {
+ MS->SwitchSection(MOFI->getDwarfAbbrevSection());
+ Asm->emitDwarfAbbrevs(Abbrevs);
+}
+
+/// \brief Recursively emit the DIE tree rooted at \p Die.
+void DwarfStreamer::emitDIE(DIE &Die) {
+ MS->SwitchSection(MOFI->getDwarfInfoSection());
+ Asm->emitDwarfDIE(Die);
+}
+
+/// \brief Emit the debug_str section stored in \p Pool.
+void DwarfStreamer::emitStrings(const NonRelocatableStringpool &Pool) {
+ Asm->OutStreamer->SwitchSection(MOFI->getDwarfStrSection());
+ for (auto *Entry = Pool.getFirstEntry(); Entry;
+ Entry = Pool.getNextEntry(Entry))
+ Asm->OutStreamer->EmitBytes(
+ StringRef(Entry->getKey().data(), Entry->getKey().size() + 1));
+}
+
+/// \brief Emit the debug_range section contents for \p FuncRange by
+/// translating the original \p Entries. The debug_range section
+/// format is totally trivial, consisting just of pairs of address
+/// sized addresses describing the ranges.
+void DwarfStreamer::emitRangesEntries(
+ int64_t UnitPcOffset, uint64_t OrigLowPc,
+ FunctionIntervals::const_iterator FuncRange,
+ const std::vector<DWARFDebugRangeList::RangeListEntry> &Entries,
+ unsigned AddressSize) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+
+ // Offset each range by the right amount.
+ int64_t PcOffset = FuncRange.value() + UnitPcOffset;
+ for (const auto &Range : Entries) {
+ if (Range.isBaseAddressSelectionEntry(AddressSize)) {
+ warn("unsupported base address selection operation",
+ "emitting debug_ranges");
+ break;
+ }
+ // Do not emit empty ranges.
+ if (Range.StartAddress == Range.EndAddress)
+ continue;
+
+ // All range entries should lie in the function range.
+ if (!(Range.StartAddress + OrigLowPc >= FuncRange.start() &&
+ Range.EndAddress + OrigLowPc <= FuncRange.stop()))
+ warn("inconsistent range data.", "emitting debug_ranges");
+ MS->EmitIntValue(Range.StartAddress + PcOffset, AddressSize);
+ MS->EmitIntValue(Range.EndAddress + PcOffset, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+ }
+
+ // Add the terminator entry.
+ MS->EmitIntValue(0, AddressSize);
+ MS->EmitIntValue(0, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+}
+
+/// \brief Emit the debug_aranges contribution of a unit and
+/// if \p DoDebugRanges is true the debug_range contents for a
+/// compile_unit level DW_AT_ranges attribute (Which are basically the
+/// same thing with a different base address).
+/// Just aggregate all the ranges gathered inside that unit.
+void DwarfStreamer::emitUnitRangesEntries(CompileUnit &Unit,
+ bool DoDebugRanges) {
+ unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+ // Gather the ranges in a vector, so that we can simplify them. The
+ // IntervalMap will have coalesced the non-linked ranges, but here
+ // we want to coalesce the linked addresses.
+ std::vector<std::pair<uint64_t, uint64_t>> Ranges;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ for (auto Range = FunctionRanges.begin(), End = FunctionRanges.end();
+ Range != End; ++Range)
+ Ranges.push_back(std::make_pair(Range.start() + Range.value(),
+ Range.stop() + Range.value()));
+
+ // The object addresses where sorted, but again, the linked
+ // addresses might end up in a different order.
+ std::sort(Ranges.begin(), Ranges.end());
+
+ if (!Ranges.empty()) {
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
+
+ MCSymbol *BeginLabel = Asm->createTempSymbol("Barange");
+ MCSymbol *EndLabel = Asm->createTempSymbol("Earange");
+
+ unsigned HeaderSize =
+ sizeof(int32_t) + // Size of contents (w/o this field
+ sizeof(int16_t) + // DWARF ARange version number
+ sizeof(int32_t) + // Offset of CU in the .debug_info section
+ sizeof(int8_t) + // Pointer Size (in bytes)
+ sizeof(int8_t); // Segment Size (in bytes)
+
+ unsigned TupleSize = AddressSize * 2;
+ unsigned Padding = OffsetToAlignment(HeaderSize, TupleSize);
+
+ Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Arange length
+ Asm->OutStreamer->EmitLabel(BeginLabel);
+ Asm->EmitInt16(dwarf::DW_ARANGES_VERSION); // Version number
+ Asm->EmitInt32(Unit.getStartOffset()); // Corresponding unit's offset
+ Asm->EmitInt8(AddressSize); // Address size
+ Asm->EmitInt8(0); // Segment size
+
+ Asm->OutStreamer->EmitFill(Padding, 0x0);
+
+ for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End;
+ ++Range) {
+ uint64_t RangeStart = Range->first;
+ MS->EmitIntValue(RangeStart, AddressSize);
+ while ((Range + 1) != End && Range->second == (Range + 1)->first)
+ ++Range;
+ MS->EmitIntValue(Range->second - RangeStart, AddressSize);
+ }
+
+ // Emit terminator
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitLabel(EndLabel);
+ }
+
+ if (!DoDebugRanges)
+ return;
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+ // Offset each range by the right amount.
+ int64_t PcOffset = -Unit.getLowPc();
+ // Emit coalesced ranges.
+ for (auto Range = Ranges.begin(), End = Ranges.end(); Range != End; ++Range) {
+ MS->EmitIntValue(Range->first + PcOffset, AddressSize);
+ while (Range + 1 != End && Range->second == (Range + 1)->first)
+ ++Range;
+ MS->EmitIntValue(Range->second + PcOffset, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+ }
+
+ // Add the terminator entry.
+ MS->EmitIntValue(0, AddressSize);
+ MS->EmitIntValue(0, AddressSize);
+ RangesSectionSize += 2 * AddressSize;
+}
+
+/// \brief Emit location lists for \p Unit and update attribtues to
+/// point to the new entries.
+void DwarfStreamer::emitLocationsForUnit(const CompileUnit &Unit,
+ DWARFContext &Dwarf) {
+ const std::vector<std::pair<DIEInteger *, int64_t>> &Attributes =
+ Unit.getLocationAttributes();
+
+ if (Attributes.empty())
+ return;
+
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
+
+ unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+ const DWARFSection &InputSec = Dwarf.getLocSection();
+ DataExtractor Data(InputSec.Data, Dwarf.isLittleEndian(), AddressSize);
+ DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
+ int64_t UnitPcOffset = 0;
+ uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
+ &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
+ if (OrigLowPc != -1ULL)
+ UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
+
+ for (const auto &Attr : Attributes) {
+ uint32_t Offset = Attr.first->getValue();
+ Attr.first->setValue(LocSectionSize);
+ // This is the quantity to add to the old location address to get
+ // the correct address for the new one.
+ int64_t LocPcOffset = Attr.second + UnitPcOffset;
+ while (Data.isValidOffset(Offset)) {
+ uint64_t Low = Data.getUnsigned(&Offset, AddressSize);
+ uint64_t High = Data.getUnsigned(&Offset, AddressSize);
+ LocSectionSize += 2 * AddressSize;
+ if (Low == 0 && High == 0) {
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ Asm->OutStreamer->EmitIntValue(0, AddressSize);
+ break;
+ }
+ Asm->OutStreamer->EmitIntValue(Low + LocPcOffset, AddressSize);
+ Asm->OutStreamer->EmitIntValue(High + LocPcOffset, AddressSize);
+ uint64_t Length = Data.getU16(&Offset);
+ Asm->OutStreamer->EmitIntValue(Length, 2);
+ // Just copy the bytes over.
+ Asm->OutStreamer->EmitBytes(
+ StringRef(InputSec.Data.substr(Offset, Length)));
+ Offset += Length;
+ LocSectionSize += Length + 2;
+ }
+ }
+}
+
+void DwarfStreamer::emitLineTableForUnit(StringRef PrologueBytes,
+ unsigned MinInstLength,
+ std::vector<DWARFDebugLine::Row> &Rows,
+ unsigned PointerSize) {
+ // Switch to the section where the table will be emitted into.
+ MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+ MCSymbol *LineStartSym = MC->createTempSymbol();
+ MCSymbol *LineEndSym = MC->createTempSymbol();
+
+ // The first 4 bytes is the total length of the information for this
+ // compilation unit (not including these 4 bytes for the length).
+ Asm->EmitLabelDifference(LineEndSym, LineStartSym, 4);
+ Asm->OutStreamer->EmitLabel(LineStartSym);
+ // Copy Prologue.
+ MS->EmitBytes(PrologueBytes);
+ LineSectionSize += PrologueBytes.size() + 4;
+
+ SmallString<128> EncodingBuffer;
+ raw_svector_ostream EncodingOS(EncodingBuffer);
+
+ if (Rows.empty()) {
+ // We only have the dummy entry, dsymutil emits an entry with a 0
+ // address in that case.
+ MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ MS->EmitLabel(LineEndSym);
+ return;
+ }
+
+ // Line table state machine fields
+ unsigned FileNum = 1;
+ unsigned LastLine = 1;
+ unsigned Column = 0;
+ unsigned IsStatement = 1;
+ unsigned Isa = 0;
+ uint64_t Address = -1ULL;
+
+ unsigned RowsSinceLastSequence = 0;
+
+ for (unsigned Idx = 0; Idx < Rows.size(); ++Idx) {
+ auto &Row = Rows[Idx];
+
+ int64_t AddressDelta;
+ if (Address == -1ULL) {
+ MS->EmitIntValue(dwarf::DW_LNS_extended_op, 1);
+ MS->EmitULEB128IntValue(PointerSize + 1);
+ MS->EmitIntValue(dwarf::DW_LNE_set_address, 1);
+ MS->EmitIntValue(Row.Address, PointerSize);
+ LineSectionSize += 2 + PointerSize + getULEB128Size(PointerSize + 1);
+ AddressDelta = 0;
+ } else {
+ AddressDelta = (Row.Address - Address) / MinInstLength;
+ }
+
+ // FIXME: code copied and transfromed from
+ // MCDwarf.cpp::EmitDwarfLineTable. We should find a way to share
+ // this code, but the current compatibility requirement with
+ // classic dsymutil makes it hard. Revisit that once this
+ // requirement is dropped.
+
+ if (FileNum != Row.File) {
+ FileNum = Row.File;
+ MS->EmitIntValue(dwarf::DW_LNS_set_file, 1);
+ MS->EmitULEB128IntValue(FileNum);
+ LineSectionSize += 1 + getULEB128Size(FileNum);
+ }
+ if (Column != Row.Column) {
+ Column = Row.Column;
+ MS->EmitIntValue(dwarf::DW_LNS_set_column, 1);
+ MS->EmitULEB128IntValue(Column);
+ LineSectionSize += 1 + getULEB128Size(Column);
+ }
+
+ // FIXME: We should handle the discriminator here, but dsymutil
+ // doesn' consider it, thus ignore it for now.
+
+ if (Isa != Row.Isa) {
+ Isa = Row.Isa;
+ MS->EmitIntValue(dwarf::DW_LNS_set_isa, 1);
+ MS->EmitULEB128IntValue(Isa);
+ LineSectionSize += 1 + getULEB128Size(Isa);
+ }
+ if (IsStatement != Row.IsStmt) {
+ IsStatement = Row.IsStmt;
+ MS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1);
+ LineSectionSize += 1;
+ }
+ if (Row.BasicBlock) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1);
+ LineSectionSize += 1;
+ }
+
+ if (Row.PrologueEnd) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1);
+ LineSectionSize += 1;
+ }
+
+ if (Row.EpilogueBegin) {
+ MS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1);
+ LineSectionSize += 1;
+ }
+
+ int64_t LineDelta = int64_t(Row.Line) - LastLine;
+ if (!Row.EndSequence) {
+ MCDwarfLineAddr::Encode(*MC, LineDelta, AddressDelta, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ EncodingOS.resync();
+ Address = Row.Address;
+ LastLine = Row.Line;
+ RowsSinceLastSequence++;
+ } else {
+ if (LineDelta) {
+ MS->EmitIntValue(dwarf::DW_LNS_advance_line, 1);
+ MS->EmitSLEB128IntValue(LineDelta);
+ LineSectionSize += 1 + getSLEB128Size(LineDelta);
+ }
+ if (AddressDelta) {
+ MS->EmitIntValue(dwarf::DW_LNS_advance_pc, 1);
+ MS->EmitULEB128IntValue(AddressDelta);
+ LineSectionSize += 1 + getULEB128Size(AddressDelta);
+ }
+ MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ EncodingOS.resync();
+ Address = -1ULL;
+ LastLine = FileNum = IsStatement = 1;
+ RowsSinceLastSequence = Column = Isa = 0;
+ }
+ }
+
+ if (RowsSinceLastSequence) {
+ MCDwarfLineAddr::Encode(*MC, INT64_MAX, 0, EncodingOS);
+ MS->EmitBytes(EncodingOS.str());
+ LineSectionSize += EncodingBuffer.size();
+ EncodingBuffer.resize(0);
+ EncodingOS.resync();
+ }
+
+ MS->EmitLabel(LineEndSym);
+}
+
+/// \brief Emit the pubnames or pubtypes section contribution for \p
+/// Unit into \p Sec. The data is provided in \p Names.
+void DwarfStreamer::emitPubSectionForUnit(
+ MCSection *Sec, StringRef SecName, const CompileUnit &Unit,
+ const std::vector<CompileUnit::AccelInfo> &Names) {
+ if (Names.empty())
+ return;
+
+ // Start the dwarf pubnames section.
+ Asm->OutStreamer->SwitchSection(Sec);
+ MCSymbol *BeginLabel = Asm->createTempSymbol("pub" + SecName + "_begin");
+ MCSymbol *EndLabel = Asm->createTempSymbol("pub" + SecName + "_end");
+
+ bool HeaderEmitted = false;
+ // Emit the pubnames for this compilation unit.
+ for (const auto &Name : Names) {
+ if (Name.SkipPubSection)
+ continue;
+
+ if (!HeaderEmitted) {
+ // Emit the header.
+ Asm->EmitLabelDifference(EndLabel, BeginLabel, 4); // Length
+ Asm->OutStreamer->EmitLabel(BeginLabel);
+ Asm->EmitInt16(dwarf::DW_PUBNAMES_VERSION); // Version
+ Asm->EmitInt32(Unit.getStartOffset()); // Unit offset
+ Asm->EmitInt32(Unit.getNextUnitOffset() - Unit.getStartOffset()); // Size
+ HeaderEmitted = true;
+ }
+ Asm->EmitInt32(Name.Die->getOffset());
+ Asm->OutStreamer->EmitBytes(
+ StringRef(Name.Name.data(), Name.Name.size() + 1));
+ }
+
+ if (!HeaderEmitted)
+ return;
+ Asm->EmitInt32(0); // End marker.
+ Asm->OutStreamer->EmitLabel(EndLabel);
+}
+
+/// \brief Emit .debug_pubnames for \p Unit.
+void DwarfStreamer::emitPubNamesForUnit(const CompileUnit &Unit) {
+ emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubNamesSection(),
+ "names", Unit, Unit.getPubnames());
+}
+
+/// \brief Emit .debug_pubtypes for \p Unit.
+void DwarfStreamer::emitPubTypesForUnit(const CompileUnit &Unit) {
+ emitPubSectionForUnit(MC->getObjectFileInfo()->getDwarfPubTypesSection(),
+ "types", Unit, Unit.getPubtypes());
+}
+
+/// \brief The core of the Dwarf linking logic.
+///
+/// The link of the dwarf information from the object files will be
+/// driven by the selection of 'root DIEs', which are DIEs that
+/// describe variables or functions that are present in the linked
+/// binary (and thus have entries in the debug map). All the debug
+/// information that will be linked (the DIEs, but also the line
+/// tables, ranges, ...) is derived from that set of root DIEs.
+///
+/// The root DIEs are identified because they contain relocations that
+/// correspond to a debug map entry at specific places (the low_pc for
+/// a function, the location for a variable). These relocations are
+/// called ValidRelocs in the DwarfLinker and are gathered as a very
+/// first step when we start processing a DebugMapObject.
+class DwarfLinker {
+public:
+ DwarfLinker(StringRef OutputFilename, const LinkOptions &Options)
+ : OutputFilename(OutputFilename), Options(Options),
+ BinHolder(Options.Verbose) {}
+
+ ~DwarfLinker() {
+ for (auto *Abbrev : Abbreviations)
+ delete Abbrev;
+ }
+
+ /// \brief Link the contents of the DebugMap.
+ bool link(const DebugMap &);
+
+private:
+ /// \brief Called at the start of a debug object link.
+ void startDebugObject(DWARFContext &, DebugMapObject &);
+
+ /// \brief Called at the end of a debug object link.
+ void endDebugObject();
+
+ /// \defgroup FindValidRelocations Translate debug map into a list
+ /// of relevant relocations
+ ///
+ /// @{
+ struct ValidReloc {
+ uint32_t Offset;
+ uint32_t Size;
+ uint64_t Addend;
+ const DebugMapObject::DebugMapEntry *Mapping;
+
+ ValidReloc(uint32_t Offset, uint32_t Size, uint64_t Addend,
+ const DebugMapObject::DebugMapEntry *Mapping)
+ : Offset(Offset), Size(Size), Addend(Addend), Mapping(Mapping) {}
+
+ bool operator<(const ValidReloc &RHS) const { return Offset < RHS.Offset; }
+ };
+
+ /// \brief The valid relocations for the current DebugMapObject.
+ /// This vector is sorted by relocation offset.
+ std::vector<ValidReloc> ValidRelocs;
+
+ /// \brief Index into ValidRelocs of the next relocation to
+ /// consider. As we walk the DIEs in acsending file offset and as
+ /// ValidRelocs is sorted by file offset, keeping this index
+ /// uptodate is all we have to do to have a cheap lookup during the
+ /// root DIE selection and during DIE cloning.
+ unsigned NextValidReloc;
+
+ bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ bool findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
+ const DebugMapObject &DMO);
+
+ void findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO);
+ /// @}
+
+ /// \defgroup FindRootDIEs Find DIEs corresponding to debug map entries.
+ ///
+ /// @{
+ /// \brief Recursively walk the \p DIE tree and look for DIEs to
+ /// keep. Store that information in \p CU's DIEInfo.
+ void lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE,
+ const DebugMapObject &DMO, CompileUnit &CU,
+ unsigned Flags);
+
+ /// \brief Flags passed to DwarfLinker::lookForDIEsToKeep
+ enum TravesalFlags {
+ TF_Keep = 1 << 0, ///< Mark the traversed DIEs as kept.
+ TF_InFunctionScope = 1 << 1, ///< Current scope is a fucntion scope.
+ TF_DependencyWalk = 1 << 2, ///< Walking the dependencies of a kept DIE.
+ TF_ParentWalk = 1 << 3, ///< Walking up the parents of a kept DIE.
+ };
+
+ /// \brief Mark the passed DIE as well as all the ones it depends on
+ /// as kept.
+ void keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit::DIEInfo &MyInfo,
+ const DebugMapObject &DMO, CompileUnit &CU,
+ unsigned Flags);
+
+ unsigned shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit &Unit, CompileUnit::DIEInfo &MyInfo,
+ unsigned Flags);
+
+ unsigned shouldKeepVariableDIE(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo, unsigned Flags);
+
+ unsigned shouldKeepSubprogramDIE(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo,
+ unsigned Flags);
+
+ bool hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+ CompileUnit::DIEInfo &Info);
+ /// @}
+
+ /// \defgroup Linking Methods used to link the debug information
+ ///
+ /// @{
+ /// \brief Recursively clone \p InputDIE into an tree of DIE objects
+ /// where useless (as decided by lookForDIEsToKeep()) bits have been
+ /// stripped out and addresses have been rewritten according to the
+ /// debug map.
+ ///
+ /// \param OutOffset is the offset the cloned DIE in the output
+ /// compile unit.
+ /// \param PCOffset (while cloning a function scope) is the offset
+ /// applied to the entry point of the function to get the linked address.
+ ///
+ /// \returns the root of the cloned tree.
+ DIE *cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &U,
+ int64_t PCOffset, uint32_t OutOffset);
+
+ typedef DWARFAbbreviationDeclaration::AttributeSpec AttributeSpec;
+
+ /// \brief Information gathered and exchanged between the various
+ /// clone*Attributes helpers about the attributes of a particular DIE.
+ struct AttributesInfo {
+ const char *Name, *MangledName; ///< Names.
+ uint32_t NameOffset, MangledNameOffset; ///< Offsets in the string pool.
+
+ uint64_t OrigHighPc; ///< Value of AT_high_pc in the input DIE
+ int64_t PCOffset; ///< Offset to apply to PC addresses inside a function.
+
+ bool HasLowPc; ///< Does the DIE have a low_pc attribute?
+ bool IsDeclaration; ///< Is this DIE only a declaration?
+
+ AttributesInfo()
+ : Name(nullptr), MangledName(nullptr), NameOffset(0),
+ MangledNameOffset(0), OrigHighPc(0), PCOffset(0), HasLowPc(false),
+ IsDeclaration(false) {}
+ };
+
+ /// \brief Helper for cloneDIE.
+ unsigned cloneAttribute(DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE,
+ CompileUnit &U, const DWARFFormValue &Val,
+ const AttributeSpec AttrSpec, unsigned AttrSize,
+ AttributesInfo &AttrInfo);
+
+ /// \brief Helper for cloneDIE.
+ unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, const DWARFUnit &U);
+
+ /// \brief Helper for cloneDIE.
+ unsigned
+ cloneDieReferenceAttribute(DIE &Die,
+ const DWARFDebugInfoEntryMinimal &InputDIE,
+ AttributeSpec AttrSpec, unsigned AttrSize,
+ const DWARFFormValue &Val, CompileUnit &Unit);
+
+ /// \brief Helper for cloneDIE.
+ unsigned cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, unsigned AttrSize);
+
+ /// \brief Helper for cloneDIE.
+ unsigned cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ const CompileUnit &Unit, AttributesInfo &Info);
+
+ /// \brief Helper for cloneDIE.
+ unsigned cloneScalarAttribute(DIE &Die,
+ const DWARFDebugInfoEntryMinimal &InputDIE,
+ CompileUnit &U, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val, unsigned AttrSize,
+ AttributesInfo &Info);
+
+ /// \brief Helper for cloneDIE.
+ bool applyValidRelocs(MutableArrayRef<char> Data, uint32_t BaseOffset,
+ bool isLittleEndian);
+
+ /// \brief Assign an abbreviation number to \p Abbrev
+ void AssignAbbrev(DIEAbbrev &Abbrev);
+
+ /// \brief FoldingSet that uniques the abbreviations.
+ FoldingSet<DIEAbbrev> AbbreviationsSet;
+ /// \brief Storage for the unique Abbreviations.
+ /// This is passed to AsmPrinter::emitDwarfAbbrevs(), thus it cannot
+ /// be changed to a vecot of unique_ptrs.
+ std::vector<DIEAbbrev *> Abbreviations;
+
+ /// \brief Compute and emit debug_ranges section for \p Unit, and
+ /// patch the attributes referencing it.
+ void patchRangesForUnit(const CompileUnit &Unit, DWARFContext &Dwarf) const;
+
+ /// \brief Generate and emit the DW_AT_ranges attribute for a
+ /// compile_unit if it had one.
+ void generateUnitRanges(CompileUnit &Unit) const;
+
+ /// \brief Extract the line tables fromt he original dwarf, extract
+ /// the relevant parts according to the linked function ranges and
+ /// emit the result in the debug_line section.
+ void patchLineTableForUnit(CompileUnit &Unit, DWARFContext &OrigDwarf);
+
+ /// \brief Emit the accelerator entries for \p Unit.
+ void emitAcceleratorEntriesForUnit(CompileUnit &Unit);
+
+ /// \brief DIELoc objects that need to be destructed (but not freed!).
+ std::vector<DIELoc *> DIELocs;
+ /// \brief DIEBlock objects that need to be destructed (but not freed!).
+ std::vector<DIEBlock *> DIEBlocks;
+ /// \brief Allocator used for all the DIEValue objects.
+ BumpPtrAllocator DIEAlloc;
+ /// @}
+
+ /// \defgroup Helpers Various helper methods.
+ ///
+ /// @{
+ const DWARFDebugInfoEntryMinimal *
+ resolveDIEReference(DWARFFormValue &RefValue, const DWARFUnit &Unit,
+ const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit *&ReferencedCU);
+
+ CompileUnit *getUnitForOffset(unsigned Offset);
+
+ bool getDIENames(const DWARFDebugInfoEntryMinimal &Die, DWARFUnit &U,
+ AttributesInfo &Info);
+
+ void reportWarning(const Twine &Warning, const DWARFUnit *Unit = nullptr,
+ const DWARFDebugInfoEntryMinimal *DIE = nullptr) const;
+
+ bool createStreamer(Triple TheTriple, StringRef OutputFilename);
+ /// @}
+
+private:
+ std::string OutputFilename;
+ LinkOptions Options;
+ BinaryHolder BinHolder;
+ std::unique_ptr<DwarfStreamer> Streamer;
+
+ /// The units of the current debug map object.
+ std::vector<CompileUnit> Units;
+
+ /// The debug map object curently under consideration.
+ DebugMapObject *CurrentDebugObject;
+
+ /// \brief The Dwarf string pool
+ NonRelocatableStringpool StringPool;
+
+ /// \brief This map is keyed by the entry PC of functions in that
+ /// debug object and the associated value is a pair storing the
+ /// corresponding end PC and the offset to apply to get the linked
+ /// address.
+ ///
+ /// See startDebugObject() for a more complete description of its use.
+ std::map<uint64_t, std::pair<uint64_t, int64_t>> Ranges;
+};
+
+/// \brief Similar to DWARFUnitSection::getUnitForOffset(), but
+/// returning our CompileUnit object instead.
+CompileUnit *DwarfLinker::getUnitForOffset(unsigned Offset) {
+ auto CU =
+ std::upper_bound(Units.begin(), Units.end(), Offset,
+ [](uint32_t LHS, const CompileUnit &RHS) {
+ return LHS < RHS.getOrigUnit().getNextUnitOffset();
+ });
+ return CU != Units.end() ? &*CU : nullptr;
+}
+
+/// \brief Resolve the DIE attribute reference that has been
+/// extracted in \p RefValue. The resulting DIE migh be in another
+/// CompileUnit which is stored into \p ReferencedCU.
+/// \returns null if resolving fails for any reason.
+const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference(
+ DWARFFormValue &RefValue, const DWARFUnit &Unit,
+ const DWARFDebugInfoEntryMinimal &DIE, CompileUnit *&RefCU) {
+ assert(RefValue.isFormClass(DWARFFormValue::FC_Reference));
+ uint64_t RefOffset = *RefValue.getAsReference(&Unit);
+
+ if ((RefCU = getUnitForOffset(RefOffset)))
+ if (const auto *RefDie = RefCU->getOrigUnit().getDIEForOffset(RefOffset))
+ return RefDie;
+
+ reportWarning("could not find referenced DIE", &Unit, &DIE);
+ return nullptr;
+}
+
+/// \brief Get the potential name and mangled name for the entity
+/// described by \p Die and store them in \Info if they are not
+/// already there.
+/// \returns is a name was found.
+bool DwarfLinker::getDIENames(const DWARFDebugInfoEntryMinimal &Die,
+ DWARFUnit &U, AttributesInfo &Info) {
+ // FIXME: a bit wastefull as the first getName might return the
+ // short name.
+ if (!Info.MangledName &&
+ (Info.MangledName = Die.getName(&U, DINameKind::LinkageName)))
+ Info.MangledNameOffset = StringPool.getStringOffset(Info.MangledName);
+
+ if (!Info.Name && (Info.Name = Die.getName(&U, DINameKind::ShortName)))
+ Info.NameOffset = StringPool.getStringOffset(Info.Name);
+
+ return Info.Name || Info.MangledName;
+}
+
+/// \brief Report a warning to the user, optionaly including
+/// information about a specific \p DIE related to the warning.
+void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit,
+ const DWARFDebugInfoEntryMinimal *DIE) const {
+ StringRef Context = "<debug map>";
+ if (CurrentDebugObject)
+ Context = CurrentDebugObject->getObjectFilename();
+ warn(Warning, Context);
+
+ if (!Options.Verbose || !DIE)
+ return;
+
+ errs() << " in DIE:\n";
+ DIE->dump(errs(), const_cast<DWARFUnit *>(Unit), 0 /* RecurseDepth */,
+ 6 /* Indent */);
+}
+
+bool DwarfLinker::createStreamer(Triple TheTriple, StringRef OutputFilename) {
+ if (Options.NoOutput)
+ return true;
+
+ Streamer = llvm::make_unique<DwarfStreamer>();
+ return Streamer->init(TheTriple, OutputFilename);
+}
+
+/// \brief Recursive helper to gather the child->parent relationships in the
+/// original compile unit.
+static void gatherDIEParents(const DWARFDebugInfoEntryMinimal *DIE,
+ unsigned ParentIdx, CompileUnit &CU) {
+ unsigned MyIdx = CU.getOrigUnit().getDIEIndex(DIE);
+ CU.getInfo(MyIdx).ParentIdx = ParentIdx;
+
+ if (DIE->hasChildren())
+ for (auto *Child = DIE->getFirstChild(); Child && !Child->isNULL();
+ Child = Child->getSibling())
+ gatherDIEParents(Child, MyIdx, CU);
+}
+
+static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
+ switch (Tag) {
+ default:
+ return false;
+ case dwarf::DW_TAG_subprogram:
+ case dwarf::DW_TAG_lexical_block:
+ case dwarf::DW_TAG_subroutine_type:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_union_type:
+ return true;
+ }
+ llvm_unreachable("Invalid Tag");
+}
+
+void DwarfLinker::startDebugObject(DWARFContext &Dwarf, DebugMapObject &Obj) {
+ Units.reserve(Dwarf.getNumCompileUnits());
+ NextValidReloc = 0;
+ // Iterate over the debug map entries and put all the ones that are
+ // functions (because they have a size) into the Ranges map. This
+ // map is very similar to the FunctionRanges that are stored in each
+ // unit, with 2 notable differences:
+ // - obviously this one is global, while the other ones are per-unit.
+ // - this one contains not only the functions described in the DIE
+ // tree, but also the ones that are only in the debug map.
+ // The latter information is required to reproduce dsymutil's logic
+ // while linking line tables. The cases where this information
+ // matters look like bugs that need to be investigated, but for now
+ // we need to reproduce dsymutil's behavior.
+ // FIXME: Once we understood exactly if that information is needed,
+ // maybe totally remove this (or try to use it to do a real
+ // -gline-tables-only on Darwin.
+ for (const auto &Entry : Obj.symbols()) {
+ const auto &Mapping = Entry.getValue();
+ if (Mapping.Size)
+ Ranges[Mapping.ObjectAddress] = std::make_pair(
+ Mapping.ObjectAddress + Mapping.Size,
+ int64_t(Mapping.BinaryAddress) - Mapping.ObjectAddress);
+ }
+}
+
+void DwarfLinker::endDebugObject() {
+ Units.clear();
+ ValidRelocs.clear();
+ Ranges.clear();
+
+ for (auto *Block : DIEBlocks)
+ Block->~DIEBlock();
+ for (auto *Loc : DIELocs)
+ Loc->~DIELoc();
+
+ DIEBlocks.clear();
+ DIELocs.clear();
+ DIEAlloc.Reset();
+}
+
+/// \brief Iterate over the relocations of the given \p Section and
+/// store the ones that correspond to debug map entries into the
+/// ValidRelocs array.
+void DwarfLinker::findValidRelocsMachO(const object::SectionRef &Section,
+ const object::MachOObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ StringRef Contents;
+ Section.getContents(Contents);
+ DataExtractor Data(Contents, Obj.isLittleEndian(), 0);
+
+ for (const object::RelocationRef &Reloc : Section.relocations()) {
+ object::DataRefImpl RelocDataRef = Reloc.getRawDataRefImpl();
+ MachO::any_relocation_info MachOReloc = Obj.getRelocation(RelocDataRef);
+ unsigned RelocSize = 1 << Obj.getAnyRelocationLength(MachOReloc);
+ uint64_t Offset64;
+ if ((RelocSize != 4 && RelocSize != 8) || Reloc.getOffset(Offset64)) {
+ reportWarning(" unsupported relocation in debug_info section.");
+ continue;
+ }
+ uint32_t Offset = Offset64;
+ // Mach-o uses REL relocations, the addend is at the relocation offset.
+ uint64_t Addend = Data.getUnsigned(&Offset, RelocSize);
+
+ auto Sym = Reloc.getSymbol();
+ if (Sym != Obj.symbol_end()) {
+ StringRef SymbolName;
+ if (Sym->getName(SymbolName)) {
+ reportWarning("error getting relocation symbol name.");
+ continue;
+ }
+ if (const auto *Mapping = DMO.lookupSymbol(SymbolName))
+ ValidRelocs.emplace_back(Offset64, RelocSize, Addend, Mapping);
+ } else if (const auto *Mapping = DMO.lookupObjectAddress(Addend)) {
+ // Do not store the addend. The addend was the address of the
+ // symbol in the object file, the address in the binary that is
+ // stored in the debug map doesn't need to be offseted.
+ ValidRelocs.emplace_back(Offset64, RelocSize, 0, Mapping);
+ }
+ }
+}
+
+/// \brief Dispatch the valid relocation finding logic to the
+/// appropriate handler depending on the object file format.
+bool DwarfLinker::findValidRelocs(const object::SectionRef &Section,
+ const object::ObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ // Dispatch to the right handler depending on the file type.
+ if (auto *MachOObj = dyn_cast<object::MachOObjectFile>(&Obj))
+ findValidRelocsMachO(Section, *MachOObj, DMO);
+ else
+ reportWarning(Twine("unsupported object file type: ") + Obj.getFileName());
+
+ if (ValidRelocs.empty())
+ return false;
+
+ // Sort the relocations by offset. We will walk the DIEs linearly in
+ // the file, this allows us to just keep an index in the relocation
+ // array that we advance during our walk, rather than resorting to
+ // some associative container. See DwarfLinker::NextValidReloc.
+ std::sort(ValidRelocs.begin(), ValidRelocs.end());
+ return true;
+}
+
+/// \brief Look for relocations in the debug_info section that match
+/// entries in the debug map. These relocations will drive the Dwarf
+/// link by indicating which DIEs refer to symbols present in the
+/// linked binary.
+/// \returns wether there are any valid relocations in the debug info.
+bool DwarfLinker::findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
+ const DebugMapObject &DMO) {
+ // Find the debug_info section.
+ for (const object::SectionRef &Section : Obj.sections()) {
+ StringRef SectionName;
+ Section.getName(SectionName);
+ SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+ if (SectionName != "debug_info")
+ continue;
+ return findValidRelocs(Section, Obj, DMO);
+ }
+ return false;
+}
+
+/// \brief Checks that there is a relocation against an actual debug
+/// map entry between \p StartOffset and \p NextOffset.
+///
+/// This function must be called with offsets in strictly ascending
+/// order because it never looks back at relocations it already 'went past'.
+/// \returns true and sets Info.InDebugMap if it is the case.
+bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
+ CompileUnit::DIEInfo &Info) {
+ assert(NextValidReloc == 0 ||
+ StartOffset > ValidRelocs[NextValidReloc - 1].Offset);
+ if (NextValidReloc >= ValidRelocs.size())
+ return false;
+
+ uint64_t RelocOffset = ValidRelocs[NextValidReloc].Offset;
+
+ // We might need to skip some relocs that we didn't consider. For
+ // example the high_pc of a discarded DIE might contain a reloc that
+ // is in the list because it actually corresponds to the start of a
+ // function that is in the debug map.
+ while (RelocOffset < StartOffset && NextValidReloc < ValidRelocs.size() - 1)
+ RelocOffset = ValidRelocs[++NextValidReloc].Offset;
+
+ if (RelocOffset < StartOffset || RelocOffset >= EndOffset)
+ return false;
+
+ const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+ if (Options.Verbose)
+ outs() << "Found valid debug map entry: " << ValidReloc.Mapping->getKey()
+ << " " << format("\t%016" PRIx64 " => %016" PRIx64,
+ ValidReloc.Mapping->getValue().ObjectAddress,
+ ValidReloc.Mapping->getValue().BinaryAddress);
+
+ Info.AddrAdjust = int64_t(ValidReloc.Mapping->getValue().BinaryAddress) +
+ ValidReloc.Addend -
+ ValidReloc.Mapping->getValue().ObjectAddress;
+ Info.InDebugMap = true;
+ return true;
+}
+
+/// \brief Get the starting and ending (exclusive) offset for the
+/// attribute with index \p Idx descibed by \p Abbrev. \p Offset is
+/// supposed to point to the position of the first attribute described
+/// by \p Abbrev.
+/// \return [StartOffset, EndOffset) as a pair.
+static std::pair<uint32_t, uint32_t>
+getAttributeOffsets(const DWARFAbbreviationDeclaration *Abbrev, unsigned Idx,
+ unsigned Offset, const DWARFUnit &Unit) {
+ DataExtractor Data = Unit.getDebugInfoExtractor();
+
+ for (unsigned i = 0; i < Idx; ++i)
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(i), Data, &Offset, &Unit);
+
+ uint32_t End = Offset;
+ DWARFFormValue::skipValue(Abbrev->getFormByIndex(Idx), Data, &End, &Unit);
+
+ return std::make_pair(Offset, End);
+}
+
+/// \brief Check if a variable describing DIE should be kept.
+/// \returns updated TraversalFlags.
+unsigned DwarfLinker::shouldKeepVariableDIE(
+ const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
+ const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+
+ // Global variables with constant value can always be kept.
+ if (!(Flags & TF_InFunctionScope) &&
+ Abbrev->findAttributeIndex(dwarf::DW_AT_const_value) != -1U) {
+ MyInfo.InDebugMap = true;
+ return Flags | TF_Keep;
+ }
+
+ uint32_t LocationIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_location);
+ if (LocationIdx == -1U)
+ return Flags;
+
+ uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+ const DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ uint32_t LocationOffset, LocationEndOffset;
+ std::tie(LocationOffset, LocationEndOffset) =
+ getAttributeOffsets(Abbrev, LocationIdx, Offset, OrigUnit);
+
+ // See if there is a relocation to a valid debug map entry inside
+ // this variable's location. The order is important here. We want to
+ // always check in the variable has a valid relocation, so that the
+ // DIEInfo is filled. However, we don't want a static variable in a
+ // function to force us to keep the enclosing function.
+ if (!hasValidRelocation(LocationOffset, LocationEndOffset, MyInfo) ||
+ (Flags & TF_InFunctionScope))
+ return Flags;
+
+ if (Options.Verbose)
+ DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */);
+
+ return Flags | TF_Keep;
+}
+
+/// \brief Check if a function describing DIE should be kept.
+/// \returns updated TraversalFlags.
+unsigned DwarfLinker::shouldKeepSubprogramDIE(
+ const DWARFDebugInfoEntryMinimal &DIE, CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo, unsigned Flags) {
+ const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+
+ Flags |= TF_InFunctionScope;
+
+ uint32_t LowPcIdx = Abbrev->findAttributeIndex(dwarf::DW_AT_low_pc);
+ if (LowPcIdx == -1U)
+ return Flags;
+
+ uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+ const DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ uint32_t LowPcOffset, LowPcEndOffset;
+ std::tie(LowPcOffset, LowPcEndOffset) =
+ getAttributeOffsets(Abbrev, LowPcIdx, Offset, OrigUnit);
+
+ uint64_t LowPc =
+ DIE.getAttributeValueAsAddress(&OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
+ assert(LowPc != -1ULL && "low_pc attribute is not an address.");
+ if (LowPc == -1ULL ||
+ !hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
+ return Flags;
+
+ if (Options.Verbose)
+ DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */);
+
+ Flags |= TF_Keep;
+
+ DWARFFormValue HighPcValue;
+ if (!DIE.getAttributeValue(&OrigUnit, dwarf::DW_AT_high_pc, HighPcValue)) {
+ reportWarning("Function without high_pc. Range will be discarded.\n",
+ &OrigUnit, &DIE);
+ return Flags;
+ }
+
+ uint64_t HighPc;
+ if (HighPcValue.isFormClass(DWARFFormValue::FC_Address)) {
+ HighPc = *HighPcValue.getAsAddress(&OrigUnit);
+ } else {
+ assert(HighPcValue.isFormClass(DWARFFormValue::FC_Constant));
+ HighPc = LowPc + *HighPcValue.getAsUnsignedConstant();
+ }
+
+ // Replace the debug map range with a more accurate one.
+ Ranges[LowPc] = std::make_pair(HighPc, MyInfo.AddrAdjust);
+ Unit.addFunctionRange(LowPc, HighPc, MyInfo.AddrAdjust);
+ return Flags;
+}
+
+/// \brief Check if a DIE should be kept.
+/// \returns updated TraversalFlags.
+unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit &Unit,
+ CompileUnit::DIEInfo &MyInfo,
+ unsigned Flags) {
+ switch (DIE.getTag()) {
+ case dwarf::DW_TAG_constant:
+ case dwarf::DW_TAG_variable:
+ return shouldKeepVariableDIE(DIE, Unit, MyInfo, Flags);
+ case dwarf::DW_TAG_subprogram:
+ return shouldKeepSubprogramDIE(DIE, Unit, MyInfo, Flags);
+ case dwarf::DW_TAG_module:
+ case dwarf::DW_TAG_imported_module:
+ case dwarf::DW_TAG_imported_declaration:
+ case dwarf::DW_TAG_imported_unit:
+ // We always want to keep these.
+ return Flags | TF_Keep;
+ }
+
+ return Flags;
+}
+
+/// \brief Mark the passed DIE as well as all the ones it depends on
+/// as kept.
+///
+/// This function is called by lookForDIEsToKeep on DIEs that are
+/// newly discovered to be needed in the link. It recursively calls
+/// back to lookForDIEsToKeep while adding TF_DependencyWalk to the
+/// TraversalFlags to inform it that it's not doing the primary DIE
+/// tree walk.
+void DwarfLinker::keepDIEAndDenpendencies(const DWARFDebugInfoEntryMinimal &DIE,
+ CompileUnit::DIEInfo &MyInfo,
+ const DebugMapObject &DMO,
+ CompileUnit &CU, unsigned Flags) {
+ const DWARFUnit &Unit = CU.getOrigUnit();
+ MyInfo.Keep = true;
+
+ // First mark all the parent chain as kept.
+ unsigned AncestorIdx = MyInfo.ParentIdx;
+ while (!CU.getInfo(AncestorIdx).Keep) {
+ lookForDIEsToKeep(*Unit.getDIEAtIndex(AncestorIdx), DMO, CU,
+ TF_ParentWalk | TF_Keep | TF_DependencyWalk);
+ AncestorIdx = CU.getInfo(AncestorIdx).ParentIdx;
+ }
+
+ // Then we need to mark all the DIEs referenced by this DIE's
+ // attributes as kept.
+ DataExtractor Data = Unit.getDebugInfoExtractor();
+ const auto *Abbrev = DIE.getAbbreviationDeclarationPtr();
+ uint32_t Offset = DIE.getOffset() + getULEB128Size(Abbrev->getCode());
+
+ // Mark all DIEs referenced through atttributes as kept.
+ for (const auto &AttrSpec : Abbrev->attributes()) {
+ DWARFFormValue Val(AttrSpec.Form);
+
+ if (!Val.isFormClass(DWARFFormValue::FC_Reference)) {
+ DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset, &Unit);
+ continue;
+ }
+
+ Val.extractValue(Data, &Offset, &Unit);
+ CompileUnit *ReferencedCU;
+ if (const auto *RefDIE = resolveDIEReference(Val, Unit, DIE, ReferencedCU))
+ lookForDIEsToKeep(*RefDIE, DMO, *ReferencedCU,
+ TF_Keep | TF_DependencyWalk);
+ }
+}
+
+/// \brief Recursively walk the \p DIE tree and look for DIEs to
+/// keep. Store that information in \p CU's DIEInfo.
+///
+/// This function is the entry point of the DIE selection
+/// algorithm. It is expected to walk the DIE tree in file order and
+/// (though the mediation of its helper) call hasValidRelocation() on
+/// each DIE that might be a 'root DIE' (See DwarfLinker class
+/// comment).
+/// While walking the dependencies of root DIEs, this function is
+/// also called, but during these dependency walks the file order is
+/// not respected. The TF_DependencyWalk flag tells us which kind of
+/// traversal we are currently doing.
+void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE,
+ const DebugMapObject &DMO, CompileUnit &CU,
+ unsigned Flags) {
+ unsigned Idx = CU.getOrigUnit().getDIEIndex(&DIE);
+ CompileUnit::DIEInfo &MyInfo = CU.getInfo(Idx);
+ bool AlreadyKept = MyInfo.Keep;
+
+ // If the Keep flag is set, we are marking a required DIE's
+ // dependencies. If our target is already marked as kept, we're all
+ // set.
+ if ((Flags & TF_DependencyWalk) && AlreadyKept)
+ return;
+
+ // We must not call shouldKeepDIE while called from keepDIEAndDenpendencies,
+ // because it would screw up the relocation finding logic.
+ if (!(Flags & TF_DependencyWalk))
+ Flags = shouldKeepDIE(DIE, CU, MyInfo, Flags);
+
+ // If it is a newly kept DIE mark it as well as all its dependencies as kept.
+ if (!AlreadyKept && (Flags & TF_Keep))
+ keepDIEAndDenpendencies(DIE, MyInfo, DMO, CU, Flags);
+
+ // The TF_ParentWalk flag tells us that we are currently walking up
+ // the parent chain of a required DIE, and we don't want to mark all
+ // the children of the parents as kept (consider for example a
+ // DW_TAG_namespace node in the parent chain). There are however a
+ // set of DIE types for which we want to ignore that directive and still
+ // walk their children.
+ if (dieNeedsChildrenToBeMeaningful(DIE.getTag()))
+ Flags &= ~TF_ParentWalk;
+
+ if (!DIE.hasChildren() || (Flags & TF_ParentWalk))
+ return;
+
+ for (auto *Child = DIE.getFirstChild(); Child && !Child->isNULL();
+ Child = Child->getSibling())
+ lookForDIEsToKeep(*Child, DMO, CU, Flags);
+}
+
+/// \brief Assign an abbreviation numer to \p Abbrev.
+///
+/// Our DIEs get freed after every DebugMapObject has been processed,
+/// thus the FoldingSet we use to unique DIEAbbrevs cannot refer to
+/// the instances hold by the DIEs. When we encounter an abbreviation
+/// that we don't know, we create a permanent copy of it.
+void DwarfLinker::AssignAbbrev(DIEAbbrev &Abbrev) {
+ // Check the set for priors.
+ FoldingSetNodeID ID;
+ Abbrev.Profile(ID);
+ void *InsertToken;
+ DIEAbbrev *InSet = AbbreviationsSet.FindNodeOrInsertPos(ID, InsertToken);
+
+ // If it's newly added.
+ if (InSet) {
+ // Assign existing abbreviation number.
+ Abbrev.setNumber(InSet->getNumber());
+ } else {
+ // Add to abbreviation list.
+ Abbreviations.push_back(
+ new DIEAbbrev(Abbrev.getTag(), Abbrev.hasChildren()));
+ for (const auto &Attr : Abbrev.getData())
+ Abbreviations.back()->AddAttribute(Attr.getAttribute(), Attr.getForm());
+ AbbreviationsSet.InsertNode(Abbreviations.back(), InsertToken);
+ // Assign the unique abbreviation number.
+ Abbrev.setNumber(Abbreviations.size());
+ Abbreviations.back()->setNumber(Abbreviations.size());
+ }
+}
+
+/// \brief Clone a string attribute described by \p AttrSpec and add
+/// it to \p Die.
+/// \returns the size of the new attribute.
+unsigned DwarfLinker::cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ const DWARFUnit &U) {
+ // Switch everything to out of line strings.
+ const char *String = *Val.getAsCString(&U);
+ unsigned Offset = StringPool.getStringOffset(String);
+ Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
+ new (DIEAlloc) DIEInteger(Offset));
+ return 4;
+}
+
+/// \brief Clone an attribute referencing another DIE and add
+/// it to \p Die.
+/// \returns the size of the new attribute.
+unsigned DwarfLinker::cloneDieReferenceAttribute(
+ DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE,
+ AttributeSpec AttrSpec, unsigned AttrSize, const DWARFFormValue &Val,
+ CompileUnit &Unit) {
+ uint32_t Ref = *Val.getAsReference(&Unit.getOrigUnit());
+ DIE *NewRefDie = nullptr;
+ CompileUnit *RefUnit = nullptr;
+ const DWARFDebugInfoEntryMinimal *RefDie = nullptr;
+
+ if (!(RefUnit = getUnitForOffset(Ref)) ||
+ !(RefDie = RefUnit->getOrigUnit().getDIEForOffset(Ref))) {
+ const char *AttributeString = dwarf::AttributeString(AttrSpec.Attr);
+ if (!AttributeString)
+ AttributeString = "DW_AT_???";
+ reportWarning(Twine("Missing DIE for ref in attribute ") + AttributeString +
+ ". Dropping.",
+ &Unit.getOrigUnit(), &InputDIE);
+ return 0;
+ }
+
+ unsigned Idx = RefUnit->getOrigUnit().getDIEIndex(RefDie);
+ CompileUnit::DIEInfo &RefInfo = RefUnit->getInfo(Idx);
+ if (!RefInfo.Clone) {
+ assert(Ref > InputDIE.getOffset());
+ // We haven't cloned this DIE yet. Just create an empty one and
+ // store it. It'll get really cloned when we process it.
+ RefInfo.Clone = new DIE(dwarf::Tag(RefDie->getTag()));
+ }
+ NewRefDie = RefInfo.Clone;
+
+ if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) {
+ // We cannot currently rely on a DIEEntry to emit ref_addr
+ // references, because the implementation calls back to DwarfDebug
+ // to find the unit offset. (We don't have a DwarfDebug)
+ // FIXME: we should be able to design DIEEntry reliance on
+ // DwarfDebug away.
+ DIEInteger *Attr;
+ if (Ref < InputDIE.getOffset()) {
+ // We must have already cloned that DIE.
+ uint32_t NewRefOffset =
+ RefUnit->getStartOffset() + NewRefDie->getOffset();
+ Attr = new (DIEAlloc) DIEInteger(NewRefOffset);
+ } else {
+ // A forward reference. Note and fixup later.
+ Attr = new (DIEAlloc) DIEInteger(0xBADDEF);
+ Unit.noteForwardReference(NewRefDie, RefUnit, Attr);
+ }
+ Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_ref_addr,
+ Attr);
+ return AttrSize;
+ }
+
+ Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
+ new (DIEAlloc) DIEEntry(*NewRefDie));
+ return AttrSize;
+}
+
+/// \brief Clone an attribute of block form (locations, constants) and add
+/// it to \p Die.
+/// \returns the size of the new attribute.
+unsigned DwarfLinker::cloneBlockAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ unsigned AttrSize) {
+ DIE *Attr;
+ DIEValue *Value;
+ DIELoc *Loc = nullptr;
+ DIEBlock *Block = nullptr;
+ // Just copy the block data over.
+ if (AttrSpec.Form == dwarf::DW_FORM_exprloc) {
+ Loc = new (DIEAlloc) DIELoc();
+ DIELocs.push_back(Loc);
+ } else {
+ Block = new (DIEAlloc) DIEBlock();
+ DIEBlocks.push_back(Block);
+ }
+ Attr = Loc ? static_cast<DIE *>(Loc) : static_cast<DIE *>(Block);
+ Value = Loc ? static_cast<DIEValue *>(Loc) : static_cast<DIEValue *>(Block);
+ ArrayRef<uint8_t> Bytes = *Val.getAsBlock();
+ for (auto Byte : Bytes)
+ Attr->addValue(static_cast<dwarf::Attribute>(0), dwarf::DW_FORM_data1,
+ new (DIEAlloc) DIEInteger(Byte));
+ // FIXME: If DIEBlock and DIELoc just reuses the Size field of
+ // the DIE class, this if could be replaced by
+ // Attr->setSize(Bytes.size()).
+ if (Streamer) {
+ if (Loc)
+ Loc->ComputeSize(&Streamer->getAsmPrinter());
+ else
+ Block->ComputeSize(&Streamer->getAsmPrinter());
+ }
+ Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
+ Value);
+ return AttrSize;
+}
+
+/// \brief Clone an address attribute and add it to \p Die.
+/// \returns the size of the new attribute.
+unsigned DwarfLinker::cloneAddressAttribute(DIE &Die, AttributeSpec AttrSpec,
+ const DWARFFormValue &Val,
+ const CompileUnit &Unit,
+ AttributesInfo &Info) {
+ uint64_t Addr = *Val.getAsAddress(&Unit.getOrigUnit());
+ if (AttrSpec.Attr == dwarf::DW_AT_low_pc) {
+ if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine ||
+ Die.getTag() == dwarf::DW_TAG_lexical_block)
+ Addr += Info.PCOffset;
+ else if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
+ Addr = Unit.getLowPc();
+ if (Addr == UINT64_MAX)
+ return 0;
+ }
+ Info.HasLowPc = true;
+ } else if (AttrSpec.Attr == dwarf::DW_AT_high_pc) {
+ if (Die.getTag() == dwarf::DW_TAG_compile_unit) {
+ if (uint64_t HighPc = Unit.getHighPc())
+ Addr = HighPc;
+ else
+ return 0;
+ } else
+ // If we have a high_pc recorded for the input DIE, use
+ // it. Otherwise (when no relocations where applied) just use the
+ // one we just decoded.
+ Addr = (Info.OrigHighPc ? Info.OrigHighPc : Addr) + Info.PCOffset;
+ }
+
+ Die.addValue(static_cast<dwarf::Attribute>(AttrSpec.Attr),
+ static_cast<dwarf::Form>(AttrSpec.Form),
+ new (DIEAlloc) DIEInteger(Addr));
+ return Unit.getOrigUnit().getAddressByteSize();
+}
+
+/// \brief Clone a scalar attribute and add it to \p Die.
+/// \returns the size of the new attribute.
+unsigned DwarfLinker::cloneScalarAttribute(
+ DIE &Die, const DWARFDebugInfoEntryMinimal &InputDIE, CompileUnit &Unit,
+ AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize,
+ AttributesInfo &Info) {
+ uint64_t Value;
+ if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
+ Die.getTag() == dwarf::DW_TAG_compile_unit) {
+ if (Unit.getLowPc() == -1ULL)
+ return 0;
+ // Dwarf >= 4 high_pc is an size, not an address.
+ Value = Unit.getHighPc() - Unit.getLowPc();
+ } else if (AttrSpec.Form == dwarf::DW_FORM_sec_offset)
+ Value = *Val.getAsSectionOffset();
+ else if (AttrSpec.Form == dwarf::DW_FORM_sdata)
+ Value = *Val.getAsSignedConstant();
+ else if (auto OptionalValue = Val.getAsUnsignedConstant())
+ Value = *OptionalValue;
+ else {
+ reportWarning("Unsupported scalar attribute form. Dropping attribute.",
+ &Unit.getOrigUnit(), &InputDIE);
+ return 0;
+ }
+ DIEInteger *Attr = new (DIEAlloc) DIEInteger(Value);
+ if (AttrSpec.Attr == dwarf::DW_AT_ranges)
+ Unit.noteRangeAttribute(Die, Attr);
+ // A more generic way to check for location attributes would be
+ // nice, but it's very unlikely that any other attribute needs a
+ // location list.
+ else if (AttrSpec.Attr == dwarf::DW_AT_location ||
+ AttrSpec.Attr == dwarf::DW_AT_frame_base)
+ Unit.noteLocationAttribute(Attr, Info.PCOffset);
+ else if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
+ Info.IsDeclaration = true;
+
+ Die.addValue(dwarf::Attribute(AttrSpec.Attr), dwarf::Form(AttrSpec.Form),
+ Attr);
+ return AttrSize;
+}
+
+/// \brief Clone \p InputDIE's attribute described by \p AttrSpec with
+/// value \p Val, and add it to \p Die.
+/// \returns the size of the cloned attribute.
+unsigned DwarfLinker::cloneAttribute(DIE &Die,
+ const DWARFDebugInfoEntryMinimal &InputDIE,
+ CompileUnit &Unit,
+ const DWARFFormValue &Val,
+ const AttributeSpec AttrSpec,
+ unsigned AttrSize, AttributesInfo &Info) {
+ const DWARFUnit &U = Unit.getOrigUnit();
+
+ switch (AttrSpec.Form) {
+ case dwarf::DW_FORM_strp:
+ case dwarf::DW_FORM_string:
+ return cloneStringAttribute(Die, AttrSpec, Val, U);
+ case dwarf::DW_FORM_ref_addr:
+ case dwarf::DW_FORM_ref1:
+ case dwarf::DW_FORM_ref2:
+ case dwarf::DW_FORM_ref4:
+ case dwarf::DW_FORM_ref8:
+ return cloneDieReferenceAttribute(Die, InputDIE, AttrSpec, AttrSize, Val,
+ Unit);
+ case dwarf::DW_FORM_block:
+ case dwarf::DW_FORM_block1:
+ case dwarf::DW_FORM_block2:
+ case dwarf::DW_FORM_block4:
+ case dwarf::DW_FORM_exprloc:
+ return cloneBlockAttribute(Die, AttrSpec, Val, AttrSize);
+ case dwarf::DW_FORM_addr:
+ return cloneAddressAttribute(Die, AttrSpec, Val, Unit, Info);
+ case dwarf::DW_FORM_data1:
+ case dwarf::DW_FORM_data2:
+ case dwarf::DW_FORM_data4:
+ case dwarf::DW_FORM_data8:
+ case dwarf::DW_FORM_udata:
+ case dwarf::DW_FORM_sdata:
+ case dwarf::DW_FORM_sec_offset:
+ case dwarf::DW_FORM_flag:
+ case dwarf::DW_FORM_flag_present:
+ return cloneScalarAttribute(Die, InputDIE, Unit, AttrSpec, Val, AttrSize,
+ Info);
+ default:
+ reportWarning("Unsupported attribute form in cloneAttribute. Dropping.", &U,
+ &InputDIE);
+ }
+
+ return 0;
+}
+
+/// \brief Apply the valid relocations found by findValidRelocs() to
+/// the buffer \p Data, taking into account that Data is at \p BaseOffset
+/// in the debug_info section.
+///
+/// Like for findValidRelocs(), this function must be called with
+/// monotonic \p BaseOffset values.
+///
+/// \returns wether any reloc has been applied.
+bool DwarfLinker::applyValidRelocs(MutableArrayRef<char> Data,
+ uint32_t BaseOffset, bool isLittleEndian) {
+ assert((NextValidReloc == 0 ||
+ BaseOffset > ValidRelocs[NextValidReloc - 1].Offset) &&
+ "BaseOffset should only be increasing.");
+ if (NextValidReloc >= ValidRelocs.size())
+ return false;
+
+ // Skip relocs that haven't been applied.
+ while (NextValidReloc < ValidRelocs.size() &&
+ ValidRelocs[NextValidReloc].Offset < BaseOffset)
+ ++NextValidReloc;
+
+ bool Applied = false;
+ uint64_t EndOffset = BaseOffset + Data.size();
+ while (NextValidReloc < ValidRelocs.size() &&
+ ValidRelocs[NextValidReloc].Offset >= BaseOffset &&
+ ValidRelocs[NextValidReloc].Offset < EndOffset) {
+ const auto &ValidReloc = ValidRelocs[NextValidReloc++];
+ assert(ValidReloc.Offset - BaseOffset < Data.size());
+ assert(ValidReloc.Offset - BaseOffset + ValidReloc.Size <= Data.size());
+ char Buf[8];
+ uint64_t Value = ValidReloc.Mapping->getValue().BinaryAddress;
+ Value += ValidReloc.Addend;
+ for (unsigned i = 0; i != ValidReloc.Size; ++i) {
+ unsigned Index = isLittleEndian ? i : (ValidReloc.Size - i - 1);
+ Buf[i] = uint8_t(Value >> (Index * 8));
+ }
+ assert(ValidReloc.Size <= sizeof(Buf));
+ memcpy(&Data[ValidReloc.Offset - BaseOffset], Buf, ValidReloc.Size);
+ Applied = true;
+ }
+
+ return Applied;
+}
+
+static bool isTypeTag(uint16_t Tag) {
+ switch (Tag) {
+ case dwarf::DW_TAG_array_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_enumeration_type:
+ case dwarf::DW_TAG_pointer_type:
+ case dwarf::DW_TAG_reference_type:
+ case dwarf::DW_TAG_string_type:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_subroutine_type:
+ case dwarf::DW_TAG_typedef:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_ptr_to_member_type:
+ case dwarf::DW_TAG_set_type:
+ case dwarf::DW_TAG_subrange_type:
+ case dwarf::DW_TAG_base_type:
+ case dwarf::DW_TAG_const_type:
+ case dwarf::DW_TAG_constant:
+ case dwarf::DW_TAG_file_type:
+ case dwarf::DW_TAG_namelist:
+ case dwarf::DW_TAG_packed_type:
+ case dwarf::DW_TAG_volatile_type:
+ case dwarf::DW_TAG_restrict_type:
+ case dwarf::DW_TAG_interface_type:
+ case dwarf::DW_TAG_unspecified_type:
+ case dwarf::DW_TAG_shared_type:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/// \brief Recursively clone \p InputDIE's subtrees that have been
+/// selected to appear in the linked output.
+///
+/// \param OutOffset is the Offset where the newly created DIE will
+/// lie in the linked compile unit.
+///
+/// \returns the cloned DIE object or null if nothing was selected.
+DIE *DwarfLinker::cloneDIE(const DWARFDebugInfoEntryMinimal &InputDIE,
+ CompileUnit &Unit, int64_t PCOffset,
+ uint32_t OutOffset) {
+ DWARFUnit &U = Unit.getOrigUnit();
+ unsigned Idx = U.getDIEIndex(&InputDIE);
+ CompileUnit::DIEInfo &Info = Unit.getInfo(Idx);
+
+ // Should the DIE appear in the output?
+ if (!Unit.getInfo(Idx).Keep)
+ return nullptr;
+
+ uint32_t Offset = InputDIE.getOffset();
+ // The DIE might have been already created by a forward reference
+ // (see cloneDieReferenceAttribute()).
+ DIE *Die = Info.Clone;
+ if (!Die)
+ Die = Info.Clone = new DIE(dwarf::Tag(InputDIE.getTag()));
+ assert(Die->getTag() == InputDIE.getTag());
+ Die->setOffset(OutOffset);
+
+ // Extract and clone every attribute.
+ DataExtractor Data = U.getDebugInfoExtractor();
+ uint32_t NextOffset = U.getDIEAtIndex(Idx + 1)->getOffset();
+ AttributesInfo AttrInfo;
+
+ // We could copy the data only if we need to aply a relocation to
+ // it. After testing, it seems there is no performance downside to
+ // doing the copy unconditionally, and it makes the code simpler.
+ SmallString<40> DIECopy(Data.getData().substr(Offset, NextOffset - Offset));
+ Data = DataExtractor(DIECopy, Data.isLittleEndian(), Data.getAddressSize());
+ // Modify the copy with relocated addresses.
+ if (applyValidRelocs(DIECopy, Offset, Data.isLittleEndian())) {
+ // If we applied relocations, we store the value of high_pc that was
+ // potentially stored in the input DIE. If high_pc is an address
+ // (Dwarf version == 2), then it might have been relocated to a
+ // totally unrelated value (because the end address in the object
+ // file might be start address of another function which got moved
+ // independantly by the linker). The computation of the actual
+ // high_pc value is done in cloneAddressAttribute().
+ AttrInfo.OrigHighPc =
+ InputDIE.getAttributeValueAsAddress(&U, dwarf::DW_AT_high_pc, 0);
+ }
+
+ // Reset the Offset to 0 as we will be working on the local copy of
+ // the data.
+ Offset = 0;
+
+ const auto *Abbrev = InputDIE.getAbbreviationDeclarationPtr();
+ Offset += getULEB128Size(Abbrev->getCode());
+
+ // We are entering a subprogram. Get and propagate the PCOffset.
+ if (Die->getTag() == dwarf::DW_TAG_subprogram)
+ PCOffset = Info.AddrAdjust;
+ AttrInfo.PCOffset = PCOffset;
+
+ for (const auto &AttrSpec : Abbrev->attributes()) {
+ DWARFFormValue Val(AttrSpec.Form);
+ uint32_t AttrSize = Offset;
+ Val.extractValue(Data, &Offset, &U);
+ AttrSize = Offset - AttrSize;
+
+ OutOffset +=
+ cloneAttribute(*Die, InputDIE, Unit, Val, AttrSpec, AttrSize, AttrInfo);
+ }
+
+ // Look for accelerator entries.
+ uint16_t Tag = InputDIE.getTag();
+ // FIXME: This is slightly wrong. An inline_subroutine without a
+ // low_pc, but with AT_ranges might be interesting to get into the
+ // accelerator tables too. For now stick with dsymutil's behavior.
+ if ((Info.InDebugMap || AttrInfo.HasLowPc) &&
+ Tag != dwarf::DW_TAG_compile_unit &&
+ getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) {
+ if (AttrInfo.MangledName && AttrInfo.MangledName != AttrInfo.Name)
+ Unit.addNameAccelerator(Die, AttrInfo.MangledName,
+ AttrInfo.MangledNameOffset,
+ Tag == dwarf::DW_TAG_inlined_subroutine);
+ if (AttrInfo.Name)
+ Unit.addNameAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset,
+ Tag == dwarf::DW_TAG_inlined_subroutine);
+ } else if (isTypeTag(Tag) && !AttrInfo.IsDeclaration &&
+ getDIENames(InputDIE, Unit.getOrigUnit(), AttrInfo)) {
+ Unit.addTypeAccelerator(Die, AttrInfo.Name, AttrInfo.NameOffset);
+ }
+
+ DIEAbbrev &NewAbbrev = Die->getAbbrev();
+ // If a scope DIE is kept, we must have kept at least one child. If
+ // it's not the case, we'll just be emitting one wasteful end of
+ // children marker, but things won't break.
+ if (InputDIE.hasChildren())
+ NewAbbrev.setChildrenFlag(dwarf::DW_CHILDREN_yes);
+ // Assign a permanent abbrev number
+ AssignAbbrev(Die->getAbbrev());
+
+ // Add the size of the abbreviation number to the output offset.
+ OutOffset += getULEB128Size(Die->getAbbrevNumber());
+
+ if (!Abbrev->hasChildren()) {
+ // Update our size.
+ Die->setSize(OutOffset - Die->getOffset());
+ return Die;
+ }
+
+ // Recursively clone children.
+ for (auto *Child = InputDIE.getFirstChild(); Child && !Child->isNULL();
+ Child = Child->getSibling()) {
+ if (DIE *Clone = cloneDIE(*Child, Unit, PCOffset, OutOffset)) {
+ Die->addChild(std::unique_ptr<DIE>(Clone));
+ OutOffset = Clone->getOffset() + Clone->getSize();
+ }
+ }
+
+ // Account for the end of children marker.
+ OutOffset += sizeof(int8_t);
+ // Update our size.
+ Die->setSize(OutOffset - Die->getOffset());
+ return Die;
+}
+
+/// \brief Patch the input object file relevant debug_ranges entries
+/// and emit them in the output file. Update the relevant attributes
+/// to point at the new entries.
+void DwarfLinker::patchRangesForUnit(const CompileUnit &Unit,
+ DWARFContext &OrigDwarf) const {
+ DWARFDebugRangeList RangeList;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ unsigned AddressSize = Unit.getOrigUnit().getAddressByteSize();
+ DataExtractor RangeExtractor(OrigDwarf.getRangeSection(),
+ OrigDwarf.isLittleEndian(), AddressSize);
+ auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
+ DWARFUnit &OrigUnit = Unit.getOrigUnit();
+ const auto *OrigUnitDie = OrigUnit.getUnitDIE(false);
+ uint64_t OrigLowPc = OrigUnitDie->getAttributeValueAsAddress(
+ &OrigUnit, dwarf::DW_AT_low_pc, -1ULL);
+ // Ranges addresses are based on the unit's low_pc. Compute the
+ // offset we need to apply to adapt to the the new unit's low_pc.
+ int64_t UnitPcOffset = 0;
+ if (OrigLowPc != -1ULL)
+ UnitPcOffset = int64_t(OrigLowPc) - Unit.getLowPc();
+
+ for (const auto &RangeAttribute : Unit.getRangesAttributes()) {
+ uint32_t Offset = RangeAttribute->getValue();
+ RangeAttribute->setValue(Streamer->getRangesSectionSize());
+ RangeList.extract(RangeExtractor, &Offset);
+ const auto &Entries = RangeList.getEntries();
+ const DWARFDebugRangeList::RangeListEntry &First = Entries.front();
+
+ if (CurrRange == InvalidRange || First.StartAddress < CurrRange.start() ||
+ First.StartAddress >= CurrRange.stop()) {
+ CurrRange = FunctionRanges.find(First.StartAddress + OrigLowPc);
+ if (CurrRange == InvalidRange ||
+ CurrRange.start() > First.StartAddress + OrigLowPc) {
+ reportWarning("no mapping for range.");
+ continue;
+ }
+ }
+
+ Streamer->emitRangesEntries(UnitPcOffset, OrigLowPc, CurrRange, Entries,
+ AddressSize);
+ }
+}
+
+/// \brief Generate the debug_aranges entries for \p Unit and if the
+/// unit has a DW_AT_ranges attribute, also emit the debug_ranges
+/// contribution for this attribute.
+/// FIXME: this could actually be done right in patchRangesForUnit,
+/// but for the sake of initial bit-for-bit compatibility with legacy
+/// dsymutil, we have to do it in a delayed pass.
+void DwarfLinker::generateUnitRanges(CompileUnit &Unit) const {
+ DIEInteger *Attr = Unit.getUnitRangesAttribute();
+ if (Attr)
+ Attr->setValue(Streamer->getRangesSectionSize());
+ Streamer->emitUnitRangesEntries(Unit, Attr != nullptr);
+}
+
+/// \brief Insert the new line info sequence \p Seq into the current
+/// set of already linked line info \p Rows.
+static void insertLineSequence(std::vector<DWARFDebugLine::Row> &Seq,
+ std::vector<DWARFDebugLine::Row> &Rows) {
+ if (Seq.empty())
+ return;
+
+ if (!Rows.empty() && Rows.back().Address < Seq.front().Address) {
+ Rows.insert(Rows.end(), Seq.begin(), Seq.end());
+ Seq.clear();
+ return;
+ }
+
+ auto InsertPoint = std::lower_bound(
+ Rows.begin(), Rows.end(), Seq.front(),
+ [](const DWARFDebugLine::Row &LHS, const DWARFDebugLine::Row &RHS) {
+ return LHS.Address < RHS.Address;
+ });
+
+ // FIXME: this only removes the unneeded end_sequence if the
+ // sequences have been inserted in order. using a global sort like
+ // described in patchLineTableForUnit() and delaying the end_sequene
+ // elimination to emitLineTableForUnit() we can get rid of all of them.
+ if (InsertPoint != Rows.end() &&
+ InsertPoint->Address == Seq.front().Address && InsertPoint->EndSequence) {
+ *InsertPoint = Seq.front();
+ Rows.insert(InsertPoint + 1, Seq.begin() + 1, Seq.end());
+ } else {
+ Rows.insert(InsertPoint, Seq.begin(), Seq.end());
+ }
+
+ Seq.clear();
+}
+
+/// \brief Extract the line table for \p Unit from \p OrigDwarf, and
+/// recreate a relocated version of these for the address ranges that
+/// are present in the binary.
+void DwarfLinker::patchLineTableForUnit(CompileUnit &Unit,
+ DWARFContext &OrigDwarf) {
+ const DWARFDebugInfoEntryMinimal *CUDie =
+ Unit.getOrigUnit().getUnitDIE();
+ uint64_t StmtList = CUDie->getAttributeValueAsSectionOffset(
+ &Unit.getOrigUnit(), dwarf::DW_AT_stmt_list, -1ULL);
+ if (StmtList == -1ULL)
+ return;
+
+ // Update the cloned DW_AT_stmt_list with the correct debug_line offset.
+ if (auto *OutputDIE = Unit.getOutputUnitDIE()) {
+ const auto &Abbrev = OutputDIE->getAbbrev().getData();
+ auto Stmt = std::find_if(
+ Abbrev.begin(), Abbrev.end(), [](const DIEAbbrevData &AbbrevData) {
+ return AbbrevData.getAttribute() == dwarf::DW_AT_stmt_list;
+ });
+ assert(Stmt < Abbrev.end() && "Didn't find DW_AT_stmt_list in cloned DIE!");
+ DIEInteger *StmtAttr =
+ cast<DIEInteger>(OutputDIE->getValues()[Stmt - Abbrev.begin()]);
+ StmtAttr->setValue(Streamer->getLineSectionSize());
+ }
+
+ // Parse the original line info for the unit.
+ DWARFDebugLine::LineTable LineTable;
+ uint32_t StmtOffset = StmtList;
+ StringRef LineData = OrigDwarf.getLineSection().Data;
+ DataExtractor LineExtractor(LineData, OrigDwarf.isLittleEndian(),
+ Unit.getOrigUnit().getAddressByteSize());
+ LineTable.parse(LineExtractor, &OrigDwarf.getLineSection().Relocs,
+ &StmtOffset);
+
+ // This vector is the output line table.
+ std::vector<DWARFDebugLine::Row> NewRows;
+ NewRows.reserve(LineTable.Rows.size());
+
+ // Current sequence of rows being extracted, before being inserted
+ // in NewRows.
+ std::vector<DWARFDebugLine::Row> Seq;
+ const auto &FunctionRanges = Unit.getFunctionRanges();
+ auto InvalidRange = FunctionRanges.end(), CurrRange = InvalidRange;
+
+ // FIXME: This logic is meant to generate exactly the same output as
+ // Darwin's classic dsynutil. There is a nicer way to implement this
+ // by simply putting all the relocated line info in NewRows and simply
+ // sorting NewRows before passing it to emitLineTableForUnit. This
+ // should be correct as sequences for a function should stay
+ // together in the sorted output. There are a few corner cases that
+ // look suspicious though, and that required to implement the logic
+ // this way. Revisit that once initial validation is finished.
+
+ // Iterate over the object file line info and extract the sequences
+ // that correspond to linked functions.
+ for (auto &Row : LineTable.Rows) {
+ // Check wether we stepped out of the range. The range is
+ // half-open, but consider accept the end address of the range if
+ // it is marked as end_sequence in the input (because in that
+ // case, the relocation offset is accurate and that entry won't
+ // serve as the start of another function).
+ if (CurrRange == InvalidRange || Row.Address < CurrRange.start() ||
+ Row.Address > CurrRange.stop() ||
+ (Row.Address == CurrRange.stop() && !Row.EndSequence)) {
+ // We just stepped out of a known range. Insert a end_sequence
+ // corresponding to the end of the range.
+ uint64_t StopAddress = CurrRange != InvalidRange
+ ? CurrRange.stop() + CurrRange.value()
+ : -1ULL;
+ CurrRange = FunctionRanges.find(Row.Address);
+ bool CurrRangeValid =
+ CurrRange != InvalidRange && CurrRange.start() <= Row.Address;
+ if (!CurrRangeValid) {
+ CurrRange = InvalidRange;
+ if (StopAddress != -1ULL) {
+ // Try harder by looking in the DebugMapObject function
+ // ranges map. There are corner cases where this finds a
+ // valid entry. It's unclear if this is right or wrong, but
+ // for now do as dsymutil.
+ // FIXME: Understand exactly what cases this addresses and
+ // potentially remove it along with the Ranges map.
+ auto Range = Ranges.lower_bound(Row.Address);
+ if (Range != Ranges.begin() && Range != Ranges.end())
+ --Range;
+
+ if (Range != Ranges.end() && Range->first <= Row.Address &&
+ Range->second.first >= Row.Address) {
+ StopAddress = Row.Address + Range->second.second;
+ }
+ }
+ }
+ if (StopAddress != -1ULL && !Seq.empty()) {
+ // Insert end sequence row with the computed end address, but
+ // the same line as the previous one.
+ Seq.emplace_back(Seq.back());
+ Seq.back().Address = StopAddress;
+ Seq.back().EndSequence = 1;
+ Seq.back().PrologueEnd = 0;
+ Seq.back().BasicBlock = 0;
+ Seq.back().EpilogueBegin = 0;
+ insertLineSequence(Seq, NewRows);
+ }
+
+ if (!CurrRangeValid)
+ continue;
+ }
+
+ // Ignore empty sequences.
+ if (Row.EndSequence && Seq.empty())
+ continue;
+
+ // Relocate row address and add it to the current sequence.
+ Row.Address += CurrRange.value();
+ Seq.emplace_back(Row);
+
+ if (Row.EndSequence)
+ insertLineSequence(Seq, NewRows);
+ }
+
+ // Finished extracting, now emit the line tables.
+ uint32_t PrologueEnd = StmtList + 10 + LineTable.Prologue.PrologueLength;
+ // FIXME: LLVM hardcodes it's prologue values. We just copy the
+ // prologue over and that works because we act as both producer and
+ // consumer. It would be nicer to have a real configurable line
+ // table emitter.
+ if (LineTable.Prologue.Version != 2 ||
+ LineTable.Prologue.DefaultIsStmt != DWARF2_LINE_DEFAULT_IS_STMT ||
+ LineTable.Prologue.LineBase != -5 || LineTable.Prologue.LineRange != 14 ||
+ LineTable.Prologue.OpcodeBase != 13)
+ reportWarning("line table paramters mismatch. Cannot emit.");
+ else
+ Streamer->emitLineTableForUnit(LineData.slice(StmtList + 4, PrologueEnd),
+ LineTable.Prologue.MinInstLength, NewRows,
+ Unit.getOrigUnit().getAddressByteSize());
+}
+
+void DwarfLinker::emitAcceleratorEntriesForUnit(CompileUnit &Unit) {
+ Streamer->emitPubNamesForUnit(Unit);
+ Streamer->emitPubTypesForUnit(Unit);
+}
+
+bool DwarfLinker::link(const DebugMap &Map) {
+
+ if (Map.begin() == Map.end()) {
+ errs() << "Empty debug map.\n";
+ return false;
+ }
+
+ if (!createStreamer(Map.getTriple(), OutputFilename))
+ return false;
+
+ // Size of the DIEs (and headers) generated for the linked output.
+ uint64_t OutputDebugInfoSize = 0;
+ // A unique ID that identifies each compile unit.
+ unsigned UnitID = 0;
+ for (const auto &Obj : Map.objects()) {
+ CurrentDebugObject = Obj.get();
+
+ if (Options.Verbose)
+ outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
+ auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename());
+ if (std::error_code EC = ErrOrObj.getError()) {
+ reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message());
+ continue;
+ }
+
+ // Look for relocations that correspond to debug map entries.
+ if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
+ if (Options.Verbose)
+ outs() << "No valid relocations found. Skipping.\n";
+ continue;
+ }
+
+ // Setup access to the debug info.
+ DWARFContextInMemory DwarfContext(*ErrOrObj);
+ startDebugObject(DwarfContext, *Obj);
+
+ // In a first phase, just read in the debug info and store the DIE
+ // parent links that we will use during the next phase.
+ for (const auto &CU : DwarfContext.compile_units()) {
+ auto *CUDie = CU->getUnitDIE(false);
+ if (Options.Verbose) {
+ outs() << "Input compilation unit:";
+ CUDie->dump(outs(), CU.get(), 0);
+ }
+ Units.emplace_back(*CU, UnitID++);
+ gatherDIEParents(CUDie, 0, Units.back());
+ }
+
+ // Then mark all the DIEs that need to be present in the linked
+ // output and collect some information about them. Note that this
+ // loop can not be merged with the previous one becaue cross-cu
+ // references require the ParentIdx to be setup for every CU in
+ // the object file before calling this.
+ for (auto &CurrentUnit : Units)
+ lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getUnitDIE(), *Obj,
+ CurrentUnit, 0);
+
+ // The calls to applyValidRelocs inside cloneDIE will walk the
+ // reloc array again (in the same way findValidRelocsInDebugInfo()
+ // did). We need to reset the NextValidReloc index to the beginning.
+ NextValidReloc = 0;
+
+ // Construct the output DIE tree by cloning the DIEs we chose to
+ // keep above. If there are no valid relocs, then there's nothing
+ // to clone/emit.
+ if (!ValidRelocs.empty())
+ for (auto &CurrentUnit : Units) {
+ const auto *InputDIE = CurrentUnit.getOrigUnit().getUnitDIE();
+ CurrentUnit.setStartOffset(OutputDebugInfoSize);
+ DIE *OutputDIE = cloneDIE(*InputDIE, CurrentUnit, 0 /* PCOffset */,
+ 11 /* Unit Header size */);
+ CurrentUnit.setOutputUnitDIE(OutputDIE);
+ OutputDebugInfoSize = CurrentUnit.computeNextUnitOffset();
+ if (Options.NoOutput)
+ continue;
+ // FIXME: for compatibility with the classic dsymutil, we emit
+ // an empty line table for the unit, even if the unit doesn't
+ // actually exist in the DIE tree.
+ patchLineTableForUnit(CurrentUnit, DwarfContext);
+ if (!OutputDIE)
+ continue;
+ patchRangesForUnit(CurrentUnit, DwarfContext);
+ Streamer->emitLocationsForUnit(CurrentUnit, DwarfContext);
+ emitAcceleratorEntriesForUnit(CurrentUnit);
+ }
+
+ // Emit all the compile unit's debug information.
+ if (!ValidRelocs.empty() && !Options.NoOutput)
+ for (auto &CurrentUnit : Units) {
+ generateUnitRanges(CurrentUnit);
+ CurrentUnit.fixupForwardReferences();
+ Streamer->emitCompileUnitHeader(CurrentUnit);
+ if (!CurrentUnit.getOutputUnitDIE())
+ continue;
+ Streamer->emitDIE(*CurrentUnit.getOutputUnitDIE());
+ }
+
+ // Clean-up before starting working on the next object.
+ endDebugObject();
+ }
+
+ // Emit everything that's global.
+ if (!Options.NoOutput) {
+ Streamer->emitAbbrevs(Abbreviations);
+ Streamer->emitStrings(StringPool);
+ }
+
+ return Options.NoOutput ? true : Streamer->finish();
+}
+}
+
+bool linkDwarf(StringRef OutputFilename, const DebugMap &DM,
+ const LinkOptions &Options) {
+ DwarfLinker Linker(OutputFilename, Options);
+ return Linker.link(DM);
+}
}
}
diff --git a/tools/dsymutil/LLVMBuild.txt b/tools/dsymutil/LLVMBuild.txt
index 24b9033c78c6..99b0b441c28e 100644
--- a/tools/dsymutil/LLVMBuild.txt
+++ b/tools/dsymutil/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-dsymutil
parent = Tools
-required_libraries = Object Support
+required_libraries = AsmPrinter DebugInfoDWARF MC Object Support all-targets
diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp
index 6b244fc369e9..bf64303b9eab 100644
--- a/tools/dsymutil/MachODebugMapParser.cpp
+++ b/tools/dsymutil/MachODebugMapParser.cpp
@@ -51,6 +51,10 @@ private:
/// Element of the debug map corresponfing to the current object file.
DebugMapObject *CurrentDebugMapObject;
+ /// Holds function info while function scope processing.
+ const char *CurrentFunctionName;
+ uint64_t CurrentFunctionAddress;
+
void switchToNewDebugMapObject(StringRef Filename);
void resetParserState();
uint64_t getMainBinarySymbolAddress(StringRef Name);
@@ -97,6 +101,13 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) {
CurrentDebugMapObject = &Result->addDebugMapObject(Path);
}
+static Triple getTriple(const object::MachOObjectFile &Obj) {
+ Triple TheTriple("unknown-unknown-unknown");
+ TheTriple.setArch(Triple::ArchType(Obj.getArch()));
+ TheTriple.setObjectFormat(Triple::MachO);
+ return TheTriple;
+}
+
/// This main parsing routine tries to open the main binary and if
/// successful iterates over the STAB entries. The real parsing is
/// done in handleStabSymbolTableEntry.
@@ -107,7 +118,7 @@ ErrorOr<std::unique_ptr<DebugMap>> MachODebugMapParser::parse() {
const MachOObjectFile &MainBinary = *MainBinOrError;
loadMainBinarySymbols();
- Result = make_unique<DebugMap>();
+ Result = make_unique<DebugMap>(getTriple(MainBinary));
MainBinaryStrings = MainBinary.getStringTableData();
for (const SymbolRef &Symbol : MainBinary.symbols()) {
const DataRefImpl &DRI = Symbol.getRawDataRefImpl();
@@ -142,6 +153,7 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
if (!CurrentDebugMapObject)
return;
+ uint32_t Size = 0;
switch (Type) {
case MachO::N_GSYM:
// This is a global variable. We need to query the main binary
@@ -152,11 +164,18 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
return;
break;
case MachO::N_FUN:
- // Functions are scopes in STABS. They have an end marker that we
- // need to ignore.
- if (Name[0] == '\0')
+ // Functions are scopes in STABS. They have an end marker that
+ // contains the function size.
+ if (Name[0] == '\0') {
+ Size = Value;
+ Value = CurrentFunctionAddress;
+ Name = CurrentFunctionName;
+ break;
+ } else {
+ CurrentFunctionName = Name;
+ CurrentFunctionAddress = Value;
return;
- break;
+ }
case MachO::N_STSYM:
break;
default:
@@ -167,7 +186,8 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex,
if (ObjectSymIt == CurrentObjectAddresses.end())
return Warning("could not find object file symbol for symbol " +
Twine(Name));
- if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value))
+ if (!CurrentDebugMapObject->addSymbol(Name, ObjectSymIt->getValue(), Value,
+ Size))
return Warning(Twine("failed to insert symbol '") + Name +
"' in the debug map.");
}
@@ -224,9 +244,8 @@ void MachODebugMapParser::loadMainBinarySymbols() {
namespace llvm {
namespace dsymutil {
-llvm::ErrorOr<std::unique_ptr<DebugMap>> parseDebugMap(StringRef InputFile,
- StringRef PrependPath,
- bool Verbose) {
+llvm::ErrorOr<std::unique_ptr<DebugMap>>
+parseDebugMap(StringRef InputFile, StringRef PrependPath, bool Verbose) {
MachODebugMapParser Parser(InputFile, PrependPath, Verbose);
return Parser.parse();
}
diff --git a/tools/dsymutil/Makefile b/tools/dsymutil/Makefile
index 9eda7dcabc0a..c4365e0196b3 100644
--- a/tools/dsymutil/Makefile
+++ b/tools/dsymutil/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-dsymutil
-LINK_COMPONENTS := Object Support
+LINK_COMPONENTS := all-targets AsmPrinter DebugInfoDWARF MC Object Support
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/dsymutil/dsymutil.cpp b/tools/dsymutil/dsymutil.cpp
index 2b4fcfe07008..4fc91b029f68 100644
--- a/tools/dsymutil/dsymutil.cpp
+++ b/tools/dsymutil/dsymutil.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/TargetSelect.h"
#include <string>
using namespace llvm::dsymutil;
@@ -29,6 +30,10 @@ using namespace llvm::cl;
static opt<std::string> InputFile(Positional, desc("<input file>"),
init("a.out"));
+static opt<std::string> OutputFileOpt("o", desc("Specify the output file."
+ " default: <input file>.dwarf"),
+ value_desc("filename"));
+
static opt<std::string> OsoPrependPath("oso-prepend-path",
desc("Specify a directory to prepend "
"to the paths of object files."),
@@ -36,6 +41,10 @@ static opt<std::string> OsoPrependPath("oso-prepend-path",
static opt<bool> Verbose("v", desc("Verbosity level"), init(false));
+static opt<bool> NoOutput("no-output", desc("Do the link in memory, but do "
+ "not emit the result file."),
+ init(false));
+
static opt<bool>
ParseOnly("parse-only",
desc("Only parse the debug map, do not actaully link "
@@ -47,10 +56,19 @@ int main(int argc, char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
llvm::llvm_shutdown_obj Shutdown;
+ LinkOptions Options;
llvm::cl::ParseCommandLineOptions(argc, argv, "llvm dsymutil\n");
auto DebugMapPtrOrErr = parseDebugMap(InputFile, OsoPrependPath, Verbose);
+ Options.Verbose = Verbose;
+ Options.NoOutput = NoOutput;
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+
if (auto EC = DebugMapPtrOrErr.getError()) {
llvm::errs() << "error: cannot parse the debug map for \"" << InputFile
<< "\": " << EC.message() << '\n';
@@ -63,9 +81,15 @@ int main(int argc, char **argv) {
if (ParseOnly)
return 0;
- std::string OutputBasename(InputFile);
- if (OutputBasename == "-")
- OutputBasename = "a.out";
+ std::string OutputFile;
+ if (OutputFileOpt.empty()) {
+ if (InputFile == "-")
+ OutputFile = "a.out.dwarf";
+ else
+ OutputFile = InputFile + ".dwarf";
+ } else {
+ OutputFile = OutputFileOpt;
+ }
- return !linkDwarf(OutputBasename + ".dwarf", **DebugMapPtrOrErr, Verbose);
+ return !linkDwarf(OutputFile, **DebugMapPtrOrErr, Options);
}
diff --git a/tools/dsymutil/dsymutil.h b/tools/dsymutil/dsymutil.h
index 9203beaf6774..e9f7cd951878 100644
--- a/tools/dsymutil/dsymutil.h
+++ b/tools/dsymutil/dsymutil.h
@@ -23,6 +23,14 @@
namespace llvm {
namespace dsymutil {
+
+struct LinkOptions {
+ bool Verbose; ///< Verbosity
+ bool NoOutput; ///< Skip emitting output
+
+ LinkOptions() : Verbose(false), NoOutput(false) {}
+};
+
/// \brief Extract the DebugMap from the given file.
/// The file has to be a MachO object file.
llvm::ErrorOr<std::unique_ptr<DebugMap>>
@@ -33,7 +41,7 @@ parseDebugMap(StringRef InputFile, StringRef PrependPath = "",
/// \p DM into a DwarfFile named \p OutputFilename.
/// \returns false if the link failed.
bool linkDwarf(StringRef OutputFilename, const DebugMap &DM,
- bool Verbose = false);
+ const LinkOptions &Options);
}
}
#endif // LLVM_TOOLS_DSYMUTIL_DSYMUTIL_H
diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt
index a70905c84bf0..1a6169d65c2c 100644
--- a/tools/gold/CMakeLists.txt
+++ b/tools/gold/CMakeLists.txt
@@ -1,6 +1,3 @@
-set(LLVM_BINUTILS_INCDIR "" CACHE PATH
- "PATH to binutils/include containing plugin-api.h for gold plugin.")
-
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/gold.exports)
if( LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR )
diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index a9909a721c1b..724e93cb8c74 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -15,26 +15,28 @@
#include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/CommandFlags.h"
+#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Linker/Linker.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Object/IRObjectFile.h"
-#include "llvm/PassManager.h"
-#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
-#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Utils/GlobalStatus.h"
@@ -89,6 +91,7 @@ namespace options {
};
static bool generate_api_file = false;
static OutputType TheOutputType = OT_NORMAL;
+ static unsigned OptLevel = 2;
static std::string obj_path;
static std::string extra_library_path;
static std::string triple;
@@ -122,6 +125,10 @@ namespace options {
TheOutputType = OT_SAVE_TEMPS;
} else if (opt == "disable-output") {
TheOutputType = OT_DISABLE;
+ } else if (opt.size() == 2 && opt[0] == 'O') {
+ if (opt[1] < '0' || opt[1] > '3')
+ report_fatal_error("Optimization level must be between 0 and 3");
+ OptLevel = opt[1] - '0';
} else {
// Save this option to pass to the code generator.
// ParseCommandLineOptions() expects argv[0] to be program name. Lazily
@@ -272,11 +279,11 @@ static bool shouldSkip(uint32_t Symflags) {
}
static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
- assert(DI.getSeverity() == DS_Error && "Only expecting errors");
- const auto &BDI = cast<BitcodeDiagnosticInfo>(DI);
- std::error_code EC = BDI.getError();
- if (EC == BitcodeError::InvalidBitcodeSignature)
- return;
+ if (const auto *BDI = dyn_cast<BitcodeDiagnosticInfo>(&DI)) {
+ std::error_code EC = BDI->getError();
+ if (EC == BitcodeError::InvalidBitcodeSignature)
+ return;
+ }
std::string ErrStorage;
{
@@ -284,8 +291,21 @@ static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
}
- message(LDPL_FATAL, "LLVM gold plugin has failed to create LTO module: %s",
- ErrStorage.c_str());
+ ld_plugin_level Level;
+ switch (DI.getSeverity()) {
+ case DS_Error:
+ message(LDPL_FATAL, "LLVM gold plugin has failed to create LTO module: %s",
+ ErrStorage.c_str());
+ llvm_unreachable("Fatal doesn't return.");
+ case DS_Warning:
+ Level = LDPL_WARNING;
+ break;
+ case DS_Note:
+ case DS_Remark:
+ Level = LDPL_INFO;
+ break;
+ }
+ message(Level, "LLVM gold plugin: %s", ErrStorage.c_str());
}
/// Called by gold to see whether this file is one that our plugin can handle.
@@ -560,7 +580,7 @@ static void freeSymName(ld_plugin_symbol &Sym) {
static std::unique_ptr<Module>
getModuleForFile(LLVMContext &Context, claimed_file &F,
- off_t Filesize, raw_fd_ostream *ApiFile,
+ ld_plugin_input_file &Info, raw_fd_ostream *ApiFile,
StringSet<> &Internalize, StringSet<> &Maybe) {
if (get_symbols(F.handle, F.syms.size(), &F.syms[0]) != LDPS_OK)
@@ -570,7 +590,8 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
if (get_view(F.handle, &View) != LDPS_OK)
message(LDPL_FATAL, "Failed to get a view of file");
- MemoryBufferRef BufferRef(StringRef((const char *)View, Filesize), "");
+ MemoryBufferRef BufferRef(StringRef((const char *)View, Info.filesize),
+ Info.name);
ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
object::IRObjectFile::create(BufferRef, Context);
@@ -582,6 +603,9 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
Module &M = Obj.getModule();
+ M.materializeMetadata();
+ UpgradeDebugInfo(M);
+
SmallPtrSet<GlobalValue *, 8> Used;
collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
@@ -692,15 +716,21 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
}
static void runLTOPasses(Module &M, TargetMachine &TM) {
- PassManager passes;
+ if (const DataLayout *DL = TM.getDataLayout())
+ M.setDataLayout(*DL);
+
+ legacy::PassManager passes;
+ passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
+
PassManagerBuilder PMB;
- PMB.LibraryInfo = new TargetLibraryInfo(Triple(TM.getTargetTriple()));
+ PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM.getTargetTriple()));
PMB.Inliner = createFunctionInliningPass();
PMB.VerifyInput = true;
PMB.VerifyOutput = true;
PMB.LoopVectorize = true;
PMB.SLPVectorize = true;
- PMB.populateLTOPassManager(passes, &TM);
+ PMB.OptLevel = options::OptLevel;
+ PMB.populateLTOPassManager(passes);
passes.run(M);
}
@@ -709,7 +739,7 @@ static void saveBCFile(StringRef Path, Module &M) {
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);
+ WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true);
}
static void codegen(Module &M) {
@@ -730,17 +760,31 @@ static void codegen(Module &M) {
Features.AddFeature(A);
TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+ CodeGenOpt::Level CGOptLevel;
+ switch (options::OptLevel) {
+ case 0:
+ CGOptLevel = CodeGenOpt::None;
+ break;
+ case 1:
+ CGOptLevel = CodeGenOpt::Less;
+ break;
+ case 2:
+ CGOptLevel = CodeGenOpt::Default;
+ break;
+ case 3:
+ CGOptLevel = CodeGenOpt::Aggressive;
+ break;
+ }
std::unique_ptr<TargetMachine> TM(TheTarget->createTargetMachine(
TripleStr, options::mcpu, Features.getString(), Options, RelocationModel,
- CodeModel::Default, CodeGenOpt::Aggressive));
+ CodeModel::Default, CGOptLevel));
runLTOPasses(M, *TM);
if (options::TheOutputType == options::OT_SAVE_TEMPS)
saveBCFile(output_name + ".opt.bc", M);
- PassManager CodeGenPasses;
- CodeGenPasses.add(new DataLayoutPass());
+ legacy::PassManager CodeGenPasses;
SmallString<128> Filename;
int FD;
@@ -760,9 +804,8 @@ static void codegen(Module &M) {
{
raw_fd_ostream OS(FD, true);
- formatted_raw_ostream FOS(OS);
- if (TM->addPassesToEmitFile(CodeGenPasses, FOS,
+ if (TM->addPassesToEmitFile(CodeGenPasses, OS,
TargetMachine::CGFT_ObjectFile))
message(LDPL_FATAL, "Failed to setup codegen");
CodeGenPasses.run(M);
@@ -785,6 +828,8 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
return LDPS_OK;
LLVMContext Context;
+ Context.setDiagnosticHandler(diagnosticHandler, nullptr, true);
+
std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
Linker L(Combined.get());
@@ -797,8 +842,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
if (get_input_file(F.handle, &File) != LDPS_OK)
message(LDPL_FATAL, "Failed to get file information");
std::unique_ptr<Module> M =
- getModuleForFile(Context, F, File.filesize, ApiFile,
- Internalize, Maybe);
+ getModuleForFile(Context, F, File, ApiFile, Internalize, Maybe);
if (!options::triple.empty())
M->setTargetTriple(options::triple.c_str());
else if (M->getTargetTriple().empty()) {
@@ -865,8 +909,13 @@ static ld_plugin_status all_symbols_read_hook(void) {
llvm_shutdown();
if (options::TheOutputType == options::OT_BC_ONLY ||
- options::TheOutputType == options::OT_DISABLE)
+ options::TheOutputType == options::OT_DISABLE) {
+ if (options::TheOutputType == options::OT_DISABLE)
+ // Remove the output file here since ld.bfd creates the output file
+ // early.
+ sys::fs::remove(output_name);
exit(0);
+ }
return Ret;
}
diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt
index 393d64c0ef08..dcbcf9da6128 100644
--- a/tools/llc/CMakeLists.txt
+++ b/tools/llc/CMakeLists.txt
@@ -1,5 +1,6 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
+ Analysis
AsmPrinter
CodeGen
Core
@@ -8,7 +9,6 @@ set(LLVM_LINK_COMPONENTS
ScalarOpts
SelectionDAG
Support
- Target
)
# Support plugins.
@@ -17,4 +17,4 @@ set(LLVM_NO_DEAD_STRIP 1)
add_llvm_tool(llc
llc.cpp
)
-set_target_properties(llc PROPERTIES ENABLE_EXPORTS 1)
+export_executable_symbols(llc)
diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp
index 35f965b2a300..0977418e0231 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -14,18 +14,21 @@
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/CodeGen/LinkAllAsmWriterComponents.h"
#include "llvm/CodeGen/LinkAllCodegenComponents.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Module.h"
+#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Pass.h"
-#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
@@ -39,7 +42,6 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#include <memory>
@@ -210,12 +212,6 @@ static int compileModule(char **argv, LLVMContext &Context) {
bool SkipModule = MCPU == "help" ||
(!MAttrs.empty() && MAttrs.front() == "help");
- // If user asked for the 'native' CPU, autodetect here. If autodection fails,
- // this will set the CPU to an empty string which tells the target to
- // pick a basic default.
- if (MCPU == "native")
- MCPU = sys::getHostCPUName();
-
// If user just wants to list available options, skip module loading
if (!SkipModule) {
M = parseIRFile(InputFilename, Err, Context);
@@ -224,6 +220,14 @@ static int compileModule(char **argv, LLVMContext &Context) {
return 1;
}
+ // Verify module immediately to catch problems before doInitialization() is
+ // called on any passes.
+ if (!NoVerify && verifyModule(*M, &errs())) {
+ errs() << argv[0] << ": " << InputFilename
+ << ": error: input module is broken!\n";
+ return 1;
+ }
+
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
@@ -244,14 +248,7 @@ static int compileModule(char **argv, LLVMContext &Context) {
return 1;
}
- // 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();
- }
+ std::string CPUStr = getCPUStr(), FeaturesStr = getFeaturesStr();
CodeGenOpt::Level OLvl = CodeGenOpt::Default;
switch (OptLevel) {
@@ -272,8 +269,9 @@ static int compileModule(char **argv, LLVMContext &Context) {
Options.MCOptions.AsmVerbose = AsmVerbose;
std::unique_ptr<TargetMachine> Target(
- TheTarget->createTargetMachine(TheTriple.getTriple(), MCPU, FeaturesStr,
+ TheTarget->createTargetMachine(TheTriple.getTriple(), CPUStr, FeaturesStr,
Options, RelocModel, CMModel, OLvl));
+
assert(Target && "Could not allocate target machine!");
// If we don't have a module then just exit now. We do this down
@@ -283,9 +281,8 @@ static int compileModule(char **argv, LLVMContext &Context) {
return 0;
assert(M && "Should have exited if we didn't have a module!");
-
- if (GenerateSoftFloatCalls)
- FloatABIForCalls = FloatABI::Soft;
+ if (FloatABIForCalls != FloatABI::Default)
+ Options.FloatABIType = FloatABIForCalls;
// Figure out where we are going to send the output.
std::unique_ptr<tool_output_file> Out =
@@ -293,18 +290,23 @@ static int compileModule(char **argv, LLVMContext &Context) {
if (!Out) return 1;
// Build up all of the passes that we want to do to the module.
- PassManager PM;
+ legacy::PassManager PM;
// Add an appropriate TargetLibraryInfo pass for the module's triple.
- TargetLibraryInfo *TLI = new TargetLibraryInfo(TheTriple);
+ TargetLibraryInfoImpl TLII(Triple(M->getTargetTriple()));
+
+ // The -disable-simplify-libcalls flag actually disables all builtin optzns.
if (DisableSimplifyLibCalls)
- TLI->disableAllFunctions();
- PM.add(TLI);
+ TLII.disableAllFunctions();
+ PM.add(new TargetLibraryInfoWrapperPass(TLII));
// Add the target data from the target machine, if it exists, or the module.
- if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
- M->setDataLayout(DL);
- PM.add(new DataLayoutPass());
+ if (const DataLayout *DL = Target->getDataLayout())
+ M->setDataLayout(*DL);
+
+ // Override function attributes based on CPUStr, FeaturesStr, and command line
+ // flags.
+ setFunctionAttributes(CPUStr, FeaturesStr, *M);
if (RelaxAll.getNumOccurrences() > 0 &&
FileType != TargetMachine::CGFT_ObjectFile)
@@ -312,7 +314,13 @@ static int compileModule(char **argv, LLVMContext &Context) {
<< ": warning: ignoring -mc-relax-all because filetype != obj";
{
- formatted_raw_ostream FOS(Out->os());
+ raw_pwrite_stream *OS = &Out->os();
+ std::unique_ptr<buffer_ostream> BOS;
+ if (FileType != TargetMachine::CGFT_AssemblyFile &&
+ !Out->os().supportsSeeking()) {
+ BOS = make_unique<buffer_ostream>(*OS);
+ OS = BOS.get();
+ }
AnalysisID StartAfterID = nullptr;
AnalysisID StopAfterID = nullptr;
@@ -335,8 +343,8 @@ static int compileModule(char **argv, LLVMContext &Context) {
}
// Ask the target to add backend passes as necessary.
- if (Target->addPassesToEmitFile(PM, FOS, FileType, NoVerify,
- StartAfterID, StopAfterID)) {
+ if (Target->addPassesToEmitFile(PM, *OS, FileType, NoVerify, StartAfterID,
+ StopAfterID)) {
errs() << argv[0] << ": target does not support generation of this"
<< " file type!\n";
return 1;
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 51f55791ea47..844b99464cb7 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -10,9 +10,11 @@ set(LLVM_LINK_COMPONENTS
MC
MCJIT
Object
+ OrcJIT
RuntimeDyld
SelectionDAG
Support
+ TransformUtils
native
)
@@ -26,7 +28,7 @@ endif( LLVM_USE_OPROFILE )
if( LLVM_USE_INTEL_JITEVENTS )
set(LLVM_LINK_COMPONENTS
${LLVM_LINK_COMPONENTS}
- DebugInfo
+ DebugInfoDWARF
IntelJITEvents
Object
)
@@ -34,8 +36,9 @@ endif( LLVM_USE_INTEL_JITEVENTS )
add_llvm_tool(lli
lli.cpp
+ OrcLazyJIT.cpp
RemoteMemoryManager.cpp
RemoteTarget.cpp
RemoteTargetExternal.cpp
)
-set_target_properties(lli PROPERTIES ENABLE_EXPORTS 1)
+export_executable_symbols(lli)
diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt
index 4c14c47bd0d5..580ba9a4ded6 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 MCJIT NativeCodeGen SelectionDAG Native
+required_libraries = AsmParser BitReader IRReader Instrumentation Interpreter MCJIT NativeCodeGen SelectionDAG TransformUtils Native
diff --git a/tools/lli/Makefile b/tools/lli/Makefile
index 94d6f061c946..70d8c80e5c0a 100644
--- a/tools/lli/Makefile
+++ b/tools/lli/Makefile
@@ -14,12 +14,12 @@ PARALLEL_DIRS := ChildTarget
include $(LEVEL)/Makefile.config
-LINK_COMPONENTS := mcjit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
+LINK_COMPONENTS := mcjit orcjit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native
# If Intel JIT Events support is confiured, link against the LLVM Intel JIT
# Events interface library
ifeq ($(USE_INTEL_JITEVENTS), 1)
- LINK_COMPONENTS += debuginfo inteljitevents object
+ LINK_COMPONENTS += debuginfodwarf inteljitevents object
endif
# If oprofile support is confiured, link against the LLVM oprofile interface
diff --git a/tools/lli/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp
new file mode 100644
index 000000000000..bda5d6dcd26c
--- /dev/null
+++ b/tools/lli/OrcLazyJIT.cpp
@@ -0,0 +1,148 @@
+//===------ OrcLazyJIT.cpp - Basic Orc-based JIT for lazy execution -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OrcLazyJIT.h"
+#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include <cstdio>
+#include <system_error>
+
+using namespace llvm;
+
+namespace {
+
+ enum class DumpKind { NoDump, DumpFuncsToStdOut, DumpModsToStdErr,
+ DumpModsToDisk };
+
+ cl::opt<DumpKind> OrcDumpKind("orc-lazy-debug",
+ cl::desc("Debug dumping for the orc-lazy JIT."),
+ cl::init(DumpKind::NoDump),
+ cl::values(
+ clEnumValN(DumpKind::NoDump, "no-dump",
+ "Don't dump anything."),
+ clEnumValN(DumpKind::DumpFuncsToStdOut,
+ "funcs-to-stdout",
+ "Dump function names to stdout."),
+ clEnumValN(DumpKind::DumpModsToStdErr,
+ "mods-to-stderr",
+ "Dump modules to stderr."),
+ clEnumValN(DumpKind::DumpModsToDisk,
+ "mods-to-disk",
+ "Dump modules to the current "
+ "working directory. (WARNING: "
+ "will overwrite existing files)."),
+ clEnumValEnd));
+}
+
+OrcLazyJIT::CallbackManagerBuilder
+OrcLazyJIT::createCallbackManagerBuilder(Triple T) {
+ switch (T.getArch()) {
+ default: return nullptr;
+
+ case Triple::x86_64: {
+ typedef orc::JITCompileCallbackManager<IRDumpLayerT,
+ orc::OrcX86_64> CCMgrT;
+ return [](IRDumpLayerT &IRDumpLayer, RuntimeDyld::MemoryManager &MemMgr,
+ LLVMContext &Context) {
+ return llvm::make_unique<CCMgrT>(IRDumpLayer, MemMgr, Context, 0,
+ 64);
+ };
+ }
+ }
+}
+
+OrcLazyJIT::TransformFtor OrcLazyJIT::createDebugDumper() {
+
+ switch (OrcDumpKind) {
+ case DumpKind::NoDump:
+ return [](std::unique_ptr<Module> M) { return M; };
+
+ case DumpKind::DumpFuncsToStdOut:
+ return [](std::unique_ptr<Module> M) {
+ printf("[ ");
+
+ for (const auto &F : *M) {
+ if (F.isDeclaration())
+ continue;
+
+ if (F.hasName()) {
+ std::string Name(F.getName());
+ printf("%s ", Name.c_str());
+ } else
+ printf("<anon> ");
+ }
+
+ printf("]\n");
+ return M;
+ };
+
+ case DumpKind::DumpModsToStdErr:
+ return [](std::unique_ptr<Module> M) {
+ dbgs() << "----- Module Start -----\n" << *M
+ << "----- Module End -----\n";
+
+ return M;
+ };
+
+ case DumpKind::DumpModsToDisk:
+ return [](std::unique_ptr<Module> M) {
+ std::error_code EC;
+ raw_fd_ostream Out(M->getModuleIdentifier() + ".ll", EC,
+ sys::fs::F_Text);
+ if (EC) {
+ errs() << "Couldn't open " << M->getModuleIdentifier()
+ << " for dumping.\nError:" << EC.message() << "\n";
+ exit(1);
+ }
+ Out << *M;
+ return M;
+ };
+ }
+ llvm_unreachable("Unknown DumpKind");
+}
+
+int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) {
+ // Add the program's symbols into the JIT's search space.
+ if (sys::DynamicLibrary::LoadLibraryPermanently(nullptr)) {
+ errs() << "Error loading program symbols.\n";
+ return 1;
+ }
+
+ // Grab a target machine and try to build a factory function for the
+ // target-specific Orc callback manager.
+ auto TM = std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget());
+ auto &Context = getGlobalContext();
+ auto CallbackMgrBuilder =
+ OrcLazyJIT::createCallbackManagerBuilder(Triple(TM->getTargetTriple()));
+
+ // If we couldn't build the factory function then there must not be a callback
+ // manager for this target. Bail out.
+ if (!CallbackMgrBuilder) {
+ errs() << "No callback manager available for target '"
+ << TM->getTargetTriple() << "'.\n";
+ return 1;
+ }
+
+ // Everything looks good. Build the JIT.
+ OrcLazyJIT J(std::move(TM), Context, CallbackMgrBuilder);
+
+ // Add the module, look up main and run it.
+ auto MainHandle = J.addModule(std::move(M));
+ auto MainSym = J.findSymbolIn(MainHandle, "main");
+
+ if (!MainSym) {
+ errs() << "Could not find main function.\n";
+ return 1;
+ }
+
+ typedef int (*MainFnPtr)(int, char*[]);
+ auto Main = OrcLazyJIT::fromTargetAddress<MainFnPtr>(MainSym.getAddress());
+ return Main(ArgC, ArgV);
+}
diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h
new file mode 100644
index 000000000000..bff2eca26a5f
--- /dev/null
+++ b/tools/lli/OrcLazyJIT.h
@@ -0,0 +1,164 @@
+//===--- OrcLazyJIT.h - Basic Orc-based JIT for lazy execution --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Simple Orc-based JIT. Uses the compile-on-demand layer to break up and
+// lazily compile modules.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLI_ORCLAZYJIT_H
+#define LLVM_TOOLS_LLI_ORCLAZYJIT_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+#include "llvm/IR/LLVMContext.h"
+
+namespace llvm {
+
+class OrcLazyJIT {
+public:
+
+ typedef orc::JITCompileCallbackManagerBase CompileCallbackMgr;
+ typedef orc::ObjectLinkingLayer<> ObjLayerT;
+ typedef orc::IRCompileLayer<ObjLayerT> CompileLayerT;
+ typedef std::function<std::unique_ptr<Module>(std::unique_ptr<Module>)>
+ TransformFtor;
+ typedef orc::IRTransformLayer<CompileLayerT, TransformFtor> IRDumpLayerT;
+ typedef orc::CompileOnDemandLayer<IRDumpLayerT, CompileCallbackMgr> CODLayerT;
+ typedef CODLayerT::ModuleSetHandleT ModuleHandleT;
+
+ typedef std::function<
+ std::unique_ptr<CompileCallbackMgr>(IRDumpLayerT&,
+ RuntimeDyld::MemoryManager&,
+ LLVMContext&)>
+ CallbackManagerBuilder;
+
+ static CallbackManagerBuilder createCallbackManagerBuilder(Triple T);
+
+ OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context,
+ CallbackManagerBuilder &BuildCallbackMgr)
+ : TM(std::move(TM)),
+ Mang(this->TM->getDataLayout()),
+ ObjectLayer(),
+ CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)),
+ IRDumpLayer(CompileLayer, createDebugDumper()),
+ CCMgr(BuildCallbackMgr(IRDumpLayer, CCMgrMemMgr, Context)),
+ CODLayer(IRDumpLayer, *CCMgr),
+ CXXRuntimeOverrides([this](const std::string &S) { return mangle(S); }) {}
+
+ ~OrcLazyJIT() {
+ // Run any destructors registered with __cxa_atexit.
+ CXXRuntimeOverrides.runDestructors();
+ // Run any IR destructors.
+ for (auto &DtorRunner : IRStaticDestructorRunners)
+ DtorRunner.runViaLayer(CODLayer);
+ }
+
+ template <typename PtrTy>
+ static PtrTy fromTargetAddress(orc::TargetAddress Addr) {
+ return reinterpret_cast<PtrTy>(static_cast<uintptr_t>(Addr));
+ }
+
+ ModuleHandleT addModule(std::unique_ptr<Module> M) {
+ // Attach a data-layout if one isn't already present.
+ if (M->getDataLayout().isDefault())
+ M->setDataLayout(*TM->getDataLayout());
+
+ // Record the static constructors and destructors. We have to do this before
+ // we hand over ownership of the module to the JIT.
+ std::vector<std::string> CtorNames, DtorNames;
+ for (auto Ctor : orc::getConstructors(*M))
+ CtorNames.push_back(mangle(Ctor.Func->getName()));
+ for (auto Dtor : orc::getDestructors(*M))
+ DtorNames.push_back(mangle(Dtor.Func->getName()));
+
+ // Symbol resolution order:
+ // 1) Search the JIT symbols.
+ // 2) Check for C++ runtime overrides.
+ // 3) Search the host process (LLI)'s symbol table.
+ auto Resolver =
+ orc::createLambdaResolver(
+ [this](const std::string &Name) {
+
+ if (auto Sym = CODLayer.findSymbol(Name, true))
+ return RuntimeDyld::SymbolInfo(Sym.getAddress(), Sym.getFlags());
+
+ if (auto Sym = CXXRuntimeOverrides.searchOverrides(Name))
+ return Sym;
+
+ if (auto Addr = RTDyldMemoryManager::getSymbolAddressInProcess(Name))
+ return RuntimeDyld::SymbolInfo(Addr, JITSymbolFlags::Exported);
+
+ return RuntimeDyld::SymbolInfo(nullptr);
+ },
+ [](const std::string &Name) { return RuntimeDyld::SymbolInfo(nullptr); }
+ );
+
+ // Add the module to the JIT.
+ std::vector<std::unique_ptr<Module>> S;
+ S.push_back(std::move(M));
+ auto H = CODLayer.addModuleSet(std::move(S), nullptr, std::move(Resolver));
+
+ // Run the static constructors, and save the static destructor runner for
+ // execution when the JIT is torn down.
+ orc::CtorDtorRunner<CODLayerT> CtorRunner(std::move(CtorNames), H);
+ CtorRunner.runViaLayer(CODLayer);
+
+ IRStaticDestructorRunners.push_back(
+ orc::CtorDtorRunner<CODLayerT>(std::move(DtorNames), H));
+
+ return H;
+ }
+
+ orc::JITSymbol findSymbol(const std::string &Name) {
+ return CODLayer.findSymbol(mangle(Name), true);
+ }
+
+ orc::JITSymbol findSymbolIn(ModuleHandleT H, const std::string &Name) {
+ return CODLayer.findSymbolIn(H, mangle(Name), true);
+ }
+
+private:
+
+ std::string mangle(const std::string &Name) {
+ std::string MangledName;
+ {
+ raw_string_ostream MangledNameStream(MangledName);
+ Mang.getNameWithPrefix(MangledNameStream, Name);
+ }
+ return MangledName;
+ }
+
+ static TransformFtor createDebugDumper();
+
+ std::unique_ptr<TargetMachine> TM;
+ Mangler Mang;
+ SectionMemoryManager CCMgrMemMgr;
+
+ ObjLayerT ObjectLayer;
+ CompileLayerT CompileLayer;
+ IRDumpLayerT IRDumpLayer;
+ std::unique_ptr<CompileCallbackMgr> CCMgr;
+ CODLayerT CODLayer;
+
+ orc::LocalCXXRuntimeOverrides CXXRuntimeOverrides;
+ std::vector<orc::CtorDtorRunner<CODLayerT>> IRStaticDestructorRunners;
+};
+
+int runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]);
+
+} // end namespace llvm
+
+#endif
diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp
index 47da8fb60c98..0a16210d2ea5 100644
--- a/tools/lli/RemoteMemoryManager.cpp
+++ b/tools/lli/RemoteMemoryManager.cpp
@@ -16,6 +16,7 @@
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
using namespace llvm;
diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h
index 895bcdac4d14..5733fa53f3e4 100644
--- a/tools/lli/RemoteMemoryManager.h
+++ b/tools/lli/RemoteMemoryManager.h
@@ -64,7 +64,7 @@ private:
public:
RemoteMemoryManager() : Target(nullptr) {}
- virtual ~RemoteMemoryManager();
+ ~RemoteMemoryManager() override;
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID,
diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h
index bb621f5c50f0..afe8570ff49f 100644
--- a/tools/lli/RemoteTargetExternal.h
+++ b/tools/lli/RemoteTargetExternal.h
@@ -106,7 +106,7 @@ public:
void stop() override;
RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {}
- virtual ~RemoteTargetExternal() {}
+ ~RemoteTargetExternal() override {}
private:
std::string ChildName;
diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp
index 730911b07c65..6916d1609b83 100644
--- a/tools/lli/lli.cpp
+++ b/tools/lli/lli.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/IR/LLVMContext.h"
+#include "OrcLazyJIT.h"
#include "RemoteMemoryManager.h"
#include "RemoteTarget.h"
#include "RemoteTargetExternal.h"
@@ -25,6 +26,7 @@
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/ObjectCache.h"
+#include "llvm/ExecutionEngine/OrcMCJITReplacement.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
@@ -41,6 +43,7 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
@@ -64,6 +67,9 @@ using namespace llvm;
#define DEBUG_TYPE "lli"
namespace {
+
+ enum class JITKind { MCJIT, OrcMCJITReplacement, OrcLazy };
+
cl::opt<std::string>
InputFile(cl::desc("<input bitcode>"), cl::Positional, cl::init("-"));
@@ -74,6 +80,20 @@ namespace {
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
+ cl::opt<JITKind> UseJITKind("jit-kind",
+ cl::desc("Choose underlying JIT kind."),
+ cl::init(JITKind::MCJIT),
+ cl::values(
+ clEnumValN(JITKind::MCJIT, "mcjit",
+ "MCJIT"),
+ clEnumValN(JITKind::OrcMCJITReplacement,
+ "orc-mcjit",
+ "Orc-based MCJIT replacement"),
+ clEnumValN(JITKind::OrcLazy,
+ "orc-lazy",
+ "Orc-based lazy JIT."),
+ clEnumValEnd));
+
// The MCJIT supports building for a target address space separate from
// the JIT compilation process. Use a forked process and a copying
// memory manager with IPC to execute using this functionality.
@@ -215,23 +235,6 @@ namespace {
clEnumValN(FloatABI::Hard, "hard",
"Hard float ABI (uses FP registers)"),
clEnumValEnd));
- cl::opt<bool>
-// In debug builds, make this default to true.
-#ifdef NDEBUG
-#define EMIT_DEBUG false
-#else
-#define EMIT_DEBUG true
-#endif
- EmitJitDebugInfo("jit-emit-debug",
- cl::desc("Emit debug information to debugger"),
- cl::init(EMIT_DEBUG));
-#undef EMIT_DEBUG
-
- static cl::opt<bool>
- EmitJitDebugInfoToDisk("jit-emit-debug-to-disk",
- cl::Hidden,
- cl::desc("Emit debug info objfiles to disk"),
- cl::init(false));
}
//===----------------------------------------------------------------------===//
@@ -251,7 +254,7 @@ public:
this->CacheDir[this->CacheDir.size() - 1] != '/')
this->CacheDir += '/';
}
- virtual ~LLIObjectCache() {}
+ ~LLIObjectCache() override {}
void notifyObjectCompiled(const Module *M, MemoryBufferRef Obj) override {
const std::string ModuleID = M->getModuleIdentifier();
@@ -395,6 +398,9 @@ int main(int argc, char **argv, char * const *envp) {
return 1;
}
+ if (UseJITKind == JITKind::OrcLazy)
+ return runOrcLazyJIT(std::move(Owner), argc, argv);
+
if (EnableCacheManager) {
std::string CacheName("file:");
CacheName.append(InputFile);
@@ -421,6 +427,7 @@ int main(int argc, char **argv, char * const *envp) {
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
: EngineKind::JIT);
+ builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement);
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
@@ -458,17 +465,8 @@ int main(int argc, char **argv, char * const *envp) {
builder.setOptLevel(OLvl);
TargetOptions Options;
- Options.UseSoftFloat = GenerateSoftFloatCalls;
if (FloatABIForCalls != FloatABI::Default)
Options.FloatABIType = FloatABIForCalls;
- if (GenerateSoftFloatCalls)
- FloatABIForCalls = FloatABI::Soft;
-
- // Remote target execution doesn't handle EH or debug registration.
- if (!RemoteMCJIT) {
- Options.JITEmitDebugInfo = EmitJitDebugInfo;
- Options.JITEmitDebugInfoToDisk = EmitJitDebugInfoToDisk;
- }
builder.setTargetOptions(Options);
@@ -556,7 +554,7 @@ int main(int argc, char **argv, char * const *envp) {
// If the user specifically requested an argv[0] to pass into the program,
// do it now.
if (!FakeArgv0.empty()) {
- InputFile = FakeArgv0;
+ InputFile = static_cast<std::string>(FakeArgv0);
} else {
// Otherwise, if there is a .bc suffix on the executable strip it off, it
// might confuse the program.
@@ -588,7 +586,7 @@ int main(int argc, char **argv, char * const *envp) {
// function later on to make an explicit call, so get the function now.
Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context),
Type::getInt32Ty(Context),
- NULL);
+ nullptr);
// Run static constructors.
if (!ForceInterpreter) {
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index f72762ac174a..f813465daafa 100644
--- a/tools/llvm-ar/llvm-ar.cpp
+++ b/tools/llvm-ar/llvm-ar.cpp
@@ -24,6 +24,7 @@
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
@@ -92,7 +93,6 @@ static cl::extrahelp MoreHelp(
" [a] - put file(s) after [relpos]\n"
" [b] - put file(s) before [relpos] (same as [i])\n"
" [i] - put file(s) before [relpos] (same as [b])\n"
- " [N] - use instance [count] of name\n"
" [o] - preserve original dates\n"
" [s] - create an archive index (cf. ranlib)\n"
" [S] - do not build a symbol table\n"
diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp
index 5ccf505923f2..4455d24fb60d 100644
--- a/tools/llvm-as/llvm-as.cpp
+++ b/tools/llvm-as/llvm-as.cpp
@@ -51,20 +51,19 @@ static cl::opt<bool>
DisableVerify("disable-verify", cl::Hidden,
cl::desc("Do not run verifier on input LLVM (dangerous!)"));
+static cl::opt<bool> PreserveBitcodeUseListOrder(
+ "preserve-bc-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM bitcode."),
+ cl::init(true), cl::Hidden);
+
static void WriteOutputFile(const Module *M) {
// Infer the output filename if needed.
if (OutputFilename.empty()) {
if (InputFilename == "-") {
OutputFilename = "-";
} else {
- std::string IFN = InputFilename;
- int Len = IFN.length();
- if (IFN[Len-3] == '.' && IFN[Len-2] == 'l' && IFN[Len-1] == 'l') {
- // Source ends in .ll
- OutputFilename = std::string(IFN.begin(), IFN.end()-3);
- } else {
- OutputFilename = IFN; // Append a .bc to it
- }
+ StringRef IFN = InputFilename;
+ OutputFilename = (IFN.endswith(".ll") ? IFN.drop_back(3) : IFN).str();
OutputFilename += ".bc";
}
}
@@ -78,7 +77,7 @@ static void WriteOutputFile(const Module *M) {
}
if (Force || !CheckBitcodeOutputToConsole(Out->os(), true))
- WriteBitcodeToFile(M, Out->os());
+ WriteBitcodeToFile(M, Out->os(), PreserveBitcodeUseListOrder);
// Declare success.
Out->keep();
diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
index 396e03036989..58b02be7b92f 100644
--- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
+++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp
@@ -66,6 +66,10 @@ static cl::opt<std::string>
BlockInfoFilename("block-info",
cl::desc("Use the BLOCK_INFO from the given file"));
+static cl::opt<bool>
+ ShowBinaryBlobs("show-binary-blobs",
+ cl::desc("Print binary blobs using hex escapes"));
+
namespace {
/// CurStreamTypeType - A type for CurStreamType
@@ -222,8 +226,10 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::FUNC_CODE_INST_BINOP: return "INST_BINOP";
case bitc::FUNC_CODE_INST_CAST: return "INST_CAST";
- case bitc::FUNC_CODE_INST_GEP: return "INST_GEP";
- case bitc::FUNC_CODE_INST_INBOUNDS_GEP: return "INST_INBOUNDS_GEP";
+ case bitc::FUNC_CODE_INST_GEP_OLD:
+ return "INST_GEP_OLD";
+ case bitc::FUNC_CODE_INST_INBOUNDS_GEP_OLD:
+ return "INST_INBOUNDS_GEP_OLD";
case bitc::FUNC_CODE_INST_SELECT: return "INST_SELECT";
case bitc::FUNC_CODE_INST_EXTRACTELT: return "INST_EXTRACTELT";
case bitc::FUNC_CODE_INST_INSERTELT: return "INST_INSERTELT";
@@ -248,6 +254,8 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID,
case bitc::FUNC_CODE_DEBUG_LOC_AGAIN: return "DEBUG_LOC_AGAIN";
case bitc::FUNC_CODE_INST_CALL: return "INST_CALL";
case bitc::FUNC_CODE_DEBUG_LOC: return "DEBUG_LOC";
+ case bitc::FUNC_CODE_INST_GEP:
+ return "INST_GEP";
}
case bitc::VALUE_SYMTAB_BLOCK_ID:
switch (CodeID) {
@@ -456,17 +464,22 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID,
if (Blob.data()) {
outs() << " blob data = ";
- bool BlobIsPrintable = true;
- for (unsigned i = 0, e = Blob.size(); i != e; ++i)
- if (!isprint(static_cast<unsigned char>(Blob[i]))) {
- BlobIsPrintable = false;
- break;
- }
-
- if (BlobIsPrintable)
- outs() << "'" << Blob << "'";
- else
- outs() << "unprintable, " << Blob.size() << " bytes.";
+ if (ShowBinaryBlobs) {
+ outs() << "'";
+ outs().write_escaped(Blob, /*hex=*/true) << "'";
+ } else {
+ bool BlobIsPrintable = true;
+ for (unsigned i = 0, e = Blob.size(); i != e; ++i)
+ if (!isprint(static_cast<unsigned char>(Blob[i]))) {
+ BlobIsPrintable = false;
+ break;
+ }
+
+ if (BlobIsPrintable)
+ outs() << "'" << Blob << "'";
+ else
+ outs() << "unprintable, " << Blob.size() << " bytes.";
+ }
}
outs() << "\n";
diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt
index 50c84e6c3d08..d2ef45a16815 100644
--- a/tools/llvm-config/CMakeLists.txt
+++ b/tools/llvm-config/CMakeLists.txt
@@ -44,7 +44,7 @@ if(CMAKE_CROSSCOMPILING)
WORKING_DIRECTORY ${LLVM_NATIVE_BUILD}
COMMENT "Building native llvm-config...")
add_custom_target(${project}NativeLLVMConfig DEPENDS ${${project}_LLVM_CONFIG_EXE})
- add_dependencies(${project}NativeLLVMConfig ConfigureNativeLLVM)
+ add_dependencies(${project}NativeLLVMConfig CONFIGURE_LLVM_NATIVE)
add_dependencies(llvm-config ${project}NativeLLVMConfig)
endif(CMAKE_CROSSCOMPILING)
diff --git a/tools/llvm-config/llvm-config.cpp b/tools/llvm-config/llvm-config.cpp
index 224035ac497b..879b9ab0945b 100644
--- a/tools/llvm-config/llvm-config.cpp
+++ b/tools/llvm-config/llvm-config.cpp
@@ -91,9 +91,9 @@ static void VisitComponent(StringRef Name,
/// are required to link the given components.
/// \param IncludeNonInstalled - Whether non-installed components should be
/// reported.
-void ComputeLibsForComponents(const std::vector<StringRef> &Components,
- std::vector<StringRef> &RequiredLibs,
- bool IncludeNonInstalled) {
+static void ComputeLibsForComponents(const std::vector<StringRef> &Components,
+ std::vector<StringRef> &RequiredLibs,
+ bool IncludeNonInstalled) {
std::set<AvailableComponent*> VisitedComponents;
// Build a map of component names to information.
@@ -126,7 +126,7 @@ void ComputeLibsForComponents(const std::vector<StringRef> &Components,
/* *** */
-void usage() {
+static void usage() {
errs() << "\
usage: llvm-config <OPTION>... [<COMPONENT>...]\n\
\n\
diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt
index b2d2b897ec95..193218a6639f 100644
--- a/tools/llvm-cov/CMakeLists.txt
+++ b/tools/llvm-cov/CMakeLists.txt
@@ -6,7 +6,6 @@ add_llvm_tool(llvm-cov
CodeCoverage.cpp
CoverageFilters.cpp
CoverageReport.cpp
- CoverageSummary.cpp
CoverageSummaryInfo.cpp
SourceCoverageView.cpp
TestingSupport.cpp
diff --git a/tools/llvm-cov/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp
index 7cee4d4b3f2e..f85f3b13b675 100644
--- a/tools/llvm-cov/CodeCoverage.cpp
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -16,13 +16,12 @@
#include "RenderingSupport.h"
#include "CoverageFilters.h"
#include "CoverageReport.h"
-#include "CoverageSummary.h"
#include "CoverageViewOptions.h"
#include "SourceCoverageView.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
#include "llvm/ProfileData/CoverageMapping.h"
-#include "llvm/ProfileData/CoverageMappingReader.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
@@ -30,6 +29,7 @@
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/Signals.h"
#include <functional>
#include <system_error>
@@ -89,6 +89,7 @@ public:
LoadedSourceFiles;
bool CompareFilenamesOnly;
StringMap<std::string> RemappedFilenames;
+ llvm::Triple::ArchType CoverageArch;
};
}
@@ -194,8 +195,22 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
return View;
}
+static bool modifiedTimeGT(StringRef LHS, StringRef RHS) {
+ sys::fs::file_status Status;
+ if (sys::fs::status(LHS, Status))
+ return false;
+ auto LHSTime = Status.getLastModificationTime();
+ if (sys::fs::status(RHS, Status))
+ return false;
+ auto RHSTime = Status.getLastModificationTime();
+ return LHSTime > RHSTime;
+}
+
std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
- auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename);
+ if (modifiedTimeGT(ObjectFilename, PGOFilename))
+ errs() << "warning: profile data may be out of date - object is newer\n";
+ auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename,
+ CoverageArch);
if (std::error_code EC = CoverageOrErr.getError()) {
colored_ostream(errs(), raw_ostream::RED)
<< "error: Failed to load coverage: " << EC.message();
@@ -244,6 +259,9 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
cl::desc(
"File with the profile data obtained after an instrumented run"));
+ cl::opt<std::string> Arch(
+ "arch", cl::desc("architecture of the coverage mapping binary"));
+
cl::opt<bool> DebugDump("dump", cl::Optional,
cl::desc("Show internal debug dump"));
@@ -289,11 +307,19 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
"greater than the given threshold"),
cl::cat(FilteringCategory));
+ cl::opt<cl::boolOrDefault> UseColor(
+ "use-color", cl::desc("Emit colored output (default=autodetect)"),
+ cl::init(cl::BOU_UNSET));
+
auto commandLineParser = [&, this](int argc, const char **argv) -> int {
cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n");
ViewOpts.Debug = DebugDump;
CompareFilenamesOnly = FilenameEquivalence;
+ ViewOpts.Colors = UseColor == cl::BOU_UNSET
+ ? sys::Process::StandardOutHasColors()
+ : UseColor == cl::BOU_TRUE;
+
// Create the function filters
if (!NameFilters.empty() || !NameRegexFilters.empty()) {
auto NameFilterer = new CoverageFilters;
@@ -324,12 +350,23 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
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();
+ if (Arch.empty())
+ CoverageArch = llvm::Triple::ArchType::UnknownArch;
+ else {
+ CoverageArch = Triple(Arch).getArch();
+ if (CoverageArch == llvm::Triple::ArchType::UnknownArch) {
+ errs() << "error: Unknown architecture: " << Arch << "\n";
return 1;
}
+ }
+
+ for (const auto &File : InputSourceFiles) {
+ SmallString<128> Path(File);
+ if (!CompareFilenamesOnly)
+ if (std::error_code EC = sys::fs::make_absolute(Path)) {
+ errs() << "error: " << File << ": " << EC.message();
+ return 1;
+ }
SourceFiles.push_back(Path.str());
}
return 0;
@@ -373,15 +410,10 @@ int CodeCoverageTool::show(int argc, const char **argv,
cl::desc("Show function instantiations"),
cl::cat(ViewCategory));
- cl::opt<bool> NoColors("no-colors", cl::Optional,
- cl::desc("Don't show text colors"), cl::init(false),
- cl::cat(ViewCategory));
-
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
- ViewOpts.Colors = !NoColors;
ViewOpts.ShowLineNumbers = true;
ViewOpts.ShowLineStats = ShowLineExecutionCounts.getNumOccurrences() != 0 ||
!ShowRegions || ShowBestLineRegionsCounts;
@@ -447,28 +479,19 @@ int CodeCoverageTool::show(int argc, const char **argv,
int CodeCoverageTool::report(int argc, const char **argv,
CommandLineParserType commandLineParser) {
- cl::opt<bool> NoColors("no-colors", cl::Optional,
- cl::desc("Don't show text colors"), cl::init(false));
-
auto Err = commandLineParser(argc, argv);
if (Err)
return Err;
- ViewOpts.Colors = !NoColors;
-
auto Coverage = load();
if (!Coverage)
return 1;
- CoverageSummary Summarizer;
- Summarizer.createSummaries(*Coverage);
- CoverageReport Report(ViewOpts, Summarizer);
- if (SourceFiles.empty() && Filters.empty()) {
+ CoverageReport Report(ViewOpts, std::move(Coverage));
+ if (SourceFiles.empty())
Report.renderFileReports(llvm::outs());
- return 0;
- }
-
- Report.renderFunctionReports(llvm::outs());
+ else
+ Report.renderFunctionReports(SourceFiles, llvm::outs());
return 0;
}
diff --git a/tools/llvm-cov/CoverageReport.cpp b/tools/llvm-cov/CoverageReport.cpp
index 6ae6ba55eb9c..497c2f88f268 100644
--- a/tools/llvm-cov/CoverageReport.cpp
+++ b/tools/llvm-cov/CoverageReport.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "CoverageReport.h"
-#include "CoverageSummary.h"
#include "RenderingSupport.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
@@ -156,14 +155,15 @@ void CoverageReport::render(const FunctionCoverageSummary &Function,
OS << "\n";
}
-void CoverageReport::renderFunctionReports(raw_ostream &OS) {
+void CoverageReport::renderFunctionReports(ArrayRef<std::string> Files,
+ raw_ostream &OS) {
bool isFirst = true;
- for (const auto &File : Summary.getFileSummaries()) {
+ for (StringRef Filename : Files) {
if (isFirst)
isFirst = false;
else
OS << "\n";
- OS << "File '" << File.Name << "':\n";
+ OS << "File '" << Filename << "':\n";
OS << column("Name", FunctionReportColumns[0])
<< column("Regions", FunctionReportColumns[1], Column::RightAlignment)
<< column("Miss", FunctionReportColumns[2], Column::RightAlignment)
@@ -174,13 +174,19 @@ void CoverageReport::renderFunctionReports(raw_ostream &OS) {
OS << "\n";
renderDivider(FunctionReportColumns, OS);
OS << "\n";
- for (const auto &Function : File.FunctionSummaries)
+ FunctionCoverageSummary Totals("TOTAL");
+ for (const auto &F : Coverage->getCoveredFunctions(Filename)) {
+ FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
+ ++Totals.ExecutionCount;
+ Totals.RegionCoverage += Function.RegionCoverage;
+ Totals.LineCoverage += Function.LineCoverage;
render(Function, OS);
- renderDivider(FunctionReportColumns, OS);
- OS << "\n";
- render(FunctionCoverageSummary("TOTAL", /*ExecutionCount=*/0,
- File.RegionCoverage, File.LineCoverage),
- OS);
+ }
+ if (Totals.ExecutionCount) {
+ renderDivider(FunctionReportColumns, OS);
+ OS << "\n";
+ render(Totals, OS);
+ }
}
}
@@ -194,9 +200,17 @@ void CoverageReport::renderFileReports(raw_ostream &OS) {
<< "\n";
renderDivider(FileReportColumns, OS);
OS << "\n";
- for (const auto &File : Summary.getFileSummaries())
- render(File, OS);
+ FileCoverageSummary Totals("TOTAL");
+ for (StringRef Filename : Coverage->getUniqueSourceFiles()) {
+ FileCoverageSummary Summary(Filename);
+ for (const auto &F : Coverage->getCoveredFunctions(Filename)) {
+ FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
+ Summary.addFunction(Function);
+ Totals.addFunction(Function);
+ }
+ render(Summary, OS);
+ }
renderDivider(FileReportColumns, OS);
OS << "\n";
- render(Summary.getCombinedFileSummaries(), OS);
+ render(Totals, OS);
}
diff --git a/tools/llvm-cov/CoverageReport.h b/tools/llvm-cov/CoverageReport.h
index d18611740ae6..7ec3df90b8f9 100644
--- a/tools/llvm-cov/CoverageReport.h
+++ b/tools/llvm-cov/CoverageReport.h
@@ -14,7 +14,7 @@
#ifndef LLVM_COV_COVERAGEREPORT_H
#define LLVM_COV_COVERAGEREPORT_H
-#include "CoverageSummary.h"
+#include "CoverageSummaryInfo.h"
#include "CoverageViewOptions.h"
namespace llvm {
@@ -22,16 +22,17 @@ namespace llvm {
/// \brief Displays the code coverage report.
class CoverageReport {
const CoverageViewOptions &Options;
- CoverageSummary &Summary;
+ std::unique_ptr<coverage::CoverageMapping> Coverage;
void render(const FileCoverageSummary &File, raw_ostream &OS);
void render(const FunctionCoverageSummary &Function, raw_ostream &OS);
public:
- CoverageReport(const CoverageViewOptions &Options, CoverageSummary &Summary)
- : Options(Options), Summary(Summary) {}
+ CoverageReport(const CoverageViewOptions &Options,
+ std::unique_ptr<coverage::CoverageMapping> Coverage)
+ : Options(Options), Coverage(std::move(Coverage)) {}
- void renderFunctionReports(raw_ostream &OS);
+ void renderFunctionReports(ArrayRef<std::string> Files, raw_ostream &OS);
void renderFileReports(raw_ostream &OS);
};
diff --git a/tools/llvm-cov/CoverageSummary.cpp b/tools/llvm-cov/CoverageSummary.cpp
deleted file mode 100644
index 059c8c857e45..000000000000
--- a/tools/llvm-cov/CoverageSummary.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-//===- CoverageSummary.cpp - Code coverage summary ------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class implements data management and rendering for the code coverage
-// summaries of all files and functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "CoverageSummary.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Format.h"
-
-using namespace llvm;
-
-unsigned CoverageSummary::getFileID(StringRef Filename) {
- for (unsigned I = 0, E = Filenames.size(); I < E; ++I) {
- if (sys::fs::equivalent(Filenames[I], Filename))
- return I;
- }
- Filenames.push_back(Filename);
- return Filenames.size() - 1;
-}
-
-void
-CoverageSummary::createSummaries(const coverage::CoverageMapping &Coverage) {
- for (StringRef Filename : Coverage.getUniqueSourceFiles()) {
- size_t PrevSize = FunctionSummaries.size();
- for (const auto &F : Coverage.getCoveredFunctions(Filename))
- FunctionSummaries.push_back(FunctionCoverageSummary::get(F));
- size_t Count = FunctionSummaries.size() - PrevSize;
- if (Count == 0)
- continue;
- FileSummaries.push_back(FileCoverageSummary::get(
- Filename, makeArrayRef(FunctionSummaries.data() + PrevSize, Count)));
- }
-}
-
-FileCoverageSummary CoverageSummary::getCombinedFileSummaries() {
- size_t NumRegions = 0, CoveredRegions = 0;
- size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
- size_t NumFunctionsExecuted = 0, NumFunctions = 0;
- for (const auto &File : FileSummaries) {
- NumRegions += File.RegionCoverage.NumRegions;
- CoveredRegions += File.RegionCoverage.Covered;
-
- NumLines += File.LineCoverage.NumLines;
- NonCodeLines += File.LineCoverage.NonCodeLines;
- CoveredLines += File.LineCoverage.Covered;
-
- NumFunctionsExecuted += File.FunctionCoverage.Executed;
- NumFunctions += File.FunctionCoverage.NumFunctions;
- }
- return FileCoverageSummary(
- "TOTAL", RegionCoverageInfo(CoveredRegions, NumRegions),
- LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
- FunctionCoverageInfo(NumFunctionsExecuted, NumFunctions),
- None);
-}
diff --git a/tools/llvm-cov/CoverageSummary.h b/tools/llvm-cov/CoverageSummary.h
deleted file mode 100644
index 9dbebde949e5..000000000000
--- a/tools/llvm-cov/CoverageSummary.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//===- CoverageSummary.h - Code coverage summary --------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This class implements data management and rendering for the code coverage
-// summaries of all files and functions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_COV_COVERAGESUMMARY_H
-#define LLVM_COV_COVERAGESUMMARY_H
-
-#include "CoverageSummaryInfo.h"
-#include <vector>
-
-namespace llvm {
-
-/// \brief Manager for the function and file code coverage summaries.
-class CoverageSummary {
- std::vector<StringRef> Filenames;
- std::vector<FunctionCoverageSummary> FunctionSummaries;
- std::vector<std::pair<unsigned, unsigned>> FunctionSummariesFileIDs;
- std::vector<FileCoverageSummary> FileSummaries;
-
- unsigned getFileID(StringRef Filename);
-
-public:
- void createSummaries(const coverage::CoverageMapping &Coverage);
-
- ArrayRef<FileCoverageSummary> getFileSummaries() { return FileSummaries; }
-
- FileCoverageSummary getCombinedFileSummaries();
-
- void render(const FunctionCoverageSummary &Summary, raw_ostream &OS);
-
- void render(raw_ostream &OS);
-};
-}
-
-#endif // LLVM_COV_COVERAGESUMMARY_H
diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp
index dd78ace86050..de8975097e49 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -69,28 +69,3 @@ FunctionCoverageSummary::get(const coverage::FunctionRecord &Function) {
RegionCoverageInfo(CoveredRegions, NumCodeRegions),
LineCoverageInfo(CoveredLines, 0, NumLines));
}
-
-FileCoverageSummary
-FileCoverageSummary::get(StringRef Name,
- ArrayRef<FunctionCoverageSummary> FunctionSummaries) {
- size_t NumRegions = 0, CoveredRegions = 0;
- size_t NumLines = 0, NonCodeLines = 0, CoveredLines = 0;
- size_t NumFunctionsExecuted = 0;
- for (const auto &Func : FunctionSummaries) {
- CoveredRegions += Func.RegionCoverage.Covered;
- NumRegions += Func.RegionCoverage.NumRegions;
-
- CoveredLines += Func.LineCoverage.Covered;
- NonCodeLines += Func.LineCoverage.NonCodeLines;
- NumLines += Func.LineCoverage.NumLines;
-
- if (Func.ExecutionCount != 0)
- ++NumFunctionsExecuted;
- }
-
- return FileCoverageSummary(
- Name, RegionCoverageInfo(CoveredRegions, NumRegions),
- LineCoverageInfo(CoveredLines, NonCodeLines, NumLines),
- FunctionCoverageInfo(NumFunctionsExecuted, FunctionSummaries.size()),
- FunctionSummaries);
-}
diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h
index 0036032ab399..c393b00d32a4 100644
--- a/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/tools/llvm-cov/CoverageSummaryInfo.h
@@ -31,10 +31,19 @@ struct RegionCoverageInfo {
/// \brief The total number of regions in a function/file.
size_t NumRegions;
+ RegionCoverageInfo() : Covered(0), NotCovered(0), NumRegions(0) {}
+
RegionCoverageInfo(size_t Covered, size_t NumRegions)
: Covered(Covered), NotCovered(NumRegions - Covered),
NumRegions(NumRegions) {}
+ RegionCoverageInfo &operator+=(const RegionCoverageInfo &RHS) {
+ Covered += RHS.Covered;
+ NotCovered += RHS.NotCovered;
+ NumRegions += RHS.NumRegions;
+ return *this;
+ }
+
bool isFullyCovered() const { return Covered == NumRegions; }
double getPercentCovered() const {
@@ -56,10 +65,21 @@ struct LineCoverageInfo {
/// \brief The total number of lines in a function/file.
size_t NumLines;
+ LineCoverageInfo()
+ : Covered(0), NotCovered(0), NonCodeLines(0), NumLines(0) {}
+
LineCoverageInfo(size_t Covered, size_t NumNonCodeLines, size_t NumLines)
: Covered(Covered), NotCovered(NumLines - NumNonCodeLines - Covered),
NonCodeLines(NumNonCodeLines), NumLines(NumLines) {}
+ LineCoverageInfo &operator+=(const LineCoverageInfo &RHS) {
+ Covered += RHS.Covered;
+ NotCovered += RHS.NotCovered;
+ NonCodeLines += RHS.NonCodeLines;
+ NumLines += RHS.NumLines;
+ return *this;
+ }
+
bool isFullyCovered() const { return Covered == (NumLines - NonCodeLines); }
double getPercentCovered() const {
@@ -75,9 +95,17 @@ struct FunctionCoverageInfo {
/// \brief The total number of functions in this file.
size_t NumFunctions;
+ FunctionCoverageInfo() : Executed(0), NumFunctions(0) {}
+
FunctionCoverageInfo(size_t Executed, size_t NumFunctions)
: Executed(Executed), NumFunctions(NumFunctions) {}
+ void addFunction(bool Covered) {
+ if (Covered)
+ ++Executed;
+ ++NumFunctions;
+ }
+
bool isFullyCovered() const { return Executed == NumFunctions; }
double getPercentCovered() const {
@@ -92,6 +120,8 @@ struct FunctionCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
+ FunctionCoverageSummary(StringRef Name) : Name(Name), ExecutionCount(0) {}
+
FunctionCoverageSummary(StringRef Name, uint64_t ExecutionCount,
const RegionCoverageInfo &RegionCoverage,
const LineCoverageInfo &LineCoverage)
@@ -111,21 +141,14 @@ struct FileCoverageSummary {
RegionCoverageInfo RegionCoverage;
LineCoverageInfo LineCoverage;
FunctionCoverageInfo FunctionCoverage;
- /// \brief The summary of every function
- /// in this file.
- ArrayRef<FunctionCoverageSummary> FunctionSummaries;
-
- FileCoverageSummary(StringRef Name, const RegionCoverageInfo &RegionCoverage,
- const LineCoverageInfo &LineCoverage,
- const FunctionCoverageInfo &FunctionCoverage,
- ArrayRef<FunctionCoverageSummary> FunctionSummaries)
- : Name(Name), RegionCoverage(RegionCoverage), LineCoverage(LineCoverage),
- FunctionCoverage(FunctionCoverage),
- FunctionSummaries(FunctionSummaries) {}
-
- /// \brief Compute the code coverage summary for a file.
- static FileCoverageSummary
- get(StringRef Name, ArrayRef<FunctionCoverageSummary> FunctionSummaries);
+
+ FileCoverageSummary(StringRef Name) : Name(Name) {}
+
+ void addFunction(const FunctionCoverageSummary &Function) {
+ RegionCoverage += Function.RegionCoverage;
+ LineCoverage += Function.LineCoverage;
+ FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
+ }
};
} // namespace llvm
diff --git a/tools/llvm-cov/RenderingSupport.h b/tools/llvm-cov/RenderingSupport.h
index 0271329997dc..3ef155d3fd4b 100644
--- a/tools/llvm-cov/RenderingSupport.h
+++ b/tools/llvm-cov/RenderingSupport.h
@@ -18,7 +18,7 @@ namespace llvm {
/// \brief A helper class that resets the output stream's color if needed
/// when destroyed.
class ColoredRawOstream {
- ColoredRawOstream(const ColoredRawOstream &OS) LLVM_DELETED_FUNCTION;
+ ColoredRawOstream(const ColoredRawOstream &OS) = delete;
public:
raw_ostream &OS;
diff --git a/tools/llvm-cov/SourceCoverageView.cpp b/tools/llvm-cov/SourceCoverageView.cpp
index 015099c7d02b..58c8a6795294 100644
--- a/tools/llvm-cov/SourceCoverageView.cpp
+++ b/tools/llvm-cov/SourceCoverageView.cpp
@@ -14,6 +14,7 @@
#include "SourceCoverageView.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/LineIterator.h"
using namespace llvm;
@@ -77,6 +78,22 @@ void SourceCoverageView::renderViewDivider(unsigned Level, unsigned Length,
OS << "-";
}
+/// Format a count using engineering notation with 3 significant digits.
+static std::string formatCount(uint64_t N) {
+ std::string Number = utostr(N);
+ int Len = Number.size();
+ if (Len <= 3)
+ return Number;
+ int IntLen = Len % 3 == 0 ? 3 : Len % 3;
+ std::string Result(Number.data(), IntLen);
+ if (IntLen != 3) {
+ Result.push_back('.');
+ Result += Number.substr(IntLen, 3 - IntLen);
+ }
+ Result.push_back(" kMGTPEZY"[(Len - 1) / 3]);
+ return Result;
+}
+
void
SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
const LineCoverageInfo &Line) {
@@ -84,17 +101,11 @@ SourceCoverageView::renderLineCoverageColumn(raw_ostream &OS,
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());
+ std::string C = formatCount(Line.ExecutionCount);
+ OS.indent(LineCoverageColumnWidth - C.size());
colored_ostream(OS, raw_ostream::MAGENTA,
Line.hasMultipleRegions() && Options.Colors)
- << Str;
+ << C;
OS << '|';
}
@@ -111,9 +122,6 @@ void SourceCoverageView::renderLineNumberColumn(raw_ostream &OS,
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)
@@ -122,20 +130,16 @@ void SourceCoverageView::renderRegionMarkers(
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();
+ std::string C = formatCount(S->Count);
+ PrevColumn += C.size();
+ OS << '^' << C;
}
OS << "\n";
if (Options.Debug)
for (const auto *S : Segments)
- errs() << "Marker at " << S->Line << ":" << S->Col << " = " << S->Count
- << (S->IsRegionEntry ? "\n" : " (pop)\n");
+ errs() << "Marker at " << S->Line << ":" << S->Col << " = "
+ << formatCount(S->Count) << (S->IsRegionEntry ? "\n" : " (pop)\n");
}
void SourceCoverageView::render(raw_ostream &OS, bool WholeFile,
diff --git a/tools/llvm-cov/SourceCoverageView.h b/tools/llvm-cov/SourceCoverageView.h
index d92a7486d9d3..9e6fe5f35001 100644
--- a/tools/llvm-cov/SourceCoverageView.h
+++ b/tools/llvm-cov/SourceCoverageView.h
@@ -90,15 +90,14 @@ private:
bool hasMultipleRegions() const { return RegionCount > 1; }
void addRegionStartCount(uint64_t Count) {
- Mapped = true;
- ExecutionCount = Count;
+ // The max of all region starts is the most interesting value.
+ addRegionCount(RegionCount ? std::max(ExecutionCount, Count) : Count);
++RegionCount;
}
void addRegionCount(uint64_t Count) {
Mapped = true;
- if (!RegionCount)
- ExecutionCount = Count;
+ ExecutionCount = Count;
}
};
diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp
index 12011cea7f26..4377a50b5566 100644
--- a/tools/llvm-cov/gcov.cpp
+++ b/tools/llvm-cov/gcov.cpp
@@ -23,9 +23,10 @@
#include <system_error>
using namespace llvm;
-void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
- const std::string &InputGCNO, const std::string &InputGCDA,
- bool DumpGCOV, const GCOVOptions &Options) {
+static void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
+ const std::string &InputGCNO,
+ const std::string &InputGCDA, bool DumpGCOV,
+ const GCOVOptions &Options) {
SmallString<128> CoverageFileStem(ObjectDir);
if (CoverageFileStem.empty()) {
// If no directory was specified with -o, look next to the source file.
@@ -80,7 +81,7 @@ void reportCoverage(StringRef SourceFile, StringRef ObjectDir,
FileInfo FI(Options);
GF.collectLineCounts(FI);
- FI.print(SourceFile, GCNO, GCDA);
+ FI.print(llvm::outs(), SourceFile, GCNO, GCDA);
}
int gcovMain(int argc, const char *argv[]) {
diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp
index 86ec26dbd188..bf66f583a528 100644
--- a/tools/llvm-cov/llvm-cov.cpp
+++ b/tools/llvm-cov/llvm-cov.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
#include <string>
@@ -32,9 +33,13 @@ int convertForTestingMain(int argc, const char *argv[]);
int gcovMain(int argc, const char *argv[]);
/// \brief Top level help.
-int helpMain(int argc, const char *argv[]) {
- errs() << "OVERVIEW: LLVM code coverage tool\n\n"
- << "USAGE: llvm-cov {gcov|report|show}\n";
+static int helpMain(int argc, const char *argv[]) {
+ errs() << "Usage: llvm-cov {gcov|report|show} [OPTION]...\n\n"
+ << "Shows code coverage information.\n\n"
+ << "Subcommands:\n"
+ << " gcov: Work with the gcov format.\n"
+ << " show: Annotate source files using instrprof style coverage.\n"
+ << " report: Summarize instrprof style coverage information.\n";
return 0;
}
@@ -61,18 +66,13 @@ int main(int argc, const char **argv) {
}
}
- // Give a warning and fall back to gcov
- errs().changeColor(raw_ostream::RED);
- errs() << "warning:";
- // Assume that argv[1] wasn't a command when it stats with a '-' or is a
- // filename (i.e. contains a '.')
- if (argc > 1 && !StringRef(argv[1]).startswith("-") &&
- StringRef(argv[1]).find(".") == StringRef::npos)
- errs() << " Unrecognized command '" << argv[1] << "'.";
- errs() << " Using the gcov compatible mode "
- "(this behaviour may be dropped in the future).";
- errs().resetColor();
- errs() << "\n";
-
- return gcovMain(argc, argv);
+ if (argc > 1) {
+ if (sys::Process::StandardErrHasColors())
+ errs().changeColor(raw_ostream::RED);
+ errs() << "Unrecognized command: " << argv[1] << ".\n\n";
+ if (sys::Process::StandardErrHasColors())
+ errs().resetColor();
+ }
+ helpMain(argc, argv);
+ return 1;
}
diff --git a/tools/llvm-vtabledump/CMakeLists.txt b/tools/llvm-cxxdump/CMakeLists.txt
index 4fe205b6efd4..ada886e88873 100644
--- a/tools/llvm-vtabledump/CMakeLists.txt
+++ b/tools/llvm-cxxdump/CMakeLists.txt
@@ -4,7 +4,7 @@ set(LLVM_LINK_COMPONENTS
Support
)
-add_llvm_tool(llvm-vtabledump
- llvm-vtabledump.cpp
+add_llvm_tool(llvm-cxxdump
+ llvm-cxxdump.cpp
Error.cpp
)
diff --git a/tools/llvm-vtabledump/Error.cpp b/tools/llvm-cxxdump/Error.cpp
index c5de8951636d..16fed96e4834 100644
--- a/tools/llvm-vtabledump/Error.cpp
+++ b/tools/llvm-cxxdump/Error.cpp
@@ -1,4 +1,4 @@
-//===- Error.cpp - system_error extensions for llvm-vtabledump --*- C++ -*-===//
+//===- Error.cxx - system_error extensions for llvm-cxxdump -----*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines a new error_category for the llvm-vtabledump tool.
+// This defines a new error_category for the llvm-cxxdump tool.
//
//===----------------------------------------------------------------------===//
@@ -17,27 +17,27 @@
using namespace llvm;
namespace {
-class vtabledump_error_category : public std::error_category {
+class cxxdump_error_category : public std::error_category {
public:
- const char *name() const LLVM_NOEXCEPT override { return "llvm.vtabledump"; }
+ const char *name() const LLVM_NOEXCEPT override { return "llvm.cxxdump"; }
std::string message(int ev) const override {
- switch (static_cast<vtabledump_error>(ev)) {
- case vtabledump_error::success:
+ switch (static_cast<cxxdump_error>(ev)) {
+ case cxxdump_error::success:
return "Success";
- case vtabledump_error::file_not_found:
+ case cxxdump_error::file_not_found:
return "No such file.";
- case vtabledump_error::unrecognized_file_format:
+ case cxxdump_error::unrecognized_file_format:
return "Unrecognized file type.";
}
llvm_unreachable(
- "An enumerator of vtabledump_error does not have a message defined.");
+ "An enumerator of cxxdump_error does not have a message defined.");
}
};
} // namespace
namespace llvm {
-const std::error_category &vtabledump_category() {
- static vtabledump_error_category o;
+const std::error_category &cxxdump_category() {
+ static cxxdump_error_category o;
return o;
}
} // namespace llvm
diff --git a/tools/llvm-vtabledump/Error.h b/tools/llvm-cxxdump/Error.h
index fd8bb18994df..7caf6d6447c9 100644
--- a/tools/llvm-vtabledump/Error.h
+++ b/tools/llvm-cxxdump/Error.h
@@ -1,4 +1,4 @@
-//===- Error.h - system_error extensions for llvm-vtabledump ----*- C++ -*-===//
+//===- Error.h - system_error extensions for llvm-cxxdump -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,33 +7,33 @@
//
//===----------------------------------------------------------------------===//
//
-// This declares a new error_category for the llvm-vtabledump tool.
+// This declares a new error_category for the llvm-cxxdump tool.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H
-#define LLVM_TOOLS_LLVM_VTABLEDUMP_ERROR_H
+#ifndef LLVM_TOOLS_LLVM_CXXDUMP_ERROR_H
+#define LLVM_TOOLS_LLVM_CXXDUMP_ERROR_H
#include <system_error>
namespace llvm {
-const std::error_category &vtabledump_category();
+const std::error_category &cxxdump_category();
-enum class vtabledump_error {
+enum class cxxdump_error {
success = 0,
file_not_found,
unrecognized_file_format,
};
-inline std::error_code make_error_code(vtabledump_error e) {
- return std::error_code(static_cast<int>(e), vtabledump_category());
+inline std::error_code make_error_code(cxxdump_error e) {
+ return std::error_code(static_cast<int>(e), cxxdump_category());
}
} // namespace llvm
namespace std {
template <>
-struct is_error_code_enum<llvm::vtabledump_error> : std::true_type {};
+struct is_error_code_enum<llvm::cxxdump_error> : std::true_type {};
}
#endif
diff --git a/tools/llvm-vtabledump/LLVMBuild.txt b/tools/llvm-cxxdump/LLVMBuild.txt
index 6a3cbfff4c13..4e088157799f 100644
--- a/tools/llvm-vtabledump/LLVMBuild.txt
+++ b/tools/llvm-cxxdump/LLVMBuild.txt
@@ -1,4 +1,4 @@
-;===- ./tools/llvm-vtabledump/LLVMBuild.txt --------------------*- Conf -*--===;
+;===- ./tools/llvm-cxxdump/LLVMBuild.txt -----------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
@@ -17,6 +17,6 @@
[component_0]
type = Tool
-name = llvm-vtabledump
+name = llvm-cxxdump
parent = Tools
required_libraries = all-targets BitReader Object
diff --git a/tools/llvm-vtabledump/Makefile b/tools/llvm-cxxdump/Makefile
index 596c64c67b6b..02e8e5f90108 100644
--- a/tools/llvm-vtabledump/Makefile
+++ b/tools/llvm-cxxdump/Makefile
@@ -1,4 +1,4 @@
-##===- tools/llvm-vtabledump/Makefile ----------------------*- Makefile -*-===##
+##===- tools/llvm-cxxdump/Makefile -------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
@@ -8,7 +8,7 @@
##===----------------------------------------------------------------------===##
LEVEL := ../..
-TOOLNAME := llvm-vtabledump
+TOOLNAME := llvm-cxxdump
LINK_COMPONENTS := bitreader object all-targets
# This tool has no plugins, optimize startup time.
diff --git a/tools/llvm-vtabledump/llvm-vtabledump.cpp b/tools/llvm-cxxdump/llvm-cxxdump.cpp
index a21acae02c3a..447d55afa8b8 100644
--- a/tools/llvm-vtabledump/llvm-vtabledump.cpp
+++ b/tools/llvm-cxxdump/llvm-cxxdump.cpp
@@ -1,4 +1,4 @@
-//===- llvm-vtabledump.cpp - Dump vtables in an Object File -----*- C++ -*-===//
+//===- llvm-cxxdump.cpp - Dump C++ data in an Object File -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,12 +7,11 @@
//
//===----------------------------------------------------------------------===//
//
-// Dumps VTables resident in object files and archives. Note, it currently only
-// supports MS-ABI style object files.
+// Dumps C++ data resident in object files and archives.
//
//===----------------------------------------------------------------------===//
-#include "llvm-vtabledump.h"
+#include "llvm-cxxdump.h"
#include "Error.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Object/Archive.h"
@@ -25,6 +24,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
#include <map>
#include <string>
#include <system_error>
@@ -43,7 +43,7 @@ static int ReturnValue = EXIT_SUCCESS;
namespace llvm {
-bool error(std::error_code EC) {
+static bool error(std::error_code EC) {
if (!EC)
return false;
@@ -135,7 +135,7 @@ static bool collectRelocationOffsets(
return false;
}
-static void dumpVTables(const ObjectFile *Obj) {
+static void dumpCXXData(const ObjectFile *Obj) {
struct CompleteObjectLocator {
StringRef Symbols[2];
ArrayRef<little32_t> Data;
@@ -153,13 +153,32 @@ static void dumpVTables(const ObjectFile *Obj) {
uint64_t AlwaysZero;
StringRef MangledName;
};
+ struct ThrowInfo {
+ uint32_t Flags;
+ };
+ struct CatchableTypeArray {
+ uint32_t NumEntries;
+ };
+ struct CatchableType {
+ uint32_t Flags;
+ uint32_t NonVirtualBaseAdjustmentOffset;
+ int32_t VirtualBasePointerOffset;
+ uint32_t VirtualBaseAdjustmentOffset;
+ uint32_t Size;
+ StringRef Symbols[2];
+ };
std::map<std::pair<StringRef, uint64_t>, StringRef> VFTableEntries;
+ std::map<std::pair<StringRef, uint64_t>, StringRef> TIEntries;
+ std::map<std::pair<StringRef, uint64_t>, StringRef> CTAEntries;
std::map<StringRef, ArrayRef<little32_t>> VBTables;
std::map<StringRef, CompleteObjectLocator> COLs;
std::map<StringRef, ClassHierarchyDescriptor> CHDs;
std::map<std::pair<StringRef, uint64_t>, StringRef> BCAEntries;
std::map<StringRef, BaseClassDescriptor> BCDs;
std::map<StringRef, TypeDescriptor> TDs;
+ std::map<StringRef, ThrowInfo> TIs;
+ std::map<StringRef, CatchableTypeArray> CTAs;
+ std::map<StringRef, CatchableType> CTs;
std::map<std::pair<StringRef, uint64_t>, StringRef> VTableSymEntries;
std::map<std::pair<StringRef, uint64_t>, int64_t> VTableDataEntries;
@@ -265,6 +284,39 @@ static void dumpVTables(const ObjectFile *Obj) {
return;
TDs[SymName] = TD;
}
+ // Throw descriptors in the MS-ABI start with '_TI'
+ else if (SymName.startswith("_TI") || SymName.startswith("__TI")) {
+ ThrowInfo TI;
+ TI.Flags = *reinterpret_cast<const little32_t *>(SymContents.data());
+ collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
+ SymName, TIEntries);
+ TIs[SymName] = TI;
+ }
+ // Catchable type arrays in the MS-ABI start with _CTA or __CTA.
+ else if (SymName.startswith("_CTA") || SymName.startswith("__CTA")) {
+ CatchableTypeArray CTA;
+ CTA.NumEntries =
+ *reinterpret_cast<const little32_t *>(SymContents.data());
+ collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
+ SymName, CTAEntries);
+ CTAs[SymName] = CTA;
+ }
+ // Catchable types in the MS-ABI start with _CT or __CT.
+ else if (SymName.startswith("_CT") || SymName.startswith("__CT")) {
+ const little32_t *DataPtr =
+ reinterpret_cast<const little32_t *>(SymContents.data());
+ CatchableType CT;
+ CT.Flags = DataPtr[0];
+ CT.NonVirtualBaseAdjustmentOffset = DataPtr[2];
+ CT.VirtualBasePointerOffset = DataPtr[3];
+ CT.VirtualBaseAdjustmentOffset = DataPtr[4];
+ CT.Size = DataPtr[5];
+ StringRef *I = std::begin(CT.Symbols), *E = std::end(CT.Symbols);
+ if (collectRelocatedSymbols(Obj, Sec, SecAddress, SymAddress, SymSize, I,
+ E))
+ return;
+ CTs[SymName] = CT;
+ }
// Construction vtables in the Itanium ABI start with '_ZTT' or '__ZTT'.
else if (SymName.startswith("_ZTT") || SymName.startswith("__ZTT")) {
collectRelocationOffsets(Obj, Sec, SecAddress, SymAddress, SymSize,
@@ -282,7 +334,8 @@ static void dumpVTables(const ObjectFile *Obj) {
auto Key = std::make_pair(SymName, SymOffI);
if (VTableSymEntries.count(Key))
continue;
- const char *DataPtr = SymContents.substr(SymOffI, BytesInAddress).data();
+ const char *DataPtr =
+ SymContents.substr(SymOffI, BytesInAddress).data();
int64_t VData;
if (BytesInAddress == 8)
VData = *reinterpret_cast<const little64_t *>(DataPtr);
@@ -296,14 +349,13 @@ static void dumpVTables(const ObjectFile *Obj) {
// FIXME: Do something with these!
}
}
- for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VFTableEntry :
- VFTableEntries) {
+ for (const auto &VFTableEntry : VFTableEntries) {
StringRef VFTableName = VFTableEntry.first.first;
uint64_t Offset = VFTableEntry.first.second;
StringRef SymName = VFTableEntry.second;
outs() << VFTableName << '[' << Offset << "]: " << SymName << '\n';
}
- for (const std::pair<StringRef, ArrayRef<little32_t>> &VBTable : VBTables) {
+ for (const auto &VBTable : VBTables) {
StringRef VBTableName = VBTable.first;
uint32_t Idx = 0;
for (little32_t Offset : VBTable.second) {
@@ -311,16 +363,17 @@ static void dumpVTables(const ObjectFile *Obj) {
Idx += sizeof(Offset);
}
}
- for (const std::pair<StringRef, CompleteObjectLocator> &COLPair : COLs) {
+ for (const auto &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';
+ outs() << COLName << "[ClassHierarchyDescriptor]: " << COL.Symbols[1]
+ << '\n';
}
- for (const std::pair<StringRef, ClassHierarchyDescriptor> &CHDPair : CHDs) {
+ for (const auto &CHDPair : CHDs) {
StringRef CHDName = CHDPair.first;
const ClassHierarchyDescriptor &CHD = CHDPair.second;
outs() << CHDName << "[AlwaysZero]: " << CHD.Data[0] << '\n';
@@ -328,14 +381,13 @@ static void dumpVTables(const ObjectFile *Obj) {
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) {
+ for (const auto &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) {
+ for (const auto &BCDPair : BCDs) {
StringRef BCDName = BCDPair.first;
const BaseClassDescriptor &BCD = BCDPair.second;
outs() << BCDName << "[TypeDescriptor]: " << BCD.Symbols[0] << '\n';
@@ -344,9 +396,10 @@ static void dumpVTables(const ObjectFile *Obj) {
outs() << BCDName << "[VBPtrOffset]: " << BCD.Data[2] << '\n';
outs() << BCDName << "[OffsetInVBTable]: " << BCD.Data[3] << '\n';
outs() << BCDName << "[Flags]: " << BCD.Data[4] << '\n';
- outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1] << '\n';
+ outs() << BCDName << "[ClassHierarchyDescriptor]: " << BCD.Symbols[1]
+ << '\n';
}
- for (const std::pair<StringRef, TypeDescriptor> &TDPair : TDs) {
+ for (const auto &TDPair : TDs) {
StringRef TDName = TDPair.first;
const TypeDescriptor &TD = TDPair.second;
outs() << TDName << "[VFPtr]: " << TD.Symbols[0] << '\n';
@@ -356,14 +409,67 @@ static void dumpVTables(const ObjectFile *Obj) {
/*UseHexEscapes=*/true)
<< '\n';
}
- for (const std::pair<std::pair<StringRef, uint64_t>, StringRef> &VTTPair :
- VTTEntries) {
+ for (const auto &TIPair : TIs) {
+ StringRef TIName = TIPair.first;
+ const ThrowInfo &TI = TIPair.second;
+ auto dumpThrowInfoFlag = [&](const char *Name, uint32_t Flag) {
+ outs() << TIName << "[Flags." << Name
+ << "]: " << (TI.Flags & Flag ? "true" : "false") << '\n';
+ };
+ auto dumpThrowInfoSymbol = [&](const char *Name, int Offset) {
+ outs() << TIName << '[' << Name << "]: ";
+ auto Entry = TIEntries.find(std::make_pair(TIName, Offset));
+ outs() << (Entry == TIEntries.end() ? "null" : Entry->second) << '\n';
+ };
+ outs() << TIName << "[Flags]: " << TI.Flags << '\n';
+ dumpThrowInfoFlag("Const", 1);
+ dumpThrowInfoFlag("Volatile", 2);
+ dumpThrowInfoSymbol("CleanupFn", 4);
+ dumpThrowInfoSymbol("ForwardCompat", 8);
+ dumpThrowInfoSymbol("CatchableTypeArray", 12);
+ }
+ for (const auto &CTAPair : CTAs) {
+ StringRef CTAName = CTAPair.first;
+ const CatchableTypeArray &CTA = CTAPair.second;
+
+ outs() << CTAName << "[NumEntries]: " << CTA.NumEntries << '\n';
+
+ unsigned Idx = 0;
+ for (auto I = CTAEntries.lower_bound(std::make_pair(CTAName, 0)),
+ E = CTAEntries.upper_bound(std::make_pair(CTAName, UINT64_MAX));
+ I != E; ++I)
+ outs() << CTAName << '[' << Idx++ << "]: " << I->second << '\n';
+ }
+ for (const auto &CTPair : CTs) {
+ StringRef CTName = CTPair.first;
+ const CatchableType &CT = CTPair.second;
+ auto dumpCatchableTypeFlag = [&](const char *Name, uint32_t Flag) {
+ outs() << CTName << "[Flags." << Name
+ << "]: " << (CT.Flags & Flag ? "true" : "false") << '\n';
+ };
+ outs() << CTName << "[Flags]: " << CT.Flags << '\n';
+ dumpCatchableTypeFlag("ScalarType", 1);
+ dumpCatchableTypeFlag("VirtualInheritance", 4);
+ outs() << CTName << "[TypeDescriptor]: " << CT.Symbols[0] << '\n';
+ outs() << CTName << "[NonVirtualBaseAdjustmentOffset]: "
+ << CT.NonVirtualBaseAdjustmentOffset << '\n';
+ outs() << CTName
+ << "[VirtualBasePointerOffset]: " << CT.VirtualBasePointerOffset
+ << '\n';
+ outs() << CTName << "[VirtualBaseAdjustmentOffset]: "
+ << CT.VirtualBaseAdjustmentOffset << '\n';
+ outs() << CTName << "[Size]: " << CT.Size << '\n';
+ outs() << CTName
+ << "[CopyCtor]: " << (CT.Symbols[1].empty() ? "null" : CT.Symbols[1])
+ << '\n';
+ }
+ for (const auto &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) {
+ for (const auto &TIPair : TINames) {
StringRef TIName = TIPair.first;
outs() << TIName << ": " << TIPair.second << '\n';
}
@@ -410,17 +516,16 @@ static void dumpArchive(const Archive *Arc) {
}
if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
- dumpVTables(Obj);
+ dumpCXXData(Obj);
else
- reportError(Arc->getFileName(),
- vtabledump_error::unrecognized_file_format);
+ reportError(Arc->getFileName(), cxxdump_error::unrecognized_file_format);
}
}
static void dumpInput(StringRef File) {
// If file isn't stdin, check that it exists.
if (File != "-" && !sys::fs::exists(File)) {
- reportError(File, vtabledump_error::file_not_found);
+ reportError(File, cxxdump_error::file_not_found);
return;
}
@@ -435,9 +540,9 @@ static void dumpInput(StringRef File) {
if (Archive *Arc = dyn_cast<Archive>(&Binary))
dumpArchive(Arc);
else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
- dumpVTables(Obj);
+ dumpCXXData(Obj);
else
- reportError(File, vtabledump_error::unrecognized_file_format);
+ reportError(File, cxxdump_error::unrecognized_file_format);
}
int main(int argc, const char *argv[]) {
@@ -451,7 +556,7 @@ int main(int argc, const char *argv[]) {
// Register the target printer for --version.
cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion);
- cl::ParseCommandLineOptions(argc, argv, "LLVM VTable Dumper\n");
+ cl::ParseCommandLineOptions(argc, argv, "LLVM C++ ABI Data Dumper\n");
// Default to stdin if no filename is specified.
if (opts::InputFilenames.size() == 0)
diff --git a/tools/llvm-vtabledump/llvm-vtabledump.h b/tools/llvm-cxxdump/llvm-cxxdump.h
index 62f755739c39..daa05cb2ca0a 100644
--- a/tools/llvm-vtabledump/llvm-vtabledump.h
+++ b/tools/llvm-cxxdump/llvm-cxxdump.h
@@ -1,4 +1,4 @@
-//===-- llvm-vtabledump.h ---------------------------------------*- C++ -*-===//
+//===-- llvm-cxxdump.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H
-#define LLVM_TOOLS_LLVM_VTABLEDUMP_LLVM_VTABLEDUMP_H
+#ifndef LLVM_TOOLS_LLVM_CXXDUMP_LLVM_CXXDUMP_H
+#define LLVM_TOOLS_LLVM_CXXDUMP_LLVM_CXXDUMP_H
#include "llvm/Support/CommandLine.h"
#include <string>
@@ -17,7 +17,7 @@ namespace opts {
extern llvm::cl::list<std::string> InputFilenames;
} // namespace opts
-#define LLVM_VTABLEDUMP_ENUM_ENT(ns, enum) \
+#define LLVM_CXXDUMP_ENUM_ENT(ns, enum) \
{ #enum, ns::enum }
#endif
diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp
index 1349ecc85a4c..26f14b9b1a28 100644
--- a/tools/llvm-dis/llvm-dis.cpp
+++ b/tools/llvm-dis/llvm-dis.cpp
@@ -54,16 +54,18 @@ static cl::opt<bool>
ShowAnnotations("show-annotations",
cl::desc("Add informational comments to the .ll file"));
+static cl::opt<bool> PreserveAssemblyUseListOrder(
+ "preserve-ll-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM assembly."),
+ cl::init(false), cl::Hidden);
+
namespace {
static void printDebugLoc(const DebugLoc &DL, formatted_raw_ostream &OS) {
OS << DL.getLine() << ":" << DL.getCol();
- if (MDNode *N = DL.getInlinedAt(getGlobalContext())) {
- DebugLoc IDL = DebugLoc::getFromDILocation(N);
- if (!IDL.isUnknown()) {
- OS << "@";
- printDebugLoc(IDL,OS);
- }
+ if (DILocation *IDL = DL.getInlinedAt()) {
+ OS << "@";
+ printDebugLoc(IDL, OS);
}
}
class CommentWriter : public AssemblyAnnotationWriter {
@@ -78,11 +80,11 @@ public:
if (!V.getType()->isVoidTy()) {
OS.PadToColumn(50);
Padded = true;
- OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]"; // Output # uses and type
+ // Output # uses and type
+ OS << "; [#uses=" << V.getNumUses() << " type=" << *V.getType() << "]";
}
if (const Instruction *I = dyn_cast<Instruction>(&V)) {
- const DebugLoc &DL = I->getDebugLoc();
- if (!DL.isUnknown()) {
+ if (const DebugLoc &DL = I->getDebugLoc()) {
if (!Padded) {
OS.PadToColumn(50);
Padded = true;
@@ -93,20 +95,18 @@ public:
OS << "]";
}
if (const DbgDeclareInst *DDI = dyn_cast<DbgDeclareInst>(I)) {
- DIVariable Var(DDI->getVariable());
if (!Padded) {
OS.PadToColumn(50);
OS << ";";
}
- OS << " [debug variable = " << Var.getName() << "]";
+ OS << " [debug variable = " << DDI->getVariable()->getName() << "]";
}
else if (const DbgValueInst *DVI = dyn_cast<DbgValueInst>(I)) {
- DIVariable Var(DVI->getVariable());
if (!Padded) {
OS.PadToColumn(50);
OS << ";";
}
- OS << " [debug variable = " << Var.getName() << "]";
+ OS << " [debug variable = " << DVI->getVariable()->getName() << "]";
}
}
}
@@ -115,14 +115,21 @@ public:
} // end anon namespace
static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
- assert(DI.getSeverity() == DS_Error && "Only expecting errors");
-
raw_ostream &OS = errs();
OS << (char *)Context << ": ";
+ switch (DI.getSeverity()) {
+ case DS_Error: OS << "error: "; break;
+ case DS_Warning: OS << "warning: "; break;
+ case DS_Remark: OS << "remark: "; break;
+ case DS_Note: OS << "note: "; break;
+ }
+
DiagnosticPrinterRawOStream DP(OS);
DI.print(DP);
OS << '\n';
- exit(1);
+
+ if (DI.getSeverity() == DS_Error)
+ exit(1);
}
int main(int argc, char **argv) {
@@ -152,6 +159,9 @@ int main(int argc, char **argv) {
getStreamedBitcodeModule(DisplayFilename, Streamer, Context);
M = std::move(*MOrErr);
M->materializeAllPermanently();
+ } else {
+ errs() << argv[0] << ": " << ErrorMessage << '\n';
+ return 1;
}
// Just use stdout. We won't actually print anything on it.
@@ -162,13 +172,9 @@ int main(int argc, char **argv) {
if (InputFilename == "-") {
OutputFilename = "-";
} else {
- const std::string &IFN = InputFilename;
- int Len = IFN.length();
- // If the source ends in .bc, strip it off.
- if (IFN[Len-3] == '.' && IFN[Len-2] == 'b' && IFN[Len-1] == 'c')
- OutputFilename = std::string(IFN.begin(), IFN.end()-3)+".ll";
- else
- OutputFilename = IFN+".ll";
+ StringRef IFN = InputFilename;
+ OutputFilename = (IFN.endswith(".bc") ? IFN.drop_back(3) : IFN).str();
+ OutputFilename += ".ll";
}
}
@@ -186,7 +192,7 @@ int main(int argc, char **argv) {
// All that llvm-dis does is write the assembly to a file.
if (!DontPrint)
- M->print(Out->os(), Annotator.get());
+ M->print(Out->os(), Annotator.get(), PreserveAssemblyUseListOrder);
// Declare success.
Out->keep();
diff --git a/tools/llvm-dwarfdump/CMakeLists.txt b/tools/llvm-dwarfdump/CMakeLists.txt
index 288b3237010b..086b13974614 100644
--- a/tools/llvm-dwarfdump/CMakeLists.txt
+++ b/tools/llvm-dwarfdump/CMakeLists.txt
@@ -1,5 +1,5 @@
set(LLVM_LINK_COMPONENTS
- DebugInfo
+ DebugInfoDWARF
Object
Support
)
diff --git a/tools/llvm-dwarfdump/LLVMBuild.txt b/tools/llvm-dwarfdump/LLVMBuild.txt
index 28b7c4cda480..a9dca3e0cfff 100644
--- a/tools/llvm-dwarfdump/LLVMBuild.txt
+++ b/tools/llvm-dwarfdump/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-dwarfdump
parent = Tools
-required_libraries = DebugInfo Object
+required_libraries = DebugInfoDWARF Object
diff --git a/tools/llvm-dwarfdump/Makefile b/tools/llvm-dwarfdump/Makefile
index 7ca1a8d877d0..00b18c60bb2a 100644
--- a/tools/llvm-dwarfdump/Makefile
+++ b/tools/llvm-dwarfdump/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-dwarfdump
-LINK_COMPONENTS := DebugInfo Object
+LINK_COMPONENTS := DebugInfoDWARF Object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
index cff8216403b7..c1cb0218ac38 100644
--- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
+++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp
@@ -14,6 +14,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/RelocVisitor.h"
#include "llvm/Support/CommandLine.h"
@@ -86,7 +87,7 @@ static void DumpInput(StringRef Filename) {
}
ObjectFile &Obj = *ObjOrErr.get();
- std::unique_ptr<DIContext> DICtx(DIContext::getDWARFContext(Obj));
+ std::unique_ptr<DIContext> DICtx(new DWARFContextInMemory(Obj));
outs() << Filename
<< ":\tfile format " << Obj.getFileFormatName() << "\n\n";
diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 53b2f0d00f41..936496cd7fe6 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -20,7 +20,7 @@
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -90,6 +90,16 @@ static cl::opt<bool>
OutputAssembly("S",
cl::desc("Write output as LLVM assembly"), cl::Hidden);
+static cl::opt<bool> PreserveBitcodeUseListOrder(
+ "preserve-bc-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM bitcode."),
+ cl::init(true), cl::Hidden);
+
+static cl::opt<bool> PreserveAssemblyUseListOrder(
+ "preserve-ll-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM assembly."),
+ cl::init(false), cl::Hidden);
+
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
@@ -246,8 +256,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()); // Use correct DataLayout
+ legacy::PassManager Passes;
std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
@@ -265,9 +274,10 @@ int main(int argc, char **argv) {
}
if (OutputAssembly)
- Passes.add(createPrintModulePass(Out.os()));
+ Passes.add(
+ createPrintModulePass(Out.os(), "", PreserveAssemblyUseListOrder));
else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true))
- Passes.add(createBitcodeWriterPass(Out.os()));
+ Passes.add(createBitcodeWriterPass(Out.os(), PreserveBitcodeUseListOrder));
Passes.run(*M.get());
diff --git a/tools/llvm-go/llvm-go.go b/tools/llvm-go/llvm-go.go
index cf520bd90e9d..c5c3fd244cad 100644
--- a/tools/llvm-go/llvm-go.go
+++ b/tools/llvm-go/llvm-go.go
@@ -46,7 +46,7 @@ var components = []string{
"bitwriter",
"codegen",
"core",
- "debuginfo",
+ "debuginfodwarf",
"executionengine",
"instrumentation",
"interpreter",
@@ -137,7 +137,7 @@ type (run_build_sh int)
`, flags.cpp, flags.cxx, flags.ld)
}
-func runGoWithLLVMEnv(args []string, cc, cxx, llgo, cppflags, cxxflags, ldflags string) {
+func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string) {
args = addTag(args, "byollvm")
srcdir := llvmConfig("--src-root")
@@ -162,26 +162,6 @@ func runGoWithLLVMEnv(args []string, cc, cxx, llgo, cppflags, cxxflags, ldflags
newpath := os.Getenv("PATH")
- if llgo != "" {
- bindir := filepath.Join(tmpgopath, "bin")
-
- err = os.MkdirAll(bindir, os.ModePerm)
- if err != nil {
- panic(err.Error())
- }
-
- err = os.Symlink(llgo, filepath.Join(bindir, "gccgo"))
- if err != nil {
- panic(err.Error())
- }
-
- newpathlist := []string{bindir}
- newpathlist = append(newpathlist, filepath.SplitList(newpath)...)
- newpath = strings.Join(newpathlist, string(filepath.ListSeparator))
-
- args = append([]string{args[0], "-compiler", "gccgo"}, args[1:]...)
- }
-
newgopathlist := []string{tmpgopath}
newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
@@ -197,24 +177,29 @@ func runGoWithLLVMEnv(args []string, cc, cxx, llgo, cppflags, cxxflags, ldflags
"GOPATH=" + newgopath,
"PATH=" + newpath,
}
+ if llgo != "" {
+ newenv = append(newenv, "GCCGO=" + llgo)
+ }
+
for _, v := range os.Environ() {
if !strings.HasPrefix(v, "CC=") &&
!strings.HasPrefix(v, "CXX=") &&
!strings.HasPrefix(v, "CGO_CPPFLAGS=") &&
!strings.HasPrefix(v, "CGO_CXXFLAGS=") &&
!strings.HasPrefix(v, "CGO_LDFLAGS=") &&
+ !strings.HasPrefix(v, "GCCGO=") &&
!strings.HasPrefix(v, "GOPATH=") &&
!strings.HasPrefix(v, "PATH=") {
newenv = append(newenv, v)
}
}
- gocmdpath, err := exec.LookPath("go")
+ gocmdpath, err := exec.LookPath(gocmd)
if err != nil {
panic(err.Error())
}
- proc, err := os.StartProcess(gocmdpath, append([]string{"go"}, args...),
+ proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...),
&os.ProcAttr{
Env: newenv,
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
@@ -247,6 +232,7 @@ func main() {
cppflags := os.Getenv("CGO_CPPFLAGS")
cxxflags := os.Getenv("CGO_CXXFLAGS")
ldflags := os.Getenv("CGO_LDFLAGS")
+ gocmd := "go"
llgo := ""
args := os.Args[1:]
@@ -260,6 +246,9 @@ func main() {
case strings.HasPrefix(args[0], "cxx="):
cxx = args[0][4:]
args = args[1:]
+ case strings.HasPrefix(args[0], "go="):
+ gocmd = args[0][3:]
+ args = args[1:]
case strings.HasPrefix(args[0], "llgo="):
llgo = args[0][5:]
args = args[1:]
@@ -279,7 +268,7 @@ func main() {
switch args[0] {
case "build", "get", "install", "run", "test":
- runGoWithLLVMEnv(args, cc, cxx, llgo, cppflags, cxxflags, ldflags)
+ runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags)
case "print-components":
printComponents()
case "print-config":
diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile
index 6d72427e96e8..4acb6a561715 100644
--- a/tools/llvm-jitlistener/Makefile
+++ b/tools/llvm-jitlistener/Makefile
@@ -1,27 +1,27 @@
-##===- tools/llvm-jitlistener/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-jitlistener
-
-include $(LEVEL)/Makefile.config
-
-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
-# will build correctly.
-ifeq ($(USE_INTEL_JITEVENTS), 1)
- LINK_COMPONENTS += debuginfo inteljitevents
-endif
-
-# This tool has no plugins, optimize startup time.
-TOOL_NO_EXPORTS := 1
-
-include $(LLVM_SRC_ROOT)/Makefile.rules
+##===- tools/llvm-jitlistener/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-jitlistener
+
+include $(LEVEL)/Makefile.config
+
+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
+# will build correctly.
+ifeq ($(USE_INTEL_JITEVENTS), 1)
+ LINK_COMPONENTS += debuginfodwarf inteljitevents
+endif
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp
index c3091a559550..af1a59bdbd37 100644
--- a/tools/llvm-jitlistener/llvm-jitlistener.cpp
+++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp
@@ -13,12 +13,12 @@
//
//===----------------------------------------------------------------------===//
-#include "llvm/IR/LLVMContext.h"
#include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h"
#include "llvm/ADT/Triple.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
#include "llvm/Support/CommandLine.h"
@@ -30,6 +30,7 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/raw_ostream.h"
#include <string>
using namespace llvm;
diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp
index 828b9bb8ef70..369f3477fe5c 100644
--- a/tools/llvm-link/llvm-link.cpp
+++ b/tools/llvm-link/llvm-link.cpp
@@ -13,7 +13,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Linker/Linker.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LLVMContext.h"
@@ -36,6 +38,11 @@ static cl::list<std::string>
InputFilenames(cl::Positional, cl::OneOrMore,
cl::desc("<input bitcode files>"));
+static cl::list<std::string> OverridingInputs(
+ "override", cl::ZeroOrMore, cl::value_desc("filename"),
+ cl::desc(
+ "input bitcode file which can override previously defined symbol(s)"));
+
static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"), cl::init("-"),
cl::value_desc("filename"));
@@ -57,6 +64,16 @@ static cl::opt<bool>
SuppressWarnings("suppress-warnings", cl::desc("Suppress all linking warnings"),
cl::init(false));
+static cl::opt<bool> PreserveBitcodeUseListOrder(
+ "preserve-bc-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM bitcode."),
+ cl::init(true), cl::Hidden);
+
+static cl::opt<bool> PreserveAssemblyUseListOrder(
+ "preserve-ll-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM assembly."),
+ cl::init(false), cl::Hidden);
+
// Read the specified bitcode file in and return it. This routine searches the
// link path for the specified file to try to find it...
//
@@ -68,6 +85,9 @@ loadFile(const char *argv0, const std::string &FN, LLVMContext &Context) {
if (!Result)
Err.print(argv0, errs());
+ Result->materializeMetadata();
+ UpgradeDebugInfo(*Result);
+
return Result;
}
@@ -92,6 +112,31 @@ static void diagnosticHandler(const DiagnosticInfo &DI) {
errs() << '\n';
}
+static bool linkFiles(const char *argv0, LLVMContext &Context, Linker &L,
+ const cl::list<std::string> &Files,
+ bool OverrideDuplicateSymbols) {
+ for (const auto &File : Files) {
+ std::unique_ptr<Module> M = loadFile(argv0, File, Context);
+ if (!M.get()) {
+ errs() << argv0 << ": error loading file '" << File << "'\n";
+ return false;
+ }
+
+ if (verifyModule(*M, &errs())) {
+ errs() << argv0 << ": " << File << ": error: input module is broken!\n";
+ return false;
+ }
+
+ if (Verbose)
+ errs() << "Linking in '" << File << "'\n";
+
+ if (L.linkInModule(M.get(), OverrideDuplicateSymbols))
+ return false;
+ }
+
+ return true;
+}
+
int main(int argc, char **argv) {
// Print a stack trace if we signal out.
sys::PrintStackTraceOnErrorSignal();
@@ -104,18 +149,13 @@ int main(int argc, char **argv) {
auto Composite = make_unique<Module>("llvm-link", Context);
Linker L(Composite.get(), diagnosticHandler);
- 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;
- }
-
- if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n";
+ // First add all the regular input files
+ if (!linkFiles(argv[0], Context, L, InputFilenames, false))
+ return 1;
- if (L.linkInModule(M.get()))
- return 1;
- }
+ // Next the -override ones.
+ if (!linkFiles(argv[0], Context, L, OverridingInputs, true))
+ return 1;
if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite;
@@ -126,16 +166,16 @@ int main(int argc, char **argv) {
return 1;
}
- if (verifyModule(*Composite)) {
- errs() << argv[0] << ": linked module is broken!\n";
+ if (verifyModule(*Composite, &errs())) {
+ errs() << argv[0] << ": error: linked module is broken!\n";
return 1;
}
if (Verbose) errs() << "Writing bitcode...\n";
if (OutputAssembly) {
- Out.os() << *Composite;
+ Composite->print(Out.os(), nullptr, PreserveAssemblyUseListOrder);
} else if (Force || !CheckBitcodeOutputToConsole(Out.os(), true))
- WriteBitcodeToFile(Composite.get(), Out.os());
+ WriteBitcodeToFile(Composite.get(), Out.os(), PreserveBitcodeUseListOrder);
// Declare success.
Out.keep();
diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp
index 9cd031eaf8d3..9cd6587c2622 100644
--- a/tools/llvm-lto/llvm-lto.cpp
+++ b/tools/llvm-lto/llvm-lto.cpp
@@ -26,9 +26,13 @@
using namespace llvm;
-static cl::opt<bool>
-DisableOpt("disable-opt", cl::init(false),
- cl::desc("Do not run any optimization passes"));
+static cl::opt<char>
+OptLevel("O",
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default = '-O2')"),
+ cl::Prefix,
+ cl::ZeroOrMore,
+ cl::init('2'));
static cl::opt<bool>
DisableInline("disable-inlining", cl::init(false),
@@ -69,14 +73,18 @@ static cl::opt<bool> ListSymbolsOnly(
"list-symbols-only", cl::init(false),
cl::desc("Instead of running LTO, list the symbols in each IR file"));
+static cl::opt<bool> SetMergedModule(
+ "set-merged-module", cl::init(false),
+ cl::desc("Use the first input module as the merged module"));
+
namespace {
struct ModuleInfo {
std::vector<bool> CanBeHidden;
};
}
-void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
- const char *Msg, void *) {
+static void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
+ const char *Msg, void *) {
switch (Severity) {
case LTO_DS_NOTE:
errs() << "note: ";
@@ -94,7 +102,7 @@ void handleDiagnostics(lto_codegen_diagnostic_severity_t Severity,
errs() << Msg << "\n";
}
-std::unique_ptr<LTOModule>
+static std::unique_ptr<LTOModule>
getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
const TargetOptions &Options, std::string &Error) {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
@@ -114,7 +122,7 @@ getLocalLTOModule(StringRef Path, std::unique_ptr<MemoryBuffer> &Buffer,
/// functionality that's exposed by the C API to list symbols. Moreover, this
/// provides testing coverage for modules that have been created in their own
/// contexts.
-int listSymbols(StringRef Command, const TargetOptions &Options) {
+static int listSymbols(StringRef Command, const TargetOptions &Options) {
for (auto &Filename : InputFilenames) {
std::string Error;
std::unique_ptr<MemoryBuffer> Buffer;
@@ -142,6 +150,11 @@ int main(int argc, char **argv) {
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
cl::ParseCommandLineOptions(argc, argv, "llvm LTO linker\n");
+ if (OptLevel < '0' || OptLevel > '3') {
+ errs() << argv[0] << ": optimization level must be between 0 and 3\n";
+ return 1;
+ }
+
// Initialize the configured targets.
InitializeAllTargets();
InitializeAllTargetMCs();
@@ -194,15 +207,22 @@ int main(int argc, char **argv) {
return 1;
}
- if (!CodeGen.addModule(Module.get()))
+ LTOModule *LTOMod = Module.get();
+
+ // We use the first input module as the destination module when
+ // SetMergedModule is true.
+ if (SetMergedModule && i == BaseArg) {
+ // Transfer ownership to the code generator.
+ CodeGen.setModule(Module.release());
+ } else if (!CodeGen.addModule(Module.get()))
return 1;
- unsigned NumSyms = Module->getSymbolCount();
+ unsigned NumSyms = LTOMod->getSymbolCount();
for (unsigned I = 0; I < NumSyms; ++I) {
- StringRef Name = Module->getSymbolName(I);
+ StringRef Name = LTOMod->getSymbolName(I);
if (!DSOSymbolsSet.count(Name))
continue;
- lto_symbol_attributes Attrs = Module->getSymbolAttributes(I);
+ lto_symbol_attributes Attrs = LTOMod->getSymbolAttributes(I);
unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK;
if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN)
KeptDSOSyms.push_back(Name);
@@ -217,6 +237,11 @@ int main(int argc, char **argv) {
for (unsigned i = 0; i < KeptDSOSyms.size(); ++i)
CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str());
+ // Set cpu and attrs strings for the default target/subtarget.
+ CodeGen.setCpu(MCPU.c_str());
+
+ CodeGen.setOptLevel(OptLevel - '0');
+
std::string attrs;
for (unsigned i = 0; i < MAttrs.size(); ++i) {
if (i > 0)
@@ -231,7 +256,7 @@ int main(int argc, char **argv) {
size_t len = 0;
std::string ErrorInfo;
const void *Code =
- CodeGen.compile(&len, DisableOpt, DisableInline, DisableGVNLoadPRE,
+ CodeGen.compile(&len, DisableInline, DisableGVNLoadPRE,
DisableLTOVectorization, ErrorInfo);
if (!Code) {
errs() << argv[0]
@@ -251,7 +276,7 @@ int main(int argc, char **argv) {
} else {
std::string ErrorInfo;
const char *OutputName = nullptr;
- if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline,
+ if (!CodeGen.compile_to_file(&OutputName, DisableInline,
DisableGVNLoadPRE, DisableLTOVectorization,
ErrorInfo)) {
errs() << argv[0]
diff --git a/tools/llvm-mc/CMakeLists.txt b/tools/llvm-mc/CMakeLists.txt
index 6f8e9e5405f9..15c6dda1b258 100644
--- a/tools/llvm-mc/CMakeLists.txt
+++ b/tools/llvm-mc/CMakeLists.txt
@@ -1,5 +1,9 @@
set(LLVM_LINK_COMPONENTS
- ${LLVM_TARGETS_TO_BUILD}
+ AllTargetsAsmPrinters
+ AllTargetsAsmParsers
+ AllTargetsDescs
+ AllTargetsDisassemblers
+ AllTargetsInfos
MC
MCParser
Support
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 78fe9b72f208..6a8b49373df5 100644
--- a/tools/llvm-mc/llvm-mc.cpp
+++ b/tools/llvm-mc/llvm-mc.cpp
@@ -357,6 +357,7 @@ int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n");
MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags();
TripleName = Triple::normalize(TripleName);
+ Triple TheTriple(TripleName);
setDwarfDebugFlags(argc, argv);
setDwarfDebugProducer();
@@ -438,7 +439,8 @@ int main(int argc, char **argv) {
if (!Out)
return 1;
- formatted_raw_ostream FOS(Out->os());
+ std::unique_ptr<buffer_ostream> BOS;
+ raw_pwrite_stream *OS = &Out->os();
std::unique_ptr<MCStreamer> Str;
std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
@@ -447,8 +449,8 @@ int main(int argc, char **argv) {
MCInstPrinter *IP = nullptr;
if (FileType == OFT_AssemblyFile) {
- IP =
- TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI);
+ IP = TheTarget->createMCInstPrinter(Triple(TripleName), OutputAsmVariant,
+ *MAI, *MCII, *MRI);
// Set the display preference for hex vs. decimal immediates.
IP->setPrintImmHex(PrintImmHex);
@@ -457,21 +459,29 @@ int main(int argc, char **argv) {
MCCodeEmitter *CE = nullptr;
MCAsmBackend *MAB = nullptr;
if (ShowEncoding) {
- CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
+ CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU);
}
- Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/ true,
- /*useDwarfDirectory*/ true, IP, CE,
- MAB, ShowInst));
+ auto FOut = llvm::make_unique<formatted_raw_ostream>(*OS);
+ Str.reset(TheTarget->createAsmStreamer(
+ Ctx, std::move(FOut), /*asmverbose*/ true,
+ /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst));
} else if (FileType == OFT_Null) {
- Str.reset(createNullStreamer(Ctx));
+ Str.reset(TheTarget->createNullStreamer(Ctx));
} else {
assert(FileType == OFT_ObjectFile && "Invalid file type!");
- MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
+
+ if (!Out->os().supportsSeeking()) {
+ BOS = make_unique<buffer_ostream>(Out->os());
+ OS = BOS.get();
+ }
+
+ MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx);
MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU);
- Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, FOS, CE,
- *STI, RelaxAll));
+ Str.reset(TheTarget->createMCObjectStreamer(TheTriple, Ctx, *MAB, *OS, CE,
+ *STI, RelaxAll,
+ /*DWARFMustBeAtTheEnd*/ false));
if (NoExecStack)
Str->InitSections(true);
}
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index f911c724646c..f3197bbfd104 100644
--- a/tools/llvm-nm/llvm-nm.cpp
+++ b/tools/llvm-nm/llvm-nm.cpp
@@ -188,85 +188,77 @@ static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) {
if (!ReverseSort) {
if (A.Address < B.Address)
return true;
- else if (A.Address == B.Address && A.Name < B.Name)
+ if (A.Address == B.Address && A.Name < B.Name)
return true;
- else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size)
+ if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size)
return true;
- else
- return false;
- } else {
- if (A.Address > B.Address)
- return true;
- else if (A.Address == B.Address && A.Name > B.Name)
- return true;
- else if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size)
- return true;
- else
- return false;
+ return false;
}
+
+ if (A.Address > B.Address)
+ return true;
+ if (A.Address == B.Address && A.Name > B.Name)
+ return true;
+ if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size)
+ return true;
+ return false;
}
static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) {
if (!ReverseSort) {
if (A.Size < B.Size)
return true;
- else if (A.Size == B.Size && A.Name < B.Name)
- return true;
- else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address)
- return true;
- else
- return false;
- } else {
- if (A.Size > B.Size)
+ if (A.Size == B.Size && A.Name < B.Name)
return true;
- else if (A.Size == B.Size && A.Name > B.Name)
+ if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address)
return true;
- else if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address)
- return true;
- else
- return false;
+ return false;
}
+
+ if (A.Size > B.Size)
+ return true;
+ if (A.Size == B.Size && A.Name > B.Name)
+ return true;
+ if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address)
+ return true;
+ return false;
}
static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) {
if (!ReverseSort) {
if (A.Name < B.Name)
return true;
- else if (A.Name == B.Name && A.Size < B.Size)
- return true;
- else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address)
- return true;
- else
- return false;
- } else {
- if (A.Name > B.Name)
+ if (A.Name == B.Name && A.Size < B.Size)
return true;
- else if (A.Name == B.Name && A.Size > B.Size)
+ if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address)
return true;
- else if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address)
- return true;
- else
- return false;
+ return false;
}
+ if (A.Name > B.Name)
+ return true;
+ if (A.Name == B.Name && A.Size > B.Size)
+ return true;
+ if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address)
+ return true;
+ return false;
}
static char isSymbolList64Bit(SymbolicFile &Obj) {
if (isa<IRObjectFile>(Obj))
return false;
- else if (isa<COFFObjectFile>(Obj))
+ if (isa<COFFObjectFile>(Obj))
return false;
- else if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
+ if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(&Obj))
return MachO->is64Bit();
- else if (isa<ELF32LEObjectFile>(Obj))
+ if (isa<ELF32LEObjectFile>(Obj))
return false;
- else if (isa<ELF64LEObjectFile>(Obj))
+ if (isa<ELF64LEObjectFile>(Obj))
return true;
- else if (isa<ELF32BEObjectFile>(Obj))
+ if (isa<ELF32BEObjectFile>(Obj))
return false;
- else if (isa<ELF64BEObjectFile>(Obj))
+ if (isa<ELF64BEObjectFile>(Obj))
return true;
- else
- return false;
+ return false;
}
static StringRef CurrentFilename;
@@ -940,7 +932,7 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
NMSymbol S;
S.Size = UnknownAddressOrSize;
S.Address = UnknownAddressOrSize;
- if ((PrintSize || SizeSort) && isa<ObjectFile>(Obj)) {
+ if (PrintSize && isa<ELFObjectFileBase>(Obj)) {
symbol_iterator SymI = I;
if (error(SymI->getSize(S.Size)))
break;
@@ -973,30 +965,26 @@ static void dumpSymbolNamesFromObject(SymbolicFile &Obj, bool printName,
// architectures was specificed. If not then an error is generated and this
// routine returns false. Else it returns true.
static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) {
- if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) {
- MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
- bool ArchFound = false;
- MachO::mach_header H;
- MachO::mach_header_64 H_64;
- Triple T;
- if (MachO->is64Bit()) {
- H_64 = MachO->MachOObjectFile::getHeader64();
- T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
- } else {
- H = MachO->MachOObjectFile::getHeader();
- T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
- }
- unsigned i;
- for (i = 0; i < ArchFlags.size(); ++i) {
- if (ArchFlags[i] == T.getArchName())
- ArchFound = true;
- break;
- }
- if (!ArchFound) {
- error(ArchFlags[i],
- "file: " + Filename + " does not contain architecture");
- return false;
- }
+ MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O);
+
+ if (!MachO || ArchAll || ArchFlags.size() == 0)
+ return true;
+
+ MachO::mach_header H;
+ MachO::mach_header_64 H_64;
+ Triple T;
+ if (MachO->is64Bit()) {
+ H_64 = MachO->MachOObjectFile::getHeader64();
+ T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype);
+ } else {
+ H = MachO->MachOObjectFile::getHeader();
+ T = MachOObjectFile::getArch(H.cputype, H.cpusubtype);
+ }
+ if (std::none_of(
+ ArchFlags.begin(), ArchFlags.end(),
+ [&](const std::string &Name) { return Name == T.getArchName(); })) {
+ error("No architecture specified", Filename);
+ return false;
}
return true;
}
diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt
index 61bf3b32757b..d717653685c8 100644
--- a/tools/llvm-objdump/CMakeLists.txt
+++ b/tools/llvm-objdump/CMakeLists.txt
@@ -1,6 +1,6 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
- DebugInfo
+ DebugInfoDWARF
MC
MCDisassembler
Object
diff --git a/tools/llvm-objdump/LLVMBuild.txt b/tools/llvm-objdump/LLVMBuild.txt
index d16c501a6cca..42328737a7d0 100644
--- a/tools/llvm-objdump/LLVMBuild.txt
+++ b/tools/llvm-objdump/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-objdump
parent = Tools
-required_libraries = DebugInfo MC MCDisassembler MCParser Object all-targets
+required_libraries = DebugInfoDWARF MC MCDisassembler MCParser Object all-targets
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index 03fad5f922fc..84212c94bbb2 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -18,6 +18,7 @@
#include "llvm/ADT/Triple.h"
#include "llvm/Config/config.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCDisassembler.h"
@@ -36,6 +37,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/GraphWriter.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/MachO.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TargetRegistry.h"
@@ -62,13 +64,83 @@ static cl::opt<std::string> DSYMFile("dsym",
static cl::opt<bool> FullLeadingAddr("full-leading-addr",
cl::desc("Print full leading address"));
+static cl::opt<bool> NoLeadingAddr("no-leading-addr",
+ cl::desc("Print no leading address"));
+
static cl::opt<bool>
PrintImmHex("print-imm-hex",
cl::desc("Use hex format for immediate values"));
+cl::opt<bool> llvm::UniversalHeaders("universal-headers",
+ cl::desc("Print Mach-O universal headers "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::ArchiveHeaders("archive-headers",
+ cl::desc("Print archive headers for Mach-O archives "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ ArchiveMemberOffsets("archive-member-offsets",
+ cl::desc("Print the offset to each archive member for "
+ "Mach-O archives (requires -macho and "
+ "-archive-headers)"));
+
+cl::opt<bool>
+ llvm::IndirectSymbols("indirect-symbols",
+ cl::desc("Print indirect symbol table for Mach-O "
+ "objects (requires -macho)"));
+
+cl::opt<bool>
+ llvm::DataInCode("data-in-code",
+ cl::desc("Print the data in code table for Mach-O objects "
+ "(requires -macho)"));
+
+cl::opt<bool>
+ llvm::LinkOptHints("link-opt-hints",
+ cl::desc("Print the linker optimization hints for "
+ "Mach-O objects (requires -macho)"));
+
+cl::list<std::string>
+ llvm::DumpSections("section",
+ cl::desc("Prints the specified segment,section for "
+ "Mach-O objects (requires -macho)"));
+
+cl::opt<bool> llvm::Raw("raw",
+ cl::desc("Have -section dump the raw binary contents"));
+
+cl::opt<bool>
+ llvm::InfoPlist("info-plist",
+ cl::desc("Print the info plist section as strings for "
+ "Mach-O objects (requires -macho)"));
+
+cl::opt<bool>
+ llvm::DylibsUsed("dylibs-used",
+ cl::desc("Print the shared libraries used for linked "
+ "Mach-O files (requires -macho)"));
+
+cl::opt<bool>
+ llvm::DylibId("dylib-id",
+ cl::desc("Print the shared library's id for the dylib Mach-O "
+ "file (requires -macho)"));
+
+cl::opt<bool>
+ llvm::NonVerbose("non-verbose",
+ cl::desc("Print the info for Mach-O objects in "
+ "non-verbose or numeric form (requires -macho)"));
+
cl::opt<bool>
- llvm::UniversalHeaders("universal-headers",
- cl::desc("Print Mach-O universal headers"));
+ llvm::ObjcMetaData("objc-meta-data",
+ cl::desc("Print the Objective-C runtime meta data for "
+ "Mach-O files (requires -macho)"));
+
+cl::opt<std::string> llvm::DisSymName(
+ "dis-symname",
+ cl::desc("disassemble just this symbol's instructions (requires -macho"));
+
+static cl::opt<bool> NoSymbolicOperands(
+ "no-symbolic-operands",
+ cl::desc("do not symbolic operands when disassembling (requires -macho)"));
static cl::list<std::string>
ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
@@ -147,7 +219,7 @@ static bool compareDiceTableEntries(const DiceTableEntry &i,
return j.first >= i.first && j.first < i.first + Length;
}
-static uint64_t DumpDataInCode(const char *bytes, uint64_t Length,
+static uint64_t DumpDataInCode(const uint8_t *bytes, uint64_t Length,
unsigned short Kind) {
uint32_t Value, Size = 1;
@@ -156,19 +228,19 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length,
case MachO::DICE_KIND_DATA:
if (Length >= 4) {
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 4));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 4));
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
Size = 4;
} else if (Length >= 2) {
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 2));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 2));
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << Value;
Size = 2;
} else {
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 2));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 2));
Value = bytes[0];
outs() << "\t.byte " << Value;
Size = 1;
@@ -180,14 +252,14 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length,
break;
case MachO::DICE_KIND_JUMP_TABLE8:
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 1));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 1));
Value = bytes[0];
outs() << "\t.byte " << format("%3u", Value) << "\t@ KIND_JUMP_TABLE8\n";
Size = 1;
break;
case MachO::DICE_KIND_JUMP_TABLE16:
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 2));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 2));
Value = bytes[1] << 8 | bytes[0];
outs() << "\t.short " << format("%5u", Value & 0xffff)
<< "\t@ KIND_JUMP_TABLE16\n";
@@ -196,7 +268,7 @@ static uint64_t DumpDataInCode(const char *bytes, uint64_t Length,
case MachO::DICE_KIND_JUMP_TABLE32:
case MachO::DICE_KIND_ABS_JUMP_TABLE32:
if (!NoShowRawInsn)
- DumpBytes(StringRef(bytes, 4));
+ DumpBytes(ArrayRef<uint8_t>(bytes, 4));
Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0];
outs() << "\t.long " << Value;
if (Kind == MachO::DICE_KIND_JUMP_TABLE32)
@@ -255,6 +327,842 @@ static void getSectionsAndSymbols(const MachO::mach_header Header,
}
}
+static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
+ uint32_t n, uint32_t count,
+ uint32_t stride, uint64_t addr) {
+ MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
+ uint32_t nindirectsyms = Dysymtab.nindirectsyms;
+ if (n > nindirectsyms)
+ outs() << " (entries start past the end of the indirect symbol "
+ "table) (reserved1 field greater than the table size)";
+ else if (n + count > nindirectsyms)
+ outs() << " (entries extends past the end of the indirect symbol "
+ "table)";
+ outs() << "\n";
+ uint32_t cputype = O->getHeader().cputype;
+ if (cputype & MachO::CPU_ARCH_ABI64)
+ outs() << "address index";
+ else
+ outs() << "address index";
+ if (verbose)
+ outs() << " name\n";
+ else
+ outs() << "\n";
+ for (uint32_t j = 0; j < count && n + j < nindirectsyms; j++) {
+ if (cputype & MachO::CPU_ARCH_ABI64)
+ outs() << format("0x%016" PRIx64, addr + j * stride) << " ";
+ else
+ outs() << format("0x%08" PRIx32, addr + j * stride) << " ";
+ MachO::dysymtab_command Dysymtab = O->getDysymtabLoadCommand();
+ uint32_t indirect_symbol = O->getIndirectSymbolTableEntry(Dysymtab, n + j);
+ if (indirect_symbol == MachO::INDIRECT_SYMBOL_LOCAL) {
+ outs() << "LOCAL\n";
+ continue;
+ }
+ if (indirect_symbol ==
+ (MachO::INDIRECT_SYMBOL_LOCAL | MachO::INDIRECT_SYMBOL_ABS)) {
+ outs() << "LOCAL ABSOLUTE\n";
+ continue;
+ }
+ if (indirect_symbol == MachO::INDIRECT_SYMBOL_ABS) {
+ outs() << "ABSOLUTE\n";
+ continue;
+ }
+ outs() << format("%5u ", indirect_symbol);
+ if (verbose) {
+ MachO::symtab_command Symtab = O->getSymtabLoadCommand();
+ if (indirect_symbol < Symtab.nsyms) {
+ symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
+ SymbolRef Symbol = *Sym;
+ StringRef SymName;
+ Symbol.getName(SymName);
+ outs() << SymName;
+ } else {
+ outs() << "?";
+ }
+ }
+ outs() << "\n";
+ }
+}
+
+static void PrintIndirectSymbols(MachOObjectFile *O, bool verbose) {
+ uint32_t LoadCommandCount = O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo();
+ for (unsigned I = 0;; ++I) {
+ if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ MachO::segment_command_64 Seg = O->getSegment64LoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section_64 Sec = O->getSection64(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
+ section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
+ section_type == MachO::S_SYMBOL_STUBS) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 8;
+ if (stride == 0) {
+ outs() << "Can't print indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") "
+ << "(size of stubs in reserved2 field is zero)\n";
+ continue;
+ }
+ uint32_t count = Sec.size / stride;
+ outs() << "Indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") " << count << " entries";
+ uint32_t n = Sec.reserved1;
+ PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
+ }
+ }
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ MachO::segment_command Seg = O->getSegmentLoadCommand(Load);
+ for (unsigned J = 0; J < Seg.nsects; ++J) {
+ MachO::section Sec = O->getSection(Load, J);
+ uint32_t section_type = Sec.flags & MachO::SECTION_TYPE;
+ if (section_type == MachO::S_NON_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_SYMBOL_POINTERS ||
+ section_type == MachO::S_LAZY_DYLIB_SYMBOL_POINTERS ||
+ section_type == MachO::S_THREAD_LOCAL_VARIABLE_POINTERS ||
+ section_type == MachO::S_SYMBOL_STUBS) {
+ uint32_t stride;
+ if (section_type == MachO::S_SYMBOL_STUBS)
+ stride = Sec.reserved2;
+ else
+ stride = 4;
+ if (stride == 0) {
+ outs() << "Can't print indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") "
+ << "(size of stubs in reserved2 field is zero)\n";
+ continue;
+ }
+ uint32_t count = Sec.size / stride;
+ outs() << "Indirect symbols for (" << Sec.segname << ","
+ << Sec.sectname << ") " << count << " entries";
+ uint32_t n = Sec.reserved1;
+ PrintIndirectSymbolTable(O, verbose, n, count, stride, Sec.addr);
+ }
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = O->getNextLoadCommandInfo(Load);
+ }
+}
+
+static void PrintDataInCodeTable(MachOObjectFile *O, bool verbose) {
+ MachO::linkedit_data_command DIC = O->getDataInCodeLoadCommand();
+ uint32_t nentries = DIC.datasize / sizeof(struct MachO::data_in_code_entry);
+ outs() << "Data in code table (" << nentries << " entries)\n";
+ outs() << "offset length kind\n";
+ for (dice_iterator DI = O->begin_dices(), DE = O->end_dices(); DI != DE;
+ ++DI) {
+ uint32_t Offset;
+ DI->getOffset(Offset);
+ outs() << format("0x%08" PRIx32, Offset) << " ";
+ uint16_t Length;
+ DI->getLength(Length);
+ outs() << format("%6u", Length) << " ";
+ uint16_t Kind;
+ DI->getKind(Kind);
+ if (verbose) {
+ switch (Kind) {
+ case MachO::DICE_KIND_DATA:
+ outs() << "DATA";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE8:
+ outs() << "JUMP_TABLE8";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE16:
+ outs() << "JUMP_TABLE16";
+ break;
+ case MachO::DICE_KIND_JUMP_TABLE32:
+ outs() << "JUMP_TABLE32";
+ break;
+ case MachO::DICE_KIND_ABS_JUMP_TABLE32:
+ outs() << "ABS_JUMP_TABLE32";
+ break;
+ default:
+ outs() << format("0x%04" PRIx32, Kind);
+ break;
+ }
+ } else
+ outs() << format("0x%04" PRIx32, Kind);
+ outs() << "\n";
+ }
+}
+
+static void PrintLinkOptHints(MachOObjectFile *O) {
+ MachO::linkedit_data_command LohLC = O->getLinkOptHintsLoadCommand();
+ const char *loh = O->getData().substr(LohLC.dataoff, 1).data();
+ uint32_t nloh = LohLC.datasize;
+ outs() << "Linker optimiztion hints (" << nloh << " total bytes)\n";
+ for (uint32_t i = 0; i < nloh;) {
+ unsigned n;
+ uint64_t identifier = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << " identifier " << identifier << " ";
+ if (i >= nloh)
+ return;
+ switch (identifier) {
+ case 1:
+ outs() << "AdrpAdrp\n";
+ break;
+ case 2:
+ outs() << "AdrpLdr\n";
+ break;
+ case 3:
+ outs() << "AdrpAddLdr\n";
+ break;
+ case 4:
+ outs() << "AdrpLdrGotLdr\n";
+ break;
+ case 5:
+ outs() << "AdrpAddStr\n";
+ break;
+ case 6:
+ outs() << "AdrpLdrGotStr\n";
+ break;
+ case 7:
+ outs() << "AdrpAdd\n";
+ break;
+ case 8:
+ outs() << "AdrpLdrGot\n";
+ break;
+ default:
+ outs() << "Unknown identifier value\n";
+ break;
+ }
+ uint64_t narguments = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << " narguments " << narguments << "\n";
+ if (i >= nloh)
+ return;
+
+ for (uint32_t j = 0; j < narguments; j++) {
+ uint64_t value = decodeULEB128((const uint8_t *)(loh + i), &n);
+ i += n;
+ outs() << "\tvalue " << format("0x%" PRIx64, value) << "\n";
+ if (i >= nloh)
+ return;
+ }
+ }
+}
+
+static void PrintDylibs(MachOObjectFile *O, bool JustId) {
+ uint32_t LoadCommandCount = O->getHeader().ncmds;
+ MachOObjectFile::LoadCommandInfo Load = O->getFirstLoadCommandInfo();
+ for (unsigned I = 0;; ++I) {
+ if ((JustId && Load.C.cmd == MachO::LC_ID_DYLIB) ||
+ (!JustId && (Load.C.cmd == MachO::LC_ID_DYLIB ||
+ Load.C.cmd == MachO::LC_LOAD_DYLIB ||
+ Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB ||
+ Load.C.cmd == MachO::LC_REEXPORT_DYLIB ||
+ Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB ||
+ Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB))) {
+ MachO::dylib_command dl = O->getDylibIDLoadCommand(Load);
+ if (dl.dylib.name < dl.cmdsize) {
+ const char *p = (const char *)(Load.Ptr) + dl.dylib.name;
+ if (JustId)
+ outs() << p << "\n";
+ else {
+ outs() << "\t" << p;
+ outs() << " (compatibility version "
+ << ((dl.dylib.compatibility_version >> 16) & 0xffff) << "."
+ << ((dl.dylib.compatibility_version >> 8) & 0xff) << "."
+ << (dl.dylib.compatibility_version & 0xff) << ",";
+ outs() << " current version "
+ << ((dl.dylib.current_version >> 16) & 0xffff) << "."
+ << ((dl.dylib.current_version >> 8) & 0xff) << "."
+ << (dl.dylib.current_version & 0xff) << ")\n";
+ }
+ } else {
+ outs() << "\tBad offset (" << dl.dylib.name << ") for name of ";
+ if (Load.C.cmd == MachO::LC_ID_DYLIB)
+ outs() << "LC_ID_DYLIB ";
+ else if (Load.C.cmd == MachO::LC_LOAD_DYLIB)
+ outs() << "LC_LOAD_DYLIB ";
+ else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB)
+ outs() << "LC_LOAD_WEAK_DYLIB ";
+ else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB)
+ outs() << "LC_LAZY_LOAD_DYLIB ";
+ else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB)
+ outs() << "LC_REEXPORT_DYLIB ";
+ else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB)
+ outs() << "LC_LOAD_UPWARD_DYLIB ";
+ else
+ outs() << "LC_??? ";
+ outs() << "command " << I << "\n";
+ }
+ }
+ if (I == LoadCommandCount - 1)
+ break;
+ else
+ Load = O->getNextLoadCommandInfo(Load);
+ }
+}
+
+typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
+
+static void CreateSymbolAddressMap(MachOObjectFile *O,
+ SymbolAddressMap *AddrMap) {
+ // Create a map of symbol addresses to symbol names.
+ for (const SymbolRef &Symbol : O->symbols()) {
+ SymbolRef::Type ST;
+ Symbol.getType(ST);
+ if (ST == SymbolRef::ST_Function || ST == SymbolRef::ST_Data ||
+ ST == SymbolRef::ST_Other) {
+ uint64_t Address;
+ Symbol.getAddress(Address);
+ StringRef SymName;
+ Symbol.getName(SymName);
+ if (!SymName.startswith(".objc"))
+ (*AddrMap)[Address] = SymName;
+ }
+ }
+}
+
+// GuessSymbolName is passed the address of what might be a symbol and a
+// pointer to the SymbolAddressMap. It returns the name of a symbol
+// with that address or nullptr if no symbol is found with that address.
+static const char *GuessSymbolName(uint64_t value, SymbolAddressMap *AddrMap) {
+ const char *SymbolName = nullptr;
+ // A DenseMap can't lookup up some values.
+ if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
+ StringRef name = AddrMap->lookup(value);
+ if (!name.empty())
+ SymbolName = name.data();
+ }
+ return SymbolName;
+}
+
+static void DumpCstringChar(const char c) {
+ char p[2];
+ p[0] = c;
+ p[1] = '\0';
+ outs().write_escaped(p);
+}
+
+static void DumpCstringSection(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i++) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ for (; i < sect_size && sect[i] != '\0'; i++)
+ DumpCstringChar(sect[i]);
+ if (i < sect_size && sect[i] == '\0')
+ outs() << "\n";
+ }
+}
+
+static void DumpLiteral4(uint32_t l, float f) {
+ outs() << format("0x%08" PRIx32, l);
+ if ((l & 0x7f800000) != 0x7f800000)
+ outs() << format(" (%.16e)\n", f);
+ else {
+ if (l == 0x7f800000)
+ outs() << " (+Infinity)\n";
+ else if (l == 0xff800000)
+ outs() << " (-Infinity)\n";
+ else if ((l & 0x00400000) == 0x00400000)
+ outs() << " (non-signaling Not-a-Number)\n";
+ else
+ outs() << " (signaling Not-a-Number)\n";
+ }
+}
+
+static void DumpLiteral4Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += sizeof(float)) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ float f;
+ memcpy(&f, sect + i, sizeof(float));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(f);
+ uint32_t l;
+ memcpy(&l, sect + i, sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(l);
+ DumpLiteral4(l, f);
+ }
+}
+
+static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1,
+ double d) {
+ outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
+ uint32_t Hi, Lo;
+ if (O->isLittleEndian()) {
+ Hi = l1;
+ Lo = l0;
+ } else {
+ Hi = l0;
+ Lo = l1;
+ }
+ // Hi is the high word, so this is equivalent to if(isfinite(d))
+ if ((Hi & 0x7ff00000) != 0x7ff00000)
+ outs() << format(" (%.16e)\n", d);
+ else {
+ if (Hi == 0x7ff00000 && Lo == 0)
+ outs() << " (+Infinity)\n";
+ else if (Hi == 0xfff00000 && Lo == 0)
+ outs() << " (-Infinity)\n";
+ else if ((Hi & 0x00080000) == 0x00080000)
+ outs() << " (non-signaling Not-a-Number)\n";
+ else
+ outs() << " (signaling Not-a-Number)\n";
+ }
+}
+
+static void DumpLiteral8Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += sizeof(double)) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ double d;
+ memcpy(&d, sect + i, sizeof(double));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(d);
+ uint32_t l0, l1;
+ memcpy(&l0, sect + i, sizeof(uint32_t));
+ memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ }
+ DumpLiteral8(O, l0, l1, d);
+ }
+}
+
+static void DumpLiteral16(uint32_t l0, uint32_t l1, uint32_t l2, uint32_t l3) {
+ outs() << format("0x%08" PRIx32, l0) << " ";
+ outs() << format("0x%08" PRIx32, l1) << " ";
+ outs() << format("0x%08" PRIx32, l2) << " ";
+ outs() << format("0x%08" PRIx32, l3) << "\n";
+}
+
+static void DumpLiteral16Section(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ bool print_addresses) {
+ for (uint32_t i = 0; i < sect_size; i += 16) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ uint32_t l0, l1, l2, l3;
+ memcpy(&l0, sect + i, sizeof(uint32_t));
+ memcpy(&l1, sect + i + sizeof(uint32_t), sizeof(uint32_t));
+ memcpy(&l2, sect + i + 2 * sizeof(uint32_t), sizeof(uint32_t));
+ memcpy(&l3, sect + i + 3 * sizeof(uint32_t), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ sys::swapByteOrder(l2);
+ sys::swapByteOrder(l3);
+ }
+ DumpLiteral16(l0, l1, l2, l3);
+ }
+}
+
+static void DumpLiteralPointerSection(MachOObjectFile *O,
+ const SectionRef &Section,
+ const char *sect, uint32_t sect_size,
+ uint64_t sect_addr,
+ bool print_addresses) {
+ // Collect the literal sections in this Mach-O file.
+ std::vector<SectionRef> LiteralSections;
+ for (const SectionRef &Section : O->sections()) {
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ uint32_t section_type;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ }
+ if (section_type == MachO::S_CSTRING_LITERALS ||
+ section_type == MachO::S_4BYTE_LITERALS ||
+ section_type == MachO::S_8BYTE_LITERALS ||
+ section_type == MachO::S_16BYTE_LITERALS)
+ LiteralSections.push_back(Section);
+ }
+
+ // Set the size of the literal pointer.
+ uint32_t lp_size = O->is64Bit() ? 8 : 4;
+
+ // Collect the external relocation symbols for the the literal pointers.
+ std::vector<std::pair<uint64_t, SymbolRef>> Relocs;
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ DataRefImpl Rel;
+ MachO::any_relocation_info RE;
+ bool isExtern = false;
+ Rel = Reloc.getRawDataRefImpl();
+ RE = O->getRelocation(Rel);
+ isExtern = O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ symbol_iterator RelocSym = Reloc.getSymbol();
+ Relocs.push_back(std::make_pair(RelocOffset, *RelocSym));
+ }
+ }
+ array_pod_sort(Relocs.begin(), Relocs.end());
+
+ // Dump each literal pointer.
+ for (uint32_t i = 0; i < sect_size; i += lp_size) {
+ if (print_addresses) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, sect_addr + i) << " ";
+ else
+ outs() << format("%08" PRIx64, sect_addr + i) << " ";
+ }
+ uint64_t lp;
+ if (O->is64Bit()) {
+ memcpy(&lp, sect + i, sizeof(uint64_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(lp);
+ } else {
+ uint32_t li;
+ memcpy(&li, sect + i, sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(li);
+ lp = li;
+ }
+
+ // First look for an external relocation entry for this literal pointer.
+ auto Reloc = std::find_if(
+ Relocs.begin(), Relocs.end(),
+ [&](const std::pair<uint64_t, SymbolRef> &P) { return P.first == i; });
+ if (Reloc != Relocs.end()) {
+ symbol_iterator RelocSym = Reloc->second;
+ StringRef SymName;
+ RelocSym->getName(SymName);
+ outs() << "external relocation entry for symbol:" << SymName << "\n";
+ continue;
+ }
+
+ // For local references see what the section the literal pointer points to.
+ auto Sect = std::find_if(LiteralSections.begin(), LiteralSections.end(),
+ [&](const SectionRef &R) {
+ return lp >= R.getAddress() &&
+ lp < R.getAddress() + R.getSize();
+ });
+ if (Sect == LiteralSections.end()) {
+ outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
+ continue;
+ }
+
+ uint64_t SectAddress = Sect->getAddress();
+ uint64_t SectSize = Sect->getSize();
+
+ StringRef SectName;
+ Sect->getName(SectName);
+ DataRefImpl Ref = Sect->getRawDataRefImpl();
+ StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
+ outs() << SegmentName << ":" << SectName << ":";
+
+ uint32_t section_type;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_type = Sec.flags & MachO::SECTION_TYPE;
+ }
+
+ StringRef BytesStr;
+ Sect->getContents(BytesStr);
+ const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
+
+ switch (section_type) {
+ case MachO::S_CSTRING_LITERALS:
+ for (uint64_t i = lp - SectAddress; i < SectSize && Contents[i] != '\0';
+ i++) {
+ DumpCstringChar(Contents[i]);
+ }
+ outs() << "\n";
+ break;
+ case MachO::S_4BYTE_LITERALS:
+ float f;
+ memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
+ uint32_t l;
+ memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l);
+ }
+ DumpLiteral4(l, f);
+ break;
+ case MachO::S_8BYTE_LITERALS: {
+ double d;
+ memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
+ uint32_t l0, l1;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(f);
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ }
+ DumpLiteral8(O, l0, l1, d);
+ break;
+ }
+ case MachO::S_16BYTE_LITERALS: {
+ uint32_t l0, l1, l2, l3;
+ memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
+ memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost) {
+ sys::swapByteOrder(l0);
+ sys::swapByteOrder(l1);
+ sys::swapByteOrder(l2);
+ sys::swapByteOrder(l3);
+ }
+ DumpLiteral16(l0, l1, l2, l3);
+ break;
+ }
+ }
+ }
+}
+
+static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect,
+ uint32_t sect_size, uint64_t sect_addr,
+ SymbolAddressMap *AddrMap,
+ bool verbose) {
+ uint32_t stride;
+ if (O->is64Bit())
+ stride = sizeof(uint64_t);
+ else
+ stride = sizeof(uint32_t);
+ for (uint32_t i = 0; i < sect_size; i += stride) {
+ const char *SymbolName = nullptr;
+ if (O->is64Bit()) {
+ outs() << format("0x%016" PRIx64, sect_addr + i * stride) << " ";
+ uint64_t pointer_value;
+ memcpy(&pointer_value, sect + i, stride);
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ outs() << format("0x%016" PRIx64, pointer_value);
+ if (verbose)
+ SymbolName = GuessSymbolName(pointer_value, AddrMap);
+ } else {
+ outs() << format("0x%08" PRIx64, sect_addr + i * stride) << " ";
+ uint32_t pointer_value;
+ memcpy(&pointer_value, sect + i, stride);
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(pointer_value);
+ outs() << format("0x%08" PRIx32, pointer_value);
+ if (verbose)
+ SymbolName = GuessSymbolName(pointer_value, AddrMap);
+ }
+ if (SymbolName)
+ outs() << " " << SymbolName;
+ outs() << "\n";
+ }
+}
+
+static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint64_t addr) {
+ uint32_t cputype = O->getHeader().cputype;
+ if (cputype == MachO::CPU_TYPE_I386 || cputype == MachO::CPU_TYPE_X86_64) {
+ uint32_t j;
+ for (uint32_t i = 0; i < size; i += j, addr += j) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, addr) << "\t";
+ else
+ outs() << format("%08" PRIx64, addr) << "\t";
+ for (j = 0; j < 16 && i + j < size; j++) {
+ uint8_t byte_word = *(sect + i + j);
+ outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
+ }
+ outs() << "\n";
+ }
+ } else {
+ uint32_t j;
+ for (uint32_t i = 0; i < size; i += j, addr += j) {
+ if (O->is64Bit())
+ outs() << format("%016" PRIx64, addr) << "\t";
+ else
+ outs() << format("%08" PRIx64, sect) << "\t";
+ for (j = 0; j < 4 * sizeof(int32_t) && i + j < size;
+ j += sizeof(int32_t)) {
+ if (i + j + sizeof(int32_t) < size) {
+ uint32_t long_word;
+ memcpy(&long_word, sect + i + j, sizeof(int32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(long_word);
+ outs() << format("%08" PRIx32, long_word) << " ";
+ } else {
+ for (uint32_t k = 0; i + j + k < size; k++) {
+ uint8_t byte_word = *(sect + i + j);
+ outs() << format("%02" PRIx32, (uint32_t)byte_word) << " ";
+ }
+ }
+ }
+ outs() << "\n";
+ }
+ }
+}
+
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
+ StringRef DisSegName, StringRef DisSectName);
+static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint32_t addr);
+
+static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
+ bool verbose) {
+ SymbolAddressMap AddrMap;
+ if (verbose)
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ for (unsigned i = 0; i < DumpSections.size(); ++i) {
+ StringRef DumpSection = DumpSections[i];
+ std::pair<StringRef, StringRef> DumpSegSectName;
+ DumpSegSectName = DumpSection.split(',');
+ StringRef DumpSegName, DumpSectName;
+ if (DumpSegSectName.second.size()) {
+ DumpSegName = DumpSegSectName.first;
+ DumpSectName = DumpSegSectName.second;
+ } else {
+ DumpSegName = "";
+ DumpSectName = DumpSegSectName.first;
+ }
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ if ((DumpSegName.empty() || SegName == DumpSegName) &&
+ (SectName == DumpSectName)) {
+
+ uint32_t section_flags;
+ if (O->is64Bit()) {
+ const MachO::section_64 Sec = O->getSection64(Ref);
+ section_flags = Sec.flags;
+
+ } else {
+ const MachO::section Sec = O->getSection(Ref);
+ section_flags = Sec.flags;
+ }
+ uint32_t section_type = section_flags & MachO::SECTION_TYPE;
+
+ StringRef BytesStr;
+ Section.getContents(BytesStr);
+ const char *sect = reinterpret_cast<const char *>(BytesStr.data());
+ uint32_t sect_size = BytesStr.size();
+ uint64_t sect_addr = Section.getAddress();
+
+ if (Raw) {
+ outs().write(BytesStr.data(), BytesStr.size());
+ continue;
+ }
+
+ outs() << "Contents of (" << SegName << "," << SectName
+ << ") section\n";
+
+ if (verbose) {
+ if ((section_flags & MachO::S_ATTR_PURE_INSTRUCTIONS) ||
+ (section_flags & MachO::S_ATTR_SOME_INSTRUCTIONS)) {
+ DisassembleMachO(Filename, O, SegName, SectName);
+ continue;
+ }
+ if (SegName == "__TEXT" && SectName == "__info_plist") {
+ outs() << sect;
+ continue;
+ }
+ if (SegName == "__OBJC" && SectName == "__protocol") {
+ DumpProtocolSection(O, sect, sect_size, sect_addr);
+ continue;
+ }
+ switch (section_type) {
+ case MachO::S_REGULAR:
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ break;
+ case MachO::S_ZEROFILL:
+ outs() << "zerofill section and has no contents in the file\n";
+ break;
+ case MachO::S_CSTRING_LITERALS:
+ DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr);
+ break;
+ case MachO::S_4BYTE_LITERALS:
+ DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
+ break;
+ case MachO::S_8BYTE_LITERALS:
+ DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
+ break;
+ case MachO::S_16BYTE_LITERALS:
+ DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
+ break;
+ case MachO::S_LITERAL_POINTERS:
+ DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
+ !NoLeadingAddr);
+ break;
+ case MachO::S_MOD_INIT_FUNC_POINTERS:
+ case MachO::S_MOD_TERM_FUNC_POINTERS:
+ DumpInitTermPointerSection(O, sect, sect_size, sect_addr, &AddrMap,
+ verbose);
+ break;
+ default:
+ outs() << "Unknown section type ("
+ << format("0x%08" PRIx32, section_type) << ")\n";
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ break;
+ }
+ } else {
+ if (section_type == MachO::S_ZEROFILL)
+ outs() << "zerofill section and has no contents in the file\n";
+ else
+ DumpRawSectionContents(O, sect, sect_size, sect_addr);
+ }
+ }
+ }
+ }
+}
+
+static void DumpInfoPlistSectionContents(StringRef Filename,
+ MachOObjectFile *O) {
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ if (SegName == "__TEXT" && SectName == "__info_plist") {
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ StringRef BytesStr;
+ Section.getContents(BytesStr);
+ const char *sect = reinterpret_cast<const char *>(BytesStr.data());
+ outs() << sect;
+ return;
+ }
+ }
+}
+
// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file
// and if it is and there is a list of architecture flags is specified then
// check to make sure this Mach-O file is one of those architectures or all
@@ -289,7 +1197,7 @@ static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) {
return true;
}
-static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF);
+static void printObjcMetaData(MachOObjectFile *O, bool verbose);
// ProcessMachO() is passed a single opened Mach-O file, which may be an
// archive member and or in a slice of a universal file. It prints the
@@ -300,9 +1208,11 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
StringRef ArchitectureName = StringRef()) {
// If we are doing some processing here on the Mach-O file print the header
// info. And don't print it otherwise like in the case of printing the
- // UniversalHeaders.
+ // UniversalHeaders or ArchiveHeaders.
if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
- LazyBind || WeakBind) {
+ LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
+ DylibsUsed || DylibId || ObjcMetaData ||
+ (DumpSections.size() != 0 && !Raw)) {
outs() << Filename;
if (!ArchiveMemberName.empty())
outs() << '(' << ArchiveMemberName << ')';
@@ -312,23 +1222,35 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
}
if (Disassemble)
- DisassembleMachO(Filename, MachOOF);
- // TODO: These should/could be printed in Darwin's otool(1) or nm(1) style
- // for -macho. Or just used a new option that maps to the otool(1)
- // option like -r, -l, etc. Or just the normal llvm-objdump option
- // but now for this slice so that the -arch options can be used.
- // if (Relocations)
- // PrintRelocations(MachOOF);
- // if (SectionHeaders)
- // PrintSectionHeaders(MachOOF);
- // if (SectionContents)
- // PrintSectionContents(MachOOF);
- // if (SymbolTable)
- // PrintSymbolTable(MachOOF);
- // if (UnwindInfo)
- // PrintUnwindInfo(MachOOF);
+ DisassembleMachO(Filename, MachOOF, "__TEXT", "__text");
+ if (IndirectSymbols)
+ PrintIndirectSymbols(MachOOF, !NonVerbose);
+ if (DataInCode)
+ PrintDataInCodeTable(MachOOF, !NonVerbose);
+ if (LinkOptHints)
+ PrintLinkOptHints(MachOOF);
+ if (Relocations)
+ PrintRelocations(MachOOF);
+ if (SectionHeaders)
+ PrintSectionHeaders(MachOOF);
+ if (SectionContents)
+ PrintSectionContents(MachOOF);
+ if (DumpSections.size() != 0)
+ DumpSectionContents(Filename, MachOOF, !NonVerbose);
+ if (InfoPlist)
+ DumpInfoPlistSectionContents(Filename, MachOOF);
+ if (DylibsUsed)
+ PrintDylibs(MachOOF, false);
+ if (DylibId)
+ PrintDylibs(MachOOF, true);
+ if (SymbolTable)
+ PrintSymbolTable(MachOOF);
+ if (UnwindInfo)
+ printMachOUnwindInfo(MachOOF);
if (PrivateHeaders)
printMachOFileHeader(MachOOF);
+ if (ObjcMetaData)
+ printObjcMetaData(MachOOF, !NonVerbose);
if (ExportsTrie)
printExportsTrie(MachOOF);
if (Rebase)
@@ -514,6 +1436,106 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
}
}
+static void printArchiveChild(Archive::Child &C, bool verbose,
+ bool print_offset) {
+ if (print_offset)
+ outs() << C.getChildOffset() << "\t";
+ sys::fs::perms Mode = C.getAccessMode();
+ if (verbose) {
+ // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
+ // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
+ outs() << "-";
+ if (Mode & sys::fs::owner_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::owner_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::owner_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::group_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_read)
+ outs() << "r";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_write)
+ outs() << "w";
+ else
+ outs() << "-";
+ if (Mode & sys::fs::others_exe)
+ outs() << "x";
+ else
+ outs() << "-";
+ } else {
+ outs() << format("0%o ", Mode);
+ }
+
+ unsigned UID = C.getUID();
+ outs() << format("%3d/", UID);
+ unsigned GID = C.getGID();
+ outs() << format("%-3d ", GID);
+ uint64_t Size = C.getRawSize();
+ outs() << format("%5" PRId64, Size) << " ";
+
+ StringRef RawLastModified = C.getRawLastModified();
+ if (verbose) {
+ unsigned Seconds;
+ if (RawLastModified.getAsInteger(10, Seconds))
+ outs() << "(date: \"%s\" contains non-decimal chars) " << RawLastModified;
+ else {
+ // Since cime(3) returns a 26 character string of the form:
+ // "Sun Sep 16 01:03:52 1973\n\0"
+ // just print 24 characters.
+ time_t t = Seconds;
+ outs() << format("%.24s ", ctime(&t));
+ }
+ } else {
+ outs() << RawLastModified << " ";
+ }
+
+ if (verbose) {
+ ErrorOr<StringRef> NameOrErr = C.getName();
+ if (NameOrErr.getError()) {
+ StringRef RawName = C.getRawName();
+ outs() << RawName << "\n";
+ } else {
+ StringRef Name = NameOrErr.get();
+ outs() << Name << "\n";
+ }
+ } else {
+ StringRef RawName = C.getRawName();
+ outs() << RawName << "\n";
+ }
+}
+
+static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) {
+ if (A->hasSymbolTable()) {
+ Archive::child_iterator S = A->getSymbolTableChild();
+ Archive::Child C = *S;
+ printArchiveChild(C, verbose, print_offset);
+ }
+ for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E;
+ ++I) {
+ Archive::Child C = *I;
+ printArchiveChild(C, verbose, print_offset);
+ }
+}
+
// ParseInputMachO() parses the named Mach-O file in Filename and handles the
// -arch flags selecting just those slices as specified by them and also parses
// archive files. Then for each individual Mach-O file ProcessMachO() is
@@ -542,6 +1564,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
if (Archive *A = dyn_cast<Archive>(&Bin)) {
outs() << "Archive : " << Filename << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
I != E; ++I) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary();
@@ -557,7 +1581,7 @@ void llvm::ParseInputMachO(StringRef Filename) {
}
if (UniversalHeaders) {
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin))
- printMachOUniversalHeaders(UB, true);
+ printMachOUniversalHeaders(UB, !NonVerbose);
}
if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(&Bin)) {
// If we have a list of architecture flags specified dump only those.
@@ -587,6 +1611,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
if (!ArchitectureName.empty())
outs() << " (architecture " << ArchitectureName << ")";
outs() << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
@@ -627,6 +1653,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
I->getAsArchive()) {
std::unique_ptr<Archive> &A = *AOrErr;
outs() << "Archive : " << Filename << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
@@ -662,6 +1690,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
if (!ArchitectureName.empty())
outs() << " (architecture " << ArchitectureName << ")";
outs() << "\n";
+ if (ArchiveHeaders)
+ printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
AI != AE; ++AI) {
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
@@ -691,7 +1721,6 @@ void llvm::ParseInputMachO(StringRef Filename) {
<< "Unrecognized file type.\n";
}
-typedef DenseMap<uint64_t, StringRef> SymbolAddressMap;
typedef std::pair<uint64_t, const char *> BindInfoEntry;
typedef std::vector<BindInfoEntry> BindTable;
typedef BindTable::iterator bind_table_iterator;
@@ -712,21 +1741,6 @@ struct DisassembleInfo {
BindTable *bindtable;
};
-// GuessSymbolName is passed the address of what might be a symbol and a
-// pointer to the DisassembleInfo struct. It returns the name of a symbol
-// with that address or nullptr if no symbol is found with that address.
-static const char *GuessSymbolName(uint64_t value,
- struct DisassembleInfo *info) {
- const char *SymbolName = nullptr;
- // A DenseMap can't lookup up some values.
- if (value != 0xffffffffffffffffULL && value != 0xfffffffffffffffeULL) {
- StringRef name = info->AddrMap->lookup(value);
- if (!name.empty())
- SymbolName = name.data();
- }
- return SymbolName;
-}
-
// SymbolizerGetOpInfo() is the operand information call back function.
// This is called to get the symbolic information for operand(s) of an
// instruction when it is being done. This routine does this from
@@ -742,8 +1756,8 @@ static const char *GuessSymbolName(uint64_t value,
// names and addends of the symbolic expression to add for the operand. The
// value of TagType is currently 1 (for the LLVMOpInfo1 struct). If symbolic
// information is returned then this function returns 1 else it returns 0.
-int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
- uint64_t Size, int TagType, void *TagBuf) {
+static int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
+ uint64_t Size, int TagType, void *TagBuf) {
struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
struct LLVMOpInfo1 *op_info = (struct LLVMOpInfo1 *)TagBuf;
uint64_t value = op_info->Value;
@@ -755,7 +1769,7 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// If the TagType is not the value 1 which it code knows about or if no
// verbose symbolic information is wanted then just return 0, indicating no
// information is being returned.
- if (TagType != 1 || info->verbose == false)
+ if (TagType != 1 || !info->verbose)
return 0;
unsigned int Arch = info->O->getArch();
@@ -817,8 +1831,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
if (reloc_found && (r_type == MachO::GENERIC_RELOC_SECTDIFF ||
r_type == MachO::GENERIC_RELOC_LOCAL_SECTDIFF)) {
- const char *add = GuessSymbolName(r_value, info);
- const char *sub = GuessSymbolName(pair_r_value, info);
+ const char *add = GuessSymbolName(r_value, info->AddrMap);
+ const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
uint32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@@ -838,7 +1852,8 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// (if any) for an entry that matches this segment offset.
// uint32_t seg_offset = (Pc + Offset);
return 0;
- } else if (Arch == Triple::x86_64) {
+ }
+ if (Arch == Triple::x86_64) {
if (Size != 1 && Size != 2 && Size != 4 && Size != 0)
return 0;
// First search the section's relocation entries (if any) for an entry
@@ -904,89 +1919,77 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// (if any) for an entry that matches this segment offset.
// uint64_t seg_offset = (Pc + Offset);
return 0;
- } else if (Arch == Triple::arm) {
+ }
+ if (Arch == Triple::arm) {
if (Offset != 0 || (Size != 4 && Size != 2))
return 0;
// First search the section's relocation entries (if any) for an entry
// for this section offset.
uint32_t sect_addr = info->S.getAddress();
uint32_t sect_offset = (Pc + Offset) - sect_addr;
- bool reloc_found = false;
DataRefImpl Rel;
MachO::any_relocation_info RE;
bool isExtern = false;
SymbolRef Symbol;
bool r_scattered = false;
uint32_t r_value, pair_r_value, r_type, r_length, other_half;
- for (const RelocationRef &Reloc : info->S.relocations()) {
- uint64_t RelocOffset;
- Reloc.getOffset(RelocOffset);
- if (RelocOffset == sect_offset) {
- Rel = Reloc.getRawDataRefImpl();
- RE = info->O->getRelocation(Rel);
- r_length = info->O->getAnyRelocationLength(RE);
- r_scattered = info->O->isRelocationScattered(RE);
- if (r_scattered) {
- r_value = info->O->getScatteredRelocationValue(RE);
- r_type = info->O->getScatteredRelocationType(RE);
- } else {
- r_type = info->O->getAnyRelocationType(RE);
- isExtern = info->O->getPlainRelocationExternal(RE);
- if (isExtern) {
- symbol_iterator RelocSym = Reloc.getSymbol();
- Symbol = *RelocSym;
- }
- }
- if (r_type == MachO::ARM_RELOC_HALF ||
- r_type == MachO::ARM_RELOC_SECTDIFF ||
- r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
- r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
- DataRefImpl RelNext = Rel;
- info->O->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext;
- RENext = info->O->getRelocation(RelNext);
- other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
- if (info->O->isRelocationScattered(RENext))
- pair_r_value = info->O->getScatteredRelocationValue(RENext);
- }
- reloc_found = true;
- break;
+ auto Reloc =
+ std::find_if(info->S.relocations().begin(), info->S.relocations().end(),
+ [&](const RelocationRef &Reloc) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ return RelocOffset == sect_offset;
+ });
+
+ if (Reloc == info->S.relocations().end())
+ return 0;
+
+ Rel = Reloc->getRawDataRefImpl();
+ RE = info->O->getRelocation(Rel);
+ r_length = info->O->getAnyRelocationLength(RE);
+ r_scattered = info->O->isRelocationScattered(RE);
+ if (r_scattered) {
+ r_value = info->O->getScatteredRelocationValue(RE);
+ r_type = info->O->getScatteredRelocationType(RE);
+ } else {
+ r_type = info->O->getAnyRelocationType(RE);
+ isExtern = info->O->getPlainRelocationExternal(RE);
+ if (isExtern) {
+ symbol_iterator RelocSym = Reloc->getSymbol();
+ Symbol = *RelocSym;
}
}
- if (reloc_found && isExtern) {
+ if (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_SECTDIFF ||
+ r_type == MachO::ARM_RELOC_LOCAL_SECTDIFF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext;
+ RENext = info->O->getRelocation(RelNext);
+ other_half = info->O->getAnyRelocationAddress(RENext) & 0xffff;
+ if (info->O->isRelocationScattered(RENext))
+ pair_r_value = info->O->getScatteredRelocationValue(RENext);
+ }
+
+ if (isExtern) {
StringRef SymName;
Symbol.getName(SymName);
const char *name = SymName.data();
op_info->AddSymbol.Present = 1;
op_info->AddSymbol.Name = name;
- if (value != 0) {
- switch (r_type) {
- case MachO::ARM_RELOC_HALF:
- if ((r_length & 0x1) == 1) {
- op_info->Value = value << 16 | other_half;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
- } else {
- op_info->Value = other_half << 16 | value;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- }
- break;
- default:
- break;
- }
- } else {
- switch (r_type) {
- case MachO::ARM_RELOC_HALF:
- if ((r_length & 0x1) == 1) {
- op_info->Value = value << 16 | other_half;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
- } else {
- op_info->Value = other_half << 16 | value;
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- }
- break;
- default:
- break;
+ switch (r_type) {
+ case MachO::ARM_RELOC_HALF:
+ if ((r_length & 0x1) == 1) {
+ op_info->Value = value << 16 | other_half;
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
+ } else {
+ op_info->Value = other_half << 16 | value;
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
}
+ break;
+ default:
+ break;
}
return 1;
}
@@ -994,33 +1997,31 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
// return 0 so the code in tryAddingSymbolicOperand() can use the
// SymbolLookUp call back with the branch target address to look up the
// symbol and possiblity add an annotation for a symbol stub.
- if (reloc_found && isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
- r_type == MachO::ARM_THUMB_RELOC_BR22))
+ if (isExtern == 0 && (r_type == MachO::ARM_RELOC_BR24 ||
+ r_type == MachO::ARM_THUMB_RELOC_BR22))
return 0;
uint32_t offset = 0;
- if (reloc_found) {
- if (r_type == MachO::ARM_RELOC_HALF ||
- r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
- if ((r_length & 0x1) == 1)
- value = value << 16 | other_half;
- else
- value = other_half << 16 | value;
- }
- if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
- r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
- offset = value - r_value;
- value = r_value;
- }
+ if (r_type == MachO::ARM_RELOC_HALF ||
+ r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ if ((r_length & 0x1) == 1)
+ value = value << 16 | other_half;
+ else
+ value = other_half << 16 | value;
+ }
+ if (r_scattered && (r_type != MachO::ARM_RELOC_HALF &&
+ r_type != MachO::ARM_RELOC_HALF_SECTDIFF)) {
+ offset = value - r_value;
+ value = r_value;
}
- if (reloc_found && r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
+ if (r_type == MachO::ARM_RELOC_HALF_SECTDIFF) {
if ((r_length & 0x1) == 1)
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
else
op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- const char *add = GuessSymbolName(r_value, info);
- const char *sub = GuessSymbolName(pair_r_value, info);
+ const char *add = GuessSymbolName(r_value, info->AddrMap);
+ const char *sub = GuessSymbolName(pair_r_value, info->AddrMap);
int32_t offset = value - (r_value - pair_r_value);
op_info->AddSymbol.Present = 1;
if (add != nullptr)
@@ -1036,115 +2037,101 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
return 1;
}
- if (reloc_found == false)
- return 0;
-
op_info->AddSymbol.Present = 1;
op_info->Value = offset;
- if (reloc_found) {
- if (r_type == MachO::ARM_RELOC_HALF) {
- if ((r_length & 0x1) == 1)
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
- else
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
- }
+ if (r_type == MachO::ARM_RELOC_HALF) {
+ if ((r_length & 0x1) == 1)
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_HI16;
+ else
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM_LO16;
}
- const char *add = GuessSymbolName(value, info);
+ const char *add = GuessSymbolName(value, info->AddrMap);
if (add != nullptr) {
op_info->AddSymbol.Name = add;
return 1;
}
op_info->AddSymbol.Value = value;
return 1;
- } else if (Arch == Triple::aarch64) {
+ }
+ if (Arch == Triple::aarch64) {
if (Offset != 0 || Size != 4)
return 0;
// First search the section's relocation entries (if any) for an entry
// for this section offset.
uint64_t sect_addr = info->S.getAddress();
uint64_t sect_offset = (Pc + Offset) - sect_addr;
- bool reloc_found = false;
- DataRefImpl Rel;
- MachO::any_relocation_info RE;
- bool isExtern = false;
- SymbolRef Symbol;
- uint32_t r_type = 0;
- for (const RelocationRef &Reloc : info->S.relocations()) {
- uint64_t RelocOffset;
- Reloc.getOffset(RelocOffset);
- if (RelocOffset == sect_offset) {
- Rel = Reloc.getRawDataRefImpl();
- RE = info->O->getRelocation(Rel);
- r_type = info->O->getAnyRelocationType(RE);
- if (r_type == MachO::ARM64_RELOC_ADDEND) {
- DataRefImpl RelNext = Rel;
- info->O->moveRelocationNext(RelNext);
- MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
- if (value == 0) {
- value = info->O->getPlainRelocationSymbolNum(RENext);
- op_info->Value = value;
- }
- }
- // NOTE: Scattered relocations don't exist on arm64.
- isExtern = info->O->getPlainRelocationExternal(RE);
- if (isExtern) {
- symbol_iterator RelocSym = Reloc.getSymbol();
- Symbol = *RelocSym;
- }
- reloc_found = true;
- break;
+ auto Reloc =
+ std::find_if(info->S.relocations().begin(), info->S.relocations().end(),
+ [&](const RelocationRef &Reloc) {
+ uint64_t RelocOffset;
+ Reloc.getOffset(RelocOffset);
+ return RelocOffset == sect_offset;
+ });
+
+ if (Reloc == info->S.relocations().end())
+ return 0;
+
+ DataRefImpl Rel = Reloc->getRawDataRefImpl();
+ MachO::any_relocation_info RE = info->O->getRelocation(Rel);
+ uint32_t r_type = info->O->getAnyRelocationType(RE);
+ if (r_type == MachO::ARM64_RELOC_ADDEND) {
+ DataRefImpl RelNext = Rel;
+ info->O->moveRelocationNext(RelNext);
+ MachO::any_relocation_info RENext = info->O->getRelocation(RelNext);
+ if (value == 0) {
+ value = info->O->getPlainRelocationSymbolNum(RENext);
+ op_info->Value = value;
}
}
- if (reloc_found && isExtern) {
- StringRef SymName;
- Symbol.getName(SymName);
- const char *name = SymName.data();
- op_info->AddSymbol.Present = 1;
- op_info->AddSymbol.Name = name;
+ // NOTE: Scattered relocations don't exist on arm64.
+ if (!info->O->getPlainRelocationExternal(RE))
+ return 0;
+ StringRef SymName;
+ Reloc->getSymbol()->getName(SymName);
+ const char *name = SymName.data();
+ op_info->AddSymbol.Present = 1;
+ op_info->AddSymbol.Name = name;
- switch (r_type) {
- case MachO::ARM64_RELOC_PAGE21:
- /* @page */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
- break;
- case MachO::ARM64_RELOC_PAGEOFF12:
- /* @pageoff */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
- break;
- case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
- /* @gotpage */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
- break;
- case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
- /* @gotpageoff */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
- break;
- case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
- /* @tvlppage is not implemented in llvm-mc */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
- break;
- case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
- /* @tvlppageoff is not implemented in llvm-mc */
- op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
- break;
- default:
- case MachO::ARM64_RELOC_BRANCH26:
- op_info->VariantKind = LLVMDisassembler_VariantKind_None;
- break;
- }
- return 1;
+ switch (r_type) {
+ case MachO::ARM64_RELOC_PAGE21:
+ /* @page */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGE;
+ break;
+ case MachO::ARM64_RELOC_PAGEOFF12:
+ /* @pageoff */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_PAGEOFF;
+ break;
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21:
+ /* @gotpage */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGE;
+ break;
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12:
+ /* @gotpageoff */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF;
+ break;
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
+ /* @tvlppage is not implemented in llvm-mc */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVP;
+ break;
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
+ /* @tvlppageoff is not implemented in llvm-mc */
+ op_info->VariantKind = LLVMDisassembler_VariantKind_ARM64_TLVOFF;
+ break;
+ default:
+ case MachO::ARM64_RELOC_BRANCH26:
+ op_info->VariantKind = LLVMDisassembler_VariantKind_None;
+ break;
}
- return 0;
- } else {
- return 0;
+ return 1;
}
+ return 0;
}
// GuessCstringPointer is passed the address of what might be a pointer to a
// literal string in a cstring section. If that address is in a cstring section
// it returns a pointer to that string. Else it returns nullptr.
-const char *GuessCstringPointer(uint64_t ReferenceValue,
- struct DisassembleInfo *info) {
+static const char *GuessCstringPointer(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
uint32_t LoadCommandCount = info->O->getHeader().ncmds;
MachOObjectFile::LoadCommandInfo Load = info->O->getFirstLoadCommandInfo();
for (unsigned I = 0;; ++I) {
@@ -1429,14 +2416,24 @@ static uint64_t GuessPointerPointer(uint64_t ReferenceValue,
// offset into the section, number of bytes left in the section past the offset
// and which section is was being referenced. If the Address is not in a
// section nullptr is returned.
-const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left,
- SectionRef &S, DisassembleInfo *info) {
+static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
+ uint32_t &left, SectionRef &S,
+ DisassembleInfo *info,
+ bool objc_only = false) {
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 (objc_only) {
+ StringRef SectName;
+ ((*(info->Sections))[SectIdx]).getName(SectName);
+ DataRefImpl Ref = ((*(info->Sections))[SectIdx]).getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ if (SegName != "__OBJC" && SectName != "__cstring")
+ continue;
+ }
if (Address >= SectAddress && Address < SectAddress + SectSize) {
S = (*(info->Sections))[SectIdx];
offset = Address - SectAddress;
@@ -1449,13 +2446,24 @@ const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left,
return nullptr;
}
+static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
+ uint32_t &left, SectionRef &S,
+ DisassembleInfo *info,
+ bool objc_only = false) {
+ return get_pointer_64(Address, offset, left, S, info, objc_only);
+}
+
// 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) {
+// If no relocation information is found and a non-zero ReferenceValue for the
+// symbol is passed, look up that address in the info's AddrMap.
+static const char *
+get_symbol_64(uint32_t sect_offset, SectionRef S, DisassembleInfo *info,
+ uint64_t &n_value,
+ uint64_t ReferenceValue = UnknownAddressOrSize) {
n_value = 0;
- if (info->verbose == false)
+ if (!info->verbose)
return nullptr;
// See if there is an external relocation entry at the sect_offset.
@@ -1487,6 +2495,8 @@ const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
const char *SymbolName = nullptr;
if (reloc_found && isExtern) {
Symbol.getAddress(n_value);
+ if (n_value == UnknownAddressOrSize)
+ n_value = 0;
StringRef name;
Symbol.getName(name);
if (!name.empty()) {
@@ -1504,17 +2514,21 @@ const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
//
// 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);
+ // 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.
+ if (ReferenceValue != UnknownAddressOrSize)
+ SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
return SymbolName;
}
+static const char *get_symbol_32(uint32_t sect_offset, SectionRef S,
+ DisassembleInfo *info,
+ uint32_t ReferenceValue) {
+ uint64_t n_value64;
+ return get_symbol_64(sect_offset, S, info, n_value64, ReferenceValue);
+}
+
// 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 .
@@ -1536,6 +2550,14 @@ struct class64_t {
uint64_t data; // class_ro64_t * (64-bit pointer)
};
+struct class32_t {
+ uint32_t isa; /* class32_t * (32-bit pointer) */
+ uint32_t superclass; /* class32_t * (32-bit pointer) */
+ uint32_t cache; /* Cache (32-bit pointer) */
+ uint32_t vtable; /* IMP * (32-bit pointer) */
+ uint32_t data; /* class_ro32_t * (32-bit pointer) */
+};
+
struct class_ro64_t {
uint32_t flags;
uint32_t instanceStart;
@@ -1550,6 +2572,276 @@ struct class_ro64_t {
uint64_t baseProperties; // const struct objc_property_list (64-bit pointer)
};
+struct class_ro32_t {
+ uint32_t flags;
+ uint32_t instanceStart;
+ uint32_t instanceSize;
+ uint32_t ivarLayout; /* const uint8_t * (32-bit pointer) */
+ uint32_t name; /* const char * (32-bit pointer) */
+ uint32_t baseMethods; /* const method_list_t * (32-bit pointer) */
+ uint32_t baseProtocols; /* const protocol_list_t * (32-bit pointer) */
+ uint32_t ivars; /* const ivar_list_t * (32-bit pointer) */
+ uint32_t weakIvarLayout; /* const uint8_t * (32-bit pointer) */
+ uint32_t baseProperties; /* const struct objc_property_list *
+ (32-bit pointer) */
+};
+
+/* Values for class_ro{64,32}_t->flags */
+#define RO_META (1 << 0)
+#define RO_ROOT (1 << 1)
+#define RO_HAS_CXX_STRUCTORS (1 << 2)
+
+struct method_list64_t {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct method64_t first; These structures follow inline */
+};
+
+struct method_list32_t {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct method32_t first; These structures follow inline */
+};
+
+struct method64_t {
+ uint64_t name; /* SEL (64-bit pointer) */
+ uint64_t types; /* const char * (64-bit pointer) */
+ uint64_t imp; /* IMP (64-bit pointer) */
+};
+
+struct method32_t {
+ uint32_t name; /* SEL (32-bit pointer) */
+ uint32_t types; /* const char * (32-bit pointer) */
+ uint32_t imp; /* IMP (32-bit pointer) */
+};
+
+struct protocol_list64_t {
+ uint64_t count; /* uintptr_t (a 64-bit value) */
+ /* struct protocol64_t * list[0]; These pointers follow inline */
+};
+
+struct protocol_list32_t {
+ uint32_t count; /* uintptr_t (a 32-bit value) */
+ /* struct protocol32_t * list[0]; These pointers follow inline */
+};
+
+struct protocol64_t {
+ uint64_t isa; /* id * (64-bit pointer) */
+ uint64_t name; /* const char * (64-bit pointer) */
+ uint64_t protocols; /* struct protocol_list64_t *
+ (64-bit pointer) */
+ uint64_t instanceMethods; /* method_list_t * (64-bit pointer) */
+ uint64_t classMethods; /* method_list_t * (64-bit pointer) */
+ uint64_t optionalInstanceMethods; /* method_list_t * (64-bit pointer) */
+ uint64_t optionalClassMethods; /* method_list_t * (64-bit pointer) */
+ uint64_t instanceProperties; /* struct objc_property_list *
+ (64-bit pointer) */
+};
+
+struct protocol32_t {
+ uint32_t isa; /* id * (32-bit pointer) */
+ uint32_t name; /* const char * (32-bit pointer) */
+ uint32_t protocols; /* struct protocol_list_t *
+ (32-bit pointer) */
+ uint32_t instanceMethods; /* method_list_t * (32-bit pointer) */
+ uint32_t classMethods; /* method_list_t * (32-bit pointer) */
+ uint32_t optionalInstanceMethods; /* method_list_t * (32-bit pointer) */
+ uint32_t optionalClassMethods; /* method_list_t * (32-bit pointer) */
+ uint32_t instanceProperties; /* struct objc_property_list *
+ (32-bit pointer) */
+};
+
+struct ivar_list64_t {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct ivar64_t first; These structures follow inline */
+};
+
+struct ivar_list32_t {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct ivar32_t first; These structures follow inline */
+};
+
+struct ivar64_t {
+ uint64_t offset; /* uintptr_t * (64-bit pointer) */
+ uint64_t name; /* const char * (64-bit pointer) */
+ uint64_t type; /* const char * (64-bit pointer) */
+ uint32_t alignment;
+ uint32_t size;
+};
+
+struct ivar32_t {
+ uint32_t offset; /* uintptr_t * (32-bit pointer) */
+ uint32_t name; /* const char * (32-bit pointer) */
+ uint32_t type; /* const char * (32-bit pointer) */
+ uint32_t alignment;
+ uint32_t size;
+};
+
+struct objc_property_list64 {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct objc_property64 first; These structures follow inline */
+};
+
+struct objc_property_list32 {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct objc_property32 first; These structures follow inline */
+};
+
+struct objc_property64 {
+ uint64_t name; /* const char * (64-bit pointer) */
+ uint64_t attributes; /* const char * (64-bit pointer) */
+};
+
+struct objc_property32 {
+ uint32_t name; /* const char * (32-bit pointer) */
+ uint32_t attributes; /* const char * (32-bit pointer) */
+};
+
+struct category64_t {
+ uint64_t name; /* const char * (64-bit pointer) */
+ uint64_t cls; /* struct class_t * (64-bit pointer) */
+ uint64_t instanceMethods; /* struct method_list_t * (64-bit pointer) */
+ uint64_t classMethods; /* struct method_list_t * (64-bit pointer) */
+ uint64_t protocols; /* struct protocol_list_t * (64-bit pointer) */
+ uint64_t instanceProperties; /* struct objc_property_list *
+ (64-bit pointer) */
+};
+
+struct category32_t {
+ uint32_t name; /* const char * (32-bit pointer) */
+ uint32_t cls; /* struct class_t * (32-bit pointer) */
+ uint32_t instanceMethods; /* struct method_list_t * (32-bit pointer) */
+ uint32_t classMethods; /* struct method_list_t * (32-bit pointer) */
+ uint32_t protocols; /* struct protocol_list_t * (32-bit pointer) */
+ uint32_t instanceProperties; /* struct objc_property_list *
+ (32-bit pointer) */
+};
+
+struct objc_image_info64 {
+ uint32_t version;
+ uint32_t flags;
+};
+struct objc_image_info32 {
+ uint32_t version;
+ uint32_t flags;
+};
+struct imageInfo_t {
+ uint32_t version;
+ uint32_t flags;
+};
+/* masks for objc_image_info.flags */
+#define OBJC_IMAGE_IS_REPLACEMENT (1 << 0)
+#define OBJC_IMAGE_SUPPORTS_GC (1 << 1)
+
+struct message_ref64 {
+ uint64_t imp; /* IMP (64-bit pointer) */
+ uint64_t sel; /* SEL (64-bit pointer) */
+};
+
+struct message_ref32 {
+ uint32_t imp; /* IMP (32-bit pointer) */
+ uint32_t sel; /* SEL (32-bit pointer) */
+};
+
+// Objective-C 1 (32-bit only) meta data structs.
+
+struct objc_module_t {
+ uint32_t version;
+ uint32_t size;
+ uint32_t name; /* char * (32-bit pointer) */
+ uint32_t symtab; /* struct objc_symtab * (32-bit pointer) */
+};
+
+struct objc_symtab_t {
+ uint32_t sel_ref_cnt;
+ uint32_t refs; /* SEL * (32-bit pointer) */
+ uint16_t cls_def_cnt;
+ uint16_t cat_def_cnt;
+ // uint32_t defs[1]; /* void * (32-bit pointer) variable size */
+};
+
+struct objc_class_t {
+ uint32_t isa; /* struct objc_class * (32-bit pointer) */
+ uint32_t super_class; /* struct objc_class * (32-bit pointer) */
+ uint32_t name; /* const char * (32-bit pointer) */
+ int32_t version;
+ int32_t info;
+ int32_t instance_size;
+ uint32_t ivars; /* struct objc_ivar_list * (32-bit pointer) */
+ uint32_t methodLists; /* struct objc_method_list ** (32-bit pointer) */
+ uint32_t cache; /* struct objc_cache * (32-bit pointer) */
+ uint32_t protocols; /* struct objc_protocol_list * (32-bit pointer) */
+};
+
+#define CLS_GETINFO(cls, infomask) ((cls)->info & (infomask))
+// class is not a metaclass
+#define CLS_CLASS 0x1
+// class is a metaclass
+#define CLS_META 0x2
+
+struct objc_category_t {
+ uint32_t category_name; /* char * (32-bit pointer) */
+ uint32_t class_name; /* char * (32-bit pointer) */
+ uint32_t instance_methods; /* struct objc_method_list * (32-bit pointer) */
+ uint32_t class_methods; /* struct objc_method_list * (32-bit pointer) */
+ uint32_t protocols; /* struct objc_protocol_list * (32-bit ptr) */
+};
+
+struct objc_ivar_t {
+ uint32_t ivar_name; /* char * (32-bit pointer) */
+ uint32_t ivar_type; /* char * (32-bit pointer) */
+ int32_t ivar_offset;
+};
+
+struct objc_ivar_list_t {
+ int32_t ivar_count;
+ // struct objc_ivar_t ivar_list[1]; /* variable length structure */
+};
+
+struct objc_method_list_t {
+ uint32_t obsolete; /* struct objc_method_list * (32-bit pointer) */
+ int32_t method_count;
+ // struct objc_method_t method_list[1]; /* variable length structure */
+};
+
+struct objc_method_t {
+ uint32_t method_name; /* SEL, aka struct objc_selector * (32-bit pointer) */
+ uint32_t method_types; /* char * (32-bit pointer) */
+ uint32_t method_imp; /* IMP, aka function pointer, (*IMP)(id, SEL, ...)
+ (32-bit pointer) */
+};
+
+struct objc_protocol_list_t {
+ uint32_t next; /* struct objc_protocol_list * (32-bit pointer) */
+ int32_t count;
+ // uint32_t list[1]; /* Protocol *, aka struct objc_protocol_t *
+ // (32-bit pointer) */
+};
+
+struct objc_protocol_t {
+ uint32_t isa; /* struct objc_class * (32-bit pointer) */
+ uint32_t protocol_name; /* char * (32-bit pointer) */
+ uint32_t protocol_list; /* struct objc_protocol_list * (32-bit pointer) */
+ uint32_t instance_methods; /* struct objc_method_description_list *
+ (32-bit pointer) */
+ uint32_t class_methods; /* struct objc_method_description_list *
+ (32-bit pointer) */
+};
+
+struct objc_method_description_list_t {
+ int32_t count;
+ // struct objc_method_description_t list[1];
+};
+
+struct objc_method_description_t {
+ uint32_t name; /* SEL, aka struct objc_selector * (32-bit pointer) */
+ uint32_t types; /* char * (32-bit pointer) */
+};
+
inline void swapStruct(struct cfstring64_t &cfs) {
sys::swapByteOrder(cfs.isa);
sys::swapByteOrder(cfs.flags);
@@ -1565,6 +2857,14 @@ inline void swapStruct(struct class64_t &c) {
sys::swapByteOrder(c.data);
}
+inline void swapStruct(struct class32_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);
@@ -1579,6 +2879,238 @@ inline void swapStruct(struct class_ro64_t &cro) {
sys::swapByteOrder(cro.baseProperties);
}
+inline void swapStruct(struct class_ro32_t &cro) {
+ sys::swapByteOrder(cro.flags);
+ sys::swapByteOrder(cro.instanceStart);
+ sys::swapByteOrder(cro.instanceSize);
+ 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);
+}
+
+inline void swapStruct(struct method_list64_t &ml) {
+ sys::swapByteOrder(ml.entsize);
+ sys::swapByteOrder(ml.count);
+}
+
+inline void swapStruct(struct method_list32_t &ml) {
+ sys::swapByteOrder(ml.entsize);
+ sys::swapByteOrder(ml.count);
+}
+
+inline void swapStruct(struct method64_t &m) {
+ sys::swapByteOrder(m.name);
+ sys::swapByteOrder(m.types);
+ sys::swapByteOrder(m.imp);
+}
+
+inline void swapStruct(struct method32_t &m) {
+ sys::swapByteOrder(m.name);
+ sys::swapByteOrder(m.types);
+ sys::swapByteOrder(m.imp);
+}
+
+inline void swapStruct(struct protocol_list64_t &pl) {
+ sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct protocol_list32_t &pl) {
+ sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct protocol64_t &p) {
+ sys::swapByteOrder(p.isa);
+ sys::swapByteOrder(p.name);
+ sys::swapByteOrder(p.protocols);
+ sys::swapByteOrder(p.instanceMethods);
+ sys::swapByteOrder(p.classMethods);
+ sys::swapByteOrder(p.optionalInstanceMethods);
+ sys::swapByteOrder(p.optionalClassMethods);
+ sys::swapByteOrder(p.instanceProperties);
+}
+
+inline void swapStruct(struct protocol32_t &p) {
+ sys::swapByteOrder(p.isa);
+ sys::swapByteOrder(p.name);
+ sys::swapByteOrder(p.protocols);
+ sys::swapByteOrder(p.instanceMethods);
+ sys::swapByteOrder(p.classMethods);
+ sys::swapByteOrder(p.optionalInstanceMethods);
+ sys::swapByteOrder(p.optionalClassMethods);
+ sys::swapByteOrder(p.instanceProperties);
+}
+
+inline void swapStruct(struct ivar_list64_t &il) {
+ sys::swapByteOrder(il.entsize);
+ sys::swapByteOrder(il.count);
+}
+
+inline void swapStruct(struct ivar_list32_t &il) {
+ sys::swapByteOrder(il.entsize);
+ sys::swapByteOrder(il.count);
+}
+
+inline void swapStruct(struct ivar64_t &i) {
+ sys::swapByteOrder(i.offset);
+ sys::swapByteOrder(i.name);
+ sys::swapByteOrder(i.type);
+ sys::swapByteOrder(i.alignment);
+ sys::swapByteOrder(i.size);
+}
+
+inline void swapStruct(struct ivar32_t &i) {
+ sys::swapByteOrder(i.offset);
+ sys::swapByteOrder(i.name);
+ sys::swapByteOrder(i.type);
+ sys::swapByteOrder(i.alignment);
+ sys::swapByteOrder(i.size);
+}
+
+inline void swapStruct(struct objc_property_list64 &pl) {
+ sys::swapByteOrder(pl.entsize);
+ sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct objc_property_list32 &pl) {
+ sys::swapByteOrder(pl.entsize);
+ sys::swapByteOrder(pl.count);
+}
+
+inline void swapStruct(struct objc_property64 &op) {
+ sys::swapByteOrder(op.name);
+ sys::swapByteOrder(op.attributes);
+}
+
+inline void swapStruct(struct objc_property32 &op) {
+ sys::swapByteOrder(op.name);
+ sys::swapByteOrder(op.attributes);
+}
+
+inline void swapStruct(struct category64_t &c) {
+ sys::swapByteOrder(c.name);
+ sys::swapByteOrder(c.cls);
+ sys::swapByteOrder(c.instanceMethods);
+ sys::swapByteOrder(c.classMethods);
+ sys::swapByteOrder(c.protocols);
+ sys::swapByteOrder(c.instanceProperties);
+}
+
+inline void swapStruct(struct category32_t &c) {
+ sys::swapByteOrder(c.name);
+ sys::swapByteOrder(c.cls);
+ sys::swapByteOrder(c.instanceMethods);
+ sys::swapByteOrder(c.classMethods);
+ sys::swapByteOrder(c.protocols);
+ sys::swapByteOrder(c.instanceProperties);
+}
+
+inline void swapStruct(struct objc_image_info64 &o) {
+ sys::swapByteOrder(o.version);
+ sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct objc_image_info32 &o) {
+ sys::swapByteOrder(o.version);
+ sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct imageInfo_t &o) {
+ sys::swapByteOrder(o.version);
+ sys::swapByteOrder(o.flags);
+}
+
+inline void swapStruct(struct message_ref64 &mr) {
+ sys::swapByteOrder(mr.imp);
+ sys::swapByteOrder(mr.sel);
+}
+
+inline void swapStruct(struct message_ref32 &mr) {
+ sys::swapByteOrder(mr.imp);
+ sys::swapByteOrder(mr.sel);
+}
+
+inline void swapStruct(struct objc_module_t &module) {
+ sys::swapByteOrder(module.version);
+ sys::swapByteOrder(module.size);
+ sys::swapByteOrder(module.name);
+ sys::swapByteOrder(module.symtab);
+}
+
+inline void swapStruct(struct objc_symtab_t &symtab) {
+ sys::swapByteOrder(symtab.sel_ref_cnt);
+ sys::swapByteOrder(symtab.refs);
+ sys::swapByteOrder(symtab.cls_def_cnt);
+ sys::swapByteOrder(symtab.cat_def_cnt);
+}
+
+inline void swapStruct(struct objc_class_t &objc_class) {
+ sys::swapByteOrder(objc_class.isa);
+ sys::swapByteOrder(objc_class.super_class);
+ sys::swapByteOrder(objc_class.name);
+ sys::swapByteOrder(objc_class.version);
+ sys::swapByteOrder(objc_class.info);
+ sys::swapByteOrder(objc_class.instance_size);
+ sys::swapByteOrder(objc_class.ivars);
+ sys::swapByteOrder(objc_class.methodLists);
+ sys::swapByteOrder(objc_class.cache);
+ sys::swapByteOrder(objc_class.protocols);
+}
+
+inline void swapStruct(struct objc_category_t &objc_category) {
+ sys::swapByteOrder(objc_category.category_name);
+ sys::swapByteOrder(objc_category.class_name);
+ sys::swapByteOrder(objc_category.instance_methods);
+ sys::swapByteOrder(objc_category.class_methods);
+ sys::swapByteOrder(objc_category.protocols);
+}
+
+inline void swapStruct(struct objc_ivar_list_t &objc_ivar_list) {
+ sys::swapByteOrder(objc_ivar_list.ivar_count);
+}
+
+inline void swapStruct(struct objc_ivar_t &objc_ivar) {
+ sys::swapByteOrder(objc_ivar.ivar_name);
+ sys::swapByteOrder(objc_ivar.ivar_type);
+ sys::swapByteOrder(objc_ivar.ivar_offset);
+}
+
+inline void swapStruct(struct objc_method_list_t &method_list) {
+ sys::swapByteOrder(method_list.obsolete);
+ sys::swapByteOrder(method_list.method_count);
+}
+
+inline void swapStruct(struct objc_method_t &method) {
+ sys::swapByteOrder(method.method_name);
+ sys::swapByteOrder(method.method_types);
+ sys::swapByteOrder(method.method_imp);
+}
+
+inline void swapStruct(struct objc_protocol_list_t &protocol_list) {
+ sys::swapByteOrder(protocol_list.next);
+ sys::swapByteOrder(protocol_list.count);
+}
+
+inline void swapStruct(struct objc_protocol_t &protocol) {
+ sys::swapByteOrder(protocol.isa);
+ sys::swapByteOrder(protocol.protocol_name);
+ sys::swapByteOrder(protocol.protocol_list);
+ sys::swapByteOrder(protocol.instance_methods);
+ sys::swapByteOrder(protocol.class_methods);
+}
+
+inline void swapStruct(struct objc_method_description_list_t &mdl) {
+ sys::swapByteOrder(mdl.count);
+}
+
+inline void swapStruct(struct objc_method_description_t &md) {
+ sys::swapByteOrder(md.name);
+ sys::swapByteOrder(md.types);
+}
+
static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
struct DisassembleInfo *info);
@@ -1587,9 +3119,9 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue,
// address of the pointer, so when the pointer is zero as it can be in an .o
// file, that is used to look for an external relocation entry with a symbol
// name.
-const char *get_objc2_64bit_class_name(uint64_t pointer_value,
- uint64_t ReferenceValue,
- struct DisassembleInfo *info) {
+static const char *get_objc2_64bit_class_name(uint64_t pointer_value,
+ uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
const char *r;
uint32_t offset, left;
SectionRef S;
@@ -1638,8 +3170,8 @@ const char *get_objc2_64bit_class_name(uint64_t pointer_value,
// get_objc2_64bit_cfstring_name is used for disassembly and is passed a
// pointer to a cfstring and returns its name or nullptr.
-const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
- struct DisassembleInfo *info) {
+static const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
const char *r, *name;
uint32_t offset, left;
SectionRef S;
@@ -1672,8 +3204,8 @@ const char *get_objc2_64bit_cfstring_name(uint64_t ReferenceValue,
// who's symbol's n_value is the real pointer to the selector name. If that is
// the case the real pointer to the selector name is returned else 0 is
// returned
-uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
- struct DisassembleInfo *info) {
+static uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
+ struct DisassembleInfo *info) {
uint32_t offset, left;
SectionRef S;
@@ -1687,6 +3219,2411 @@ uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
return n_value;
}
+static const SectionRef get_section(MachOObjectFile *O, const char *segname,
+ const char *sectname) {
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ DataRefImpl Ref = Section.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ if (SegName == segname && SectName == sectname)
+ return Section;
+ }
+ return SectionRef();
+}
+
+static void
+walk_pointer_list_64(const char *listname, const SectionRef S,
+ MachOObjectFile *O, struct DisassembleInfo *info,
+ void (*func)(uint64_t, struct DisassembleInfo *info)) {
+ if (S == SectionRef())
+ return;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+
+ StringRef BytesStr;
+ S.getContents(BytesStr);
+ const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
+
+ for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint64_t)) {
+ uint32_t left = S.getSize() - i;
+ uint32_t size = left < sizeof(uint64_t) ? left : sizeof(uint64_t);
+ uint64_t p = 0;
+ memcpy(&p, Contents + i, size);
+ if (i + sizeof(uint64_t) > S.getSize())
+ outs() << listname << " list pointer extends past end of (" << SegName
+ << "," << SectName << ") section\n";
+ outs() << format("%016" PRIx64, S.getAddress() + i) << " ";
+
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(p);
+
+ uint64_t n_value = 0;
+ const char *name = get_symbol_64(i, S, info, n_value, p);
+ if (name == nullptr)
+ name = get_dyld_bind_info_symbolname(S.getAddress() + i, info);
+
+ if (n_value != 0) {
+ outs() << format("0x%" PRIx64, n_value);
+ if (p != 0)
+ outs() << " + " << format("0x%" PRIx64, p);
+ } else
+ outs() << format("0x%" PRIx64, p);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ p += n_value;
+ if (func)
+ func(p, info);
+ }
+}
+
+static void
+walk_pointer_list_32(const char *listname, const SectionRef S,
+ MachOObjectFile *O, struct DisassembleInfo *info,
+ void (*func)(uint32_t, struct DisassembleInfo *info)) {
+ if (S == SectionRef())
+ return;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+
+ StringRef BytesStr;
+ S.getContents(BytesStr);
+ const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
+
+ for (uint32_t i = 0; i < S.getSize(); i += sizeof(uint32_t)) {
+ uint32_t left = S.getSize() - i;
+ uint32_t size = left < sizeof(uint32_t) ? left : sizeof(uint32_t);
+ uint32_t p = 0;
+ memcpy(&p, Contents + i, size);
+ if (i + sizeof(uint32_t) > S.getSize())
+ outs() << listname << " list pointer extends past end of (" << SegName
+ << "," << SectName << ") section\n";
+ uint32_t Address = S.getAddress() + i;
+ outs() << format("%08" PRIx32, Address) << " ";
+
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(p);
+ outs() << format("0x%" PRIx32, p);
+
+ const char *name = get_symbol_32(i, S, info, p);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ if (func)
+ func(p, info);
+ }
+}
+
+static void print_layout_map(const char *layout_map, uint32_t left) {
+ outs() << " layout map: ";
+ do {
+ outs() << format("0x%02" PRIx32, (*layout_map) & 0xff) << " ";
+ left--;
+ layout_map++;
+ } while (*layout_map != '\0' && left != 0);
+ outs() << "\n";
+}
+
+static void print_layout_map64(uint64_t p, struct DisassembleInfo *info) {
+ uint32_t offset, left;
+ SectionRef S;
+ const char *layout_map;
+
+ if (p == 0)
+ return;
+ layout_map = get_pointer_64(p, offset, left, S, info);
+ print_layout_map(layout_map, left);
+}
+
+static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
+ uint32_t offset, left;
+ SectionRef S;
+ const char *layout_map;
+
+ if (p == 0)
+ return;
+ layout_map = get_pointer_32(p, offset, left, S, info);
+ print_layout_map(layout_map, left);
+}
+
+static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
+ const char *indent) {
+ struct method_list64_t ml;
+ struct method64_t m;
+ const char *r;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+ const char *name, *sym_name;
+ uint64_t n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&ml, '\0', sizeof(struct method_list64_t));
+ if (left < sizeof(struct method_list64_t)) {
+ memcpy(&ml, r, left);
+ outs() << " (method_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&ml, r, sizeof(struct method_list64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(ml);
+ outs() << indent << "\t\t entsize " << ml.entsize << "\n";
+ outs() << indent << "\t\t count " << ml.count << "\n";
+
+ p += sizeof(struct method_list64_t);
+ offset += sizeof(struct method_list64_t);
+ for (i = 0; i < ml.count; i++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&m, '\0', sizeof(struct method64_t));
+ if (left < sizeof(struct method64_t)) {
+ memcpy(&ml, r, left);
+ outs() << indent << " (method_t entends past the end of the section)\n";
+ } else
+ memcpy(&m, r, sizeof(struct method64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(m);
+
+ outs() << indent << "\t\t name ";
+ sym_name = get_symbol_64(offset + offsetof(struct method64_t, name), S,
+ info, n_value, m.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (m.name != 0)
+ outs() << " + " << format("0x%" PRIx64, m.name);
+ } else
+ outs() << format("0x%" PRIx64, m.name);
+ name = get_pointer_64(m.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t types ";
+ sym_name = get_symbol_64(offset + offsetof(struct method64_t, types), S,
+ info, n_value, m.types);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (m.types != 0)
+ outs() << " + " << format("0x%" PRIx64, m.types);
+ } else
+ outs() << format("0x%" PRIx64, m.types);
+ name = get_pointer_64(m.types + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t imp ";
+ name = get_symbol_64(offset + offsetof(struct method64_t, imp), S, info,
+ n_value, m.imp);
+ if (info->verbose && name == nullptr) {
+ if (n_value != 0) {
+ outs() << format("0x%" PRIx64, n_value) << " ";
+ if (m.imp != 0)
+ outs() << "+ " << format("0x%" PRIx64, m.imp) << " ";
+ } else
+ outs() << format("0x%" PRIx64, m.imp) << " ";
+ }
+ if (name != nullptr)
+ outs() << name;
+ outs() << "\n";
+
+ p += sizeof(struct method64_t);
+ offset += sizeof(struct method64_t);
+ }
+}
+
+static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
+ const char *indent) {
+ struct method_list32_t ml;
+ struct method32_t m;
+ const char *r, *name;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&ml, '\0', sizeof(struct method_list32_t));
+ if (left < sizeof(struct method_list32_t)) {
+ memcpy(&ml, r, left);
+ outs() << " (method_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&ml, r, sizeof(struct method_list32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(ml);
+ outs() << indent << "\t\t entsize " << ml.entsize << "\n";
+ outs() << indent << "\t\t count " << ml.count << "\n";
+
+ p += sizeof(struct method_list32_t);
+ offset += sizeof(struct method_list32_t);
+ for (i = 0; i < ml.count; i++) {
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&m, '\0', sizeof(struct method32_t));
+ if (left < sizeof(struct method32_t)) {
+ memcpy(&ml, r, left);
+ outs() << indent << " (method_t entends past the end of the section)\n";
+ } else
+ memcpy(&m, r, sizeof(struct method32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(m);
+
+ outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
+ name = get_pointer_32(m.name, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
+ name = get_pointer_32(m.types, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
+ name = get_symbol_32(offset + offsetof(struct method32_t, imp), S, info,
+ m.imp);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ p += sizeof(struct method32_t);
+ offset += sizeof(struct method32_t);
+ }
+}
+
+static bool print_method_list(uint32_t p, struct DisassembleInfo *info) {
+ uint32_t offset, left, xleft;
+ SectionRef S;
+ struct objc_method_list_t method_list;
+ struct objc_method_t method;
+ const char *r, *methods, *name, *SymbolName;
+ int32_t i;
+
+ r = get_pointer_32(p, offset, left, S, info, true);
+ if (r == nullptr)
+ return true;
+
+ outs() << "\n";
+ if (left > sizeof(struct objc_method_list_t)) {
+ memcpy(&method_list, r, sizeof(struct objc_method_list_t));
+ } else {
+ outs() << "\t\t objc_method_list extends past end of the section\n";
+ memset(&method_list, '\0', sizeof(struct objc_method_list_t));
+ memcpy(&method_list, r, left);
+ }
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(method_list);
+
+ outs() << "\t\t obsolete "
+ << format("0x%08" PRIx32, method_list.obsolete) << "\n";
+ outs() << "\t\t method_count " << method_list.method_count << "\n";
+
+ methods = r + sizeof(struct objc_method_list_t);
+ for (i = 0; i < method_list.method_count; i++) {
+ if ((i + 1) * sizeof(struct objc_method_t) > left) {
+ outs() << "\t\t remaining method's extend past the of the section\n";
+ break;
+ }
+ memcpy(&method, methods + i * sizeof(struct objc_method_t),
+ sizeof(struct objc_method_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(method);
+
+ outs() << "\t\t method_name "
+ << format("0x%08" PRIx32, method.method_name);
+ if (info->verbose) {
+ name = get_pointer_32(method.method_name, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t method_types "
+ << format("0x%08" PRIx32, method.method_types);
+ if (info->verbose) {
+ name = get_pointer_32(method.method_types, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t method_imp "
+ << format("0x%08" PRIx32, method.method_imp) << " ";
+ if (info->verbose) {
+ SymbolName = GuessSymbolName(method.method_imp, info->AddrMap);
+ if (SymbolName != nullptr)
+ outs() << SymbolName;
+ }
+ outs() << "\n";
+ }
+ return false;
+}
+
+static void print_protocol_list64_t(uint64_t p, struct DisassembleInfo *info) {
+ struct protocol_list64_t pl;
+ uint64_t q, n_value;
+ struct protocol64_t pc;
+ const char *r;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+ const char *name, *sym_name;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&pl, '\0', sizeof(struct protocol_list64_t));
+ if (left < sizeof(struct protocol_list64_t)) {
+ memcpy(&pl, r, left);
+ outs() << " (protocol_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&pl, r, sizeof(struct protocol_list64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(pl);
+ outs() << " count " << pl.count << "\n";
+
+ p += sizeof(struct protocol_list64_t);
+ offset += sizeof(struct protocol_list64_t);
+ for (i = 0; i < pl.count; i++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ q = 0;
+ if (left < sizeof(uint64_t)) {
+ memcpy(&q, r, left);
+ outs() << " (protocol_t * entends past the end of the section)\n";
+ } else
+ memcpy(&q, r, sizeof(uint64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(q);
+
+ outs() << "\t\t list[" << i << "] ";
+ sym_name = get_symbol_64(offset, S, info, n_value, q);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (q != 0)
+ outs() << " + " << format("0x%" PRIx64, q);
+ } else
+ outs() << format("0x%" PRIx64, q);
+ outs() << " (struct protocol_t *)\n";
+
+ r = get_pointer_64(q + n_value, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&pc, '\0', sizeof(struct protocol64_t));
+ if (left < sizeof(struct protocol64_t)) {
+ memcpy(&pc, r, left);
+ outs() << " (protocol_t entends past the end of the section)\n";
+ } else
+ memcpy(&pc, r, sizeof(struct protocol64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(pc);
+
+ outs() << "\t\t\t isa " << format("0x%" PRIx64, pc.isa) << "\n";
+
+ outs() << "\t\t\t name ";
+ sym_name = get_symbol_64(offset + offsetof(struct protocol64_t, name), S,
+ info, n_value, pc.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (pc.name != 0)
+ outs() << " + " << format("0x%" PRIx64, pc.name);
+ } else
+ outs() << format("0x%" PRIx64, pc.name);
+ name = get_pointer_64(pc.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\tprotocols " << format("0x%" PRIx64, pc.protocols) << "\n";
+
+ outs() << "\t\t instanceMethods ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct protocol64_t, instanceMethods),
+ S, info, n_value, pc.instanceMethods);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (pc.instanceMethods != 0)
+ outs() << " + " << format("0x%" PRIx64, pc.instanceMethods);
+ } else
+ outs() << format("0x%" PRIx64, pc.instanceMethods);
+ outs() << " (struct method_list_t *)\n";
+ if (pc.instanceMethods + n_value != 0)
+ print_method_list64_t(pc.instanceMethods + n_value, info, "\t");
+
+ outs() << "\t\t classMethods ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct protocol64_t, classMethods), S,
+ info, n_value, pc.classMethods);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (pc.classMethods != 0)
+ outs() << " + " << format("0x%" PRIx64, pc.classMethods);
+ } else
+ outs() << format("0x%" PRIx64, pc.classMethods);
+ outs() << " (struct method_list_t *)\n";
+ if (pc.classMethods + n_value != 0)
+ print_method_list64_t(pc.classMethods + n_value, info, "\t");
+
+ outs() << "\t optionalInstanceMethods "
+ << format("0x%" PRIx64, pc.optionalInstanceMethods) << "\n";
+ outs() << "\t optionalClassMethods "
+ << format("0x%" PRIx64, pc.optionalClassMethods) << "\n";
+ outs() << "\t instanceProperties "
+ << format("0x%" PRIx64, pc.instanceProperties) << "\n";
+
+ p += sizeof(uint64_t);
+ offset += sizeof(uint64_t);
+ }
+}
+
+static void print_protocol_list32_t(uint32_t p, struct DisassembleInfo *info) {
+ struct protocol_list32_t pl;
+ uint32_t q;
+ struct protocol32_t pc;
+ const char *r;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+ const char *name;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&pl, '\0', sizeof(struct protocol_list32_t));
+ if (left < sizeof(struct protocol_list32_t)) {
+ memcpy(&pl, r, left);
+ outs() << " (protocol_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&pl, r, sizeof(struct protocol_list32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(pl);
+ outs() << " count " << pl.count << "\n";
+
+ p += sizeof(struct protocol_list32_t);
+ offset += sizeof(struct protocol_list32_t);
+ for (i = 0; i < pl.count; i++) {
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ q = 0;
+ if (left < sizeof(uint32_t)) {
+ memcpy(&q, r, left);
+ outs() << " (protocol_t * entends past the end of the section)\n";
+ } else
+ memcpy(&q, r, sizeof(uint32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(q);
+ outs() << "\t\t list[" << i << "] " << format("0x%" PRIx32, q)
+ << " (struct protocol_t *)\n";
+ r = get_pointer_32(q, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&pc, '\0', sizeof(struct protocol32_t));
+ if (left < sizeof(struct protocol32_t)) {
+ memcpy(&pc, r, left);
+ outs() << " (protocol_t entends past the end of the section)\n";
+ } else
+ memcpy(&pc, r, sizeof(struct protocol32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(pc);
+ outs() << "\t\t\t isa " << format("0x%" PRIx32, pc.isa) << "\n";
+ outs() << "\t\t\t name " << format("0x%" PRIx32, pc.name);
+ name = get_pointer_32(pc.name, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+ outs() << "\t\t\tprotocols " << format("0x%" PRIx32, pc.protocols) << "\n";
+ outs() << "\t\t instanceMethods "
+ << format("0x%" PRIx32, pc.instanceMethods)
+ << " (struct method_list_t *)\n";
+ if (pc.instanceMethods != 0)
+ print_method_list32_t(pc.instanceMethods, info, "\t");
+ outs() << "\t\t classMethods " << format("0x%" PRIx32, pc.classMethods)
+ << " (struct method_list_t *)\n";
+ if (pc.classMethods != 0)
+ print_method_list32_t(pc.classMethods, info, "\t");
+ outs() << "\t optionalInstanceMethods "
+ << format("0x%" PRIx32, pc.optionalInstanceMethods) << "\n";
+ outs() << "\t optionalClassMethods "
+ << format("0x%" PRIx32, pc.optionalClassMethods) << "\n";
+ outs() << "\t instanceProperties "
+ << format("0x%" PRIx32, pc.instanceProperties) << "\n";
+ p += sizeof(uint32_t);
+ offset += sizeof(uint32_t);
+ }
+}
+
+static void print_indent(uint32_t indent) {
+ for (uint32_t i = 0; i < indent;) {
+ if (indent - i >= 8) {
+ outs() << "\t";
+ i += 8;
+ } else {
+ for (uint32_t j = i; j < indent; j++)
+ outs() << " ";
+ return;
+ }
+ }
+}
+
+static bool print_method_description_list(uint32_t p, uint32_t indent,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left, xleft;
+ SectionRef S;
+ struct objc_method_description_list_t mdl;
+ struct objc_method_description_t md;
+ const char *r, *list, *name;
+ int32_t i;
+
+ r = get_pointer_32(p, offset, left, S, info, true);
+ if (r == nullptr)
+ return true;
+
+ outs() << "\n";
+ if (left > sizeof(struct objc_method_description_list_t)) {
+ memcpy(&mdl, r, sizeof(struct objc_method_description_list_t));
+ } else {
+ print_indent(indent);
+ outs() << " objc_method_description_list extends past end of the section\n";
+ memset(&mdl, '\0', sizeof(struct objc_method_description_list_t));
+ memcpy(&mdl, r, left);
+ }
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(mdl);
+
+ print_indent(indent);
+ outs() << " count " << mdl.count << "\n";
+
+ list = r + sizeof(struct objc_method_description_list_t);
+ for (i = 0; i < mdl.count; i++) {
+ if ((i + 1) * sizeof(struct objc_method_description_t) > left) {
+ print_indent(indent);
+ outs() << " remaining list entries extend past the of the section\n";
+ break;
+ }
+ print_indent(indent);
+ outs() << " list[" << i << "]\n";
+ memcpy(&md, list + i * sizeof(struct objc_method_description_t),
+ sizeof(struct objc_method_description_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(md);
+
+ print_indent(indent);
+ outs() << " name " << format("0x%08" PRIx32, md.name);
+ if (info->verbose) {
+ name = get_pointer_32(md.name, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ print_indent(indent);
+ outs() << " types " << format("0x%08" PRIx32, md.types);
+ if (info->verbose) {
+ name = get_pointer_32(md.types, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+ }
+ return false;
+}
+
+static bool print_protocol_list(uint32_t p, uint32_t indent,
+ struct DisassembleInfo *info);
+
+static bool print_protocol(uint32_t p, uint32_t indent,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left;
+ SectionRef S;
+ struct objc_protocol_t protocol;
+ const char *r, *name;
+
+ r = get_pointer_32(p, offset, left, S, info, true);
+ if (r == nullptr)
+ return true;
+
+ outs() << "\n";
+ if (left >= sizeof(struct objc_protocol_t)) {
+ memcpy(&protocol, r, sizeof(struct objc_protocol_t));
+ } else {
+ print_indent(indent);
+ outs() << " Protocol extends past end of the section\n";
+ memset(&protocol, '\0', sizeof(struct objc_protocol_t));
+ memcpy(&protocol, r, left);
+ }
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(protocol);
+
+ print_indent(indent);
+ outs() << " isa " << format("0x%08" PRIx32, protocol.isa)
+ << "\n";
+
+ print_indent(indent);
+ outs() << " protocol_name "
+ << format("0x%08" PRIx32, protocol.protocol_name);
+ if (info->verbose) {
+ name = get_pointer_32(protocol.protocol_name, offset, left, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ print_indent(indent);
+ outs() << " protocol_list "
+ << format("0x%08" PRIx32, protocol.protocol_list);
+ if (print_protocol_list(protocol.protocol_list, indent + 4, info))
+ outs() << " (not in an __OBJC section)\n";
+
+ print_indent(indent);
+ outs() << " instance_methods "
+ << format("0x%08" PRIx32, protocol.instance_methods);
+ if (print_method_description_list(protocol.instance_methods, indent, info))
+ outs() << " (not in an __OBJC section)\n";
+
+ print_indent(indent);
+ outs() << " class_methods "
+ << format("0x%08" PRIx32, protocol.class_methods);
+ if (print_method_description_list(protocol.class_methods, indent, info))
+ outs() << " (not in an __OBJC section)\n";
+
+ return false;
+}
+
+static bool print_protocol_list(uint32_t p, uint32_t indent,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left, l;
+ SectionRef S;
+ struct objc_protocol_list_t protocol_list;
+ const char *r, *list;
+ int32_t i;
+
+ r = get_pointer_32(p, offset, left, S, info, true);
+ if (r == nullptr)
+ return true;
+
+ outs() << "\n";
+ if (left > sizeof(struct objc_protocol_list_t)) {
+ memcpy(&protocol_list, r, sizeof(struct objc_protocol_list_t));
+ } else {
+ outs() << "\t\t objc_protocol_list_t extends past end of the section\n";
+ memset(&protocol_list, '\0', sizeof(struct objc_protocol_list_t));
+ memcpy(&protocol_list, r, left);
+ }
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(protocol_list);
+
+ print_indent(indent);
+ outs() << " next " << format("0x%08" PRIx32, protocol_list.next)
+ << "\n";
+ print_indent(indent);
+ outs() << " count " << protocol_list.count << "\n";
+
+ list = r + sizeof(struct objc_protocol_list_t);
+ for (i = 0; i < protocol_list.count; i++) {
+ if ((i + 1) * sizeof(uint32_t) > left) {
+ outs() << "\t\t remaining list entries extend past the of the section\n";
+ break;
+ }
+ memcpy(&l, list + i * sizeof(uint32_t), sizeof(uint32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(l);
+
+ print_indent(indent);
+ outs() << " list[" << i << "] " << format("0x%08" PRIx32, l);
+ if (print_protocol(l, indent, info))
+ outs() << "(not in an __OBJC section)\n";
+ }
+ return false;
+}
+
+static void print_ivar_list64_t(uint64_t p, struct DisassembleInfo *info) {
+ struct ivar_list64_t il;
+ struct ivar64_t i;
+ const char *r;
+ uint32_t offset, xoffset, left, j;
+ SectionRef S, xS;
+ const char *name, *sym_name, *ivar_offset_p;
+ uint64_t ivar_offset, n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&il, '\0', sizeof(struct ivar_list64_t));
+ if (left < sizeof(struct ivar_list64_t)) {
+ memcpy(&il, r, left);
+ outs() << " (ivar_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&il, r, sizeof(struct ivar_list64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(il);
+ outs() << " entsize " << il.entsize << "\n";
+ outs() << " count " << il.count << "\n";
+
+ p += sizeof(struct ivar_list64_t);
+ offset += sizeof(struct ivar_list64_t);
+ for (j = 0; j < il.count; j++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&i, '\0', sizeof(struct ivar64_t));
+ if (left < sizeof(struct ivar64_t)) {
+ memcpy(&i, r, left);
+ outs() << " (ivar_t entends past the end of the section)\n";
+ } else
+ memcpy(&i, r, sizeof(struct ivar64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(i);
+
+ outs() << "\t\t\t offset ";
+ sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, offset), S,
+ info, n_value, i.offset);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (i.offset != 0)
+ outs() << " + " << format("0x%" PRIx64, i.offset);
+ } else
+ outs() << format("0x%" PRIx64, i.offset);
+ ivar_offset_p = get_pointer_64(i.offset + n_value, xoffset, left, xS, info);
+ if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
+ memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(ivar_offset);
+ outs() << " " << ivar_offset << "\n";
+ } else
+ outs() << "\n";
+
+ outs() << "\t\t\t name ";
+ sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, name), S, info,
+ n_value, i.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (i.name != 0)
+ outs() << " + " << format("0x%" PRIx64, i.name);
+ } else
+ outs() << format("0x%" PRIx64, i.name);
+ name = get_pointer_64(i.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\t type ";
+ sym_name = get_symbol_64(offset + offsetof(struct ivar64_t, type), S, info,
+ n_value, i.name);
+ name = get_pointer_64(i.type + n_value, xoffset, left, xS, info);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (i.type != 0)
+ outs() << " + " << format("0x%" PRIx64, i.type);
+ } else
+ outs() << format("0x%" PRIx64, i.type);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\talignment " << i.alignment << "\n";
+ outs() << "\t\t\t size " << i.size << "\n";
+
+ p += sizeof(struct ivar64_t);
+ offset += sizeof(struct ivar64_t);
+ }
+}
+
+static void print_ivar_list32_t(uint32_t p, struct DisassembleInfo *info) {
+ struct ivar_list32_t il;
+ struct ivar32_t i;
+ const char *r;
+ uint32_t offset, xoffset, left, j;
+ SectionRef S, xS;
+ const char *name, *ivar_offset_p;
+ uint32_t ivar_offset;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&il, '\0', sizeof(struct ivar_list32_t));
+ if (left < sizeof(struct ivar_list32_t)) {
+ memcpy(&il, r, left);
+ outs() << " (ivar_list_t entends past the end of the section)\n";
+ } else
+ memcpy(&il, r, sizeof(struct ivar_list32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(il);
+ outs() << " entsize " << il.entsize << "\n";
+ outs() << " count " << il.count << "\n";
+
+ p += sizeof(struct ivar_list32_t);
+ offset += sizeof(struct ivar_list32_t);
+ for (j = 0; j < il.count; j++) {
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&i, '\0', sizeof(struct ivar32_t));
+ if (left < sizeof(struct ivar32_t)) {
+ memcpy(&i, r, left);
+ outs() << " (ivar_t entends past the end of the section)\n";
+ } else
+ memcpy(&i, r, sizeof(struct ivar32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(i);
+
+ outs() << "\t\t\t offset " << format("0x%" PRIx32, i.offset);
+ ivar_offset_p = get_pointer_32(i.offset, xoffset, left, xS, info);
+ if (ivar_offset_p != nullptr && left >= sizeof(*ivar_offset_p)) {
+ memcpy(&ivar_offset, ivar_offset_p, sizeof(ivar_offset));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(ivar_offset);
+ outs() << " " << ivar_offset << "\n";
+ } else
+ outs() << "\n";
+
+ outs() << "\t\t\t name " << format("0x%" PRIx32, i.name);
+ name = get_pointer_32(i.name, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\t type " << format("0x%" PRIx32, i.type);
+ name = get_pointer_32(i.type, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\talignment " << i.alignment << "\n";
+ outs() << "\t\t\t size " << i.size << "\n";
+
+ p += sizeof(struct ivar32_t);
+ offset += sizeof(struct ivar32_t);
+ }
+}
+
+static void print_objc_property_list64(uint64_t p,
+ struct DisassembleInfo *info) {
+ struct objc_property_list64 opl;
+ struct objc_property64 op;
+ const char *r;
+ uint32_t offset, xoffset, left, j;
+ SectionRef S, xS;
+ const char *name, *sym_name;
+ uint64_t n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&opl, '\0', sizeof(struct objc_property_list64));
+ if (left < sizeof(struct objc_property_list64)) {
+ memcpy(&opl, r, left);
+ outs() << " (objc_property_list entends past the end of the section)\n";
+ } else
+ memcpy(&opl, r, sizeof(struct objc_property_list64));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(opl);
+ outs() << " entsize " << opl.entsize << "\n";
+ outs() << " count " << opl.count << "\n";
+
+ p += sizeof(struct objc_property_list64);
+ offset += sizeof(struct objc_property_list64);
+ for (j = 0; j < opl.count; j++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&op, '\0', sizeof(struct objc_property64));
+ if (left < sizeof(struct objc_property64)) {
+ memcpy(&op, r, left);
+ outs() << " (objc_property entends past the end of the section)\n";
+ } else
+ memcpy(&op, r, sizeof(struct objc_property64));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(op);
+
+ outs() << "\t\t\t name ";
+ sym_name = get_symbol_64(offset + offsetof(struct objc_property64, name), S,
+ info, n_value, op.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (op.name != 0)
+ outs() << " + " << format("0x%" PRIx64, op.name);
+ } else
+ outs() << format("0x%" PRIx64, op.name);
+ name = get_pointer_64(op.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\tattributes ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct objc_property64, attributes), S,
+ info, n_value, op.attributes);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (op.attributes != 0)
+ outs() << " + " << format("0x%" PRIx64, op.attributes);
+ } else
+ outs() << format("0x%" PRIx64, op.attributes);
+ name = get_pointer_64(op.attributes + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ p += sizeof(struct objc_property64);
+ offset += sizeof(struct objc_property64);
+ }
+}
+
+static void print_objc_property_list32(uint32_t p,
+ struct DisassembleInfo *info) {
+ struct objc_property_list32 opl;
+ struct objc_property32 op;
+ const char *r;
+ uint32_t offset, xoffset, left, j;
+ SectionRef S, xS;
+ const char *name;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&opl, '\0', sizeof(struct objc_property_list32));
+ if (left < sizeof(struct objc_property_list32)) {
+ memcpy(&opl, r, left);
+ outs() << " (objc_property_list entends past the end of the section)\n";
+ } else
+ memcpy(&opl, r, sizeof(struct objc_property_list32));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(opl);
+ outs() << " entsize " << opl.entsize << "\n";
+ outs() << " count " << opl.count << "\n";
+
+ p += sizeof(struct objc_property_list32);
+ offset += sizeof(struct objc_property_list32);
+ for (j = 0; j < opl.count; j++) {
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&op, '\0', sizeof(struct objc_property32));
+ if (left < sizeof(struct objc_property32)) {
+ memcpy(&op, r, left);
+ outs() << " (objc_property entends past the end of the section)\n";
+ } else
+ memcpy(&op, r, sizeof(struct objc_property32));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(op);
+
+ outs() << "\t\t\t name " << format("0x%" PRIx32, op.name);
+ name = get_pointer_32(op.name, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << "\t\t\tattributes " << format("0x%" PRIx32, op.attributes);
+ name = get_pointer_32(op.attributes, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ p += sizeof(struct objc_property32);
+ offset += sizeof(struct objc_property32);
+ }
+}
+
+static void print_class_ro64_t(uint64_t p, struct DisassembleInfo *info,
+ bool &is_meta_class) {
+ struct class_ro64_t cro;
+ const char *r;
+ uint32_t offset, xoffset, left;
+ SectionRef S, xS;
+ const char *name, *sym_name;
+ uint64_t n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr || left < sizeof(struct class_ro64_t))
+ return;
+ memset(&cro, '\0', sizeof(struct class_ro64_t));
+ if (left < sizeof(struct class_ro64_t)) {
+ memcpy(&cro, r, left);
+ outs() << " (class_ro_t entends past the end of the section)\n";
+ } else
+ memcpy(&cro, r, sizeof(struct class_ro64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(cro);
+ outs() << " flags " << format("0x%" PRIx32, cro.flags);
+ if (cro.flags & RO_META)
+ outs() << " RO_META";
+ if (cro.flags & RO_ROOT)
+ outs() << " RO_ROOT";
+ if (cro.flags & RO_HAS_CXX_STRUCTORS)
+ outs() << " RO_HAS_CXX_STRUCTORS";
+ outs() << "\n";
+ outs() << " instanceStart " << cro.instanceStart << "\n";
+ outs() << " instanceSize " << cro.instanceSize << "\n";
+ outs() << " reserved " << format("0x%" PRIx32, cro.reserved)
+ << "\n";
+ outs() << " ivarLayout " << format("0x%" PRIx64, cro.ivarLayout)
+ << "\n";
+ print_layout_map64(cro.ivarLayout, info);
+
+ outs() << " name ";
+ sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, name), S,
+ info, n_value, cro.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.name != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.name);
+ } else
+ outs() << format("0x%" PRIx64, cro.name);
+ name = get_pointer_64(cro.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << " baseMethods ";
+ sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, baseMethods),
+ S, info, n_value, cro.baseMethods);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.baseMethods != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.baseMethods);
+ } else
+ outs() << format("0x%" PRIx64, cro.baseMethods);
+ outs() << " (struct method_list_t *)\n";
+ if (cro.baseMethods + n_value != 0)
+ print_method_list64_t(cro.baseMethods + n_value, info, "");
+
+ outs() << " baseProtocols ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct class_ro64_t, baseProtocols), S,
+ info, n_value, cro.baseProtocols);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.baseProtocols != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.baseProtocols);
+ } else
+ outs() << format("0x%" PRIx64, cro.baseProtocols);
+ outs() << "\n";
+ if (cro.baseProtocols + n_value != 0)
+ print_protocol_list64_t(cro.baseProtocols + n_value, info);
+
+ outs() << " ivars ";
+ sym_name = get_symbol_64(offset + offsetof(struct class_ro64_t, ivars), S,
+ info, n_value, cro.ivars);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.ivars != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.ivars);
+ } else
+ outs() << format("0x%" PRIx64, cro.ivars);
+ outs() << "\n";
+ if (cro.ivars + n_value != 0)
+ print_ivar_list64_t(cro.ivars + n_value, info);
+
+ outs() << " weakIvarLayout ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct class_ro64_t, weakIvarLayout), S,
+ info, n_value, cro.weakIvarLayout);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.weakIvarLayout != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.weakIvarLayout);
+ } else
+ outs() << format("0x%" PRIx64, cro.weakIvarLayout);
+ outs() << "\n";
+ print_layout_map64(cro.weakIvarLayout + n_value, info);
+
+ outs() << " baseProperties ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct class_ro64_t, baseProperties), S,
+ info, n_value, cro.baseProperties);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (cro.baseProperties != 0)
+ outs() << " + " << format("0x%" PRIx64, cro.baseProperties);
+ } else
+ outs() << format("0x%" PRIx64, cro.baseProperties);
+ outs() << "\n";
+ if (cro.baseProperties + n_value != 0)
+ print_objc_property_list64(cro.baseProperties + n_value, info);
+
+ is_meta_class = (cro.flags & RO_META) ? true : false;
+}
+
+static void print_class_ro32_t(uint32_t p, struct DisassembleInfo *info,
+ bool &is_meta_class) {
+ struct class_ro32_t cro;
+ const char *r;
+ uint32_t offset, xoffset, left;
+ SectionRef S, xS;
+ const char *name;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&cro, '\0', sizeof(struct class_ro32_t));
+ if (left < sizeof(struct class_ro32_t)) {
+ memcpy(&cro, r, left);
+ outs() << " (class_ro_t entends past the end of the section)\n";
+ } else
+ memcpy(&cro, r, sizeof(struct class_ro32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(cro);
+ outs() << " flags " << format("0x%" PRIx32, cro.flags);
+ if (cro.flags & RO_META)
+ outs() << " RO_META";
+ if (cro.flags & RO_ROOT)
+ outs() << " RO_ROOT";
+ if (cro.flags & RO_HAS_CXX_STRUCTORS)
+ outs() << " RO_HAS_CXX_STRUCTORS";
+ outs() << "\n";
+ outs() << " instanceStart " << cro.instanceStart << "\n";
+ outs() << " instanceSize " << cro.instanceSize << "\n";
+ outs() << " ivarLayout " << format("0x%" PRIx32, cro.ivarLayout)
+ << "\n";
+ print_layout_map32(cro.ivarLayout, info);
+
+ outs() << " name " << format("0x%" PRIx32, cro.name);
+ name = get_pointer_32(cro.name, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << " baseMethods "
+ << format("0x%" PRIx32, cro.baseMethods)
+ << " (struct method_list_t *)\n";
+ if (cro.baseMethods != 0)
+ print_method_list32_t(cro.baseMethods, info, "");
+
+ outs() << " baseProtocols "
+ << format("0x%" PRIx32, cro.baseProtocols) << "\n";
+ if (cro.baseProtocols != 0)
+ print_protocol_list32_t(cro.baseProtocols, info);
+ outs() << " ivars " << format("0x%" PRIx32, cro.ivars)
+ << "\n";
+ if (cro.ivars != 0)
+ print_ivar_list32_t(cro.ivars, info);
+ outs() << " weakIvarLayout "
+ << format("0x%" PRIx32, cro.weakIvarLayout) << "\n";
+ print_layout_map32(cro.weakIvarLayout, info);
+ outs() << " baseProperties "
+ << format("0x%" PRIx32, cro.baseProperties) << "\n";
+ if (cro.baseProperties != 0)
+ print_objc_property_list32(cro.baseProperties, info);
+ is_meta_class = (cro.flags & RO_META) ? true : false;
+}
+
+static void print_class64_t(uint64_t p, struct DisassembleInfo *info) {
+ struct class64_t c;
+ const char *r;
+ uint32_t offset, left;
+ SectionRef S;
+ const char *name;
+ uint64_t isa_n_value, n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr || left < sizeof(struct class64_t))
+ return;
+ memset(&c, '\0', sizeof(struct class64_t));
+ if (left < sizeof(struct class64_t)) {
+ memcpy(&c, r, left);
+ outs() << " (class_t entends past the end of the section)\n";
+ } else
+ memcpy(&c, r, sizeof(struct class64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(c);
+
+ outs() << " isa " << format("0x%" PRIx64, c.isa);
+ name = get_symbol_64(offset + offsetof(struct class64_t, isa), S, info,
+ isa_n_value, c.isa);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " superclass " << format("0x%" PRIx64, c.superclass);
+ name = get_symbol_64(offset + offsetof(struct class64_t, superclass), S, info,
+ n_value, c.superclass);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " cache " << format("0x%" PRIx64, c.cache);
+ name = get_symbol_64(offset + offsetof(struct class64_t, cache), S, info,
+ n_value, c.cache);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " vtable " << format("0x%" PRIx64, c.vtable);
+ name = get_symbol_64(offset + offsetof(struct class64_t, vtable), S, info,
+ n_value, c.vtable);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ name = get_symbol_64(offset + offsetof(struct class64_t, data), S, info,
+ n_value, c.data);
+ outs() << " data ";
+ if (n_value != 0) {
+ if (info->verbose && name != nullptr)
+ outs() << name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.data != 0)
+ outs() << " + " << format("0x%" PRIx64, c.data);
+ } else
+ outs() << format("0x%" PRIx64, c.data);
+ outs() << " (struct class_ro_t *)";
+
+ // This is a Swift class if some of the low bits of the pointer are set.
+ if ((c.data + n_value) & 0x7)
+ outs() << " Swift class";
+ outs() << "\n";
+ bool is_meta_class;
+ print_class_ro64_t((c.data + n_value) & ~0x7, info, is_meta_class);
+
+ if (is_meta_class == false) {
+ outs() << "Meta Class\n";
+ print_class64_t(c.isa + isa_n_value, info);
+ }
+}
+
+static void print_class32_t(uint32_t p, struct DisassembleInfo *info) {
+ struct class32_t c;
+ const char *r;
+ uint32_t offset, left;
+ SectionRef S;
+ const char *name;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&c, '\0', sizeof(struct class32_t));
+ if (left < sizeof(struct class32_t)) {
+ memcpy(&c, r, left);
+ outs() << " (class_t entends past the end of the section)\n";
+ } else
+ memcpy(&c, r, sizeof(struct class32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(c);
+
+ outs() << " isa " << format("0x%" PRIx32, c.isa);
+ name =
+ get_symbol_32(offset + offsetof(struct class32_t, isa), S, info, c.isa);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " superclass " << format("0x%" PRIx32, c.superclass);
+ name = get_symbol_32(offset + offsetof(struct class32_t, superclass), S, info,
+ c.superclass);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " cache " << format("0x%" PRIx32, c.cache);
+ name = get_symbol_32(offset + offsetof(struct class32_t, cache), S, info,
+ c.cache);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " vtable " << format("0x%" PRIx32, c.vtable);
+ name = get_symbol_32(offset + offsetof(struct class32_t, vtable), S, info,
+ c.vtable);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ name =
+ get_symbol_32(offset + offsetof(struct class32_t, data), S, info, c.data);
+ outs() << " data " << format("0x%" PRIx32, c.data)
+ << " (struct class_ro_t *)";
+
+ // This is a Swift class if some of the low bits of the pointer are set.
+ if (c.data & 0x3)
+ outs() << " Swift class";
+ outs() << "\n";
+ bool is_meta_class;
+ print_class_ro32_t(c.data & ~0x3, info, is_meta_class);
+
+ if (is_meta_class == false) {
+ outs() << "Meta Class\n";
+ print_class32_t(c.isa, info);
+ }
+}
+
+static void print_objc_class_t(struct objc_class_t *objc_class,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left, xleft;
+ const char *name, *p, *ivar_list;
+ SectionRef S;
+ int32_t i;
+ struct objc_ivar_list_t objc_ivar_list;
+ struct objc_ivar_t ivar;
+
+ outs() << "\t\t isa " << format("0x%08" PRIx32, objc_class->isa);
+ if (info->verbose && CLS_GETINFO(objc_class, CLS_META)) {
+ name = get_pointer_32(objc_class->isa, offset, left, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t super_class "
+ << format("0x%08" PRIx32, objc_class->super_class);
+ if (info->verbose) {
+ name = get_pointer_32(objc_class->super_class, offset, left, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t name " << format("0x%08" PRIx32, objc_class->name);
+ if (info->verbose) {
+ name = get_pointer_32(objc_class->name, offset, left, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t version " << format("0x%08" PRIx32, objc_class->version)
+ << "\n";
+
+ outs() << "\t\t info " << format("0x%08" PRIx32, objc_class->info);
+ if (info->verbose) {
+ if (CLS_GETINFO(objc_class, CLS_CLASS))
+ outs() << " CLS_CLASS";
+ else if (CLS_GETINFO(objc_class, CLS_META))
+ outs() << " CLS_META";
+ }
+ outs() << "\n";
+
+ outs() << "\t instance_size "
+ << format("0x%08" PRIx32, objc_class->instance_size) << "\n";
+
+ p = get_pointer_32(objc_class->ivars, offset, left, S, info, true);
+ outs() << "\t\t ivars " << format("0x%08" PRIx32, objc_class->ivars);
+ if (p != nullptr) {
+ if (left > sizeof(struct objc_ivar_list_t)) {
+ outs() << "\n";
+ memcpy(&objc_ivar_list, p, sizeof(struct objc_ivar_list_t));
+ } else {
+ outs() << " (entends past the end of the section)\n";
+ memset(&objc_ivar_list, '\0', sizeof(struct objc_ivar_list_t));
+ memcpy(&objc_ivar_list, p, left);
+ }
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(objc_ivar_list);
+ outs() << "\t\t ivar_count " << objc_ivar_list.ivar_count << "\n";
+ ivar_list = p + sizeof(struct objc_ivar_list_t);
+ for (i = 0; i < objc_ivar_list.ivar_count; i++) {
+ if ((i + 1) * sizeof(struct objc_ivar_t) > left) {
+ outs() << "\t\t remaining ivar's extend past the of the section\n";
+ break;
+ }
+ memcpy(&ivar, ivar_list + i * sizeof(struct objc_ivar_t),
+ sizeof(struct objc_ivar_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(ivar);
+
+ outs() << "\t\t\tivar_name " << format("0x%08" PRIx32, ivar.ivar_name);
+ if (info->verbose) {
+ name = get_pointer_32(ivar.ivar_name, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t\tivar_type " << format("0x%08" PRIx32, ivar.ivar_type);
+ if (info->verbose) {
+ name = get_pointer_32(ivar.ivar_type, offset, xleft, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", xleft, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t ivar_offset "
+ << format("0x%08" PRIx32, ivar.ivar_offset) << "\n";
+ }
+ } else {
+ outs() << " (not in an __OBJC section)\n";
+ }
+
+ outs() << "\t\t methods " << format("0x%08" PRIx32, objc_class->methodLists);
+ if (print_method_list(objc_class->methodLists, info))
+ outs() << " (not in an __OBJC section)\n";
+
+ outs() << "\t\t cache " << format("0x%08" PRIx32, objc_class->cache)
+ << "\n";
+
+ outs() << "\t\tprotocols " << format("0x%08" PRIx32, objc_class->protocols);
+ if (print_protocol_list(objc_class->protocols, 16, info))
+ outs() << " (not in an __OBJC section)\n";
+}
+
+static void print_objc_objc_category_t(struct objc_category_t *objc_category,
+ struct DisassembleInfo *info) {
+ uint32_t offset, left;
+ const char *name;
+ SectionRef S;
+
+ outs() << "\t category name "
+ << format("0x%08" PRIx32, objc_category->category_name);
+ if (info->verbose) {
+ name = get_pointer_32(objc_category->category_name, offset, left, S, info,
+ true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t\t class name "
+ << format("0x%08" PRIx32, objc_category->class_name);
+ if (info->verbose) {
+ name =
+ get_pointer_32(objc_category->class_name, offset, left, S, info, true);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ else
+ outs() << " (not in an __OBJC section)";
+ }
+ outs() << "\n";
+
+ outs() << "\t instance methods "
+ << format("0x%08" PRIx32, objc_category->instance_methods);
+ if (print_method_list(objc_category->instance_methods, info))
+ outs() << " (not in an __OBJC section)\n";
+
+ outs() << "\t class methods "
+ << format("0x%08" PRIx32, objc_category->class_methods);
+ if (print_method_list(objc_category->class_methods, info))
+ outs() << " (not in an __OBJC section)\n";
+}
+
+static void print_category64_t(uint64_t p, struct DisassembleInfo *info) {
+ struct category64_t c;
+ const char *r;
+ uint32_t offset, xoffset, left;
+ SectionRef S, xS;
+ const char *name, *sym_name;
+ uint64_t n_value;
+
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&c, '\0', sizeof(struct category64_t));
+ if (left < sizeof(struct category64_t)) {
+ memcpy(&c, r, left);
+ outs() << " (category_t entends past the end of the section)\n";
+ } else
+ memcpy(&c, r, sizeof(struct category64_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(c);
+
+ outs() << " name ";
+ sym_name = get_symbol_64(offset + offsetof(struct category64_t, name), S,
+ info, n_value, c.name);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.name != 0)
+ outs() << " + " << format("0x%" PRIx64, c.name);
+ } else
+ outs() << format("0x%" PRIx64, c.name);
+ name = get_pointer_64(c.name + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << " cls ";
+ sym_name = get_symbol_64(offset + offsetof(struct category64_t, cls), S, info,
+ n_value, c.cls);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.cls != 0)
+ outs() << " + " << format("0x%" PRIx64, c.cls);
+ } else
+ outs() << format("0x%" PRIx64, c.cls);
+ outs() << "\n";
+ if (c.cls + n_value != 0)
+ print_class64_t(c.cls + n_value, info);
+
+ outs() << " instanceMethods ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct category64_t, instanceMethods), S,
+ info, n_value, c.instanceMethods);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.instanceMethods != 0)
+ outs() << " + " << format("0x%" PRIx64, c.instanceMethods);
+ } else
+ outs() << format("0x%" PRIx64, c.instanceMethods);
+ outs() << "\n";
+ if (c.instanceMethods + n_value != 0)
+ print_method_list64_t(c.instanceMethods + n_value, info, "");
+
+ outs() << " classMethods ";
+ sym_name = get_symbol_64(offset + offsetof(struct category64_t, classMethods),
+ S, info, n_value, c.classMethods);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.classMethods != 0)
+ outs() << " + " << format("0x%" PRIx64, c.classMethods);
+ } else
+ outs() << format("0x%" PRIx64, c.classMethods);
+ outs() << "\n";
+ if (c.classMethods + n_value != 0)
+ print_method_list64_t(c.classMethods + n_value, info, "");
+
+ outs() << " protocols ";
+ sym_name = get_symbol_64(offset + offsetof(struct category64_t, protocols), S,
+ info, n_value, c.protocols);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.protocols != 0)
+ outs() << " + " << format("0x%" PRIx64, c.protocols);
+ } else
+ outs() << format("0x%" PRIx64, c.protocols);
+ outs() << "\n";
+ if (c.protocols + n_value != 0)
+ print_protocol_list64_t(c.protocols + n_value, info);
+
+ outs() << "instanceProperties ";
+ sym_name =
+ get_symbol_64(offset + offsetof(struct category64_t, instanceProperties),
+ S, info, n_value, c.instanceProperties);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (c.instanceProperties != 0)
+ outs() << " + " << format("0x%" PRIx64, c.instanceProperties);
+ } else
+ outs() << format("0x%" PRIx64, c.instanceProperties);
+ outs() << "\n";
+ if (c.instanceProperties + n_value != 0)
+ print_objc_property_list64(c.instanceProperties + n_value, info);
+}
+
+static void print_category32_t(uint32_t p, struct DisassembleInfo *info) {
+ struct category32_t c;
+ const char *r;
+ uint32_t offset, left;
+ SectionRef S, xS;
+ const char *name;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&c, '\0', sizeof(struct category32_t));
+ if (left < sizeof(struct category32_t)) {
+ memcpy(&c, r, left);
+ outs() << " (category_t entends past the end of the section)\n";
+ } else
+ memcpy(&c, r, sizeof(struct category32_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(c);
+
+ outs() << " name " << format("0x%" PRIx32, c.name);
+ name = get_symbol_32(offset + offsetof(struct category32_t, name), S, info,
+ c.name);
+ if (name != NULL)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " cls " << format("0x%" PRIx32, c.cls) << "\n";
+ if (c.cls != 0)
+ print_class32_t(c.cls, info);
+ outs() << " instanceMethods " << format("0x%" PRIx32, c.instanceMethods)
+ << "\n";
+ if (c.instanceMethods != 0)
+ print_method_list32_t(c.instanceMethods, info, "");
+ outs() << " classMethods " << format("0x%" PRIx32, c.classMethods)
+ << "\n";
+ if (c.classMethods != 0)
+ print_method_list32_t(c.classMethods, info, "");
+ outs() << " protocols " << format("0x%" PRIx32, c.protocols) << "\n";
+ if (c.protocols != 0)
+ print_protocol_list32_t(c.protocols, info);
+ outs() << "instanceProperties " << format("0x%" PRIx32, c.instanceProperties)
+ << "\n";
+ if (c.instanceProperties != 0)
+ print_objc_property_list32(c.instanceProperties, info);
+}
+
+static void print_message_refs64(SectionRef S, struct DisassembleInfo *info) {
+ uint32_t i, left, offset, xoffset;
+ uint64_t p, n_value;
+ struct message_ref64 mr;
+ const char *name, *sym_name;
+ const char *r;
+ SectionRef xS;
+
+ if (S == SectionRef())
+ return;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ offset = 0;
+ for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
+ p = S.getAddress() + i;
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&mr, '\0', sizeof(struct message_ref64));
+ if (left < sizeof(struct message_ref64)) {
+ memcpy(&mr, r, left);
+ outs() << " (message_ref entends past the end of the section)\n";
+ } else
+ memcpy(&mr, r, sizeof(struct message_ref64));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(mr);
+
+ outs() << " imp ";
+ name = get_symbol_64(offset + offsetof(struct message_ref64, imp), S, info,
+ n_value, mr.imp);
+ if (n_value != 0) {
+ outs() << format("0x%" PRIx64, n_value) << " ";
+ if (mr.imp != 0)
+ outs() << "+ " << format("0x%" PRIx64, mr.imp) << " ";
+ } else
+ outs() << format("0x%" PRIx64, mr.imp) << " ";
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " sel ";
+ sym_name = get_symbol_64(offset + offsetof(struct message_ref64, sel), S,
+ info, n_value, mr.sel);
+ if (n_value != 0) {
+ if (info->verbose && sym_name != nullptr)
+ outs() << sym_name;
+ else
+ outs() << format("0x%" PRIx64, n_value);
+ if (mr.sel != 0)
+ outs() << " + " << format("0x%" PRIx64, mr.sel);
+ } else
+ outs() << format("0x%" PRIx64, mr.sel);
+ name = get_pointer_64(mr.sel + n_value, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ offset += sizeof(struct message_ref64);
+ }
+}
+
+static void print_message_refs32(SectionRef S, struct DisassembleInfo *info) {
+ uint32_t i, left, offset, xoffset, p;
+ struct message_ref32 mr;
+ const char *name, *r;
+ SectionRef xS;
+
+ if (S == SectionRef())
+ return;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ offset = 0;
+ for (i = 0; i < S.getSize(); i += sizeof(struct message_ref64)) {
+ p = S.getAddress() + i;
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&mr, '\0', sizeof(struct message_ref32));
+ if (left < sizeof(struct message_ref32)) {
+ memcpy(&mr, r, left);
+ outs() << " (message_ref entends past the end of the section)\n";
+ } else
+ memcpy(&mr, r, sizeof(struct message_ref32));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(mr);
+
+ outs() << " imp " << format("0x%" PRIx32, mr.imp);
+ name = get_symbol_32(offset + offsetof(struct message_ref32, imp), S, info,
+ mr.imp);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ outs() << " sel " << format("0x%" PRIx32, mr.sel);
+ name = get_pointer_32(mr.sel, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ offset += sizeof(struct message_ref32);
+ }
+}
+
+static void print_image_info64(SectionRef S, struct DisassembleInfo *info) {
+ uint32_t left, offset, swift_version;
+ uint64_t p;
+ struct objc_image_info64 o;
+ const char *r;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ p = S.getAddress();
+ r = get_pointer_64(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&o, '\0', sizeof(struct objc_image_info64));
+ if (left < sizeof(struct objc_image_info64)) {
+ memcpy(&o, r, left);
+ outs() << " (objc_image_info entends past the end of the section)\n";
+ } else
+ memcpy(&o, r, sizeof(struct objc_image_info64));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(o);
+ outs() << " version " << o.version << "\n";
+ outs() << " flags " << format("0x%" PRIx32, o.flags);
+ if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
+ outs() << " OBJC_IMAGE_IS_REPLACEMENT";
+ if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
+ outs() << " OBJC_IMAGE_SUPPORTS_GC";
+ swift_version = (o.flags >> 8) & 0xff;
+ if (swift_version != 0) {
+ if (swift_version == 1)
+ outs() << " Swift 1.0";
+ else if (swift_version == 2)
+ outs() << " Swift 1.1";
+ else
+ outs() << " unknown future Swift version (" << swift_version << ")";
+ }
+ outs() << "\n";
+}
+
+static void print_image_info32(SectionRef S, struct DisassembleInfo *info) {
+ uint32_t left, offset, swift_version, p;
+ struct objc_image_info32 o;
+ const char *r;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ p = S.getAddress();
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&o, '\0', sizeof(struct objc_image_info32));
+ if (left < sizeof(struct objc_image_info32)) {
+ memcpy(&o, r, left);
+ outs() << " (objc_image_info entends past the end of the section)\n";
+ } else
+ memcpy(&o, r, sizeof(struct objc_image_info32));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(o);
+ outs() << " version " << o.version << "\n";
+ outs() << " flags " << format("0x%" PRIx32, o.flags);
+ if (o.flags & OBJC_IMAGE_IS_REPLACEMENT)
+ outs() << " OBJC_IMAGE_IS_REPLACEMENT";
+ if (o.flags & OBJC_IMAGE_SUPPORTS_GC)
+ outs() << " OBJC_IMAGE_SUPPORTS_GC";
+ swift_version = (o.flags >> 8) & 0xff;
+ if (swift_version != 0) {
+ if (swift_version == 1)
+ outs() << " Swift 1.0";
+ else if (swift_version == 2)
+ outs() << " Swift 1.1";
+ else
+ outs() << " unknown future Swift version (" << swift_version << ")";
+ }
+ outs() << "\n";
+}
+
+static void print_image_info(SectionRef S, struct DisassembleInfo *info) {
+ uint32_t left, offset, p;
+ struct imageInfo_t o;
+ const char *r;
+
+ StringRef SectName;
+ S.getName(SectName);
+ DataRefImpl Ref = S.getRawDataRefImpl();
+ StringRef SegName = info->O->getSectionFinalSegmentName(Ref);
+ outs() << "Contents of (" << SegName << "," << SectName << ") section\n";
+ p = S.getAddress();
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return;
+ memset(&o, '\0', sizeof(struct imageInfo_t));
+ if (left < sizeof(struct imageInfo_t)) {
+ memcpy(&o, r, left);
+ outs() << " (imageInfo entends past the end of the section)\n";
+ } else
+ memcpy(&o, r, sizeof(struct imageInfo_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(o);
+ outs() << " version " << o.version << "\n";
+ outs() << " flags " << format("0x%" PRIx32, o.flags);
+ if (o.flags & 0x1)
+ outs() << " F&C";
+ if (o.flags & 0x2)
+ outs() << " GC";
+ if (o.flags & 0x4)
+ outs() << " GC-only";
+ else
+ outs() << " RR";
+ outs() << "\n";
+}
+
+static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) {
+ SymbolAddressMap AddrMap;
+ if (verbose)
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ std::vector<SectionRef> Sections;
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ Sections.push_back(Section);
+ }
+
+ struct DisassembleInfo info;
+ // Set up the block of info used by the Symbolizer call backs.
+ info.verbose = verbose;
+ info.O = O;
+ info.AddrMap = &AddrMap;
+ info.Sections = &Sections;
+ info.class_name = nullptr;
+ info.selector_name = nullptr;
+ info.method = nullptr;
+ info.demangled_name = nullptr;
+ info.bindtable = nullptr;
+ info.adrp_addr = 0;
+ info.adrp_inst = 0;
+
+ const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
+ if (CL != SectionRef()) {
+ info.S = CL;
+ walk_pointer_list_64("class", CL, O, &info, print_class64_t);
+ } else {
+ const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
+ info.S = CL;
+ walk_pointer_list_64("class", CL, O, &info, print_class64_t);
+ }
+
+ const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
+ if (CR != SectionRef()) {
+ info.S = CR;
+ walk_pointer_list_64("class refs", CR, O, &info, nullptr);
+ } else {
+ const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
+ info.S = CR;
+ walk_pointer_list_64("class refs", CR, O, &info, nullptr);
+ }
+
+ const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
+ if (SR != SectionRef()) {
+ info.S = SR;
+ walk_pointer_list_64("super refs", SR, O, &info, nullptr);
+ } else {
+ const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
+ info.S = SR;
+ walk_pointer_list_64("super refs", SR, O, &info, nullptr);
+ }
+
+ const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
+ if (CA != SectionRef()) {
+ info.S = CA;
+ walk_pointer_list_64("category", CA, O, &info, print_category64_t);
+ } else {
+ const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
+ info.S = CA;
+ walk_pointer_list_64("category", CA, O, &info, print_category64_t);
+ }
+
+ const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
+ if (PL != SectionRef()) {
+ info.S = PL;
+ walk_pointer_list_64("protocol", PL, O, &info, nullptr);
+ } else {
+ const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
+ info.S = PL;
+ walk_pointer_list_64("protocol", PL, O, &info, nullptr);
+ }
+
+ const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
+ if (MR != SectionRef()) {
+ info.S = MR;
+ print_message_refs64(MR, &info);
+ } else {
+ const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
+ info.S = MR;
+ print_message_refs64(MR, &info);
+ }
+
+ const SectionRef II = get_section(O, "__OBJC2", "__image_info");
+ if (II != SectionRef()) {
+ info.S = II;
+ print_image_info64(II, &info);
+ } else {
+ const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
+ info.S = II;
+ print_image_info64(II, &info);
+ }
+
+ if (info.bindtable != nullptr)
+ delete info.bindtable;
+}
+
+static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) {
+ SymbolAddressMap AddrMap;
+ if (verbose)
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ std::vector<SectionRef> Sections;
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ Sections.push_back(Section);
+ }
+
+ struct DisassembleInfo info;
+ // Set up the block of info used by the Symbolizer call backs.
+ info.verbose = verbose;
+ info.O = O;
+ info.AddrMap = &AddrMap;
+ info.Sections = &Sections;
+ info.class_name = nullptr;
+ info.selector_name = nullptr;
+ info.method = nullptr;
+ info.demangled_name = nullptr;
+ info.bindtable = nullptr;
+ info.adrp_addr = 0;
+ info.adrp_inst = 0;
+
+ const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
+ if (CL != SectionRef()) {
+ info.S = CL;
+ walk_pointer_list_32("class", CL, O, &info, print_class32_t);
+ } else {
+ const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
+ info.S = CL;
+ walk_pointer_list_32("class", CL, O, &info, print_class32_t);
+ }
+
+ const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
+ if (CR != SectionRef()) {
+ info.S = CR;
+ walk_pointer_list_32("class refs", CR, O, &info, nullptr);
+ } else {
+ const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
+ info.S = CR;
+ walk_pointer_list_32("class refs", CR, O, &info, nullptr);
+ }
+
+ const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
+ if (SR != SectionRef()) {
+ info.S = SR;
+ walk_pointer_list_32("super refs", SR, O, &info, nullptr);
+ } else {
+ const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
+ info.S = SR;
+ walk_pointer_list_32("super refs", SR, O, &info, nullptr);
+ }
+
+ const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
+ if (CA != SectionRef()) {
+ info.S = CA;
+ walk_pointer_list_32("category", CA, O, &info, print_category32_t);
+ } else {
+ const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
+ info.S = CA;
+ walk_pointer_list_32("category", CA, O, &info, print_category32_t);
+ }
+
+ const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
+ if (PL != SectionRef()) {
+ info.S = PL;
+ walk_pointer_list_32("protocol", PL, O, &info, nullptr);
+ } else {
+ const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
+ info.S = PL;
+ walk_pointer_list_32("protocol", PL, O, &info, nullptr);
+ }
+
+ const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
+ if (MR != SectionRef()) {
+ info.S = MR;
+ print_message_refs32(MR, &info);
+ } else {
+ const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
+ info.S = MR;
+ print_message_refs32(MR, &info);
+ }
+
+ const SectionRef II = get_section(O, "__OBJC2", "__image_info");
+ if (II != SectionRef()) {
+ info.S = II;
+ print_image_info32(II, &info);
+ } else {
+ const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
+ info.S = II;
+ print_image_info32(II, &info);
+ }
+}
+
+static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) {
+ uint32_t i, j, p, offset, xoffset, left, defs_left, def;
+ const char *r, *name, *defs;
+ struct objc_module_t module;
+ SectionRef S, xS;
+ struct objc_symtab_t symtab;
+ struct objc_class_t objc_class;
+ struct objc_category_t objc_category;
+
+ outs() << "Objective-C segment\n";
+ S = get_section(O, "__OBJC", "__module_info");
+ if (S == SectionRef())
+ return false;
+
+ SymbolAddressMap AddrMap;
+ if (verbose)
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ std::vector<SectionRef> Sections;
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ Sections.push_back(Section);
+ }
+
+ struct DisassembleInfo info;
+ // Set up the block of info used by the Symbolizer call backs.
+ info.verbose = verbose;
+ info.O = O;
+ info.AddrMap = &AddrMap;
+ info.Sections = &Sections;
+ info.class_name = nullptr;
+ info.selector_name = nullptr;
+ info.method = nullptr;
+ info.demangled_name = nullptr;
+ info.bindtable = nullptr;
+ info.adrp_addr = 0;
+ info.adrp_inst = 0;
+
+ for (i = 0; i < S.getSize(); i += sizeof(struct objc_module_t)) {
+ p = S.getAddress() + i;
+ r = get_pointer_32(p, offset, left, S, &info, true);
+ if (r == nullptr)
+ return true;
+ memset(&module, '\0', sizeof(struct objc_module_t));
+ if (left < sizeof(struct objc_module_t)) {
+ memcpy(&module, r, left);
+ outs() << " (module extends past end of __module_info section)\n";
+ } else
+ memcpy(&module, r, sizeof(struct objc_module_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(module);
+
+ outs() << "Module " << format("0x%" PRIx32, p) << "\n";
+ outs() << " version " << module.version << "\n";
+ outs() << " size " << module.size << "\n";
+ outs() << " name ";
+ name = get_pointer_32(module.name, xoffset, left, xS, &info, true);
+ if (name != nullptr)
+ outs() << format("%.*s", left, name);
+ else
+ outs() << format("0x%08" PRIx32, module.name)
+ << "(not in an __OBJC section)";
+ outs() << "\n";
+
+ r = get_pointer_32(module.symtab, xoffset, left, xS, &info, true);
+ if (module.symtab == 0 || r == nullptr) {
+ outs() << " symtab " << format("0x%08" PRIx32, module.symtab)
+ << " (not in an __OBJC section)\n";
+ continue;
+ }
+ outs() << " symtab " << format("0x%08" PRIx32, module.symtab) << "\n";
+ memset(&symtab, '\0', sizeof(struct objc_symtab_t));
+ defs_left = 0;
+ defs = nullptr;
+ if (left < sizeof(struct objc_symtab_t)) {
+ memcpy(&symtab, r, left);
+ outs() << "\tsymtab extends past end of an __OBJC section)\n";
+ } else {
+ memcpy(&symtab, r, sizeof(struct objc_symtab_t));
+ if (left > sizeof(struct objc_symtab_t)) {
+ defs_left = left - sizeof(struct objc_symtab_t);
+ defs = r + sizeof(struct objc_symtab_t);
+ }
+ }
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(symtab);
+
+ outs() << "\tsel_ref_cnt " << symtab.sel_ref_cnt << "\n";
+ r = get_pointer_32(symtab.refs, xoffset, left, xS, &info, true);
+ outs() << "\trefs " << format("0x%08" PRIx32, symtab.refs);
+ if (r == nullptr)
+ outs() << " (not in an __OBJC section)";
+ outs() << "\n";
+ outs() << "\tcls_def_cnt " << symtab.cls_def_cnt << "\n";
+ outs() << "\tcat_def_cnt " << symtab.cat_def_cnt << "\n";
+ if (symtab.cls_def_cnt > 0)
+ outs() << "\tClass Definitions\n";
+ for (j = 0; j < symtab.cls_def_cnt; j++) {
+ if ((j + 1) * sizeof(uint32_t) > defs_left) {
+ outs() << "\t(remaining class defs entries entends past the end of the "
+ << "section)\n";
+ break;
+ }
+ memcpy(&def, defs + j * sizeof(uint32_t), sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(def);
+
+ r = get_pointer_32(def, xoffset, left, xS, &info, true);
+ outs() << "\tdefs[" << j << "] " << format("0x%08" PRIx32, def);
+ if (r != nullptr) {
+ if (left > sizeof(struct objc_class_t)) {
+ outs() << "\n";
+ memcpy(&objc_class, r, sizeof(struct objc_class_t));
+ } else {
+ outs() << " (entends past the end of the section)\n";
+ memset(&objc_class, '\0', sizeof(struct objc_class_t));
+ memcpy(&objc_class, r, left);
+ }
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(objc_class);
+ print_objc_class_t(&objc_class, &info);
+ } else {
+ outs() << "(not in an __OBJC section)\n";
+ }
+
+ if (CLS_GETINFO(&objc_class, CLS_CLASS)) {
+ outs() << "\tMeta Class";
+ r = get_pointer_32(objc_class.isa, xoffset, left, xS, &info, true);
+ if (r != nullptr) {
+ if (left > sizeof(struct objc_class_t)) {
+ outs() << "\n";
+ memcpy(&objc_class, r, sizeof(struct objc_class_t));
+ } else {
+ outs() << " (entends past the end of the section)\n";
+ memset(&objc_class, '\0', sizeof(struct objc_class_t));
+ memcpy(&objc_class, r, left);
+ }
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(objc_class);
+ print_objc_class_t(&objc_class, &info);
+ } else {
+ outs() << "(not in an __OBJC section)\n";
+ }
+ }
+ }
+ if (symtab.cat_def_cnt > 0)
+ outs() << "\tCategory Definitions\n";
+ for (j = 0; j < symtab.cat_def_cnt; j++) {
+ if ((j + symtab.cls_def_cnt + 1) * sizeof(uint32_t) > defs_left) {
+ outs() << "\t(remaining category defs entries entends past the end of "
+ << "the section)\n";
+ break;
+ }
+ memcpy(&def, defs + (j + symtab.cls_def_cnt) * sizeof(uint32_t),
+ sizeof(uint32_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(def);
+
+ r = get_pointer_32(def, xoffset, left, xS, &info, true);
+ outs() << "\tdefs[" << j + symtab.cls_def_cnt << "] "
+ << format("0x%08" PRIx32, def);
+ if (r != nullptr) {
+ if (left > sizeof(struct objc_category_t)) {
+ outs() << "\n";
+ memcpy(&objc_category, r, sizeof(struct objc_category_t));
+ } else {
+ outs() << " (entends past the end of the section)\n";
+ memset(&objc_category, '\0', sizeof(struct objc_category_t));
+ memcpy(&objc_category, r, left);
+ }
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(objc_category);
+ print_objc_objc_category_t(&objc_category, &info);
+ } else {
+ outs() << "(not in an __OBJC section)\n";
+ }
+ }
+ }
+ const SectionRef II = get_section(O, "__OBJC", "__image_info");
+ if (II != SectionRef())
+ print_image_info(II, &info);
+
+ return true;
+}
+
+static void DumpProtocolSection(MachOObjectFile *O, const char *sect,
+ uint32_t size, uint32_t addr) {
+ SymbolAddressMap AddrMap;
+ CreateSymbolAddressMap(O, &AddrMap);
+
+ std::vector<SectionRef> Sections;
+ for (const SectionRef &Section : O->sections()) {
+ StringRef SectName;
+ Section.getName(SectName);
+ Sections.push_back(Section);
+ }
+
+ struct DisassembleInfo info;
+ // Set up the block of info used by the Symbolizer call backs.
+ info.verbose = true;
+ info.O = O;
+ info.AddrMap = &AddrMap;
+ info.Sections = &Sections;
+ info.class_name = nullptr;
+ info.selector_name = nullptr;
+ info.method = nullptr;
+ info.demangled_name = nullptr;
+ info.bindtable = nullptr;
+ info.adrp_addr = 0;
+ info.adrp_inst = 0;
+
+ const char *p;
+ struct objc_protocol_t protocol;
+ uint32_t left, paddr;
+ for (p = sect; p < sect + size; p += sizeof(struct objc_protocol_t)) {
+ memset(&protocol, '\0', sizeof(struct objc_protocol_t));
+ left = size - (p - sect);
+ if (left < sizeof(struct objc_protocol_t)) {
+ outs() << "Protocol extends past end of __protocol section\n";
+ memcpy(&protocol, p, left);
+ } else
+ memcpy(&protocol, p, sizeof(struct objc_protocol_t));
+ if (O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(protocol);
+ paddr = addr + (p - sect);
+ outs() << "Protocol " << format("0x%" PRIx32, paddr);
+ if (print_protocol(paddr, 0, &info))
+ outs() << "(not in an __OBJC section)\n";
+ }
+}
+
+static void printObjcMetaData(MachOObjectFile *O, bool verbose) {
+ if (O->is64Bit())
+ printObjc2_64bit_MetaData(O, verbose);
+ else {
+ MachO::mach_header H;
+ H = O->getHeader();
+ if (H.cputype == MachO::CPU_TYPE_ARM)
+ printObjc2_32bit_MetaData(O, verbose);
+ else {
+ // This is the 32-bit non-arm cputype case. Which is normally
+ // the first Objective-C ABI. But it may be the case of a
+ // binary for the iOS simulator which is the second Objective-C
+ // ABI. In that case printObjc1_32bit_MetaData() will determine that
+ // and return false.
+ if (printObjc1_32bit_MetaData(O, verbose) == false)
+ printObjc2_32bit_MetaData(O, verbose);
+ }
+ }
+}
+
// 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
@@ -1705,9 +5642,10 @@ uint64_t get_objc2_64bit_selref(uint64_t ReferenceValue,
//
// If there is no item in the Mach-O file for the address passed in as
// ReferenceValue nullptr is returned and ReferenceType is unchanged.
-const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
- uint64_t *ReferenceType,
- struct DisassembleInfo *info) {
+static const char *GuessLiteralPointer(uint64_t ReferenceValue,
+ uint64_t ReferencePC,
+ uint64_t *ReferenceType,
+ struct DisassembleInfo *info) {
// First see if there is an external relocation entry at the ReferencePC.
uint64_t sect_addr = info->S.getAddress();
uint64_t sect_offset = ReferencePC - sect_addr;
@@ -1749,7 +5687,7 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
bool classref, selref, msgref, cfstring;
uint64_t pointer_value = GuessPointerPointer(ReferenceValue, info, classref,
selref, msgref, cfstring);
- if (classref == true && pointer_value == 0) {
+ if (classref && pointer_value == 0) {
// Note the ReferenceValue is a pointer into the __objc_classrefs section.
// And the pointer_value in that section is typically zero as it will be
// set by dyld as part of the "bind information".
@@ -1765,7 +5703,7 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
}
}
- if (classref == true) {
+ if (classref) {
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref;
const char *name =
get_objc2_64bit_class_name(pointer_value, ReferenceValue, info);
@@ -1776,13 +5714,13 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
return name;
}
- if (cfstring == true) {
+ if (cfstring) {
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref;
const char *name = get_objc2_64bit_cfstring_name(ReferenceValue, info);
return name;
}
- if (selref == true && pointer_value == 0)
+ if (selref && pointer_value == 0)
pointer_value = get_objc2_64bit_selref(ReferenceValue, info);
if (pointer_value != 0)
@@ -1790,10 +5728,10 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
const char *name = GuessCstringPointer(ReferenceValue, info);
if (name) {
- if (pointer_value != 0 && selref == true) {
+ if (pointer_value != 0 && selref) {
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref;
info->selector_name = name;
- } else if (pointer_value != 0 && msgref == true) {
+ } else if (pointer_value != 0 && msgref) {
info->class_name = nullptr;
*ReferenceType = LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref;
info->selector_name = name;
@@ -1841,19 +5779,20 @@ const char *GuessLiteralPointer(uint64_t ReferenceValue, uint64_t ReferencePC,
// SymbolValue is checked to be an address of literal pointer, symbol pointer,
// or an Objective-C meta data reference. If so the output ReferenceType is
// set to correspond to that as well as setting the ReferenceName.
-const char *SymbolizerSymbolLookUp(void *DisInfo, uint64_t ReferenceValue,
- uint64_t *ReferenceType,
- uint64_t ReferencePC,
- const char **ReferenceName) {
+static const char *SymbolizerSymbolLookUp(void *DisInfo,
+ uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName) {
struct DisassembleInfo *info = (struct DisassembleInfo *)DisInfo;
// If no verbose symbolic information is wanted then just return nullptr.
- if (info->verbose == false) {
+ if (!info->verbose) {
*ReferenceName = nullptr;
*ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
return nullptr;
}
- const char *SymbolName = GuessSymbolName(ReferenceValue, info);
+ const char *SymbolName = GuessSymbolName(ReferenceValue, info->AddrMap);
if (*ReferenceType == LLVMDisassembler_ReferenceType_In_Branch) {
*ReferenceName = GuessIndirectSymbol(ReferenceValue, info);
@@ -2017,7 +5956,8 @@ static void emitComments(raw_svector_ostream &CommentStream,
CommentStream.resync();
}
-static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
+static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF,
+ StringRef DisSegName, StringRef DisSectName) {
const char *McpuDefault = nullptr;
const Target *ThumbTarget = nullptr;
const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget);
@@ -2059,12 +5999,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
if (RelInfo) {
Symbolizer.reset(TheTarget->createMCSymbolizer(
TripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
- &SymbolizerInfo, &Ctx, RelInfo.release()));
+ &SymbolizerInfo, &Ctx, std::move(RelInfo)));
DisAsm->setSymbolizer(std::move(Symbolizer));
}
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI, *STI));
+ Triple(TripleName), AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI));
// Set the display preference for hex vs. decimal immediates.
IP->setPrintImmHex(PrintImmHex);
// Comment stream and backing vector.
@@ -2107,13 +6047,13 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
if (ThumbRelInfo) {
ThumbSymbolizer.reset(ThumbTarget->createMCSymbolizer(
ThumbTripleName, SymbolizerGetOpInfo, SymbolizerSymbolLookUp,
- &ThumbSymbolizerInfo, PtrThumbCtx, ThumbRelInfo.release()));
+ &ThumbSymbolizerInfo, PtrThumbCtx, std::move(ThumbRelInfo)));
ThumbDisAsm->setSymbolizer(std::move(ThumbSymbolizer));
}
int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect();
ThumbIP.reset(ThumbTarget->createMCInstPrinter(
- ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo, *ThumbMRI,
- *ThumbSTI));
+ Triple(ThumbTripleName), ThumbAsmPrinterVariant, *ThumbAsmInfo,
+ *ThumbInstrInfo, *ThumbMRI));
// Set the display preference for hex vs. decimal immediates.
ThumbIP->setPrintImmHex(PrintImmHex);
}
@@ -2182,31 +6122,21 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
}
// Setup the DIContext
- diContext.reset(DIContext::getDWARFContext(*DbgObj));
+ diContext.reset(new DWARFContextInMemory(*DbgObj));
}
- // TODO: For now this only disassembles the (__TEXT,__text) section (see the
- // checks in the code below at the top of this loop). It should allow a
- // darwin otool(1) like -s option to disassemble any named segment & section
- // that is marked as containing instructions with the attributes
- // S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS in the flags field of
- // the section structure.
- outs() << "(__TEXT,__text) section\n";
+ if (DumpSections.size() == 0)
+ outs() << "(" << DisSegName << "," << DisSectName << ") section\n";
for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) {
-
- bool SectIsText = Sections[SectIdx].isText();
- if (SectIsText == false)
- continue;
-
StringRef SectName;
- if (Sections[SectIdx].getName(SectName) || SectName != "__text")
- continue; // Skip non-text sections
+ if (Sections[SectIdx].getName(SectName) || SectName != DisSectName)
+ continue;
DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl();
StringRef SegmentName = MachOOF->getSectionFinalSegmentName(DR);
- if (SegmentName != "__TEXT")
+ if (SegmentName != DisSegName)
continue;
StringRef BytesStr;
@@ -2234,6 +6164,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
// Create a map of symbol addresses to symbol names for use by
// the SymbolizerSymbolLookUp() routine.
SymbolAddressMap AddrMap;
+ bool DisSymNameFound = false;
for (const SymbolRef &Symbol : MachOOF->symbols()) {
SymbolRef::Type ST;
Symbol.getType(ST);
@@ -2244,10 +6175,16 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
StringRef SymName;
Symbol.getName(SymName);
AddrMap[Address] = SymName;
+ if (!DisSymName.empty() && DisSymName == SymName)
+ DisSymNameFound = true;
}
}
+ if (!DisSymName.empty() && !DisSymNameFound) {
+ outs() << "Can't find -dis-symname: " << DisSymName << "\n";
+ return;
+ }
// Set up the block of info used by the Symbolizer call backs.
- SymbolizerInfo.verbose = true;
+ SymbolizerInfo.verbose = !NoSymbolicOperands;
SymbolizerInfo.O = MachOOF;
SymbolizerInfo.S = Sections[SectIdx];
SymbolizerInfo.AddrMap = &AddrMap;
@@ -2260,7 +6197,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
SymbolizerInfo.adrp_addr = 0;
SymbolizerInfo.adrp_inst = 0;
// Same for the ThumbSymbolizer
- ThumbSymbolizerInfo.verbose = true;
+ ThumbSymbolizerInfo.verbose = !NoSymbolicOperands;
ThumbSymbolizerInfo.O = MachOOF;
ThumbSymbolizerInfo.S = Sections[SectIdx];
ThumbSymbolizerInfo.AddrMap = &AddrMap;
@@ -2288,6 +6225,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
if (!containsSym)
continue;
+ // If we are only disassembling one symbol see if this is that symbol.
+ if (!DisSymName.empty() && DisSymName != SymName)
+ continue;
+
// Start at the address of the symbol relative to the section's address.
uint64_t Start = 0;
uint64_t SectionAddress = Sections[SectIdx].getAddress();
@@ -2328,13 +6269,15 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
MCInst Inst;
uint64_t PC = SectAddress + Index;
- if (FullLeadingAddr) {
- if (MachOOF->is64Bit())
- outs() << format("%016" PRIx64, PC);
- else
- outs() << format("%08" PRIx64, PC);
- } else {
- outs() << format("%8" PRIx64 ":", PC);
+ if (!NoLeadingAddr) {
+ if (FullLeadingAddr) {
+ if (MachOOF->is64Bit())
+ outs() << format("%016" PRIx64, PC);
+ else
+ outs() << format("%08" PRIx64, PC);
+ } else {
+ outs() << format("%8" PRIx64 ":", PC);
+ }
}
if (!NoShowRawInsn)
outs() << "\t";
@@ -2351,9 +6294,7 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
DTI->second.getLength(Length);
uint16_t Kind;
DTI->second.getKind(Kind);
- Size = DumpDataInCode(reinterpret_cast<const char *>(Bytes.data()) +
- Index,
- Length, Kind);
+ Size = DumpDataInCode(Bytes.data() + Index, Length, Kind);
if ((Kind == MachO::DICE_KIND_JUMP_TABLE8) &&
(PC == (DTI->first + Length - 1)) && (Length & 1))
Size++;
@@ -2372,16 +6313,15 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
DebugOut, Annotations);
if (gotInst) {
if (!NoShowRawInsn) {
- DumpBytes(StringRef(
- reinterpret_cast<const char *>(Bytes.data()) + Index, Size));
+ DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size));
}
formatted_raw_ostream FormattedOS(outs());
Annotations.flush();
StringRef AnnotationsStr = Annotations.str();
if (isThumb)
- ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr);
+ ThumbIP->printInst(&Inst, FormattedOS, AnnotationsStr, *ThumbSTI);
else
- IP->printInst(&Inst, FormattedOS, AnnotationsStr);
+ IP->printInst(&Inst, FormattedOS, AnnotationsStr, *STI);
emitComments(CommentStream, CommentsToEmit, FormattedOS, *AsmInfo);
// Print debug info.
@@ -2426,21 +6366,21 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF) {
uint64_t PC = SectAddress + Index;
if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC,
DebugOut, nulls())) {
- if (FullLeadingAddr) {
- if (MachOOF->is64Bit())
- outs() << format("%016" PRIx64, PC);
- else
- outs() << format("%08" PRIx64, PC);
- } else {
- outs() << format("%8" PRIx64 ":", PC);
+ if (!NoLeadingAddr) {
+ if (FullLeadingAddr) {
+ if (MachOOF->is64Bit())
+ outs() << format("%016" PRIx64, PC);
+ else
+ outs() << format("%08" PRIx64, PC);
+ } else {
+ outs() << format("%8" PRIx64 ":", PC);
+ }
}
if (!NoShowRawInsn) {
outs() << "\t";
- DumpBytes(
- StringRef(reinterpret_cast<const char *>(Bytes.data()) + Index,
- InstSize));
+ DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, InstSize));
}
- IP->printInst(&Inst, outs(), "");
+ IP->printInst(&Inst, outs(), "", *STI);
outs() << "\n";
} else {
unsigned int Arch = MachOOF->getArch();
@@ -2544,7 +6484,7 @@ static void findUnwindRelocNameAddend(const MachOObjectFile *Obj,
}
auto RE = Obj->getRelocation(Reloc.getRawDataRefImpl());
- SectionRef RelocSection = Obj->getRelocationSection(RE);
+ SectionRef RelocSection = Obj->getAnyRelocationSection(RE);
uint64_t SectionAddr = RelocSection.getAddress();
@@ -4588,8 +8528,8 @@ void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
uint32_t ncmds = 0;
uint32_t filetype = 0;
uint32_t cputype = 0;
- getAndPrintMachHeader(file, ncmds, filetype, cputype, true);
- PrintLoadCommands(file, ncmds, filetype, cputype, true);
+ getAndPrintMachHeader(file, ncmds, filetype, cputype, !NonVerbose);
+ PrintLoadCommands(file, ncmds, filetype, cputype, !NonVerbose);
}
//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile
index 4616b78adb2e..7c165230dde4 100644
--- a/tools/llvm-objdump/Makefile
+++ b/tools/llvm-objdump/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-objdump
-LINK_COMPONENTS := all-targets DebugInfo MC MCParser MCDisassembler Object
+LINK_COMPONENTS := all-targets DebugInfoDWARF MC MCParser MCDisassembler Object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index aff6272d2fa3..e442ac050fce 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -68,14 +68,14 @@ static cl::alias
Disassembled("d", cl::desc("Alias for --disassemble"),
cl::aliasopt(Disassemble));
-static cl::opt<bool>
-Relocations("r", cl::desc("Display the relocation entries in the file"));
+cl::opt<bool>
+llvm::Relocations("r", cl::desc("Display the relocation entries in the file"));
-static cl::opt<bool>
-SectionContents("s", cl::desc("Display the content of each section"));
+cl::opt<bool>
+llvm::SectionContents("s", cl::desc("Display the content of each section"));
-static cl::opt<bool>
-SymbolTable("t", cl::desc("Display the symbol table"));
+cl::opt<bool>
+llvm::SymbolTable("t", cl::desc("Display the symbol table"));
cl::opt<bool>
llvm::ExportsTrie("exports-trie", cl::desc("Display mach-o exported symbols"));
@@ -111,9 +111,9 @@ cl::opt<std::string>
llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, "
"see -version for available targets"));
-static cl::opt<bool>
-SectionHeaders("section-headers", cl::desc("Display summaries of the headers "
- "for each section."));
+cl::opt<bool>
+llvm::SectionHeaders("section-headers", cl::desc("Display summaries of the "
+ "headers for each section."));
static cl::alias
SectionHeadersShort("headers", cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders));
@@ -132,8 +132,8 @@ llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling "
"instructions, do not print "
"the instruction bytes."));
-static cl::opt<bool>
-UnwindInfo("unwind-info", cl::desc("Display unwind information"));
+cl::opt<bool>
+llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information"));
static cl::alias
UnwindInfoShort("u", cl::desc("Alias for --unwind-info"),
@@ -194,30 +194,17 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) {
return TheTarget;
}
-void llvm::DumpBytes(StringRef bytes) {
+void llvm::DumpBytes(ArrayRef<uint8_t> bytes) {
static const char hex_rep[] = "0123456789abcdef";
- // FIXME: The real way to do this is to figure out the longest instruction
- // and align to that size before printing. I'll fix this when I get
- // around to outputting relocations.
- // 15 is the longest x86 instruction
- // 3 is for the hex rep of a byte + a space.
- // 1 is for the null terminator.
- enum { OutputSize = (15 * 3) + 1 };
- char output[OutputSize];
-
- assert(bytes.size() <= 15
- && "DumpBytes only supports instructions of up to 15 bytes");
- memset(output, ' ', sizeof(output));
- unsigned index = 0;
- for (StringRef::iterator i = bytes.begin(),
- e = bytes.end(); i != e; ++i) {
- output[index] = hex_rep[(*i & 0xF0) >> 4];
- output[index + 1] = hex_rep[*i & 0xF];
- index += 3;
+ SmallString<64> output;
+
+ for (char i: bytes) {
+ output.push_back(hex_rep[(i & 0xF0) >> 4]);
+ output.push_back(hex_rep[i & 0xF]);
+ output.push_back(' ');
}
- output[sizeof(output) - 1] = 0;
- outs() << output;
+ outs() << output.c_str();
}
bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) {
@@ -287,7 +274,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
- AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
+ Triple(TripleName), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
if (!IP) {
errs() << "error: no instruction printer for target " << TripleName
<< '\n';
@@ -412,10 +399,9 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
outs() << format("%8" PRIx64 ":", SectionAddr + Index);
if (!NoShowRawInsn) {
outs() << "\t";
- DumpBytes(StringRef(
- reinterpret_cast<const char *>(Bytes.data()) + Index, Size));
+ DumpBytes(ArrayRef<uint8_t>(Bytes.data() + Index, Size));
}
- IP->printInst(&Inst, outs(), "");
+ IP->printInst(&Inst, outs(), "", *STI);
outs() << CommentStream.str();
Comments.clear();
outs() << "\n";
@@ -453,7 +439,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
}
}
-static void PrintRelocations(const ObjectFile *Obj) {
+void llvm::PrintRelocations(const ObjectFile *Obj) {
StringRef Fmt = Obj->getBytesInAddress() > 4 ? "%016" PRIx64 :
"%08" PRIx64;
// Regular objdump doesn't print relocations in non-relocatable object
@@ -490,7 +476,7 @@ static void PrintRelocations(const ObjectFile *Obj) {
}
}
-static void PrintSectionHeaders(const ObjectFile *Obj) {
+void llvm::PrintSectionHeaders(const ObjectFile *Obj) {
outs() << "Sections:\n"
"Idx Name Size Address Type\n";
unsigned i = 0;
@@ -511,7 +497,7 @@ static void PrintSectionHeaders(const ObjectFile *Obj) {
}
}
-static void PrintSectionContents(const ObjectFile *Obj) {
+void llvm::PrintSectionContents(const ObjectFile *Obj) {
std::error_code EC;
for (const SectionRef &Section : Obj->sections()) {
StringRef Name;
@@ -614,7 +600,7 @@ static void PrintCOFFSymbolTable(const COFFObjectFile *coff) {
}
}
-static void PrintSymbolTable(const ObjectFile *o) {
+void llvm::PrintSymbolTable(const ObjectFile *o) {
outs() << "SYMBOL TABLE:\n";
if (const COFFObjectFile *coff = dyn_cast<const COFFObjectFile>(o)) {
@@ -642,7 +628,16 @@ static void PrintSymbolTable(const ObjectFile *o) {
bool Global = Flags & SymbolRef::SF_Global;
bool Weak = Flags & SymbolRef::SF_Weak;
bool Absolute = Flags & SymbolRef::SF_Absolute;
-
+ bool Common = Flags & SymbolRef::SF_Common;
+ bool Hidden = Flags & SymbolRef::SF_Hidden;
+
+ if (Common) {
+ uint32_t Alignment;
+ if (error(Symbol.getAlignment(Alignment)))
+ Alignment = 0;
+ Address = Size;
+ Size = Alignment;
+ }
if (Address == UnknownAddressOrSize)
Address = 0;
if (Size == UnknownAddressOrSize)
@@ -672,6 +667,8 @@ static void PrintSymbolTable(const ObjectFile *o) {
<< ' ';
if (Absolute) {
outs() << "*ABS*";
+ } else if (Common) {
+ outs() << "*COM*";
} else if (Section == o->section_end()) {
outs() << "*UND*";
} else {
@@ -687,8 +684,11 @@ static void PrintSymbolTable(const ObjectFile *o) {
outs() << SectionName;
}
outs() << '\t'
- << format("%08" PRIx64 " ", Size)
- << Name
+ << format("%08" PRIx64 " ", Size);
+ if (Hidden) {
+ outs() << ".hidden ";
+ }
+ outs() << Name
<< '\n';
}
}
@@ -892,7 +892,16 @@ int main(int argc, char **argv) {
&& !Bind
&& !LazyBind
&& !WeakBind
- && !(UniversalHeaders && MachOOpt)) {
+ && !(UniversalHeaders && MachOOpt)
+ && !(ArchiveHeaders && MachOOpt)
+ && !(IndirectSymbols && MachOOpt)
+ && !(DataInCode && MachOOpt)
+ && !(LinkOptHints && MachOOpt)
+ && !(InfoPlist && MachOOpt)
+ && !(DylibsUsed && MachOOpt)
+ && !(DylibId && MachOOpt)
+ && !(ObjcMetaData && MachOOpt)
+ && !(DumpSections.size() != 0 && MachOOpt)) {
cl::PrintHelpMessage();
return 2;
}
diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h
index f829dd1a71c3..bde72e004a1f 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -1,4 +1,3 @@
-//===-- llvm-objdump.h ----------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -26,6 +25,8 @@ extern cl::opt<std::string> TripleName;
extern cl::opt<std::string> ArchName;
extern cl::opt<std::string> MCPU;
extern cl::list<std::string> MAttrs;
+extern cl::list<std::string> DumpSections;
+extern cl::opt<bool> Raw;
extern cl::opt<bool> Disassemble;
extern cl::opt<bool> NoShowRawInsn;
extern cl::opt<bool> PrivateHeaders;
@@ -35,11 +36,26 @@ extern cl::opt<bool> Bind;
extern cl::opt<bool> LazyBind;
extern cl::opt<bool> WeakBind;
extern cl::opt<bool> UniversalHeaders;
+extern cl::opt<bool> ArchiveHeaders;
+extern cl::opt<bool> IndirectSymbols;
+extern cl::opt<bool> DataInCode;
+extern cl::opt<bool> LinkOptHints;
+extern cl::opt<bool> InfoPlist;
+extern cl::opt<bool> DylibsUsed;
+extern cl::opt<bool> DylibId;
+extern cl::opt<bool> ObjcMetaData;
+extern cl::opt<std::string> DisSymName;
+extern cl::opt<bool> NonVerbose;
+extern cl::opt<bool> Relocations;
+extern cl::opt<bool> SectionHeaders;
+extern cl::opt<bool> SectionContents;
+extern cl::opt<bool> SymbolTable;
+extern cl::opt<bool> UnwindInfo;
// Various helper functions.
bool error(std::error_code ec);
bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b);
-void DumpBytes(StringRef bytes);
+void DumpBytes(ArrayRef<uint8_t> bytes);
void ParseInputMachO(StringRef Filename);
void printCOFFUnwindInfo(const object::COFFObjectFile* o);
void printMachOUnwindInfo(const object::MachOObjectFile* o);
@@ -56,6 +72,10 @@ void printRebaseTable(const object::ObjectFile *o);
void printBindTable(const object::ObjectFile *o);
void printLazyBindTable(const object::ObjectFile *o);
void printWeakBindTable(const object::ObjectFile *o);
+void PrintRelocations(const object::ObjectFile *o);
+void PrintSectionHeaders(const object::ObjectFile *o);
+void PrintSectionContents(const object::ObjectFile *o);
+void PrintSymbolTable(const object::ObjectFile *o);
} // end namespace llvm
diff --git a/tools/llvm-pdbdump/BuiltinDumper.cpp b/tools/llvm-pdbdump/BuiltinDumper.cpp
new file mode 100644
index 000000000000..d80829841f3a
--- /dev/null
+++ b/tools/llvm-pdbdump/BuiltinDumper.cpp
@@ -0,0 +1,87 @@
+//===- BuiltinDumper.cpp ---------------------------------------- *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BuiltinDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+using namespace llvm;
+
+BuiltinDumper::BuiltinDumper(LinePrinter &P)
+ : PDBSymDumper(false), Printer(P) {}
+
+void BuiltinDumper::start(const PDBSymbolTypeBuiltin &Symbol) {
+ PDB_BuiltinType Type = Symbol.getBuiltinType();
+ switch (Type) {
+ case PDB_BuiltinType::Float:
+ if (Symbol.getLength() == 4)
+ WithColor(Printer, PDB_ColorItem::Type).get() << "float";
+ else
+ WithColor(Printer, PDB_ColorItem::Type).get() << "double";
+ break;
+ case PDB_BuiltinType::UInt:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned";
+ if (Symbol.getLength() == 8)
+ WithColor(Printer, PDB_ColorItem::Type).get() << " __int64";
+ break;
+ case PDB_BuiltinType::Int:
+ if (Symbol.getLength() == 4)
+ WithColor(Printer, PDB_ColorItem::Type).get() << "int";
+ else
+ WithColor(Printer, PDB_ColorItem::Type).get() << "__int64";
+ break;
+ case PDB_BuiltinType::Char:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "char";
+ break;
+ case PDB_BuiltinType::WCharT:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "wchar_t";
+ break;
+ case PDB_BuiltinType::Void:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "void";
+ break;
+ case PDB_BuiltinType::Long:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "long";
+ break;
+ case PDB_BuiltinType::ULong:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "unsigned long";
+ break;
+ case PDB_BuiltinType::Bool:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "bool";
+ break;
+ case PDB_BuiltinType::Currency:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "CURRENCY";
+ break;
+ case PDB_BuiltinType::Date:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "DATE";
+ break;
+ case PDB_BuiltinType::Variant:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "VARIANT";
+ break;
+ case PDB_BuiltinType::Complex:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "complex";
+ break;
+ case PDB_BuiltinType::Bitfield:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "bitfield";
+ break;
+ case PDB_BuiltinType::BSTR:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "BSTR";
+ break;
+ case PDB_BuiltinType::HResult:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT";
+ break;
+ case PDB_BuiltinType::BCD:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "HRESULT";
+ break;
+ default:
+ WithColor(Printer, PDB_ColorItem::Type).get() << "void";
+ break;
+ }
+}
diff --git a/tools/llvm-pdbdump/BuiltinDumper.h b/tools/llvm-pdbdump/BuiltinDumper.h
new file mode 100644
index 000000000000..8cf984a0ca61
--- /dev/null
+++ b/tools/llvm-pdbdump/BuiltinDumper.h
@@ -0,0 +1,30 @@
+//===- BuiltinDumper.h ---------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_BUILTINDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class BuiltinDumper : public PDBSymDumper {
+public:
+ BuiltinDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeBuiltin &Symbol);
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/CMakeLists.txt b/tools/llvm-pdbdump/CMakeLists.txt
new file mode 100644
index 000000000000..1907f917079a
--- /dev/null
+++ b/tools/llvm-pdbdump/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_LINK_COMPONENTS
+ Support
+ DebugInfoPDB
+ )
+
+add_llvm_tool(llvm-pdbdump
+ llvm-pdbdump.cpp
+ BuiltinDumper.cpp
+ ClassDefinitionDumper.cpp
+ CompilandDumper.cpp
+ EnumDumper.cpp
+ ExternalSymbolDumper.cpp
+ FunctionDumper.cpp
+ LinePrinter.cpp
+ TypeDumper.cpp
+ TypedefDumper.cpp
+ VariableDumper.cpp
+ )
diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp
new file mode 100644
index 000000000000..8abf3fa3912a
--- /dev/null
+++ b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp
@@ -0,0 +1,190 @@
+//===- ClassDefinitionDumper.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClassDefinitionDumper.h"
+#include "EnumDumper.h"
+#include "FunctionDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+#include "TypedefDumper.h"
+#include "VariableDumper.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+ClassDefinitionDumper::ClassDefinitionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class) {
+ std::string Name = Class.getName();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Class.getUdtKind() << " ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Class.getName();
+
+ auto Bases = Class.findAllChildren<PDBSymbolTypeBaseClass>();
+ if (Bases->getChildCount() > 0) {
+ Printer.Indent();
+ Printer.NewLine();
+ Printer << ":";
+ uint32_t BaseIndex = 0;
+ while (auto Base = Bases->getNext()) {
+ Printer << " ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << Base->getAccess();
+ if (Base->isVirtualBaseClass())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " virtual";
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Base->getName();
+ if (++BaseIndex < Bases->getChildCount()) {
+ Printer.NewLine();
+ Printer << ",";
+ }
+ }
+ Printer.Unindent();
+ }
+
+ Printer << " {";
+ auto Children = Class.findAllChildren();
+ if (Children->getChildCount() == 0) {
+ Printer << "}";
+ return;
+ }
+
+ // Try to dump symbols organized by member access level. Public members
+ // first, then protected, then private. This might be slow, so it's worth
+ // reconsidering the value of this if performance of large PDBs is a problem.
+ // NOTE: Access level of nested types is not recorded in the PDB, so we have
+ // a special case for them.
+ SymbolGroupByAccess Groups;
+ Groups.insert(std::make_pair(0, SymbolGroup()));
+ Groups.insert(std::make_pair((int)PDB_MemberAccess::Private, SymbolGroup()));
+ Groups.insert(
+ std::make_pair((int)PDB_MemberAccess::Protected, SymbolGroup()));
+ Groups.insert(std::make_pair((int)PDB_MemberAccess::Public, SymbolGroup()));
+
+ while (auto Child = Children->getNext()) {
+ PDB_MemberAccess Access = Child->getRawSymbol().getAccess();
+ if (isa<PDBSymbolTypeBaseClass>(*Child))
+ continue;
+
+ auto &AccessGroup = Groups.find((int)Access)->second;
+
+ if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
+ if (Func->isCompilerGenerated() && opts::ExcludeCompilerGenerated)
+ continue;
+ if (Func->getLength() == 0 && !Func->isPureVirtual() &&
+ !Func->isIntroVirtualFunction())
+ continue;
+ Child.release();
+ AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
+ } else if (auto Data = dyn_cast<PDBSymbolData>(Child.get())) {
+ Child.release();
+ AccessGroup.Data.push_back(std::unique_ptr<PDBSymbolData>(Data));
+ } else {
+ AccessGroup.Unknown.push_back(std::move(Child));
+ }
+ }
+
+ int Count = 0;
+ Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
+ Count += dumpAccessGroup(PDB_MemberAccess::Public,
+ Groups[(int)PDB_MemberAccess::Public]);
+ Count += dumpAccessGroup(PDB_MemberAccess::Protected,
+ Groups[(int)PDB_MemberAccess::Protected]);
+ Count += dumpAccessGroup(PDB_MemberAccess::Private,
+ Groups[(int)PDB_MemberAccess::Private]);
+ if (Count > 0)
+ Printer.NewLine();
+ Printer << "}";
+}
+
+int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
+ const SymbolGroup &Group) {
+ if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
+ return 0;
+
+ int Count = 0;
+ if (Access == PDB_MemberAccess::Private) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "private";
+ Printer << ":";
+ } else if (Access == PDB_MemberAccess::Protected) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "protected";
+ Printer << ":";
+ } else if (Access == PDB_MemberAccess::Public) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "public";
+ Printer << ":";
+ }
+ Printer.Indent();
+ for (auto iter = Group.Functions.begin(), end = Group.Functions.end();
+ iter != end; ++iter) {
+ ++Count;
+ (*iter)->dump(*this);
+ }
+ for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
+ ++iter) {
+ ++Count;
+ (*iter)->dump(*this);
+ }
+ for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
+ iter != end; ++iter) {
+ ++Count;
+ (*iter)->dump(*this);
+ }
+ Printer.Unindent();
+ return Count;
+}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
+
+void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
+ VariableDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.h b/tools/llvm-pdbdump/ClassDefinitionDumper.h
new file mode 100644
index 000000000000..5b48ba879cf7
--- /dev/null
+++ b/tools/llvm-pdbdump/ClassDefinitionDumper.h
@@ -0,0 +1,62 @@
+//===- ClassDefinitionDumper.h - --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_CLASSDEFINITIONDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_CLASSDEFINITIONDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+
+#include <list>
+#include <memory>
+#include <unordered_map>
+
+namespace llvm {
+
+class LinePrinter;
+
+class ClassDefinitionDumper : public PDBSymDumper {
+public:
+ ClassDefinitionDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeUDT &Exe);
+
+ void dump(const PDBSymbolTypeBaseClass &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+ void dump(const PDBSymbolTypeVTable &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+
+ struct SymbolGroup {
+ SymbolGroup() {}
+ SymbolGroup(SymbolGroup &&Other) {
+ Functions = std::move(Other.Functions);
+ Data = std::move(Other.Data);
+ Unknown = std::move(Other.Unknown);
+ }
+
+ std::list<std::unique_ptr<PDBSymbolFunc>> Functions;
+ std::list<std::unique_ptr<PDBSymbolData>> Data;
+ std::list<std::unique_ptr<PDBSymbol>> Unknown;
+ SymbolGroup(const SymbolGroup &other) = delete;
+ SymbolGroup &operator=(const SymbolGroup &other) = delete;
+ };
+ typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
+
+ int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/CompilandDumper.cpp b/tools/llvm-pdbdump/CompilandDumper.cpp
new file mode 100644
index 000000000000..68ceb620627b
--- /dev/null
+++ b/tools/llvm-pdbdump/CompilandDumper.cpp
@@ -0,0 +1,140 @@
+//===- CompilandDumper.cpp - llvm-pdbdump compiland symbol dumper *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompilandDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "FunctionDumper.h"
+
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+CompilandDumper::CompilandDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {}
+
+void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {}
+
+void CompilandDumper::start(const PDBSymbolCompiland &Symbol, bool Children) {
+ std::string FullName = Symbol.getName();
+ if (Printer.IsCompilandExcluded(FullName))
+ return;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Path).get() << FullName;
+ if (!Children)
+ return;
+
+ auto ChildrenEnum = Symbol.findAllChildren();
+ Printer.Indent();
+ while (auto Child = ChildrenEnum->getNext())
+ Child->dump(*this);
+ Printer.Unindent();
+}
+
+void CompilandDumper::dump(const PDBSymbolData &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+
+ switch (auto LocType = Symbol.getLocationType()) {
+ case PDB_LocType::Static:
+ Printer << "data: ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "]";
+ break;
+ case PDB_LocType::Constant:
+ Printer << "constant: ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get()
+ << "[" << Symbol.getValue() << "]";
+ break;
+ default:
+ Printer << "data(unexpected type=" << LocType << ")";
+ }
+
+ Printer << " ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+}
+
+void CompilandDumper::dump(const PDBSymbolFunc &Symbol) {
+ if (Symbol.getLength() == 0)
+ return;
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
+}
+
+void CompilandDumper::dump(const PDBSymbolLabel &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "label ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getVirtualAddress(), 10) << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+}
+
+void CompilandDumper::dump(const PDBSymbolThunk &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "thunk ";
+ PDB_ThunkOrdinal Ordinal = Symbol.getThunkOrdinal();
+ uint64_t VA = Symbol.getVirtualAddress();
+ if (Ordinal == PDB_ThunkOrdinal::TrampIncremental) {
+ uint64_t Target = Symbol.getTargetVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(VA, 10);
+ Printer << " -> ";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10);
+ } else {
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(VA, 10) << " - "
+ << format_hex(VA + Symbol.getLength(), 10) << "]";
+ }
+ Printer << " (";
+ WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal;
+ Printer << ") ";
+ std::string Name = Symbol.getName();
+ if (!Name.empty())
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+}
+
+void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {}
+
+void CompilandDumper::dump(const PDBSymbolUnknown &Symbol) {
+ Printer.NewLine();
+ Printer << "unknown (" << Symbol.getSymTag() << ")";
+}
diff --git a/tools/llvm-pdbdump/CompilandDumper.h b/tools/llvm-pdbdump/CompilandDumper.h
new file mode 100644
index 000000000000..0d1d27cd7a43
--- /dev/null
+++ b/tools/llvm-pdbdump/CompilandDumper.h
@@ -0,0 +1,39 @@
+//===- CompilandDumper.h - llvm-pdbdump compiland symbol dumper *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_COMPILANDDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_COMPILANDDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class CompilandDumper : public PDBSymDumper {
+public:
+ CompilandDumper(LinePrinter &P);
+
+ void start(const PDBSymbolCompiland &Symbol, bool Children);
+
+ void dump(const PDBSymbolCompilandDetails &Symbol) override;
+ void dump(const PDBSymbolCompilandEnv &Symbol) override;
+ void dump(const PDBSymbolData &Symbol) override;
+ void dump(const PDBSymbolFunc &Symbol) override;
+ void dump(const PDBSymbolLabel &Symbol) override;
+ void dump(const PDBSymbolThunk &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolUnknown &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/EnumDumper.cpp b/tools/llvm-pdbdump/EnumDumper.cpp
new file mode 100644
index 000000000000..3514c39f6e03
--- /dev/null
+++ b/tools/llvm-pdbdump/EnumDumper.cpp
@@ -0,0 +1,52 @@
+//===- EnumDumper.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EnumDumper.h"
+
+#include "BuiltinDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+using namespace llvm;
+
+EnumDumper::EnumDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void EnumDumper::start(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+ if (!opts::NoEnumDefs) {
+ auto BuiltinType = Symbol.getUnderlyingType();
+ if (BuiltinType->getBuiltinType() != PDB_BuiltinType::Int ||
+ BuiltinType->getLength() != 4) {
+ Printer << " : ";
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(*BuiltinType);
+ }
+ Printer << " {";
+ Printer.Indent();
+ auto EnumValues = Symbol.findAllChildren<PDBSymbolData>();
+ while (auto EnumValue = EnumValues->getNext()) {
+ if (EnumValue->getDataKind() != PDB_DataKind::Constant)
+ continue;
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << EnumValue->getName();
+ Printer << " = ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get()
+ << EnumValue->getValue();
+ }
+ Printer.Unindent();
+ Printer.NewLine();
+ Printer << "}";
+ }
+}
diff --git a/tools/llvm-pdbdump/EnumDumper.h b/tools/llvm-pdbdump/EnumDumper.h
new file mode 100644
index 000000000000..23de0614247f
--- /dev/null
+++ b/tools/llvm-pdbdump/EnumDumper.h
@@ -0,0 +1,30 @@
+//===- EnumDumper.h - -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_ENUMDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class EnumDumper : public PDBSymDumper {
+public:
+ EnumDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeEnum &Symbol);
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/ExternalSymbolDumper.cpp b/tools/llvm-pdbdump/ExternalSymbolDumper.cpp
new file mode 100644
index 000000000000..c4e9f474880e
--- /dev/null
+++ b/tools/llvm-pdbdump/ExternalSymbolDumper.cpp
@@ -0,0 +1,40 @@
+//===- ExternalSymbolDumper.cpp -------------------------------- *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ExternalSymbolDumper.h"
+#include "LinePrinter.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+ExternalSymbolDumper::ExternalSymbolDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void ExternalSymbolDumper::start(const PDBSymbolExe &Symbol) {
+ auto Vars = Symbol.findAllChildren<PDBSymbolPublicSymbol>();
+ while (auto Var = Vars->getNext())
+ Var->dump(*this);
+}
+
+void ExternalSymbolDumper::dump(const PDBSymbolPublicSymbol &Symbol) {
+ std::string LinkageName = Symbol.getName();
+ if (Printer.IsSymbolExcluded(LinkageName))
+ return;
+
+ Printer.NewLine();
+ uint64_t Addr = Symbol.getVirtualAddress();
+
+ Printer << "[";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Addr, 10);
+ Printer << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << LinkageName;
+}
diff --git a/tools/llvm-pdbdump/ExternalSymbolDumper.h b/tools/llvm-pdbdump/ExternalSymbolDumper.h
new file mode 100644
index 000000000000..d77b09cdebf1
--- /dev/null
+++ b/tools/llvm-pdbdump/ExternalSymbolDumper.h
@@ -0,0 +1,32 @@
+//===- ExternalSymbolDumper.h --------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_EXTERNALSYMBOLDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_EXTERNALSYMBOLDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class ExternalSymbolDumper : public PDBSymDumper {
+public:
+ ExternalSymbolDumper(LinePrinter &P);
+
+ void start(const PDBSymbolExe &Symbol);
+
+ void dump(const PDBSymbolPublicSymbol &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/FunctionDumper.cpp b/tools/llvm-pdbdump/FunctionDumper.cpp
new file mode 100644
index 000000000000..9584812e81a9
--- /dev/null
+++ b/tools/llvm-pdbdump/FunctionDumper.cpp
@@ -0,0 +1,254 @@
+//===- FunctionDumper.cpp ------------------------------------ *- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FunctionDumper.h"
+#include "BuiltinDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+namespace {
+template <class T>
+void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer,
+ llvm::FunctionDumper &Dumper) {
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().template getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+ if (!ClassParent)
+ return;
+
+ WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName();
+ Printer << "::";
+}
+}
+
+FunctionDumper::FunctionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
+ const char *Name, PointerType Pointer) {
+ auto ReturnType = Symbol.getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+ uint32_t ClassParentId = Symbol.getClassParentId();
+ auto ClassParent =
+ Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
+ ClassParentId);
+
+ PDB_CallingConv CC = Symbol.getCallingConvention();
+ bool ShouldDumpCallingConvention = true;
+ if ((ClassParent && CC == PDB_CallingConv::Thiscall) ||
+ (!ClassParent && CC == PDB_CallingConv::NearStdcall)) {
+ ShouldDumpCallingConvention = false;
+ }
+
+ if (Pointer == PointerType::None) {
+ if (ShouldDumpCallingConvention)
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ Printer << "(";
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::)";
+ }
+ } else {
+ Printer << "(";
+ if (ShouldDumpCallingConvention)
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
+ if (Pointer == PointerType::Reference)
+ Printer << "&";
+ else
+ Printer << "*";
+ if (Name)
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+ Printer << ")";
+ }
+
+ Printer << "(";
+ if (auto ChildEnum = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = ChildEnum->getNext()) {
+ Arg->dump(*this);
+ if (++Index < ChildEnum->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+}
+
+void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
+ uint64_t FuncStart = Symbol.getVirtualAddress();
+ uint64_t FuncEnd = FuncStart + Symbol.getLength();
+
+ Printer << "func [";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
+ if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
+ uint64_t Prologue = DebugStart->getVirtualAddress() - FuncStart;
+ WithColor(Printer, PDB_ColorItem::Offset).get() << "+" << Prologue;
+ }
+ Printer << " - ";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncEnd, 10);
+ if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>()) {
+ uint64_t Epilogue = FuncEnd - DebugEnd->getVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue;
+ }
+ Printer << "] (";
+
+ if (Symbol.hasFramePointer()) {
+ WithColor(Printer, PDB_ColorItem::Register).get()
+ << Symbol.getLocalBasePointerRegisterId();
+ } else {
+ WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
+ }
+ Printer << ") ";
+
+ if (Symbol.isVirtual() || Symbol.isPureVirtual())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual ";
+
+ auto Signature = Symbol.getSignature();
+ if (!Signature) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ if (Pointer == PointerType::Pointer)
+ Printer << "*";
+ else if (Pointer == FunctionDumper::PointerType::Reference)
+ Printer << "&";
+ return;
+ }
+
+ auto ReturnType = Signature->getReturnType();
+ ReturnType->dump(*this);
+ Printer << " ";
+
+ auto ClassParent = Symbol.getClassParent();
+ PDB_CallingConv CC = Signature->getCallingConvention();
+ if (Pointer != FunctionDumper::PointerType::None)
+ Printer << "(";
+
+ if ((ClassParent && CC != PDB_CallingConv::Thiscall) ||
+ (!ClassParent && CC != PDB_CallingConv::NearStdcall)) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get()
+ << Signature->getCallingConvention() << " ";
+ }
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ if (Pointer != FunctionDumper::PointerType::None) {
+ if (Pointer == PointerType::Pointer)
+ Printer << "*";
+ else if (Pointer == FunctionDumper::PointerType::Reference)
+ Printer << "&";
+ Printer << ")";
+ }
+
+ Printer << "(";
+ if (auto Arguments = Symbol.getArguments()) {
+ uint32_t Index = 0;
+ while (auto Arg = Arguments->getNext()) {
+ auto ArgType = Arg->getType();
+ ArgType->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Arg->getName();
+ if (++Index < Arguments->getChildCount())
+ Printer << ", ";
+ }
+ }
+ Printer << ")";
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
+ if (Symbol.isPureVirtual())
+ Printer << " = 0";
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ uint32_t ElementTypeId = Symbol.getTypeId();
+ auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId);
+ if (!ElementType)
+ return;
+
+ ElementType->dump(*this);
+ Printer << "[";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength();
+ Printer << "]";
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
+ // PDBSymbolTypeFunctionArg is just a shim over the real argument. Just drill
+ // through to the real thing and dump it.
+ uint32_t TypeId = Symbol.getTypeId();
+ auto Type = Symbol.getSession().getSymbolById(TypeId);
+ if (!Type)
+ return;
+ Type->dump(*this);
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ uint32_t PointeeId = Symbol.getTypeId();
+ auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
+ if (!PointeeType)
+ return;
+
+ if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ FunctionDumper NestedDumper(Printer);
+ PointerType Pointer =
+ Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
+ } else {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ PointeeType->dump(*this);
+ Printer << (Symbol.isReference() ? "&" : "*");
+ }
+}
+
+void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
diff --git a/tools/llvm-pdbdump/FunctionDumper.h b/tools/llvm-pdbdump/FunctionDumper.h
new file mode 100644
index 000000000000..19a00145a1fd
--- /dev/null
+++ b/tools/llvm-pdbdump/FunctionDumper.h
@@ -0,0 +1,42 @@
+//===- FunctionDumper.h --------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_FUNCTIONDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_FUNCTIONDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class FunctionDumper : public PDBSymDumper {
+public:
+ FunctionDumper(LinePrinter &P);
+
+ enum class PointerType { None, Pointer, Reference };
+
+ void start(const PDBSymbolTypeFunctionSig &Symbol, const char *Name,
+ PointerType Pointer);
+ void start(const PDBSymbolFunc &Symbol, PointerType Pointer);
+
+ void dump(const PDBSymbolTypeArray &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionArg &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/LLVMBuild.txt b/tools/llvm-pdbdump/LLVMBuild.txt
new file mode 100644
index 000000000000..487768935ddd
--- /dev/null
+++ b/tools/llvm-pdbdump/LLVMBuild.txt
@@ -0,0 +1,23 @@
+;===- ./tools/llvm-pdbdump/LLVMBuild.txt -----------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Tool
+name = llvm-pdbdump
+parent = Tools
+required_libraries = DebugInfoPDB
+
diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp
new file mode 100644
index 000000000000..6bbc403f5caf
--- /dev/null
+++ b/tools/llvm-pdbdump/LinePrinter.cpp
@@ -0,0 +1,124 @@
+//===- LinePrinter.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LinePrinter.h"
+
+#include "llvm-pdbdump.h"
+
+#include "llvm/Support/Regex.h"
+
+#include <algorithm>
+
+using namespace llvm;
+
+LinePrinter::LinePrinter(int Indent, llvm::raw_ostream &Stream)
+ : OS(Stream), IndentSpaces(Indent), CurrentIndent(0) {
+ SetFilters(TypeFilters, opts::ExcludeTypes.begin(), opts::ExcludeTypes.end());
+ SetFilters(SymbolFilters, opts::ExcludeSymbols.begin(),
+ opts::ExcludeSymbols.end());
+ SetFilters(CompilandFilters, opts::ExcludeCompilands.begin(),
+ opts::ExcludeCompilands.end());
+}
+
+void LinePrinter::Indent() { CurrentIndent += IndentSpaces; }
+
+void LinePrinter::Unindent() {
+ CurrentIndent = std::max(0, CurrentIndent - IndentSpaces);
+}
+
+void LinePrinter::NewLine() {
+ OS << "\n";
+ OS.indent(CurrentIndent);
+}
+
+bool LinePrinter::IsTypeExcluded(llvm::StringRef TypeName) {
+ if (TypeName.empty())
+ return false;
+
+ for (auto &Expr : TypeFilters) {
+ if (Expr.match(TypeName))
+ return true;
+ }
+ return false;
+}
+
+bool LinePrinter::IsSymbolExcluded(llvm::StringRef SymbolName) {
+ if (SymbolName.empty())
+ return false;
+
+ for (auto &Expr : SymbolFilters) {
+ if (Expr.match(SymbolName))
+ return true;
+ }
+ return false;
+}
+
+bool LinePrinter::IsCompilandExcluded(llvm::StringRef CompilandName) {
+ if (CompilandName.empty())
+ return false;
+
+ for (auto &Expr : CompilandFilters) {
+ if (Expr.match(CompilandName))
+ return true;
+ }
+ return false;
+}
+
+WithColor::WithColor(LinePrinter &P, PDB_ColorItem C) : OS(P.OS) {
+ if (C == PDB_ColorItem::None)
+ OS.resetColor();
+ else {
+ raw_ostream::Colors Color;
+ bool Bold;
+ translateColor(C, Color, Bold);
+ OS.changeColor(Color, Bold);
+ }
+}
+
+WithColor::~WithColor() { OS.resetColor(); }
+
+void WithColor::translateColor(PDB_ColorItem C, raw_ostream::Colors &Color,
+ bool &Bold) const {
+ switch (C) {
+ case PDB_ColorItem::Address:
+ Color = raw_ostream::YELLOW;
+ Bold = true;
+ return;
+ case PDB_ColorItem::Keyword:
+ Color = raw_ostream::MAGENTA;
+ Bold = true;
+ return;
+ case PDB_ColorItem::Register:
+ case PDB_ColorItem::Offset:
+ Color = raw_ostream::YELLOW;
+ Bold = false;
+ return;
+ case PDB_ColorItem::Type:
+ Color = raw_ostream::CYAN;
+ Bold = true;
+ return;
+ case PDB_ColorItem::Identifier:
+ Color = raw_ostream::CYAN;
+ Bold = false;
+ return;
+ case PDB_ColorItem::Path:
+ Color = raw_ostream::CYAN;
+ Bold = false;
+ return;
+ case PDB_ColorItem::SectionHeader:
+ Color = raw_ostream::RED;
+ Bold = true;
+ return;
+ case PDB_ColorItem::LiteralValue:
+ Color = raw_ostream::GREEN;
+ Bold = true;
+ default:
+ return;
+ }
+}
diff --git a/tools/llvm-pdbdump/LinePrinter.h b/tools/llvm-pdbdump/LinePrinter.h
new file mode 100644
index 000000000000..c2a3ab60d90f
--- /dev/null
+++ b/tools/llvm-pdbdump/LinePrinter.h
@@ -0,0 +1,89 @@
+//===- LinePrinter.h ------------------------------------------ *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_LINEPRINTER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Regex.h"
+
+#include <list>
+
+namespace llvm {
+
+class LinePrinter {
+ friend class WithColor;
+
+public:
+ LinePrinter(int Indent, raw_ostream &Stream);
+
+ void Indent();
+ void Unindent();
+ void NewLine();
+
+ raw_ostream &getStream() { return OS; }
+ int getIndentLevel() const { return CurrentIndent; }
+
+ bool IsTypeExcluded(llvm::StringRef TypeName);
+ bool IsSymbolExcluded(llvm::StringRef SymbolName);
+ bool IsCompilandExcluded(llvm::StringRef CompilandName);
+
+private:
+ template <typename Iter>
+ void SetFilters(std::list<Regex> &List, Iter Begin, Iter End) {
+ List.clear();
+ for (; Begin != End; ++Begin)
+ List.push_back(StringRef(*Begin));
+ }
+
+ raw_ostream &OS;
+ int IndentSpaces;
+ int CurrentIndent;
+
+ std::list<Regex> CompilandFilters;
+ std::list<Regex> TypeFilters;
+ std::list<Regex> SymbolFilters;
+};
+
+template <class T>
+inline raw_ostream &operator<<(LinePrinter &Printer, const T &Item) {
+ Printer.getStream() << Item;
+ return Printer.getStream();
+}
+
+enum class PDB_ColorItem {
+ None,
+ Address,
+ Type,
+ Keyword,
+ Offset,
+ Identifier,
+ Path,
+ SectionHeader,
+ LiteralValue,
+ Register,
+};
+
+class WithColor {
+public:
+ WithColor(LinePrinter &P, PDB_ColorItem C);
+ ~WithColor();
+
+ raw_ostream &get() { return OS; }
+
+private:
+ void translateColor(PDB_ColorItem C, raw_ostream::Colors &Color,
+ bool &Bold) const;
+ raw_ostream &OS;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/Makefile b/tools/llvm-pdbdump/Makefile
new file mode 100644
index 000000000000..18aafc4076fe
--- /dev/null
+++ b/tools/llvm-pdbdump/Makefile
@@ -0,0 +1,17 @@
+##===- tools/llvm-pdbdump/Makefile -------------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+TOOLNAME := llvm-pdbdump
+LINK_COMPONENTS := DebugInfoPDB Object
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common
diff --git a/tools/llvm-pdbdump/TypeDumper.cpp b/tools/llvm-pdbdump/TypeDumper.cpp
new file mode 100644
index 000000000000..88c0bd65697e
--- /dev/null
+++ b/tools/llvm-pdbdump/TypeDumper.cpp
@@ -0,0 +1,97 @@
+//===- TypeDumper.cpp - PDBSymDumper implementation for types *----- C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypeDumper.h"
+
+#include "BuiltinDumper.h"
+#include "ClassDefinitionDumper.h"
+#include "EnumDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+#include "TypedefDumper.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+using namespace llvm;
+
+TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void TypeDumper::start(const PDBSymbolExe &Exe) {
+ auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
+ Printer << ": (" << Enums->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Enum = Enums->getNext())
+ Enum->dump(*this);
+ Printer.Unindent();
+
+ auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
+ Printer << ": (" << Typedefs->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Typedef = Typedefs->getNext())
+ Typedef->dump(*this);
+ Printer.Unindent();
+
+ auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
+ Printer << ": (" << Classes->getChildCount() << " items)";
+ Printer.Indent();
+ while (auto Class = Classes->getNext())
+ Class->dump(*this);
+ Printer.Unindent();
+}
+
+void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ if (Symbol.getUnmodifiedTypeId() != 0)
+ return;
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+ // Dump member enums when dumping their class definition.
+ if (Symbol.isNested())
+ return;
+
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ if (Symbol.getUnmodifiedTypeId() != 0)
+ return;
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+
+ if (opts::NoClassDefs) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
+ } else {
+ ClassDefinitionDumper Dumper(Printer);
+ Dumper.start(Symbol);
+ }
+}
diff --git a/tools/llvm-pdbdump/TypeDumper.h b/tools/llvm-pdbdump/TypeDumper.h
new file mode 100644
index 000000000000..5c0832eccaf9
--- /dev/null
+++ b/tools/llvm-pdbdump/TypeDumper.h
@@ -0,0 +1,34 @@
+//===- TypeDumper.h - PDBSymDumper implementation for types *- C++ ------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class TypeDumper : public PDBSymDumper {
+public:
+ TypeDumper(LinePrinter &P);
+
+ void start(const PDBSymbolExe &Exe);
+
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/TypedefDumper.cpp b/tools/llvm-pdbdump/TypedefDumper.cpp
new file mode 100644
index 000000000000..a6b5c53a6b3a
--- /dev/null
+++ b/tools/llvm-pdbdump/TypedefDumper.cpp
@@ -0,0 +1,79 @@
+//===- TypedefDumper.cpp - PDBSymDumper impl for typedefs -------- * C++ *-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TypedefDumper.h"
+
+#include "BuiltinDumper.h"
+#include "FunctionDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+using namespace llvm;
+
+TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
+
+void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
+ uint32_t TargetId = Symbol.getTypeId();
+ if (auto TypeSymbol = Symbol.getSession().getSymbolById(TargetId))
+ TypeSymbol->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Symbol.getName();
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {}
+
+void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "enum ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << " " << Symbol.getName();
+}
+
+void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ uint32_t PointeeId = Symbol.getTypeId();
+ auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
+ if (!PointeeType)
+ return;
+ if (auto FuncSig = dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
+ if (Symbol.isReference())
+ Pointer = FunctionDumper::PointerType::Reference;
+ FunctionDumper NestedDumper(Printer);
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
+ } else {
+ PointeeType->dump(*this);
+ Printer << ((Symbol.isReference()) ? "&" : "*");
+ }
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
+}
+
+void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
diff --git a/tools/llvm-pdbdump/TypedefDumper.h b/tools/llvm-pdbdump/TypedefDumper.h
new file mode 100644
index 000000000000..8cd578cc6d29
--- /dev/null
+++ b/tools/llvm-pdbdump/TypedefDumper.h
@@ -0,0 +1,37 @@
+//===- TypedefDumper.h - llvm-pdbdump typedef dumper ---------*- C++ ----*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_TYPEDEFDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_TYPEDEFDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class TypedefDumper : public PDBSymDumper {
+public:
+ TypedefDumper(LinePrinter &P);
+
+ void start(const PDBSymbolTypeTypedef &Symbol);
+
+ void dump(const PDBSymbolTypeArray &Symbol) override;
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/VariableDumper.cpp b/tools/llvm-pdbdump/VariableDumper.cpp
new file mode 100644
index 000000000000..e5665b5fcafa
--- /dev/null
+++ b/tools/llvm-pdbdump/VariableDumper.cpp
@@ -0,0 +1,170 @@
+//===- VariableDumper.cpp - -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "VariableDumper.h"
+
+#include "BuiltinDumper.h"
+#include "LinePrinter.h"
+#include "llvm-pdbdump.h"
+#include "FunctionDumper.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+
+#include "llvm/Support/Format.h"
+
+using namespace llvm;
+
+VariableDumper::VariableDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
+
+void VariableDumper::start(const PDBSymbolData &Var) {
+ if (Var.isCompilerGenerated() && opts::ExcludeCompilerGenerated)
+ return;
+ if (Printer.IsSymbolExcluded(Var.getName()))
+ return;
+
+ auto VarType = Var.getType();
+
+ switch (auto LocType = Var.getLocationType()) {
+ case PDB_LocType::Static:
+ Printer.NewLine();
+ Printer << "data [";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << format_hex(Var.getVirtualAddress(), 10);
+ Printer << "] ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::Constant:
+ if (isa<PDBSymbolTypeEnum>(*VarType))
+ break;
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " = ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getValue();
+ break;
+ case PDB_LocType::ThisRel:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Var.getOffset(), 4) << " ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ break;
+ case PDB_LocType::BitField:
+ Printer.NewLine();
+ Printer << "data ";
+ WithColor(Printer, PDB_ColorItem::Offset).get()
+ << "+" << format_hex(Var.getOffset(), 4) << " ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
+ Printer << " : ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Var.getLength();
+ break;
+ default:
+ Printer.NewLine();
+ Printer << "data ";
+ Printer << "unknown(" << LocType << ") ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Var.getName();
+ break;
+ }
+}
+
+void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
+}
+
+void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
+
+void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ auto PointeeType = Symbol.getPointeeType();
+ if (!PointeeType)
+ return;
+
+ if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
+ FunctionDumper NestedDumper(Printer);
+ FunctionDumper::PointerType Pointer =
+ Symbol.isReference() ? FunctionDumper::PointerType::Reference
+ : FunctionDumper::PointerType::Pointer;
+ NestedDumper.start(*Func, Pointer);
+ } else {
+ if (Symbol.isConstType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
+ if (Symbol.isVolatileType())
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ PointeeType->dump(*this);
+ Printer << (Symbol.isReference() ? "&" : "*");
+ }
+}
+
+void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "typedef ";
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
+}
+
+void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
+ StringRef Name) {
+ if (auto *ArrayType = dyn_cast<PDBSymbolTypeArray>(&Type)) {
+ std::string IndexSpec;
+ raw_string_ostream IndexStream(IndexSpec);
+ std::unique_ptr<PDBSymbol> ElementType = ArrayType->getElementType();
+ while (auto NestedArray = dyn_cast<PDBSymbolTypeArray>(ElementType.get())) {
+ IndexStream << "[";
+ IndexStream << NestedArray->getCount();
+ IndexStream << "]";
+ ElementType = NestedArray->getElementType();
+ }
+ IndexStream << "[" << ArrayType->getCount() << "]";
+ ElementType->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ Printer << IndexStream.str();
+ } else {
+ if (!tryDumpFunctionPointer(Type, Name)) {
+ Type.dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ }
+ }
+}
+
+bool VariableDumper::tryDumpFunctionPointer(const PDBSymbol &Type,
+ StringRef Name) {
+ // Function pointers come across as pointers to function signatures. But the
+ // signature carries no name, so we have to handle this case separately.
+ if (auto *PointerType = dyn_cast<PDBSymbolTypePointer>(&Type)) {
+ auto PointeeType = PointerType->getPointeeType();
+ if (auto *FunctionSig =
+ dyn_cast<PDBSymbolTypeFunctionSig>(PointeeType.get())) {
+ FunctionDumper Dumper(Printer);
+ FunctionDumper::PointerType PT = FunctionDumper::PointerType::Pointer;
+ if (PointerType->isReference())
+ PT = FunctionDumper::PointerType::Reference;
+ std::string NameStr(Name.begin(), Name.end());
+ Dumper.start(*FunctionSig, NameStr.c_str(), PT);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/tools/llvm-pdbdump/VariableDumper.h b/tools/llvm-pdbdump/VariableDumper.h
new file mode 100644
index 000000000000..db8d8ea0e430
--- /dev/null
+++ b/tools/llvm-pdbdump/VariableDumper.h
@@ -0,0 +1,41 @@
+//===- VariableDumper.h - PDBSymDumper implementation for types -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H
+#define LLVM_TOOLS_LLVMPDBDUMP_VARIABLEDUMPER_H
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+class LinePrinter;
+
+class VariableDumper : public PDBSymDumper {
+public:
+ VariableDumper(LinePrinter &P);
+
+ void start(const PDBSymbolData &Var);
+
+ void dump(const PDBSymbolTypeBuiltin &Symbol) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeFunctionSig &Symbol) override;
+ void dump(const PDBSymbolTypePointer &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
+
+private:
+ void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
+ bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name);
+
+ LinePrinter &Printer;
+};
+}
+
+#endif
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp
new file mode 100644
index 000000000000..4a4c64b80cc1
--- /dev/null
+++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -0,0 +1,284 @@
+//===- llvm-pdbdump.cpp - Dump debug info from a PDB file -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Dumps debug information present in PDB files. This utility makes use of
+// the Microsoft Windows SDK, so will not compile or run on non-Windows
+// platforms.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-pdbdump.h"
+#include "CompilandDumper.h"
+#include "ExternalSymbolDumper.h"
+#include "FunctionDumper.h"
+#include "LinePrinter.h"
+#include "TypeDumper.h"
+#include "VariableDumper.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ConvertUTF.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+#if defined(HAVE_DIA_SDK)
+#include <Windows.h>
+#endif
+
+using namespace llvm;
+
+namespace opts {
+
+enum class PDB_DumpType { ByType, ByObjFile, Both };
+
+cl::list<std::string> InputFilenames(cl::Positional,
+ cl::desc("<input PDB files>"),
+ cl::OneOrMore);
+
+cl::OptionCategory TypeCategory("Symbol Type Options");
+cl::OptionCategory FilterCategory("Filtering Options");
+cl::OptionCategory OtherOptions("Other Options");
+
+cl::opt<bool> Compilands("compilands", cl::desc("Display compilands"),
+ cl::cat(TypeCategory));
+cl::opt<bool> Symbols("symbols", cl::desc("Display symbols for each compiland"),
+ cl::cat(TypeCategory));
+cl::opt<bool> Globals("globals", cl::desc("Dump global symbols"),
+ cl::cat(TypeCategory));
+cl::opt<bool> Externals("externals", cl::desc("Dump external symbols"),
+ cl::cat(TypeCategory));
+cl::opt<bool> Types("types", cl::desc("Display types"), cl::cat(TypeCategory));
+cl::opt<bool>
+ All("all", cl::desc("Implies all other options in 'Symbol Types' category"),
+ cl::cat(TypeCategory));
+
+cl::opt<uint64_t> LoadAddress(
+ "load-address",
+ cl::desc("Assume the module is loaded at the specified address"),
+ cl::cat(OtherOptions));
+
+cl::list<std::string>
+ ExcludeTypes("exclude-types",
+ cl::desc("Exclude types by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::list<std::string>
+ ExcludeSymbols("exclude-symbols",
+ cl::desc("Exclude symbols by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::list<std::string>
+ ExcludeCompilands("exclude-compilands",
+ cl::desc("Exclude compilands by regular expression"),
+ cl::ZeroOrMore, cl::cat(FilterCategory));
+cl::opt<bool> ExcludeCompilerGenerated(
+ "no-compiler-generated",
+ cl::desc("Don't show compiler generated types and symbols"),
+ cl::cat(FilterCategory));
+cl::opt<bool>
+ ExcludeSystemLibraries("no-system-libs",
+ cl::desc("Don't show symbols from system libraries"),
+ cl::cat(FilterCategory));
+cl::opt<bool> NoClassDefs("no-class-definitions",
+ cl::desc("Don't display full class definitions"),
+ cl::cat(FilterCategory));
+cl::opt<bool> NoEnumDefs("no-enum-definitions",
+ cl::desc("Don't display full enum definitions"),
+ cl::cat(FilterCategory));
+}
+
+static void dumpInput(StringRef Path) {
+ std::unique_ptr<IPDBSession> Session;
+ PDB_ErrorCode Error =
+ llvm::loadDataForPDB(PDB_ReaderType::DIA, Path, Session);
+ switch (Error) {
+ case PDB_ErrorCode::Success:
+ break;
+ case PDB_ErrorCode::NoPdbImpl:
+ outs() << "Reading PDBs is not supported on this platform.\n";
+ return;
+ case PDB_ErrorCode::InvalidPath:
+ outs() << "Unable to load PDB at '" << Path
+ << "'. Check that the file exists and is readable.\n";
+ return;
+ case PDB_ErrorCode::InvalidFileFormat:
+ outs() << "Unable to load PDB at '" << Path
+ << "'. The file has an unrecognized format.\n";
+ return;
+ default:
+ outs() << "Unable to load PDB at '" << Path
+ << "'. An unknown error occured.\n";
+ return;
+ }
+ if (opts::LoadAddress)
+ Session->setLoadAddress(opts::LoadAddress);
+
+ LinePrinter Printer(2, outs());
+
+ auto GlobalScope(Session->getGlobalScope());
+ std::string FileName(GlobalScope->getSymbolsFileName());
+
+ WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
+ WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
+ Printer.Indent();
+ uint64_t FileSize = 0;
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Size";
+ if (!llvm::sys::fs::file_size(FileName, FileSize)) {
+ Printer << ": " << FileSize << " bytes";
+ } else {
+ Printer << ": (Unable to obtain file size)";
+ }
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Guid";
+ Printer << ": " << GlobalScope->getGuid();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Age";
+ Printer << ": " << GlobalScope->getAge();
+
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Attributes";
+ Printer << ": ";
+ if (GlobalScope->hasCTypes())
+ outs() << "HasCTypes ";
+ if (GlobalScope->hasPrivateSymbols())
+ outs() << "HasPrivateSymbols ";
+ Printer.Unindent();
+
+ if (opts::Compilands) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get()
+ << "---COMPILANDS---";
+ Printer.Indent();
+ auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+ CompilandDumper Dumper(Printer);
+ while (auto Compiland = Compilands->getNext())
+ Dumper.start(*Compiland, false);
+ Printer.Unindent();
+ }
+
+ if (opts::Types) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
+ Printer.Indent();
+ TypeDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ Printer.Unindent();
+ }
+
+ if (opts::Symbols) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
+ Printer.Indent();
+ auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
+ CompilandDumper Dumper(Printer);
+ while (auto Compiland = Compilands->getNext())
+ Dumper.start(*Compiland, true);
+ Printer.Unindent();
+ }
+
+ if (opts::Globals) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---GLOBALS---";
+ Printer.Indent();
+ {
+ FunctionDumper Dumper(Printer);
+ auto Functions = GlobalScope->findAllChildren<PDBSymbolFunc>();
+ while (auto Function = Functions->getNext()) {
+ Printer.NewLine();
+ Dumper.start(*Function, FunctionDumper::PointerType::None);
+ }
+ }
+ {
+ auto Vars = GlobalScope->findAllChildren<PDBSymbolData>();
+ VariableDumper Dumper(Printer);
+ while (auto Var = Vars->getNext())
+ Dumper.start(*Var);
+ }
+ {
+ auto Thunks = GlobalScope->findAllChildren<PDBSymbolThunk>();
+ CompilandDumper Dumper(Printer);
+ while (auto Thunk = Thunks->getNext())
+ Dumper.dump(*Thunk);
+ }
+ Printer.Unindent();
+ }
+ if (opts::Externals) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---EXTERNALS---";
+ Printer.Indent();
+ ExternalSymbolDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ }
+ outs().flush();
+}
+
+int main(int argc_, const char *argv_[]) {
+ // Print a stack trace if we signal out.
+ sys::PrintStackTraceOnErrorSignal();
+ PrettyStackTraceProgram X(argc_, argv_);
+
+ SmallVector<const char *, 256> argv;
+ llvm::SpecificBumpPtrAllocator<char> ArgAllocator;
+ std::error_code EC = llvm::sys::Process::GetArgumentVector(
+ argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator);
+ if (EC) {
+ llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n';
+ return 1;
+ }
+
+ llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+ cl::ParseCommandLineOptions(argv.size(), argv.data(), "LLVM PDB Dumper\n");
+ if (opts::All) {
+ opts::Compilands = true;
+ opts::Symbols = true;
+ opts::Globals = true;
+ opts::Types = true;
+ opts::Externals = true;
+ }
+ if (opts::ExcludeCompilerGenerated) {
+ opts::ExcludeTypes.push_back("__vc_attributes");
+ opts::ExcludeCompilands.push_back("* Linker *");
+ }
+ if (opts::ExcludeSystemLibraries) {
+ opts::ExcludeCompilands.push_back(
+ "f:\\binaries\\Intermediate\\vctools\\crt_bld");
+ }
+
+#if defined(HAVE_DIA_SDK)
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+#endif
+
+ std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(),
+ dumpInput);
+
+#if defined(HAVE_DIA_SDK)
+ CoUninitialize();
+#endif
+
+ return 0;
+}
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h
new file mode 100644
index 000000000000..586a9ea374ed
--- /dev/null
+++ b/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -0,0 +1,32 @@
+//===- llvm-pdbdump.h ----------------------------------------- *- C++ --*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace opts {
+extern llvm::cl::opt<bool> Compilands;
+extern llvm::cl::opt<bool> Symbols;
+extern llvm::cl::opt<bool> Globals;
+extern llvm::cl::opt<bool> Types;
+extern llvm::cl::opt<bool> All;
+
+extern llvm::cl::opt<bool> ExcludeCompilerGenerated;
+
+extern llvm::cl::opt<bool> NoClassDefs;
+extern llvm::cl::opt<bool> NoEnumDefs;
+extern llvm::cl::list<std::string> ExcludeTypes;
+extern llvm::cl::list<std::string> ExcludeSymbols;
+extern llvm::cl::list<std::string> ExcludeCompilands;
+}
+
+#endif \ No newline at end of file
diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp
index 25531c776a31..1bfdb181d7a9 100644
--- a/tools/llvm-profdata/llvm-profdata.cpp
+++ b/tools/llvm-profdata/llvm-profdata.cpp
@@ -22,6 +22,7 @@
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
@@ -38,7 +39,8 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") {
enum ProfileKinds { instr, sample };
-void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
+static void mergeInstrProfile(const cl::list<std::string> &Inputs,
+ StringRef OutputFilename) {
if (OutputFilename.compare("-") == 0)
exitWithError("Cannot write indexed profdata format to stdout.");
@@ -64,8 +66,9 @@ void mergeInstrProfile(cl::list<std::string> Inputs, StringRef OutputFilename) {
Writer.write(Output);
}
-void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
- sampleprof::SampleProfileFormat OutputFormat) {
+static void mergeSampleProfile(const cl::list<std::string> &Inputs,
+ StringRef OutputFilename,
+ sampleprof::SampleProfileFormat OutputFormat) {
using namespace sampleprof;
auto WriterOrErr = SampleProfileWriter::create(OutputFilename, OutputFormat);
if (std::error_code EC = WriterOrErr.getError())
@@ -95,7 +98,7 @@ void mergeSampleProfile(cl::list<std::string> Inputs, StringRef OutputFilename,
Writer->write(ProfileMap);
}
-int merge_main(int argc, const char *argv[]) {
+static int merge_main(int argc, const char *argv[]) {
cl::list<std::string> Inputs(cl::Positional, cl::Required, cl::OneOrMore,
cl::desc("<filenames...>"));
@@ -128,9 +131,9 @@ int merge_main(int argc, const char *argv[]) {
return 0;
}
-int showInstrProfile(std::string Filename, bool ShowCounts,
- bool ShowAllFunctions, std::string ShowFunction,
- raw_fd_ostream &OS) {
+static int showInstrProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
auto ReaderOrErr = InstrProfReader::create(Filename);
if (std::error_code EC = ReaderOrErr.getError())
exitWithError(EC.message(), Filename);
@@ -181,9 +184,9 @@ int showInstrProfile(std::string Filename, bool ShowCounts,
return 0;
}
-int showSampleProfile(std::string Filename, bool ShowCounts,
- bool ShowAllFunctions, std::string ShowFunction,
- raw_fd_ostream &OS) {
+static int showSampleProfile(std::string Filename, bool ShowCounts,
+ bool ShowAllFunctions, std::string ShowFunction,
+ raw_fd_ostream &OS) {
using namespace sampleprof;
auto ReaderOrErr = SampleProfileReader::create(Filename, getGlobalContext());
if (std::error_code EC = ReaderOrErr.getError())
@@ -199,7 +202,7 @@ int showSampleProfile(std::string Filename, bool ShowCounts,
return 0;
}
-int show_main(int argc, const char *argv[]) {
+static int show_main(int argc, const char *argv[]) {
cl::opt<std::string> Filename(cl::Positional, cl::Required,
cl::desc("<profdata-file>"));
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 156e39a35fd5..141211134ffd 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -71,7 +71,7 @@ private:
void printBaseOfDataField(const pe32_header *Hdr);
void printBaseOfDataField(const pe32plus_header *Hdr);
- void printCodeViewLineTables(const SectionRef &Section);
+ void printCodeViewDebugInfo(const SectionRef &Section);
void printCodeViewSymbolsSubsection(StringRef Subsection,
const SectionRef &Section,
@@ -469,7 +469,7 @@ void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) {
void COFFDumper::printBaseOfDataField(const pe32plus_header *) {}
-void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
+void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) {
StringRef Data;
if (error(Section.getContents(Data)))
return;
@@ -477,7 +477,7 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
SmallVector<StringRef, 10> FunctionNames;
StringMap<StringRef> FunctionLineTables;
- ListScope D(W, "CodeViewLineTables");
+ ListScope D(W, "CodeViewDebugInfo");
{
// FIXME: Add more offset correctness checks.
DataExtractor DE(Data, true, 4);
@@ -503,14 +503,17 @@ void COFFDumper::printCodeViewLineTables(const SectionRef &Section) {
return;
}
- // Print the raw contents to simplify debugging if anything goes wrong
- // afterwards.
StringRef Contents = Data.substr(Offset, PayloadSize);
- W.printBinaryBlock("Contents", Contents);
+ if (opts::CodeViewSubsectionBytes) {
+ // Print the raw contents to simplify debugging if anything goes wrong
+ // afterwards.
+ W.printBinaryBlock("Contents", Contents);
+ }
switch (SubSectionType) {
case COFF::DEBUG_SYMBOL_SUBSECTION:
- printCodeViewSymbolsSubsection(Contents, Section, Offset);
+ if (opts::SectionSymbols)
+ printCodeViewSymbolsSubsection(Contents, Section, Offset);
break;
case COFF::DEBUG_LINE_TABLE_SUBSECTION: {
// Holds a PC to file:line table. Some data to parse this subsection is
@@ -695,10 +698,20 @@ void COFFDumper::printCodeViewSymbolsSubsection(StringRef Subsection,
InFunctionScope = false;
break;
}
- default:
+ default: {
+ if (opts::CodeViewSubsectionBytes) {
+ ListScope S(W, "Record");
+ W.printHex("Size", Size);
+ W.printHex("Type", Type);
+
+ StringRef Contents = DE.getData().substr(Offset, Size);
+ W.printBinaryBlock("Contents", Contents);
+ }
+
Offset += Size;
break;
}
+ }
}
if (InFunctionScope)
@@ -747,8 +760,8 @@ void COFFDumper::printSections() {
}
}
- if (Name == ".debug$S" && opts::CodeViewLineTables)
- printCodeViewLineTables(Sec);
+ if (Name == ".debug$S" && opts::CodeView)
+ printCodeViewDebugInfo(Sec);
if (opts::SectionData &&
!(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
@@ -1107,6 +1120,7 @@ static StringRef getBaseRelocTypeName(uint8_t Type) {
case COFF::IMAGE_REL_BASED_LOW: return "LOW";
case COFF::IMAGE_REL_BASED_HIGHLOW: return "HIGHLOW";
case COFF::IMAGE_REL_BASED_HIGHADJ: return "HIGHADJ";
+ case COFF::IMAGE_REL_BASED_ARM_MOV32T: return "ARM_MOV32(T)";
case COFF::IMAGE_REL_BASED_DIR64: return "DIR64";
default: return "unknown (" + llvm::utostr(Type) + ")";
}
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index d68c78682d23..a20512f20534 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MipsABIFlags.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
@@ -56,6 +57,7 @@ public:
void printAttributes() override;
void printMipsPLTGOT() override;
+ void printMipsABIFlags() override;
private:
typedef ELFFile<ELFT> ELFO;
@@ -170,6 +172,16 @@ findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) {
return nullptr;
}
+template <class ELFT>
+static const typename ELFFile<ELFT>::Elf_Shdr *
+findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) {
+ for (const auto &Shdr : Obj.sections()) {
+ if (Name == errorOrDefault(Obj.getSectionName(&Shdr)))
+ return &Shdr;
+ }
+ return nullptr;
+}
+
static const EnumEntry<unsigned> ElfClass[] = {
{ "None", ELF::ELFCLASSNONE },
{ "32-bit", ELF::ELFCLASS32 },
@@ -207,6 +219,7 @@ static const EnumEntry<unsigned> ElfOSABI[] = {
{ "NSK", ELF::ELFOSABI_NSK },
{ "AROS", ELF::ELFOSABI_AROS },
{ "FenixOS", ELF::ELFOSABI_FENIXOS },
+ { "CloudABI", ELF::ELFOSABI_CLOUDABI },
{ "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI },
{ "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX },
{ "ARM", ELF::ELFOSABI_ARM },
@@ -372,9 +385,10 @@ static const EnumEntry<unsigned> ElfMachineType[] = {
};
static const EnumEntry<unsigned> ElfSymbolBindings[] = {
- { "Local", ELF::STB_LOCAL },
- { "Global", ELF::STB_GLOBAL },
- { "Weak", ELF::STB_WEAK }
+ { "Local", ELF::STB_LOCAL },
+ { "Global", ELF::STB_GLOBAL },
+ { "Weak", ELF::STB_WEAK },
+ { "Unique", ELF::STB_GNU_UNIQUE }
};
static const EnumEntry<unsigned> ElfSymbolTypes[] = {
@@ -469,6 +483,7 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS);
}
}
@@ -503,10 +518,33 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_CPIC),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI2),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_32BITMODE),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_FP64),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NAN2008),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI32),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI64),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_3900),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4010),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4100),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4650),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4120),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4111),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_SB1),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_XLR),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON2),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON3),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5400),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5900),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5500),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_9000),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2E),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2F),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS3A),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MICROMIPS),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_M16),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_MDMX),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_1),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_2),
LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_3),
@@ -549,7 +587,8 @@ void ELFDumper<ELFT>::printFileHeaders() {
W.printHex ("SectionHeaderOffset", Header->e_shoff);
if (Header->e_machine == EM_MIPS)
W.printFlags("Flags", Header->e_flags, makeArrayRef(ElfHeaderMipsFlags),
- unsigned(ELF::EF_MIPS_ARCH));
+ unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
+ unsigned(ELF::EF_MIPS_MACH));
else
W.printFlags("Flags", Header->e_flags);
W.printNumber("HeaderSize", Header->e_ehsize);
@@ -739,6 +778,7 @@ static const char *getTypeString(uint64_t Type) {
LLVM_READOBJ_TYPE_CASE(FINI_ARRAY);
LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ);
LLVM_READOBJ_TYPE_CASE(FLAGS);
+ LLVM_READOBJ_TYPE_CASE(FLAGS_1);
LLVM_READOBJ_TYPE_CASE(HASH);
LLVM_READOBJ_TYPE_CASE(INIT);
LLVM_READOBJ_TYPE_CASE(INIT_ARRAY);
@@ -780,6 +820,7 @@ static const char *getTypeString(uint64_t Type) {
LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM);
LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP);
LLVM_READOBJ_TYPE_CASE(MIPS_PLTGOT);
+ LLVM_READOBJ_TYPE_CASE(MIPS_OPTIONS);
default: return "unknown";
}
}
@@ -797,6 +838,34 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags[] = {
LLVM_READOBJ_DT_FLAG_ENT(DF, STATIC_TLS)
};
+static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOW),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAL),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GROUP),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODELETE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, LOADFLTR),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, INITFIRST),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOOPEN),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, ORIGIN),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DIRECT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, TRANS),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, INTERPOSE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODEFLIB),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODUMP),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOHDR),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, EDITED),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON)
+};
+
static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = {
LLVM_READOBJ_DT_FLAG_ENT(RHF, NONE),
LLVM_READOBJ_DT_FLAG_ENT(RHF, QUICKSTART),
@@ -871,6 +940,7 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value,
case DT_MIPS_GOTSYM:
case DT_MIPS_RLD_MAP:
case DT_MIPS_PLTGOT:
+ case DT_MIPS_OPTIONS:
OS << format("0x%" PRIX64, Value);
break;
case DT_RELCOUNT:
@@ -909,6 +979,9 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value,
case DT_FLAGS:
printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
break;
+ case DT_FLAGS_1:
+ printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS);
+ break;
}
}
@@ -1240,3 +1313,112 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() {
MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr);
}
+
+static const EnumEntry<unsigned> ElfMipsISAExtType[] = {
+ {"None", Mips::AFL_EXT_NONE},
+ {"Broadcom SB-1", Mips::AFL_EXT_SB1},
+ {"Cavium Networks Octeon", Mips::AFL_EXT_OCTEON},
+ {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2},
+ {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP},
+ {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3},
+ {"LSI R4010", Mips::AFL_EXT_4010},
+ {"Loongson 2E", Mips::AFL_EXT_LOONGSON_2E},
+ {"Loongson 2F", Mips::AFL_EXT_LOONGSON_2F},
+ {"Loongson 3A", Mips::AFL_EXT_LOONGSON_3A},
+ {"MIPS R4650", Mips::AFL_EXT_4650},
+ {"MIPS R5900", Mips::AFL_EXT_5900},
+ {"MIPS R10000", Mips::AFL_EXT_10000},
+ {"NEC VR4100", Mips::AFL_EXT_4100},
+ {"NEC VR4111/VR4181", Mips::AFL_EXT_4111},
+ {"NEC VR4120", Mips::AFL_EXT_4120},
+ {"NEC VR5400", Mips::AFL_EXT_5400},
+ {"NEC VR5500", Mips::AFL_EXT_5500},
+ {"RMI Xlr", Mips::AFL_EXT_XLR},
+ {"Toshiba R3900", Mips::AFL_EXT_3900}
+};
+
+static const EnumEntry<unsigned> ElfMipsASEFlags[] = {
+ {"DSP", Mips::AFL_ASE_DSP},
+ {"DSPR2", Mips::AFL_ASE_DSPR2},
+ {"Enhanced VA Scheme", Mips::AFL_ASE_EVA},
+ {"MCU", Mips::AFL_ASE_MCU},
+ {"MDMX", Mips::AFL_ASE_MDMX},
+ {"MIPS-3D", Mips::AFL_ASE_MIPS3D},
+ {"MT", Mips::AFL_ASE_MT},
+ {"SmartMIPS", Mips::AFL_ASE_SMARTMIPS},
+ {"VZ", Mips::AFL_ASE_VIRT},
+ {"MSA", Mips::AFL_ASE_MSA},
+ {"MIPS16", Mips::AFL_ASE_MIPS16},
+ {"microMIPS", Mips::AFL_ASE_MICROMIPS},
+ {"XPA", Mips::AFL_ASE_XPA}
+};
+
+static const EnumEntry<unsigned> ElfMipsFpABIType[] = {
+ {"Hard or soft float", Mips::Val_GNU_MIPS_ABI_FP_ANY},
+ {"Hard float (double precision)", Mips::Val_GNU_MIPS_ABI_FP_DOUBLE},
+ {"Hard float (single precision)", Mips::Val_GNU_MIPS_ABI_FP_SINGLE},
+ {"Soft float", Mips::Val_GNU_MIPS_ABI_FP_SOFT},
+ {"Hard float (MIPS32r2 64-bit FPU 12 callee-saved)",
+ Mips::Val_GNU_MIPS_ABI_FP_OLD_64},
+ {"Hard float (32-bit CPU, Any FPU)", Mips::Val_GNU_MIPS_ABI_FP_XX},
+ {"Hard float (32-bit CPU, 64-bit FPU)", Mips::Val_GNU_MIPS_ABI_FP_64},
+ {"Hard float compat (32-bit CPU, 64-bit FPU)",
+ Mips::Val_GNU_MIPS_ABI_FP_64A}
+};
+
+static const EnumEntry<unsigned> ElfMipsFlags1[] {
+ {"ODDSPREG", Mips::AFL_FLAGS1_ODDSPREG},
+};
+
+static int getMipsRegisterSize(uint8_t Flag) {
+ switch (Flag) {
+ case Mips::AFL_REG_NONE:
+ return 0;
+ case Mips::AFL_REG_32:
+ return 32;
+ case Mips::AFL_REG_64:
+ return 64;
+ case Mips::AFL_REG_128:
+ return 128;
+ default:
+ return -1;
+ }
+}
+
+template <class ELFT> void ELFDumper<ELFT>::printMipsABIFlags() {
+ const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags");
+ if (!Shdr) {
+ W.startLine() << "There is no .MIPS.abiflags section in the file.\n";
+ return;
+ }
+ ErrorOr<ArrayRef<uint8_t>> Sec = Obj->getSectionContents(Shdr);
+ if (!Sec) {
+ W.startLine() << "The .MIPS.abiflags section is empty.\n";
+ return;
+ }
+ if (Sec->size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) {
+ W.startLine() << "The .MIPS.abiflags section has a wrong size.\n";
+ return;
+ }
+
+ auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec->data());
+
+ raw_ostream &OS = W.getOStream();
+ DictScope GS(W, "MIPS ABI Flags");
+
+ W.printNumber("Version", Flags->version);
+ W.startLine() << "ISA: ";
+ if (Flags->isa_rev <= 1)
+ OS << format("MIPS%u", Flags->isa_level);
+ else
+ OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev);
+ OS << "\n";
+ W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType));
+ W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags));
+ W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType));
+ W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size));
+ W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size));
+ W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size));
+ W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1));
+ W.printHex("Flags 2", Flags->flags2);
+}
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
index 7e8fdadd855b..40691a222f04 100644
--- a/tools/llvm-readobj/MachODumper.cpp
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -203,31 +203,6 @@ static const EnumEntry<uint32_t> MachOHeaderFlags[] = {
LLVM_READOBJ_ENUM_ENT(MachO, MH_APP_EXTENSION_SAFE),
};
-static const EnumEntry<unsigned> MachOSectionTypes[] = {
- { "Regular" , 0x00 },
- { "ZeroFill" , 0x01 },
- { "CStringLiterals" , 0x02 },
- { "4ByteLiterals" , 0x03 },
- { "8ByteLiterals" , 0x04 },
- { "LiteralPointers" , 0x05 },
- { "NonLazySymbolPointers" , 0x06 },
- { "LazySymbolPointers" , 0x07 },
- { "SymbolStubs" , 0x08 },
- { "ModInitFuncs" , 0x09 },
- { "ModTermFuncs" , 0x0A },
- { "Coalesced" , 0x0B },
- { "GBZeroFill" , 0x0C },
- { "Interposing" , 0x0D },
- { "16ByteLiterals" , 0x0E },
- { "DTraceDOF" , 0x0F },
- { "LazyDylibSymbolPoints" , 0x10 },
- { "ThreadLocalRegular" , 0x11 },
- { "ThreadLocalZerofill" , 0x12 },
- { "ThreadLocalVariables" , 0x13 },
- { "ThreadLocalVariablePointers" , 0x14 },
- { "ThreadLocalInitFunctionPointers", 0x15 }
-};
-
static const EnumEntry<unsigned> MachOSectionAttributes[] = {
{ "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ },
{ "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ },
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index 27e658fc731a..5750d6ffd286 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -42,6 +42,7 @@ public:
// Only implemented for MIPS ELF at this time.
virtual void printMipsPLTGOT() { }
+ virtual void printMipsABIFlags() { }
// Only implemented for PE/COFF.
virtual void printCOFFImports() { }
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
index 2fc53eeeec4a..245588ba0600 100644
--- a/tools/llvm-readobj/StreamWriter.h
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -96,9 +96,10 @@ public:
}
}
- template<typename T, typename TFlag>
- void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags,
- TFlag EnumMask = TFlag(0)) {
+ template <typename T, typename TFlag>
+ void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
+ TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
+ TFlag EnumMask3 = {}) {
typedef EnumEntry<TFlag> FlagEntry;
typedef SmallVector<FlagEntry, 10> FlagVector;
FlagVector SetFlags;
@@ -107,6 +108,13 @@ public:
if (Flag.Value == 0)
continue;
+ TFlag EnumMask{};
+ if (Flag.Value & EnumMask1)
+ EnumMask = EnumMask1;
+ else if (Flag.Value & EnumMask2)
+ EnumMask = EnumMask2;
+ else if (Flag.Value & EnumMask3)
+ EnumMask = EnumMask3;
bool IsEnum = (Flag.Value & EnumMask) != 0;
if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
(IsEnum && (Value & EnumMask) == Flag.Value)) {
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index f95fea8ec3e8..be7bbe94d9ea 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -25,6 +25,7 @@
#include "StreamWriter.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
@@ -127,9 +128,14 @@ namespace opts {
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
- // -codeview-linetables
- cl::opt<bool> CodeViewLineTables("codeview-linetables",
- cl::desc("Display CodeView line table information"));
+ // -codeview
+ cl::opt<bool> CodeView("codeview",
+ cl::desc("Display CodeView debug information"));
+
+ // -codeview-subsection-bytes
+ cl::opt<bool> CodeViewSubsectionBytes(
+ "codeview-subsection-bytes",
+ cl::desc("Dump raw contents of codeview debug sections and records"));
// -arm-attributes, -a
cl::opt<bool> ARMAttributes("arm-attributes",
@@ -142,6 +148,10 @@ namespace opts {
MipsPLTGOT("mips-plt-got",
cl::desc("Display the MIPS GOT and PLT GOT sections"));
+ // -mips-abi-flags
+ cl::opt<bool> MipsABIFlags("mips-abi-flags",
+ cl::desc("Display the MIPS.abiflags section"));
+
// -coff-imports
cl::opt<bool>
COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
@@ -281,9 +291,12 @@ static void dumpObject(const ObjectFile *Obj) {
if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())
if (opts::ARMAttributes)
Dumper->printAttributes();
- if (isMipsArch(Obj->getArch()) && Obj->isELF())
+ if (isMipsArch(Obj->getArch()) && Obj->isELF()) {
if (opts::MipsPLTGOT)
Dumper->printMipsPLTGOT();
+ if (opts::MipsABIFlags)
+ Dumper->printMipsABIFlags();
+ }
if (opts::COFFImports)
Dumper->printCOFFImports();
if (opts::COFFExports)
@@ -315,6 +328,18 @@ static void dumpArchive(const Archive *Arc) {
}
}
+/// @brief Dumps each object file in \a MachO Universal Binary;
+static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) {
+ for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) {
+ ErrorOr<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile();
+ if (ObjOrErr)
+ dumpObject(&*ObjOrErr.get());
+ else if (ErrorOr<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive())
+ dumpArchive(&*AOrErr.get());
+ else
+ reportError(UBinary->getFileName(), ObjOrErr.getError().message());
+ }
+}
/// @brief Opens \a File and dumps it.
static void dumpInput(StringRef File) {
@@ -334,6 +359,9 @@ static void dumpInput(StringRef File) {
if (Archive *Arc = dyn_cast<Archive>(&Binary))
dumpArchive(Arc);
+ else if (MachOUniversalBinary *UBinary =
+ dyn_cast<MachOUniversalBinary>(&Binary))
+ dumpMachOUniversalBinary(UBinary);
else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary))
dumpObject(Obj);
else
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index 1c334178a24e..74b9a60d34b2 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -36,7 +36,8 @@ namespace opts {
extern llvm::cl::opt<bool> DynamicSymbols;
extern llvm::cl::opt<bool> UnwindInfo;
extern llvm::cl::opt<bool> ExpandRelocs;
- extern llvm::cl::opt<bool> CodeViewLineTables;
+ extern llvm::cl::opt<bool> CodeView;
+ extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
extern llvm::cl::opt<bool> ARMAttributes;
extern llvm::cl::opt<bool> MipsPLTGOT;
} // namespace opts
diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt
index e294760801bb..c1acbe5846bd 100644
--- a/tools/llvm-rtdyld/CMakeLists.txt
+++ b/tools/llvm-rtdyld/CMakeLists.txt
@@ -1,6 +1,6 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
- DebugInfo
+ DebugInfoDWARF
ExecutionEngine
MC
Object
diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile
index 9de753ef22ad..3e868b985872 100644
--- a/tools/llvm-rtdyld/Makefile
+++ b/tools/llvm-rtdyld/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-rtdyld
-LINK_COMPONENTS := all-targets support MC object RuntimeDyld MCJIT debuginfo
+LINK_COMPONENTS := all-targets support MC object RuntimeDyld MCJIT DebugInfoDWARF
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 5b6f301994db..e87f1e2d4c19 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -13,6 +13,8 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -21,6 +23,7 @@
#include "llvm/MC/MCInstPrinter.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/DynamicLibrary.h"
@@ -45,6 +48,7 @@ InputFileList(cl::Positional, cl::ZeroOrMore,
enum ActionType {
AC_Execute,
AC_PrintLineInfo,
+ AC_PrintDebugLineInfo,
AC_Verify
};
@@ -55,6 +59,8 @@ Action(cl::desc("Action to perform:"),
"Load, link, and execute the inputs."),
clEnumValN(AC_PrintLineInfo, "printline",
"Load, link, and print line information for each function."),
+ clEnumValN(AC_PrintDebugLineInfo, "printdebugline",
+ "Load, link, and print line information for each function using the debug object"),
clEnumValN(AC_Verify, "verify",
"Load, link and verify the resulting memory image."),
clEnumValEnd));
@@ -186,7 +192,9 @@ static void loadDylibs() {
/* *** */
-static int printLineInfoForInput() {
+static int printLineInfoForInput(bool LoadObjects, bool UseDebugObj) {
+ assert(LoadObjects || !UseDebugObj);
+
// Load any dylibs requested on the command line.
loadDylibs();
@@ -196,7 +204,7 @@ static int printLineInfoForInput() {
for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
- RuntimeDyld Dyld(&MemMgr);
+ RuntimeDyld Dyld(MemMgr, MemMgr);
// Load the input memory buffer.
@@ -213,24 +221,32 @@ static int printLineInfoForInput() {
ObjectFile &Obj = **MaybeObj;
- // Load the object file
- std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo =
- Dyld.loadObject(Obj);
+ OwningBinary<ObjectFile> DebugObj;
+ std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo = nullptr;
+ ObjectFile *SymbolObj = &Obj;
+ if (LoadObjects) {
+ // Load the object file
+ LoadedObjInfo =
+ Dyld.loadObject(Obj);
- if (Dyld.hasError())
- return Error(Dyld.getErrorString());
+ if (Dyld.hasError())
+ return Error(Dyld.getErrorString());
- // Resolve all the relocations we can.
- Dyld.resolveRelocations();
+ // Resolve all the relocations we can.
+ Dyld.resolveRelocations();
- OwningBinary<ObjectFile> DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
+ if (UseDebugObj) {
+ DebugObj = LoadedObjInfo->getObjectForDebug(Obj);
+ SymbolObj = DebugObj.getBinary();
+ }
+ }
std::unique_ptr<DIContext> Context(
- DIContext::getDWARFContext(*DebugObj.getBinary()));
+ new DWARFContextInMemory(*SymbolObj,LoadedObjInfo.get()));
// Use symbol info to iterate functions in the object.
- for (object::symbol_iterator I = DebugObj.getBinary()->symbol_begin(),
- E = DebugObj.getBinary()->symbol_end();
+ for (object::symbol_iterator I = SymbolObj->symbol_begin(),
+ E = SymbolObj->symbol_end();
I != E; ++I) {
object::SymbolRef::Type SymType;
if (I->getType(SymType)) continue;
@@ -242,7 +258,21 @@ static int printLineInfoForInput() {
if (I->getAddress(Addr)) continue;
if (I->getSize(Size)) continue;
- outs() << "Function: " << Name << ", Size = " << Size << "\n";
+ // If we're not using the debug object, compute the address of the
+ // symbol in memory (rather than that in the unrelocated object file)
+ // and use that to query the DWARFContext.
+ if (!UseDebugObj && LoadObjects) {
+ object::section_iterator Sec(SymbolObj->section_end());
+ I->getSection(Sec);
+ StringRef SecName;
+ Sec->getName(SecName);
+ uint64_t SectionLoadAddress =
+ LoadedObjInfo->getSectionLoadAddress(SecName);
+ if (SectionLoadAddress != 0)
+ Addr += SectionLoadAddress - Sec->getAddress();
+ }
+
+ outs() << "Function: " << Name << ", Size = " << Size << ", Addr = " << Addr << "\n";
DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size);
DILineInfoTable::iterator Begin = Lines.begin();
@@ -264,7 +294,12 @@ static int executeInput() {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
- RuntimeDyld Dyld(&MemMgr);
+ RuntimeDyld Dyld(MemMgr, MemMgr);
+
+ // FIXME: Preserve buffers until resolveRelocations time to work around a bug
+ // in RuntimeDyldELF.
+ // This fixme should be fixed ASAP. This is a very brittle workaround.
+ std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
@@ -282,6 +317,7 @@ static int executeInput() {
return Error("unable to create object file: '" + EC.message() + "'");
ObjectFile &Obj = **MaybeObj;
+ InputBuffers.push_back(std::move(*InputBuffer));
// Load the object file
Dyld.loadObject(Obj);
@@ -298,7 +334,7 @@ static int executeInput() {
// FIXME: Error out if there are unresolved relocations.
// Get the address of the entry point (_main by default).
- void *MainAddress = Dyld.getSymbolAddress(EntryPoint);
+ void *MainAddress = Dyld.getSymbolLocalAddress(EntryPoint);
if (!MainAddress)
return Error("no definition for '" + EntryPoint + "'");
@@ -339,7 +375,7 @@ static int checkAllExpressions(RuntimeDyldChecker &Checker) {
return 0;
}
-std::map<void*, uint64_t>
+static std::map<void *, uint64_t>
applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
std::map<void*, uint64_t> SpecificMappings;
@@ -397,9 +433,9 @@ applySpecificSectionMappings(RuntimeDyldChecker &Checker) {
// Defaults to zero. Set to something big
// (e.g. 1 << 32) to stress-test stubs, GOTs, etc.
//
-void remapSections(const llvm::Triple &TargetTriple,
- const TrivialMemoryManager &MemMgr,
- RuntimeDyldChecker &Checker) {
+static void remapSections(const llvm::Triple &TargetTriple,
+ const TrivialMemoryManager &MemMgr,
+ RuntimeDyldChecker &Checker) {
// Set up a work list (section addr/size pairs).
typedef std::list<std::pair<void*, uint64_t>> WorklistT;
@@ -506,18 +542,23 @@ static int linkAndVerify() {
std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo());
std::unique_ptr<MCInstPrinter> InstPrinter(
- TheTarget->createMCInstPrinter(0, *MAI, *MII, *MRI, *STI));
+ TheTarget->createMCInstPrinter(Triple(TripleName), 0, *MAI, *MII, *MRI));
// Load any dylibs requested on the command line.
loadDylibs();
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
- RuntimeDyld Dyld(&MemMgr);
+ RuntimeDyld Dyld(MemMgr, MemMgr);
Dyld.setProcessAllSections(true);
RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(),
llvm::dbgs());
+ // FIXME: Preserve buffers until resolveRelocations time to work around a bug
+ // in RuntimeDyldELF.
+ // This fixme should be fixed ASAP. This is a very brittle workaround.
+ std::vector<std::unique_ptr<MemoryBuffer>> InputBuffers;
+
// If we don't have any input files, read from stdin.
if (!InputFileList.size())
InputFileList.push_back("-");
@@ -536,6 +577,7 @@ static int linkAndVerify() {
return Error("unable to create object file: '" + EC.message() + "'");
ObjectFile &Obj = **MaybeObj;
+ InputBuffers.push_back(std::move(*InputBuffer));
// Load the object file
Dyld.loadObject(Obj);
@@ -579,8 +621,10 @@ int main(int argc, char **argv) {
switch (Action) {
case AC_Execute:
return executeInput();
+ case AC_PrintDebugLineInfo:
+ return printLineInfoForInput(true,true);
case AC_PrintLineInfo:
- return printLineInfoForInput();
+ return printLineInfoForInput(true,false);
case AC_Verify:
return linkAndVerify();
}
diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt
index a896a8a26b52..bc1b658ba726 100644
--- a/tools/llvm-shlib/CMakeLists.txt
+++ b/tools/llvm-shlib/CMakeLists.txt
@@ -42,7 +42,9 @@ set(SOURCES
libllvm.cpp
)
-if(NOT DEFINED LLVM_EXPORTED_SYMBOL_FILE)
+llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS})
+
+if(NOT DEFINED LLVM_DYLIB_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.")
@@ -53,44 +55,57 @@ if(NOT DEFINED LLVM_EXPORTED_SYMBOL_FILE)
set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_BINARY_DIR}/libllvm.exports)
- llvm_map_components_to_libnames(LIB_NAMES ${LLVM_DYLIB_COMPONENTS})
-
- foreach (lib ${LIB_NAMES})
-
- set(LIB_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
- set(LIB_NAME ${LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${lib})
- set(LIB_PATH ${LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
- set(LIB_EXPORTS_PATH ${LIB_NAME}.exports)
-
- list(APPEND LLVM_DYLIB_REQUIRED_EXPORTS ${LIB_EXPORTS_PATH})
+ if (NOT LLVM_DYLIB_EXPORT_ALL)
+ foreach (lib ${LIB_NAMES})
+ set(LIB_DIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
+ set(LIB_NAME ${LIB_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${lib})
+ set(LIB_PATH ${LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
+ set(LIB_EXPORTS_PATH ${LIB_NAME}.exports)
+ list(APPEND LLVM_DYLIB_REQUIRED_EXPORTS ${LIB_EXPORTS_PATH})
+
+
+ add_custom_command(OUTPUT ${LIB_EXPORTS_PATH}
+ COMMAND nm ${LIB_PATH} | awk "/T _LLVM/ || /T LLVM/ { print $3 }" | sort -u | sed -e "s/^_//g" > ${LIB_EXPORTS_PATH}
+ WORKING_DIRECTORY ${LIB_DIR}
+ DEPENDS ${lib}
+ COMMENT "Generating Export list for ${lib}..."
+ VERBATIM )
+ endforeach ()
+ endif()
- 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}
+ if (LLVM_DYLIB_EXPORT_ALL)
+ add_custom_command(OUTPUT ${LLVM_EXPORTED_SYMBOL_FILE}
+ COMMAND echo \"LLVM*\" > ${LLVM_EXPORTED_SYMBOL_FILE} && echo \"_Z*llvm*\" >> ${LLVM_EXPORTED_SYMBOL_FILE}
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...")
+ DEPENDS ${LLVM_DYLIB_REQUIRED_EXPORTS}
+ COMMENT "Generating combined export list...")
+ else()
+ 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_custom_target(libLLVMExports DEPENDS ${LLVM_EXPORTED_SYMBOL_FILE})
+else()
+ set(LLVM_EXPORTED_SYMBOL_FILE ${LLVM_DYLIB_EXPORTED_SYMBOL_FILE})
+ add_custom_target(libLLVMExports DEPENDS ${LLVM_EXPORTED_SYMBOL_FILE})
endif()
add_llvm_library(LLVM SHARED ${SOURCES})
+list(REMOVE_DUPLICATES LIB_NAMES)
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)
+elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin")
+ set(LIB_NAMES -Wl,-all_load ${LIB_NAMES})
endif()
-target_link_libraries(LLVM ${cmake_2_8_12_PRIVATE} ${LIB_NAMES})
+target_link_libraries(LLVM PRIVATE ${LIB_NAMES})
-add_dependencies(LLVM ${LLVM_EXPORTED_SYMBOL_FILE})
+add_dependencies(LLVM libLLVMExports)
if (APPLE)
set_property(TARGET LLVM APPEND_STRING PROPERTY
diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp
index fc211e3180b4..0e0dd59ce92f 100644
--- a/tools/llvm-size/llvm-size.cpp
+++ b/tools/llvm-size/llvm-size.cpp
@@ -709,7 +709,7 @@ int main(int argc, char **argv) {
ToolName = argv[0];
if (OutputFormatShort.getNumOccurrences())
- OutputFormat = OutputFormatShort;
+ OutputFormat = static_cast<OutputFormatTy>(OutputFormatShort);
if (RadixShort.getNumOccurrences())
Radix = RadixShort;
diff --git a/tools/llvm-stress/CMakeLists.txt b/tools/llvm-stress/CMakeLists.txt
index 106ced141944..d5c10e13f5b3 100644
--- a/tools/llvm-stress/CMakeLists.txt
+++ b/tools/llvm-stress/CMakeLists.txt
@@ -7,4 +7,4 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(llvm-stress
llvm-stress.cpp
)
-set_target_properties(llvm-stress PROPERTIES ENABLE_EXPORTS 1)
+export_executable_symbols(llvm-stress)
diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp
index 21a79e3294a0..f5e718ba65b6 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -20,7 +20,7 @@
#include "llvm/IR/LegacyPassNameParser.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Verifier.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
@@ -711,9 +711,8 @@ int main(int argc, char **argv) {
return 1;
}
- PassManager Passes;
+ legacy::PassManager Passes;
Passes.add(createVerifierPass());
- Passes.add(createDebugInfoVerifierPass());
Passes.add(createPrintModulePass(Out->os()));
Passes.run(*M.get());
Out->keep();
diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt
index 9e76248d83d1..5df3b17a065e 100644
--- a/tools/llvm-symbolizer/CMakeLists.txt
+++ b/tools/llvm-symbolizer/CMakeLists.txt
@@ -4,7 +4,8 @@
# targets as well. Currently, there is no support for such a build strategy.
set(LLVM_LINK_COMPONENTS
- DebugInfo
+ DebugInfoDWARF
+ DebugInfoPDB
Object
Support
)
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp
index 36061d7e684f..afb7cc81c824 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.cpp
+++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp
@@ -14,6 +14,9 @@
#include "LLVMSymbolize.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBContext.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/MachO.h"
#include "llvm/Support/Casting.h"
@@ -26,6 +29,11 @@
#include <sstream>
#include <stdlib.h>
+#if defined(_MSC_VER)
+#include <Windows.h>
+#include <DbgHelp.h>
+#endif
+
namespace llvm {
namespace symbolize {
@@ -163,6 +171,7 @@ DILineInfo ModuleInfo::symbolizeCode(
DIInliningInfo ModuleInfo::symbolizeInlinedCode(
uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const {
DIInliningInfo InlinedContext;
+
if (DebugInfoContext) {
InlinedContext = DebugInfoContext->getInliningInfoForAddress(
ModuleOffset, getDILineInfoSpecifier(Opts));
@@ -460,7 +469,20 @@ LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
Modules.insert(make_pair(ModuleName, (ModuleInfo *)nullptr));
return nullptr;
}
- DIContext *Context = DIContext::getDWARFContext(*Objects.second);
+ DIContext *Context = nullptr;
+ if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
+ // If this is a COFF object, assume it contains PDB debug information. If
+ // we don't find any we will fall back to the DWARF case.
+ std::unique_ptr<IPDBSession> Session;
+ PDB_ErrorCode Error = loadDataForEXE(PDB_ReaderType::DIA,
+ Objects.first->getFileName(), Session);
+ if (Error == PDB_ErrorCode::Success) {
+ Context = new PDBContext(*CoffObject, std::move(Session),
+ Opts.RelativeAddresses);
+ }
+ }
+ if (!Context)
+ Context = new DWARFContextInMemory(*Objects.second);
assert(Context);
ModuleInfo *Info = new ModuleInfo(Objects.first, Context);
Modules.insert(make_pair(ModuleName, Info));
@@ -507,7 +529,17 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name) {
free(DemangledName);
return Result;
#else
- return Name;
+ char DemangledName[1024] = {0};
+ DWORD result = ::UnDecorateSymbolName(
+ Name.c_str(), DemangledName, 1023,
+ UNDNAME_NO_ACCESS_SPECIFIERS | // Strip public, private, protected
+ UNDNAME_NO_ALLOCATION_LANGUAGE | // Strip __thiscall, __stdcall, etc
+ UNDNAME_NO_THROW_SIGNATURES | // Strip throw() specifications
+ UNDNAME_NO_MEMBER_TYPE | // Strip virtual, static, etc specifiers
+ UNDNAME_NO_MS_KEYWORDS | // Strip all MS extension keywords
+ UNDNAME_NO_FUNCTION_RETURNS); // Strip function return types
+
+ return (result == 0) ? Name : std::string(DemangledName);
#endif
}
diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h
index ff848fceb242..1c2006fbbe75 100644
--- a/tools/llvm-symbolizer/LLVMSymbolize.h
+++ b/tools/llvm-symbolizer/LLVMSymbolize.h
@@ -35,19 +35,20 @@ class ModuleInfo;
class LLVMSymbolizer {
public:
struct Options {
- bool UseSymbolTable : 1;
FunctionNameKind PrintFunctions;
+ bool UseSymbolTable : 1;
bool PrintInlining : 1;
bool Demangle : 1;
+ bool RelativeAddresses : 1;
std::string DefaultArch;
std::vector<std::string> DsymHints;
- Options(bool UseSymbolTable = true,
- FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName,
- bool PrintInlining = true, bool Demangle = true,
+ Options(FunctionNameKind PrintFunctions = FunctionNameKind::LinkageName,
+ bool UseSymbolTable = true, bool PrintInlining = true,
+ bool Demangle = true, bool RelativeAddresses = false,
std::string DefaultArch = "")
- : UseSymbolTable(UseSymbolTable),
- PrintFunctions(PrintFunctions), PrintInlining(PrintInlining),
- Demangle(Demangle), DefaultArch(DefaultArch) {}
+ : PrintFunctions(PrintFunctions), UseSymbolTable(UseSymbolTable),
+ PrintInlining(PrintInlining), Demangle(Demangle),
+ RelativeAddresses(RelativeAddresses), DefaultArch(DefaultArch) {}
};
LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {}
diff --git a/tools/llvm-symbolizer/Makefile b/tools/llvm-symbolizer/Makefile
index 5ac83a58137d..de75befb1c97 100644
--- a/tools/llvm-symbolizer/Makefile
+++ b/tools/llvm-symbolizer/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-symbolizer
-LINK_COMPONENTS := DebugInfo Object
+LINK_COMPONENTS := DebugInfoDWARF DebugInfoPDB Object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index d554022e450c..9c9f3adbf60e 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -17,10 +17,12 @@
#include "LLVMSymbolize.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/COM.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/raw_ostream.h"
@@ -47,8 +49,13 @@ static cl::opt<FunctionNameKind> ClPrintFunctions(
clEnumValEnd));
static cl::opt<bool>
-ClPrintInlining("inlining", cl::init(true),
- cl::desc("Print all inlined frames for a given address"));
+ ClUseRelativeAddress("relative-address", cl::init(false),
+ cl::desc("Interpret addresses as relative addresses"),
+ cl::ReallyHidden);
+
+static cl::opt<bool>
+ ClPrintInlining("inlining", cl::init(true),
+ cl::desc("Print all inlined frames for a given address"));
static cl::opt<bool>
ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names"));
@@ -122,9 +129,12 @@ int main(int argc, char **argv) {
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+ llvm::sys::InitializeCOMRAII COM(llvm::sys::COMThreadingMode::MultiThreaded);
+
cl::ParseCommandLineOptions(argc, argv, "llvm-symbolizer\n");
- LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions,
- ClPrintInlining, ClDemangle, ClDefaultArch);
+ LLVMSymbolizer::Options Opts(ClPrintFunctions, ClUseSymbolTable,
+ ClPrintInlining, ClDemangle,
+ ClUseRelativeAddress, ClDefaultArch);
for (const auto &hint : ClDsymHint) {
if (sys::path::extension(hint) == ".dSYM") {
Opts.DsymHints.push_back(hint);
@@ -145,5 +155,6 @@ int main(int argc, char **argv) {
outs() << Result << "\n";
outs().flush();
}
+
return 0;
}
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index ec0372ea5607..d6ceebed728f 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -13,17 +13,23 @@
//===----------------------------------------------------------------------===//
#include "llvm-c/lto.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/LTO/LTOCodeGenerator.h"
#include "llvm/LTO/LTOModule.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Signals.h"
#include "llvm/Support/TargetSelect.h"
// extra command-line flags needed for LTOCodeGenerator
-static cl::opt<bool>
-DisableOpt("disable-opt", cl::init(false),
- cl::desc("Do not run any optimization passes"));
+static cl::opt<char>
+OptLevel("O",
+ cl::desc("Optimization level. [-O0, -O1, -O2, or -O3] "
+ "(default = '-O2')"),
+ cl::Prefix,
+ cl::ZeroOrMore,
+ cl::init('2'));
static cl::opt<bool>
DisableInline("disable-inlining", cl::init(false),
@@ -51,6 +57,12 @@ static bool parsedOptions = false;
// Initialize the configured targets if they have not been initialized.
static void lto_initialize() {
if (!initialized) {
+#ifdef LLVM_ON_WIN32
+ // Dialog box on crash disabling doesn't work across DLL boundaries, so do
+ // it here.
+ llvm::sys::DisableSystemDialogsOnCrash();
+#endif
+
InitializeAllTargetInfos();
InitializeAllTargets();
InitializeAllTargetMCs();
@@ -77,6 +89,10 @@ static void lto_add_attrs(lto_code_gen_t cg) {
CG->setAttr(attrs.c_str());
}
+
+ if (OptLevel < '0' || OptLevel > '3')
+ report_fatal_error("Optimization level must be between 0 and 3");
+ CG->setOptLevel(OptLevel - '0');
}
extern const char* lto_get_version() {
@@ -241,6 +257,10 @@ bool lto_codegen_add_module(lto_code_gen_t cg, lto_module_t mod) {
return !unwrap(cg)->addModule(unwrap(mod));
}
+void lto_codegen_set_module(lto_code_gen_t cg, lto_module_t mod) {
+ unwrap(cg)->setModule(unwrap(mod));
+}
+
bool lto_codegen_set_debug_model(lto_code_gen_t cg, lto_debug_model debug) {
unwrap(cg)->setDebugInfo(debug);
return false;
@@ -269,37 +289,57 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg,
unwrap(cg)->addMustPreserveSymbol(symbol);
}
-bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
+static void maybeParseOptions(lto_code_gen_t cg) {
if (!parsedOptions) {
unwrap(cg)->parseCodeGenDebugOptions();
lto_add_attrs(cg);
parsedOptions = true;
}
+}
+
+bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) {
+ maybeParseOptions(cg);
return !unwrap(cg)->writeMergedModules(path, sLastErrorString);
}
const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) {
- if (!parsedOptions) {
- unwrap(cg)->parseCodeGenDebugOptions();
- lto_add_attrs(cg);
- parsedOptions = true;
- }
- return unwrap(cg)->compile(length, DisableOpt, DisableInline,
+ maybeParseOptions(cg);
+ return unwrap(cg)->compile(length, DisableInline,
DisableGVNLoadPRE, DisableLTOVectorization,
sLastErrorString);
}
+bool lto_codegen_optimize(lto_code_gen_t cg) {
+ maybeParseOptions(cg);
+ return !unwrap(cg)->optimize(DisableInline,
+ DisableGVNLoadPRE, DisableLTOVectorization,
+ sLastErrorString);
+}
+
+const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) {
+ maybeParseOptions(cg);
+ return unwrap(cg)->compileOptimized(length, sLastErrorString);
+}
+
bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) {
- if (!parsedOptions) {
- unwrap(cg)->parseCodeGenDebugOptions();
- lto_add_attrs(cg);
- parsedOptions = true;
- }
+ maybeParseOptions(cg);
return !unwrap(cg)->compile_to_file(
- name, DisableOpt, DisableInline, DisableGVNLoadPRE,
+ name, DisableInline, DisableGVNLoadPRE,
DisableLTOVectorization, sLastErrorString);
}
void lto_codegen_debug_options(lto_code_gen_t cg, const char *opt) {
unwrap(cg)->setCodeGenDebugOptions(opt);
}
+
+unsigned int lto_api_version() { return LTO_API_VERSION; }
+
+void lto_codegen_set_should_internalize(lto_code_gen_t cg,
+ bool ShouldInternalize) {
+ unwrap(cg)->setShouldInternalize(ShouldInternalize);
+}
+
+void lto_codegen_set_should_embed_uselists(lto_code_gen_t cg,
+ lto_bool_t ShouldEmbedUselists) {
+ unwrap(cg)->setShouldEmbedUselists(ShouldEmbedUselists);
+}
diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports
index f6ceaac74d18..9145a6ff4dd4 100644
--- a/tools/lto/lto.exports
+++ b/tools/lto/lto.exports
@@ -22,8 +22,10 @@ lto_module_is_object_file_for_target
lto_module_is_object_file_in_memory
lto_module_is_object_file_in_memory_for_target
lto_module_dispose
+lto_api_version
lto_codegen_set_diagnostic_handler
lto_codegen_add_module
+lto_codegen_set_module
lto_codegen_add_must_preserve_symbol
lto_codegen_compile
lto_codegen_create
@@ -37,6 +39,9 @@ lto_codegen_set_assembler_args
lto_codegen_set_assembler_path
lto_codegen_set_cpu
lto_codegen_compile_to_file
+lto_codegen_optimize
+lto_codegen_compile_optimized
+lto_codegen_set_should_internalize
LLVMCreateDisasm
LLVMCreateDisasmCPU
LLVMDisasmDispose
diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp
index d770ce1151ea..8ce70bc3652a 100644
--- a/tools/obj2yaml/elf2yaml.cpp
+++ b/tools/obj2yaml/elf2yaml.cpp
@@ -21,8 +21,10 @@ namespace {
template <class ELFT>
class ELFDumper {
+ typedef object::Elf_Sym_Impl<ELFT> Elf_Sym;
typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter;
+ typedef typename object::ELFFile<ELFT>::Elf_Word Elf_Word;
const object::ELFFile<ELFT> &Obj;
@@ -38,6 +40,8 @@ class ELFDumper {
ErrorOr<ELFYAML::RelocationSection *> dumpRelaSection(const Elf_Shdr *Shdr);
ErrorOr<ELFYAML::RawContentSection *>
dumpContentSection(const Elf_Shdr *Shdr);
+ ErrorOr<ELFYAML::Group *> dumpGroup(const Elf_Shdr *Shdr);
+ ErrorOr<ELFYAML::MipsABIFlags *> dumpMipsABIFlags(const Elf_Shdr *Shdr);
public:
ELFDumper(const object::ELFFile<ELFT> &O);
@@ -86,7 +90,20 @@ ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() {
Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get()));
break;
}
- // FIXME: Support SHT_GROUP section format.
+ case ELF::SHT_GROUP: {
+ ErrorOr<ELFYAML::Group *> G = dumpGroup(&Sec);
+ if (std::error_code EC = G.getError())
+ return EC;
+ Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(G.get()));
+ break;
+ }
+ case ELF::SHT_MIPS_ABIFLAGS: {
+ ErrorOr<ELFYAML::MipsABIFlags *> G = dumpMipsABIFlags(&Sec);
+ if (std::error_code EC = G.getError())
+ return EC;
+ Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(G.get()));
+ break;
+ }
default: {
ErrorOr<ELFYAML::RawContentSection *> S = dumpContentSection(&Sec);
if (std::error_code EC = S.getError())
@@ -275,6 +292,70 @@ ELFDumper<ELFT>::dumpContentSection(const Elf_Shdr *Shdr) {
}
template <class ELFT>
+ErrorOr<ELFYAML::Group *> ELFDumper<ELFT>::dumpGroup(const Elf_Shdr *Shdr) {
+ auto S = make_unique<ELFYAML::Group>();
+
+ if (std::error_code EC = dumpCommonSection(Shdr, *S))
+ return EC;
+ // Get sh_info which is the signature.
+ const Elf_Sym *symbol = Obj.getSymbol(Shdr->sh_info);
+ const Elf_Shdr *symtab = Obj.getSection(Shdr->sh_link);
+ auto sectionContents = Obj.getSectionContents(Shdr);
+ if (std::error_code ec = sectionContents.getError())
+ return ec;
+ ErrorOr<StringRef> symbolName = Obj.getSymbolName(symtab, symbol);
+ if (std::error_code EC = symbolName.getError())
+ return EC;
+ S->Info = *symbolName;
+ const Elf_Word *groupMembers =
+ reinterpret_cast<const Elf_Word *>(sectionContents->data());
+ const long count = (Shdr->sh_size) / sizeof(Elf_Word);
+ ELFYAML::SectionOrType s;
+ for (int i = 0; i < count; i++) {
+ if (groupMembers[i] == llvm::ELF::GRP_COMDAT) {
+ s.sectionNameOrType = "GRP_COMDAT";
+ } else {
+ const Elf_Shdr *sHdr = Obj.getSection(groupMembers[i]);
+ ErrorOr<StringRef> sectionName = Obj.getSectionName(sHdr);
+ if (std::error_code ec = sectionName.getError())
+ return ec;
+ s.sectionNameOrType = *sectionName;
+ }
+ S->Members.push_back(s);
+ }
+ return S.release();
+}
+
+template <class ELFT>
+ErrorOr<ELFYAML::MipsABIFlags *>
+ELFDumper<ELFT>::dumpMipsABIFlags(const Elf_Shdr *Shdr) {
+ assert(Shdr->sh_type == ELF::SHT_MIPS_ABIFLAGS &&
+ "Section type is not SHT_MIPS_ABIFLAGS");
+ auto S = make_unique<ELFYAML::MipsABIFlags>();
+ if (std::error_code EC = dumpCommonSection(Shdr, *S))
+ return EC;
+
+ ErrorOr<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(Shdr);
+ if (std::error_code EC = ContentOrErr.getError())
+ return EC;
+
+ auto *Flags = reinterpret_cast<const object::Elf_Mips_ABIFlags<ELFT> *>(
+ ContentOrErr.get().data());
+ S->Version = Flags->version;
+ S->ISALevel = Flags->isa_level;
+ S->ISARevision = Flags->isa_rev;
+ S->GPRSize = Flags->gpr_size;
+ S->CPR1Size = Flags->cpr1_size;
+ S->CPR2Size = Flags->cpr2_size;
+ S->FpABI = Flags->fp_abi;
+ S->ISAExtension = Flags->isa_ext;
+ S->ASEs = Flags->ases;
+ S->Flags1 = Flags->flags1;
+ S->Flags2 = Flags->flags2;
+ return S.release();
+}
+
+template <class ELFT>
static std::error_code elf2yaml(raw_ostream &Out,
const object::ELFFile<ELFT> &Obj) {
ELFDumper<ELFT> Dumper(Obj);
diff --git a/tools/opt/BreakpointPrinter.cpp b/tools/opt/BreakpointPrinter.cpp
index 3cbc0ae50f14..363a7cd80074 100644
--- a/tools/opt/BreakpointPrinter.cpp
+++ b/tools/opt/BreakpointPrinter.cpp
@@ -29,18 +29,16 @@ struct BreakpointPrinter : public ModulePass {
BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) {}
- void getContextName(DIDescriptor Context, std::string &N) {
- if (Context.isNameSpace()) {
- DINameSpace NS(Context);
- if (!NS.getName().empty()) {
- getContextName(NS.getContext(), N);
- N = N + NS.getName().str() + "::";
+ void getContextName(const DIScope *Context, std::string &N) {
+ if (auto *NS = dyn_cast<DINamespace>(Context)) {
+ if (!NS->getName().empty()) {
+ getContextName(NS->getScope(), N);
+ N = N + NS->getName().str() + "::";
}
- } else if (Context.isType()) {
- DIType TY(Context);
- if (!TY.getName().empty()) {
- getContextName(TY.getContext().resolve(TypeIdentifierMap), N);
- N = N + TY.getName().str() + "::";
+ } else if (auto *TY = dyn_cast<DIType>(Context)) {
+ if (!TY->getName().empty()) {
+ getContextName(TY->getScope().resolve(TypeIdentifierMap), N);
+ N = N + TY->getName().str() + "::";
}
}
}
@@ -55,13 +53,11 @@ struct BreakpointPrinter : public ModulePass {
if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp"))
for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) {
std::string Name;
- DISubprogram SP(NMD->getOperand(i));
- assert((!SP || SP.isSubprogram()) &&
- "A MDNode in llvm.dbg.sp should be null or a DISubprogram.");
+ auto *SP = cast_or_null<DISubprogram>(NMD->getOperand(i));
if (!SP)
continue;
- getContextName(SP.getContext().resolve(TypeIdentifierMap), Name);
- Name = Name + SP.getDisplayName().str();
+ getContextName(SP->getScope().resolve(TypeIdentifierMap), Name);
+ Name = Name + SP->getDisplayName().str();
if (!Name.empty() && Processed.insert(Name).second) {
Out << Name << "\n";
}
diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt
index 1d3f08db7d29..5f825220cc88 100644
--- a/tools/opt/CMakeLists.txt
+++ b/tools/opt/CMakeLists.txt
@@ -16,6 +16,7 @@ set(LLVM_LINK_COMPONENTS
Target
TransformUtils
Vectorize
+ Passes
)
# Support plugins.
@@ -26,12 +27,11 @@ add_llvm_tool(opt
BreakpointPrinter.cpp
GraphPrinters.cpp
NewPMDriver.cpp
- Passes.cpp
PassPrinters.cpp
PrintSCC.cpp
opt.cpp
)
-set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1)
+export_executable_symbols(opt)
if(WITH_POLLY AND LINK_POLLY_INTO_TOOLS)
target_link_libraries(opt Polly)
diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt
index b3589f854ff1..b162ab6cfe9b 100644
--- a/tools/opt/LLVMBuild.txt
+++ b/tools/opt/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = opt
parent = Tools
-required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Scalar ObjCARC all-targets
+required_libraries = AsmParser BitReader BitWriter CodeGen IRReader IPO Instrumentation Scalar ObjCARC Passes all-targets
diff --git a/tools/opt/Makefile b/tools/opt/Makefile
index cfa9c31cb958..2422eb4e4056 100644
--- a/tools/opt/Makefile
+++ b/tools/opt/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := opt
-LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets codegen
+LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets codegen passes
# Support plugins.
NO_DEAD_STRIP := 1
diff --git a/tools/opt/NewPMDriver.cpp b/tools/opt/NewPMDriver.cpp
index f215c77459a8..3030d65743af 100644
--- a/tools/opt/NewPMDriver.cpp
+++ b/tools/opt/NewPMDriver.cpp
@@ -14,7 +14,6 @@
//===----------------------------------------------------------------------===//
#include "NewPMDriver.h"
-#include "Passes.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/CGSCCPassManager.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
@@ -24,9 +23,11 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/IR/Verifier.h"
+#include "llvm/Passes/PassBuilder.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Target/TargetMachine.h"
using namespace llvm;
using namespace opt_tool;
@@ -36,16 +37,21 @@ static cl::opt<bool>
cl::desc("Print pass management debugging information"));
bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
- tool_output_file *Out, StringRef PassPipeline,
- OutputKind OK, VerifierKind VK) {
+ TargetMachine *TM, tool_output_file *Out,
+ StringRef PassPipeline, OutputKind OK,
+ VerifierKind VK,
+ bool ShouldPreserveAssemblyUseListOrder,
+ bool ShouldPreserveBitcodeUseListOrder) {
+ PassBuilder PB(TM);
+
FunctionAnalysisManager FAM(DebugPM);
CGSCCAnalysisManager CGAM(DebugPM);
ModuleAnalysisManager MAM(DebugPM);
// Register all the basic analyses with the managers.
- registerModuleAnalyses(MAM);
- registerCGSCCAnalyses(CGAM);
- registerFunctionAnalyses(FAM);
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
// Cross register the analysis managers through their proxies.
MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM));
@@ -59,7 +65,8 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
if (VK > VK_NoVerifier)
MPM.addPass(VerifierPass());
- if (!parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass, DebugPM)) {
+ if (!PB.parsePassPipeline(MPM, PassPipeline, VK == VK_VerifyEachPass,
+ DebugPM)) {
errs() << Arg0 << ": unable to parse pass pipeline description.\n";
return false;
}
@@ -72,10 +79,12 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
case OK_NoOutput:
break; // No output pass needed.
case OK_OutputAssembly:
- MPM.addPass(PrintModulePass(Out->os()));
+ MPM.addPass(
+ PrintModulePass(Out->os(), "", ShouldPreserveAssemblyUseListOrder));
break;
case OK_OutputBitcode:
- MPM.addPass(BitcodeWriterPass(Out->os()));
+ MPM.addPass(
+ BitcodeWriterPass(Out->os(), ShouldPreserveBitcodeUseListOrder));
break;
}
diff --git a/tools/opt/NewPMDriver.h b/tools/opt/NewPMDriver.h
index f977baca7f83..349a7b1267f8 100644
--- a/tools/opt/NewPMDriver.h
+++ b/tools/opt/NewPMDriver.h
@@ -26,6 +26,7 @@
namespace llvm {
class LLVMContext;
class Module;
+class TargetMachine;
class tool_output_file;
namespace opt_tool {
@@ -48,8 +49,11 @@ enum VerifierKind {
/// file. It's interface is consequentially somewhat ad-hoc, but will go away
/// when the transition finishes.
bool runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
- tool_output_file *Out, StringRef PassPipeline,
- opt_tool::OutputKind OK, opt_tool::VerifierKind VK);
+ TargetMachine *TM, tool_output_file *Out,
+ StringRef PassPipeline, opt_tool::OutputKind OK,
+ opt_tool::VerifierKind VK,
+ bool ShouldPreserveAssemblyUseListOrder,
+ bool ShouldPreserveBitcodeUseListOrder);
}
#endif
diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def
deleted file mode 100644
index c98de60b5706..000000000000
--- a/tools/opt/PassRegistry.def
+++ /dev/null
@@ -1,65 +0,0 @@
-//===- PassRegistry.def - Registry of passes --------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is used as the registry of passes that are part of the core LLVM
-// libraries. This file describes both transformation passes and analyses
-// Analyses are registered while transformation passes have names registered
-// that can be used when providing a textual pass pipeline.
-//
-//===----------------------------------------------------------------------===//
-
-// NOTE: NO INCLUDE GUARD DESIRED!
-
-#ifndef MODULE_ANALYSIS
-#define MODULE_ANALYSIS(NAME, CREATE_PASS)
-#endif
-MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
-MODULE_ANALYSIS("no-op-module", NoOpModuleAnalysis())
-#undef MODULE_ANALYSIS
-
-#ifndef MODULE_PASS
-#define MODULE_PASS(NAME, CREATE_PASS)
-#endif
-MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-MODULE_PASS("no-op-module", NoOpModulePass())
-MODULE_PASS("print", PrintModulePass(dbgs()))
-MODULE_PASS("print-cg", LazyCallGraphPrinterPass(dbgs()))
-MODULE_PASS("verify", VerifierPass())
-#undef MODULE_PASS
-
-#ifndef CGSCC_ANALYSIS
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS)
-#endif
-CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
-#undef CGSCC_ANALYSIS
-
-#ifndef CGSCC_PASS
-#define CGSCC_PASS(NAME, CREATE_PASS)
-#endif
-CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
-#undef CGSCC_PASS
-
-#ifndef FUNCTION_ANALYSIS
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
-#endif
-FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis())
-FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis())
-#undef FUNCTION_ANALYSIS
-
-#ifndef FUNCTION_PASS
-#define FUNCTION_PASS(NAME, CREATE_PASS)
-#endif
-FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-FUNCTION_PASS("no-op-function", NoOpFunctionPass())
-FUNCTION_PASS("print", PrintFunctionPass(dbgs()))
-FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs()))
-FUNCTION_PASS("verify", VerifierPass())
-FUNCTION_PASS("verify<domtree>", DominatorTreeVerifierPass())
-#undef FUNCTION_PASS
diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp
deleted file mode 100644
index 518112a1c88c..000000000000
--- a/tools/opt/Passes.cpp
+++ /dev/null
@@ -1,397 +0,0 @@
-//===- Passes.cpp - Parsing, selection, and running of passes -------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file provides the infrastructure to parse and build a custom pass
-/// manager based on a commandline flag. It also provides helpers to aid in
-/// analyzing, debugging, and testing pass structures.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Passes.h"
-#include "llvm/Analysis/CGSCCPassManager.h"
-#include "llvm/Analysis/LazyCallGraph.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/IRPrintingPasses.h"
-#include "llvm/IR/PassManager.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Support/Debug.h"
-
-using namespace llvm;
-
-namespace {
-
-/// \brief No-op module pass which does nothing.
-struct NoOpModulePass {
- PreservedAnalyses run(Module &M) { return PreservedAnalyses::all(); }
- static StringRef name() { return "NoOpModulePass"; }
-};
-
-/// \brief No-op module analysis.
-struct NoOpModuleAnalysis {
- struct Result {};
- Result run(Module &) { return Result(); }
- static StringRef name() { return "NoOpModuleAnalysis"; }
- static void *ID() { return (void *)&PassID; }
-private:
- static char PassID;
-};
-
-char NoOpModuleAnalysis::PassID;
-
-/// \brief No-op CGSCC pass which does nothing.
-struct NoOpCGSCCPass {
- PreservedAnalyses run(LazyCallGraph::SCC &C) {
- return PreservedAnalyses::all();
- }
- static StringRef name() { return "NoOpCGSCCPass"; }
-};
-
-/// \brief No-op CGSCC analysis.
-struct NoOpCGSCCAnalysis {
- struct Result {};
- Result run(LazyCallGraph::SCC &) { return Result(); }
- static StringRef name() { return "NoOpCGSCCAnalysis"; }
- static void *ID() { return (void *)&PassID; }
-private:
- static char PassID;
-};
-
-char NoOpCGSCCAnalysis::PassID;
-
-/// \brief No-op function pass which does nothing.
-struct NoOpFunctionPass {
- PreservedAnalyses run(Function &F) { return PreservedAnalyses::all(); }
- static StringRef name() { return "NoOpFunctionPass"; }
-};
-
-/// \brief No-op function analysis.
-struct NoOpFunctionAnalysis {
- struct Result {};
- Result run(Function &) { return Result(); }
- static StringRef name() { return "NoOpFunctionAnalysis"; }
- static void *ID() { return (void *)&PassID; }
-private:
- static char PassID;
-};
-
-char NoOpFunctionAnalysis::PassID;
-
-} // End anonymous namespace.
-
-void llvm::registerModuleAnalyses(ModuleAnalysisManager &MAM) {
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- MAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-void llvm::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) {
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
- CGAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-void llvm::registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
- FAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-#ifndef NDEBUG
-static bool isModulePassName(StringRef Name) {
-#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) return true;
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
- return true;
-#include "PassRegistry.def"
-
- return false;
-}
-#endif
-
-static bool isCGSCCPassName(StringRef Name) {
-#define CGSCC_PASS(NAME, CREATE_PASS) if (Name == NAME) return true;
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
- return true;
-#include "PassRegistry.def"
-
- return false;
-}
-
-static bool isFunctionPassName(StringRef Name) {
-#define FUNCTION_PASS(NAME, CREATE_PASS) if (Name == NAME) return true;
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
- return true;
-#include "PassRegistry.def"
-
- return false;
-}
-
-static bool parseModulePassName(ModulePassManager &MPM, StringRef Name) {
-#define MODULE_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- MPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- MPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- MPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-static bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name) {
-#define CGSCC_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- CGPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- CGPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- CGPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-static bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) {
-#define FUNCTION_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- FPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- FPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- FPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-static bool parseFunctionPassPipeline(FunctionPassManager &FPM,
- StringRef &PipelineText,
- bool VerifyEachPass, bool DebugLogging) {
- for (;;) {
- // Parse nested pass managers by recursing.
- if (PipelineText.startswith("function(")) {
- FunctionPassManager NestedFPM(DebugLogging);
-
- // Parse the inner pipeline inte the nested manager.
- PipelineText = PipelineText.substr(strlen("function("));
- if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Add the nested pass manager with the appropriate adaptor.
- FPM.addPass(std::move(NestedFPM));
- } else {
- // Otherwise try to parse a pass name.
- size_t End = PipelineText.find_first_of(",)");
- if (!parseFunctionPassName(FPM, PipelineText.substr(0, End)))
- return false;
- if (VerifyEachPass)
- FPM.addPass(VerifierPass());
-
- PipelineText = PipelineText.substr(End);
- }
-
- if (PipelineText.empty() || PipelineText[0] == ')')
- return true;
-
- assert(PipelineText[0] == ',');
- PipelineText = PipelineText.substr(1);
- }
-}
-
-static bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM,
- StringRef &PipelineText, bool VerifyEachPass,
- bool DebugLogging) {
- for (;;) {
- // Parse nested pass managers by recursing.
- if (PipelineText.startswith("cgscc(")) {
- CGSCCPassManager NestedCGPM(DebugLogging);
-
- // Parse the inner pipeline into the nested manager.
- PipelineText = PipelineText.substr(strlen("cgscc("));
- if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Add the nested pass manager with the appropriate adaptor.
- CGPM.addPass(std::move(NestedCGPM));
- } else if (PipelineText.startswith("function(")) {
- FunctionPassManager NestedFPM(DebugLogging);
-
- // Parse the inner pipeline inte the nested manager.
- PipelineText = PipelineText.substr(strlen("function("));
- if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Add the nested pass manager with the appropriate adaptor.
- CGPM.addPass(createCGSCCToFunctionPassAdaptor(std::move(NestedFPM)));
- } else {
- // Otherwise try to parse a pass name.
- size_t End = PipelineText.find_first_of(",)");
- if (!parseCGSCCPassName(CGPM, PipelineText.substr(0, End)))
- return false;
- // FIXME: No verifier support for CGSCC passes!
-
- PipelineText = PipelineText.substr(End);
- }
-
- if (PipelineText.empty() || PipelineText[0] == ')')
- return true;
-
- assert(PipelineText[0] == ',');
- PipelineText = PipelineText.substr(1);
- }
-}
-
-static bool parseModulePassPipeline(ModulePassManager &MPM,
- StringRef &PipelineText,
- bool VerifyEachPass, bool DebugLogging) {
- for (;;) {
- // Parse nested pass managers by recursing.
- if (PipelineText.startswith("module(")) {
- ModulePassManager NestedMPM(DebugLogging);
-
- // Parse the inner pipeline into the nested manager.
- PipelineText = PipelineText.substr(strlen("module("));
- if (!parseModulePassPipeline(NestedMPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Now add the nested manager as a module pass.
- MPM.addPass(std::move(NestedMPM));
- } else if (PipelineText.startswith("cgscc(")) {
- CGSCCPassManager NestedCGPM(DebugLogging);
-
- // Parse the inner pipeline inte the nested manager.
- PipelineText = PipelineText.substr(strlen("cgscc("));
- if (!parseCGSCCPassPipeline(NestedCGPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Add the nested pass manager with the appropriate adaptor.
- MPM.addPass(
- createModuleToPostOrderCGSCCPassAdaptor(std::move(NestedCGPM)));
- } else if (PipelineText.startswith("function(")) {
- FunctionPassManager NestedFPM(DebugLogging);
-
- // Parse the inner pipeline inte the nested manager.
- PipelineText = PipelineText.substr(strlen("function("));
- if (!parseFunctionPassPipeline(NestedFPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- PipelineText.empty())
- return false;
- assert(PipelineText[0] == ')');
- PipelineText = PipelineText.substr(1);
-
- // Add the nested pass manager with the appropriate adaptor.
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(NestedFPM)));
- } else {
- // Otherwise try to parse a pass name.
- size_t End = PipelineText.find_first_of(",)");
- if (!parseModulePassName(MPM, PipelineText.substr(0, End)))
- return false;
- if (VerifyEachPass)
- MPM.addPass(VerifierPass());
-
- PipelineText = PipelineText.substr(End);
- }
-
- if (PipelineText.empty() || PipelineText[0] == ')')
- return true;
-
- assert(PipelineText[0] == ',');
- PipelineText = PipelineText.substr(1);
- }
-}
-
-// Primary pass pipeline description parsing routine.
-// FIXME: Should this routine accept a TargetMachine or require the caller to
-// pre-populate the analysis managers with target-specific stuff?
-bool llvm::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
- bool VerifyEachPass, bool DebugLogging) {
- // By default, try to parse the pipeline as-if it were within an implicit
- // 'module(...)' pass pipeline. If this will parse at all, it needs to
- // consume the entire string.
- if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass, DebugLogging))
- return PipelineText.empty();
-
- // This isn't parsable as a module pipeline, look for the end of a pass name
- // and directly drop down to that layer.
- StringRef FirstName =
- PipelineText.substr(0, PipelineText.find_first_of(",)"));
- assert(!isModulePassName(FirstName) &&
- "Already handled all module pipeline options.");
-
- // If this looks like a CGSCC pass, parse the whole thing as a CGSCC
- // pipeline.
- if (isCGSCCPassName(FirstName)) {
- CGSCCPassManager CGPM(DebugLogging);
- if (!parseCGSCCPassPipeline(CGPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- !PipelineText.empty())
- return false;
- MPM.addPass(createModuleToPostOrderCGSCCPassAdaptor(std::move(CGPM)));
- return true;
- }
-
- // Similarly, if this looks like a Function pass, parse the whole thing as
- // a Function pipelien.
- if (isFunctionPassName(FirstName)) {
- FunctionPassManager FPM(DebugLogging);
- if (!parseFunctionPassPipeline(FPM, PipelineText, VerifyEachPass,
- DebugLogging) ||
- !PipelineText.empty())
- return false;
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- return true;
- }
-
- return false;
-}
diff --git a/tools/opt/Passes.h b/tools/opt/Passes.h
deleted file mode 100644
index 623da9ff4b4a..000000000000
--- a/tools/opt/Passes.h
+++ /dev/null
@@ -1,78 +0,0 @@
-//===- Passes.h - Parsing, selection, and running of passes -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// Interfaces for producing common pass manager configurations and parsing
-/// textual pass specifications.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_TOOLS_OPT_PASSES_H
-#define LLVM_TOOLS_OPT_PASSES_H
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Analysis/CGSCCPassManager.h"
-#include "llvm/IR/PassManager.h"
-
-namespace llvm {
-
-/// \brief Registers all available module analysis passes.
-///
-/// This is an interface that can be used to populate a \c
-/// ModuleAnalysisManager with all registered module analyses. Callers can
-/// still manually register any additional analyses.
-void registerModuleAnalyses(ModuleAnalysisManager &MAM);
-
-/// \brief Registers all available CGSCC analysis passes.
-///
-/// This is an interface that can be used to populate a \c CGSCCAnalysisManager
-/// with all registered CGSCC analyses. Callers can still manually register any
-/// additional analyses.
-void registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM);
-
-/// \brief Registers all available function analysis passes.
-///
-/// This is an interface that can be used to populate a \c
-/// FunctionAnalysisManager with all registered function analyses. Callers can
-/// still manually register any additional analyses.
-void registerFunctionAnalyses(FunctionAnalysisManager &FAM);
-
-/// \brief Parse a textual pass pipeline description into a \c ModulePassManager.
-///
-/// The format of the textual pass pipeline description looks something like:
-///
-/// module(function(instcombine,sroa),dce,cgscc(inliner,function(...)),...)
-///
-/// Pass managers have ()s describing the nest structure of passes. All passes
-/// are comma separated. As a special shortcut, if the very first pass is not
-/// a module pass (as a module pass manager is), this will automatically form
-/// the shortest stack of pass managers that allow inserting that first pass.
-/// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and loop passes
-/// 'lpassN', all of these are valid:
-///
-/// fpass1,fpass2,fpass3
-/// cgpass1,cgpass2,cgpass3
-/// lpass1,lpass2,lpass3
-///
-/// And they are equivalent to the following (resp.):
-///
-/// module(function(fpass1,fpass2,fpass3))
-/// module(cgscc(cgpass1,cgpass2,cgpass3))
-/// module(function(loop(lpass1,lpass2,lpass3)))
-///
-/// This shortcut is especially useful for debugging and testing small pass
-/// combinations. Note that these shortcuts don't introduce any other magic. If
-/// the sequence of passes aren't all the exact same kind of pass, it will be
-/// an error. You cannot mix different levels implicitly, you must explicitly
-/// form a pass manager in which to nest passes.
-bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
- bool VerifyEachPass = true, bool DebugLogging = false);
-}
-
-#endif
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index 986758908061..55426e7b2743 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -20,9 +20,12 @@
#include "llvm/Analysis/CallGraphSCCPass.h"
#include "llvm/Analysis/LoopPass.h"
#include "llvm/Analysis/RegionPass.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeWriterPass.h"
#include "llvm/CodeGen/CommandFlags.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/IRPrintingPasses.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/LegacyPassNameParser.h"
@@ -33,9 +36,10 @@
#include "llvm/LinkAllIR.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/PassManager.h"
+#include "llvm/IR/LegacyPassManager.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/PrettyStackTrace.h"
@@ -45,7 +49,6 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Target/TargetLibraryInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include <algorithm>
@@ -177,27 +180,33 @@ DefaultDataLayout("default-data-layout",
cl::desc("data layout string to use if not specified by module"),
cl::value_desc("layout-string"), cl::init(""));
+static cl::opt<bool> PreserveBitcodeUseListOrder(
+ "preserve-bc-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM bitcode."),
+ cl::init(true), cl::Hidden);
+static cl::opt<bool> PreserveAssemblyUseListOrder(
+ "preserve-ll-uselistorder",
+ cl::desc("Preserve use-list order when writing LLVM assembly."),
+ cl::init(false), cl::Hidden);
-static inline void addPass(PassManagerBase &PM, Pass *P) {
+static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
// Add the pass to the pass manager...
PM.add(P);
// If we are verifying all of the intermediate steps, add the verifier...
- if (VerifyEach) {
+ if (VerifyEach)
PM.add(createVerifierPass());
- PM.add(createDebugInfoVerifierPass());
- }
}
/// This routine adds optimization passes based on selected optimization level,
/// OptLevel.
///
/// OptLevel - Optimization Level
-static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
+static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
+ legacy::FunctionPassManager &FPM,
unsigned OptLevel, unsigned SizeLevel) {
- FPM.add(createVerifierPass()); // Verify that input is correct
- MPM.add(createDebugInfoVerifierPass()); // Verify that debug info is correct
+ FPM.add(createVerifierPass()); // Verify that input is correct
PassManagerBuilder Builder;
Builder.OptLevel = OptLevel;
@@ -229,10 +238,9 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM,
Builder.populateModulePassManager(MPM);
}
-static void AddStandardLinkPasses(PassManagerBase &PM) {
+static void AddStandardLinkPasses(legacy::PassManagerBase &PM) {
PassManagerBuilder Builder;
Builder.VerifyInput = true;
- Builder.StripDebug = StripDebug;
if (DisableOptimizations)
Builder.OptLevel = 0;
@@ -245,7 +253,7 @@ static void AddStandardLinkPasses(PassManagerBase &PM) {
// CodeGen-related helper functions.
//
-CodeGenOpt::Level GetCodeGenOptLevel() {
+static CodeGenOpt::Level GetCodeGenOptLevel() {
if (OptLevelO1)
return CodeGenOpt::Less;
if (OptLevelO2)
@@ -256,7 +264,9 @@ CodeGenOpt::Level GetCodeGenOptLevel() {
}
// Returns the TargetMachine instance or zero if no triple is provided.
-static TargetMachine* GetTargetMachine(Triple TheTriple) {
+static TargetMachine* GetTargetMachine(Triple TheTriple, StringRef CPUStr,
+ StringRef FeaturesStr,
+ const TargetOptions &Options) {
std::string Error;
const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple,
Error);
@@ -265,18 +275,8 @@ static TargetMachine* GetTargetMachine(Triple TheTriple) {
return nullptr;
}
- // 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();
- }
-
return TheTarget->createTargetMachine(TheTriple.getTriple(),
- MCPU, FeaturesStr,
- InitTargetOptionsFromCodeGenFlags(),
+ CPUStr, FeaturesStr, Options,
RelocModel, CMModel,
GetCodeGenOptLevel());
}
@@ -322,6 +322,8 @@ int main(int argc, char **argv) {
initializeCodeGenPreparePass(Registry);
initializeAtomicExpandPass(Registry);
initializeRewriteSymbolsPass(Registry);
+ initializeWinEHPreparePass(Registry);
+ initializeDwarfEHPreparePass(Registry);
#ifdef LINK_POLLY_INTO_TOOLS
polly::initializePollyPasses(Registry);
@@ -345,6 +347,19 @@ int main(int argc, char **argv) {
return 1;
}
+ // Strip debug info before running the verifier.
+ if (StripDebug)
+ StripDebugInfo(*M);
+
+ // Immediately run the verifier to catch any problems before starting up the
+ // pass pipelines. Otherwise we can crash on broken code during
+ // doInitialization().
+ if (!NoVerify && verifyModule(*M, &errs())) {
+ errs() << argv[0] << ": " << InputFilename
+ << ": error: input module is broken!\n";
+ return 1;
+ }
+
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
M->setTargetTriple(Triple::normalize(TargetTriple));
@@ -368,6 +383,23 @@ int main(int argc, char **argv) {
}
}
+ Triple ModuleTriple(M->getTargetTriple());
+ std::string CPUStr, FeaturesStr;
+ TargetMachine *Machine = nullptr;
+ const TargetOptions Options = InitTargetOptionsFromCodeGenFlags();
+
+ if (ModuleTriple.getArch()) {
+ CPUStr = getCPUStr();
+ FeaturesStr = getFeaturesStr();
+ Machine = GetTargetMachine(ModuleTriple, CPUStr, FeaturesStr, Options);
+ }
+
+ std::unique_ptr<TargetMachine> TM(Machine);
+
+ // Override function attributes based on CPUStr, FeaturesStr, and command line
+ // flags.
+ setFunctionAttributes(CPUStr, FeaturesStr, *M);
+
// If the output is set to be emitted to standard out, and standard out is a
// console, print out a warning message and refuse to do it. We don't
// impress anyone by spewing tons of binary goo to a terminal.
@@ -389,8 +421,9 @@ int main(int argc, char **argv) {
// The user has asked to use the new pass manager and provided a pipeline
// string. Hand off the rest of the functionality to the new code for that
// layer.
- return runPassPipeline(argv[0], Context, *M, Out.get(), PassPipeline,
- OK, VK)
+ return runPassPipeline(argv[0], Context, *M, TM.get(), Out.get(),
+ PassPipeline, OK, VK, PreserveAssemblyUseListOrder,
+ PreserveBitcodeUseListOrder)
? 0
: 1;
}
@@ -398,44 +431,31 @@ int main(int argc, char **argv) {
// Create a PassManager to hold and optimize the collection of passes we are
// about to build.
//
- PassManager Passes;
+ legacy::PassManager Passes;
// Add an appropriate TargetLibraryInfo pass for the module's triple.
- TargetLibraryInfo *TLI = new TargetLibraryInfo(Triple(M->getTargetTriple()));
+ TargetLibraryInfoImpl TLII(ModuleTriple);
// The -disable-simplify-libcalls flag actually disables all builtin optzns.
if (DisableSimplifyLibCalls)
- TLI->disableAllFunctions();
- Passes.add(TLI);
+ TLII.disableAllFunctions();
+ Passes.add(new TargetLibraryInfoWrapperPass(TLII));
// Add an appropriate DataLayout instance for this module.
- const DataLayout *DL = M->getDataLayout();
- if (!DL && !DefaultDataLayout.empty()) {
+ const DataLayout &DL = M->getDataLayout();
+ if (DL.isDefault() && !DefaultDataLayout.empty()) {
M->setDataLayout(DefaultDataLayout);
- DL = M->getDataLayout();
}
- if (DL)
- Passes.add(new DataLayoutPass());
-
- Triple ModuleTriple(M->getTargetTriple());
- TargetMachine *Machine = nullptr;
- if (ModuleTriple.getArch())
- Machine = GetTargetMachine(Triple(ModuleTriple));
- std::unique_ptr<TargetMachine> TM(Machine);
-
// Add internal analysis passes from the target machine.
- if (TM)
- TM->addAnalysisPasses(Passes);
+ Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
+ : TargetIRAnalysis()));
- std::unique_ptr<FunctionPassManager> FPasses;
+ std::unique_ptr<legacy::FunctionPassManager> FPasses;
if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) {
- FPasses.reset(new FunctionPassManager(M.get()));
- if (DL)
- FPasses->add(new DataLayoutPass());
- if (TM)
- TM->addAnalysisPasses(*FPasses);
-
+ FPasses.reset(new legacy::FunctionPassManager(M.get()));
+ FPasses->add(createTargetTransformInfoWrapperPass(
+ TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()));
}
if (PrintBreakpoints) {
@@ -456,10 +476,6 @@ int main(int argc, char **argv) {
NoOutput = true;
}
- // 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) {
if (StandardLinkOpts &&
@@ -531,7 +547,8 @@ int main(int argc, char **argv) {
}
if (PrintEachXForm)
- Passes.add(createPrintModulePass(errs()));
+ Passes.add(
+ createPrintModulePass(errs(), "", PreserveAssemblyUseListOrder));
}
if (StandardLinkOpts) {
@@ -562,17 +579,17 @@ int main(int argc, char **argv) {
}
// Check that the module is well formed on completion of optimization
- if (!NoVerify && !VerifyEach) {
+ if (!NoVerify && !VerifyEach)
Passes.add(createVerifierPass());
- Passes.add(createDebugInfoVerifierPass());
- }
// Write bitcode or assembly to the output as the last step...
if (!NoOutput && !AnalyzeOnly) {
if (OutputAssembly)
- Passes.add(createPrintModulePass(Out->os()));
+ Passes.add(
+ createPrintModulePass(Out->os(), "", PreserveAssemblyUseListOrder));
else
- Passes.add(createBitcodeWriterPass(Out->os()));
+ Passes.add(
+ createBitcodeWriterPass(Out->os(), PreserveBitcodeUseListOrder));
}
// Before executing passes, print the final values of the LLVM options.
diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp
index a6536083e880..795d035d3df4 100644
--- a/tools/verify-uselistorder/verify-uselistorder.cpp
+++ b/tools/verify-uselistorder/verify-uselistorder.cpp
@@ -47,12 +47,13 @@
#include "llvm/Support/Signals.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/SystemUtils.h"
+#include "llvm/Support/raw_ostream.h"
#include <random>
#include <vector>
using namespace llvm;
-#define DEBUG_TYPE "use-list-order"
+#define DEBUG_TYPE "uselistorder"
static cl::opt<std::string> InputFilename(cl::Positional,
cl::desc("<input bitcode file>"),
@@ -108,16 +109,16 @@ struct ValueMapping {
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");
+ if (auto EC = sys::fs::createTemporaryFile("uselistorder", Ext, Vector)) {
+ errs() << "verify-uselistorder: 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");
+ if (SaveTemps)
+ outs() << " - filename = " << Filename << "\n";
return false;
}
@@ -126,11 +127,11 @@ bool TempFile::writeBitcode(const Module &M) const {
std::error_code EC;
raw_fd_ostream OS(Filename, EC, sys::fs::F_None);
if (EC) {
- DEBUG(dbgs() << "error: " << EC.message() << "\n");
+ errs() << "verify-uselistorder: error: " << EC.message() << "\n";
return true;
}
- WriteBitcodeToFile(&M, OS);
+ WriteBitcodeToFile(&M, OS, /* ShouldPreserveUseListOrder */ true);
return false;
}
@@ -139,11 +140,11 @@ bool TempFile::writeAssembly(const Module &M) const {
std::error_code EC;
raw_fd_ostream OS(Filename, EC, sys::fs::F_Text);
if (EC) {
- DEBUG(dbgs() << "error: " << EC.message() << "\n");
+ errs() << "verify-uselistorder: error: " << EC.message() << "\n";
return true;
}
- OS << M;
+ M.print(OS, nullptr, /* ShouldPreserveUseListOrder */ true);
return false;
}
@@ -152,7 +153,8 @@ std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOr =
MemoryBuffer::getFile(Filename);
if (!BufferOr) {
- DEBUG(dbgs() << "error: " << BufferOr.getError().message() << "\n");
+ errs() << "verify-uselistorder: error: " << BufferOr.getError().message()
+ << "\n";
return nullptr;
}
@@ -160,7 +162,8 @@ std::unique_ptr<Module> TempFile::readBitcode(LLVMContext &Context) const {
ErrorOr<Module *> ModuleOr =
parseBitcodeFile(Buffer->getMemBufferRef(), Context);
if (!ModuleOr) {
- DEBUG(dbgs() << "error: " << ModuleOr.getError().message() << "\n");
+ errs() << "verify-uselistorder: error: " << ModuleOr.getError().message()
+ << "\n";
return nullptr;
}
return std::unique_ptr<Module>(ModuleOr.get());
@@ -171,7 +174,7 @@ std::unique_ptr<Module> TempFile::readAssembly(LLVMContext &Context) const {
SMDiagnostic Err;
std::unique_ptr<Module> M = parseAssemblyFile(Filename, Err, Context);
if (!M.get())
- DEBUG(dbgs() << "error: "; Err.print("verify-use-list-order", dbgs()));
+ Err.print("verify-uselistorder", errs());
return M;
}
@@ -342,7 +345,6 @@ static void verifyAfterRoundTrip(const Module &M,
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");
@@ -355,7 +357,6 @@ static void verifyBitcodeUseListOrder(const Module &M) {
}
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");
@@ -368,7 +369,9 @@ static void verifyAssemblyUseListOrder(const Module &M) {
}
static void verifyUseListOrder(const Module &M) {
+ outs() << "verify bitcode\n";
verifyBitcodeUseListOrder(M);
+ outs() << "verify assembly\n";
verifyAssemblyUseListOrder(M);
}
@@ -497,7 +500,6 @@ static void changeUseLists(Module &M, Changer changeValueUseList) {
}
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); });
@@ -505,7 +507,6 @@ static void shuffleUseLists(Module &M, unsigned SeedOffset) {
}
static void reverseUseLists(Module &M) {
- errs() << "*** reverse-use-lists ***\n";
DenseSet<Value *> Seen;
changeUseLists(M, [&](Value *V) { reverseValueUseLists(V, Seen); });
DEBUG(dbgs() << "\n");
@@ -533,33 +534,29 @@ int main(int argc, char **argv) {
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);
+ if (verifyModule(*M, &errs())) {
+ errs() << argv[0] << ": " << InputFilename
+ << ": error: input module is broken!\n";
+ return 1;
}
// Verify the use lists now and after reversing them.
+ outs() << "*** verify-uselistorder ***\n";
verifyUseListOrder(*M);
+ outs() << "reverse\n";
reverseUseLists(*M);
verifyUseListOrder(*M);
for (unsigned I = 0, E = NumShuffles; I != E; ++I) {
- errs() << "*** shuffle iteration: " << I + 1 << " of " << E << " ***\n";
+ outs() << "\n";
// Shuffle with a different (deterministic) seed each time.
+ outs() << "shuffle (" << I + 1 << " of " << E << ")\n";
shuffleUseLists(*M, I);
// Verify again before and after reversing.
verifyUseListOrder(*M);
+ outs() << "reverse\n";
reverseUseLists(*M);
verifyUseListOrder(*M);
}
diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp
index 8322b2ff0a0d..61d985192552 100644
--- a/tools/yaml2obj/yaml2coff.cpp
+++ b/tools/yaml2obj/yaml2coff.cpp
@@ -253,10 +253,7 @@ binary_le_impl<value_type> binary_le(value_type V) {
return binary_le_impl<value_type>(V);
}
-template <size_t NumBytes>
-struct zeros_impl {
- zeros_impl() {}
-};
+template <size_t NumBytes> struct zeros_impl {};
template <size_t NumBytes>
raw_ostream &operator<<(raw_ostream &OS, const zeros_impl<NumBytes> &) {
@@ -282,7 +279,7 @@ raw_ostream &operator<<(raw_ostream &OS, const num_zeros_impl &NZI) {
return OS;
}
-num_zeros_impl num_zeros(size_t N) {
+static num_zeros_impl num_zeros(size_t N) {
num_zeros_impl NZI(N);
return NZI;
}
diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp
index 44c8c12da89d..338658805638 100644
--- a/tools/yaml2obj/yaml2elf.cpp
+++ b/tools/yaml2obj/yaml2elf.cpp
@@ -131,6 +131,11 @@ class ELFState {
bool writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::RelocationSection &Section,
ContiguousBlobAccumulator &CBA);
+ bool writeSectionContent(Elf_Shdr &SHeader, const ELFYAML::Group &Group,
+ ContiguousBlobAccumulator &CBA);
+ bool writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::MipsABIFlags &Section,
+ ContiguousBlobAccumulator &CBA);
// - SHT_NULL entry (placed first, i.e. 0'th entry)
// - symbol table (.symtab) (placed third to last)
@@ -223,6 +228,19 @@ bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
if (!writeSectionContent(SHeader, *S, CBA))
return false;
+ } else if (auto S = dyn_cast<ELFYAML::Group>(Sec.get())) {
+ unsigned SymIdx;
+ if (SymN2I.lookup(S->Info, SymIdx)) {
+ errs() << "error: Unknown symbol referenced: '" << S->Info
+ << "' at YAML section '" << S->Name << "'.\n";
+ return false;
+ }
+ SHeader.sh_info = SymIdx;
+ if (!writeSectionContent(SHeader, *S, CBA))
+ return false;
+ } else if (auto S = dyn_cast<ELFYAML::MipsABIFlags>(Sec.get())) {
+ if (!writeSectionContent(SHeader, *S, CBA))
+ return false;
} else
llvm_unreachable("Unknown section type");
@@ -321,16 +339,20 @@ ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
SHeader.sh_size = Section.Size;
}
+static bool isMips64EL(const ELFYAML::Object &Doc) {
+ return Doc.Header.Machine == ELFYAML::ELF_EM(llvm::ELF::EM_MIPS) &&
+ Doc.Header.Class == ELFYAML::ELF_ELFCLASS(ELF::ELFCLASS64) &&
+ Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB);
+}
+
template <class ELFT>
bool
ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
const ELFYAML::RelocationSection &Section,
ContiguousBlobAccumulator &CBA) {
- if (Section.Type != llvm::ELF::SHT_REL &&
- Section.Type != llvm::ELF::SHT_RELA) {
- errs() << "error: Invalid relocation section type.\n";
- return false;
- }
+ assert((Section.Type == llvm::ELF::SHT_REL ||
+ Section.Type == llvm::ELF::SHT_RELA) &&
+ "Section type is not SHT_REL nor SHT_RELA");
bool IsRela = Section.Type == llvm::ELF::SHT_RELA;
SHeader.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
@@ -339,31 +361,89 @@ ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset);
for (const auto &Rel : Section.Relocations) {
- unsigned SymIdx;
- if (SymN2I.lookup(Rel.Symbol, SymIdx)) {
- errs() << "error: Unknown symbol referenced: '" << Rel.Symbol
- << "' at YAML relocation.\n";
- return false;
- }
+ unsigned SymIdx = 0;
+ // Some special relocation, R_ARM_v4BX for instance, does not have
+ // an external reference. So it ignores the return value of lookup()
+ // here.
+ SymN2I.lookup(Rel.Symbol, SymIdx);
if (IsRela) {
Elf_Rela REntry;
zero(REntry);
REntry.r_offset = Rel.Offset;
REntry.r_addend = Rel.Addend;
- REntry.setSymbolAndType(SymIdx, Rel.Type);
+ REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc));
OS.write((const char *)&REntry, sizeof(REntry));
} else {
Elf_Rel REntry;
zero(REntry);
REntry.r_offset = Rel.Offset;
- REntry.setSymbolAndType(SymIdx, Rel.Type);
+ REntry.setSymbolAndType(SymIdx, Rel.Type, isMips64EL(Doc));
OS.write((const char *)&REntry, sizeof(REntry));
}
}
return true;
}
+template <class ELFT>
+bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::Group &Section,
+ ContiguousBlobAccumulator &CBA) {
+ typedef typename object::ELFFile<ELFT>::Elf_Word Elf_Word;
+ assert(Section.Type == llvm::ELF::SHT_GROUP &&
+ "Section type is not SHT_GROUP");
+
+ SHeader.sh_entsize = sizeof(Elf_Word);
+ SHeader.sh_size = SHeader.sh_entsize * Section.Members.size();
+
+ auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset);
+
+ for (auto member : Section.Members) {
+ Elf_Word SIdx;
+ unsigned int sectionIndex = 0;
+ if (member.sectionNameOrType == "GRP_COMDAT")
+ sectionIndex = llvm::ELF::GRP_COMDAT;
+ else if (SN2I.lookup(member.sectionNameOrType, sectionIndex)) {
+ errs() << "error: Unknown section referenced: '"
+ << member.sectionNameOrType << "' at YAML section' "
+ << Section.Name << "\n";
+ return false;
+ }
+ SIdx = sectionIndex;
+ OS.write((const char *)&SIdx, sizeof(SIdx));
+ }
+ return true;
+}
+
+template <class ELFT>
+bool ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
+ const ELFYAML::MipsABIFlags &Section,
+ ContiguousBlobAccumulator &CBA) {
+ assert(Section.Type == llvm::ELF::SHT_MIPS_ABIFLAGS &&
+ "Section type is not SHT_MIPS_ABIFLAGS");
+
+ object::Elf_Mips_ABIFlags<ELFT> Flags;
+ zero(Flags);
+ SHeader.sh_entsize = sizeof(Flags);
+ SHeader.sh_size = SHeader.sh_entsize;
+
+ auto &OS = CBA.getOSAndAlignedOffset(SHeader.sh_offset);
+ Flags.version = Section.Version;
+ Flags.isa_level = Section.ISALevel;
+ Flags.isa_rev = Section.ISARevision;
+ Flags.gpr_size = Section.GPRSize;
+ Flags.cpr1_size = Section.CPR1Size;
+ Flags.cpr2_size = Section.CPR2Size;
+ Flags.fp_abi = Section.FpABI;
+ Flags.isa_ext = Section.ISAExtension;
+ Flags.ases = Section.ASEs;
+ Flags.flags1 = Section.Flags1;
+ Flags.flags2 = Section.Flags2;
+ OS.write((const char *)&Flags, sizeof(Flags));
+
+ return true;
+}
+
template <class ELFT> bool ELFState<ELFT>::buildSectionIndex() {
SN2I.addName(".symtab", getDotSymTabSecNo());
SN2I.addName(".strtab", getDotStrTabSecNo());
diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
index 375cd89849c3..af4d86890672 100644
--- a/tools/yaml2obj/yaml2obj.cpp
+++ b/tools/yaml2obj/yaml2obj.cpp
@@ -62,7 +62,8 @@ static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"),
typedef int (*ConvertFuncPtr)(yaml::Input & YIn, raw_ostream &Out);
-int convertYAML(yaml::Input & YIn, raw_ostream &Out, ConvertFuncPtr Convert) {
+static int convertYAML(yaml::Input &YIn, raw_ostream &Out,
+ ConvertFuncPtr Convert) {
unsigned CurDocNum = 0;
do {
if (++CurDocNum == DocNum)