summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/CMakeLists.txt2
-rw-r--r--tools/Makefile2
-rw-r--r--tools/bugpoint/BugDriver.cpp26
-rw-r--r--tools/bugpoint/CMakeLists.txt2
-rw-r--r--tools/bugpoint/CrashDebugger.cpp1
-rw-r--r--tools/bugpoint/Miscompilation.cpp14
-rw-r--r--tools/dsymutil/Android.mk41
-rw-r--r--tools/dsymutil/CMakeLists.txt3
-rw-r--r--tools/dsymutil/DebugMap.cpp8
-rw-r--r--tools/dsymutil/DebugMap.h14
-rw-r--r--tools/dsymutil/DwarfLinker.cpp1934
-rw-r--r--tools/dsymutil/LLVMBuild.txt2
-rw-r--r--tools/dsymutil/MachODebugMapParser.cpp28
-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/gold-plugin.cpp32
-rw-r--r--tools/llc/CMakeLists.txt2
-rw-r--r--tools/llc/llc.cpp4
-rw-r--r--tools/lli/Android.mk1
-rw-r--r--tools/lli/CMakeLists.txt3
-rw-r--r--tools/lli/OrcLazyJIT.cpp53
-rw-r--r--tools/lli/OrcLazyJIT.h97
-rw-r--r--tools/lli/RemoteMemoryManager.cpp1
-rw-r--r--tools/lli/lli.cpp29
-rw-r--r--tools/llvm-ar/llvm-ar.cpp1
-rw-r--r--tools/llvm-config/CMakeLists.txt2
-rw-r--r--tools/llvm-config/llvm-config.cpp8
-rw-r--r--tools/llvm-cov/CodeCoverage.cpp37
-rw-r--r--tools/llvm-cov/gcov.cpp7
-rw-r--r--tools/llvm-cov/llvm-cov.cpp34
-rw-r--r--tools/llvm-cxxdump/Android.mk (renamed from tools/llvm-vtabledump/Android.mk)12
-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)143
-rw-r--r--tools/llvm-cxxdump/llvm-cxxdump.h (renamed from tools/llvm-vtabledump/llvm-vtabledump.h)8
-rw-r--r--tools/llvm-extract/llvm-extract.cpp1
-rw-r--r--tools/llvm-jitlistener/llvm-jitlistener.cpp3
-rw-r--r--tools/llvm-link/llvm-link.cpp7
-rw-r--r--tools/llvm-lto/llvm-lto.cpp29
-rw-r--r--tools/llvm-mc/Android.mk2
-rw-r--r--tools/llvm-mc/llvm-mc.cpp10
-rw-r--r--tools/llvm-nm/Android.mk2
-rw-r--r--tools/llvm-nm/llvm-nm.cpp130
-rw-r--r--tools/llvm-objdump/Android.mk2
-rw-r--r--tools/llvm-objdump/MachODump.cpp737
-rw-r--r--tools/llvm-objdump/llvm-objdump.cpp35
-rw-r--r--tools/llvm-objdump/llvm-objdump.h7
-rw-r--r--tools/llvm-pdbdump/Android.mk5
-rw-r--r--tools/llvm-pdbdump/BuiltinDumper.cpp87
-rw-r--r--tools/llvm-pdbdump/BuiltinDumper.h30
-rw-r--r--tools/llvm-pdbdump/CMakeLists.txt3
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.cpp136
-rw-r--r--tools/llvm-pdbdump/ClassDefinitionDumper.h30
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.cpp107
-rw-r--r--tools/llvm-pdbdump/CompilandDumper.h34
-rw-r--r--tools/llvm-pdbdump/EnumDumper.cpp52
-rw-r--r--tools/llvm-pdbdump/EnumDumper.h30
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.cpp199
-rw-r--r--tools/llvm-pdbdump/FunctionDumper.h37
-rw-r--r--tools/llvm-pdbdump/LinePrinter.cpp124
-rw-r--r--tools/llvm-pdbdump/LinePrinter.h89
-rw-r--r--tools/llvm-pdbdump/TypeDumper.cpp97
-rw-r--r--tools/llvm-pdbdump/TypeDumper.h20
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.cpp61
-rw-r--r--tools/llvm-pdbdump/TypedefDumper.h31
-rw-r--r--tools/llvm-pdbdump/VariableDumper.cpp136
-rw-r--r--tools/llvm-pdbdump/VariableDumper.h34
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.cpp187
-rw-r--r--tools/llvm-pdbdump/llvm-pdbdump.h24
-rw-r--r--tools/llvm-profdata/llvm-profdata.cpp27
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp1
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp17
-rw-r--r--tools/llvm-rtdyld/llvm-rtdyld.cpp10
-rw-r--r--tools/llvm-shlib/CMakeLists.txt2
-rw-r--r--tools/llvm-stress/CMakeLists.txt2
-rw-r--r--tools/llvm-stress/llvm-stress.cpp1
-rw-r--r--tools/llvm-symbolizer/llvm-symbolizer.cpp1
-rw-r--r--tools/lto/lto.cpp51
-rw-r--r--tools/opt/Android.mk2
-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.cpp14
-rw-r--r--tools/opt/PassRegistry.def77
-rw-r--r--tools/opt/Passes.cpp406
-rw-r--r--tools/opt/Passes.h105
-rw-r--r--tools/opt/opt.cpp24
-rw-r--r--tools/verify-uselistorder/verify-uselistorder.cpp1
-rw-r--r--tools/yaml2obj/yaml2coff.cpp2
-rw-r--r--tools/yaml2obj/yaml2obj.cpp3
94 files changed, 4197 insertions, 1722 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index 1f415b6..7859b49 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()
diff --git a/tools/Makefile b/tools/Makefile
index fcb6c64..d853486 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-pdbdump
+ 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/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp
index b8be17e..865cb51 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: does not verify\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 d71e097..daf502e 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 ee18169..f9f3f10 100644
--- a/tools/bugpoint/CrashDebugger.cpp
+++ b/tools/bugpoint/CrashDebugger.cpp
@@ -409,7 +409,6 @@ bool ReduceCrashingInstructions::TestInsts(std::vector<const Instruction*>
// Verify that this is still valid.
legacy::PassManager Passes;
Passes.add(createVerifierPass());
- Passes.add(createDebugInfoVerifierPass());
Passes.run(*M);
// Try running on the hacked up program...
diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp
index 8cb4583..98061bd 100644
--- a/tools/bugpoint/Miscompilation.cpp
+++ b/tools/bugpoint/Miscompilation.cpp
@@ -975,7 +975,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 +1050,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 +1068,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 +1079,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/dsymutil/Android.mk b/tools/dsymutil/Android.mk
index 873146e..f141635 100644
--- a/tools/dsymutil/Android.mk
+++ b/tools/dsymutil/Android.mk
@@ -11,13 +11,48 @@ llvm_dsymutil_SRC_FILES := \
MachODebugMapParser.cpp
llvm_dsymutil_STATIC_LIBRARIES := \
+ libLLVMARMCodeGen \
+ libLLVMARMAsmParser \
+ libLLVMARMInfo \
+ libLLVMARMDesc \
+ libLLVMARMAsmPrinter \
+ libLLVMARMDisassembler \
+ libLLVMAArch64CodeGen \
+ libLLVMAArch64Info \
+ libLLVMAArch64AsmParser \
+ libLLVMAArch64Desc \
+ libLLVMAArch64AsmPrinter \
+ libLLVMAArch64Utils \
+ libLLVMAArch64Disassembler \
+ libLLVMMipsCodeGen \
+ libLLVMMipsInfo \
+ libLLVMMipsAsmParser \
+ libLLVMMipsDesc \
+ libLLVMMipsAsmPrinter \
+ libLLVMMipsDisassembler \
+ libLLVMX86CodeGen \
+ libLLVMX86Info \
+ libLLVMX86Desc \
+ libLLVMX86AsmParser \
+ libLLVMX86AsmPrinter \
+ libLLVMX86Utils \
+ libLLVMX86Disassembler \
+ libLLVMX86CodeGen \
+ libLLVMAsmPrinter \
+ libLLVMSelectionDAG \
+ libLLVMCodeGen \
libLLVMDebugInfoDWARF \
- libLLVMObject \
libLLVMMCParser \
- libLLVMMC \
+ libLLVMMCDisassembler \
+ libLLVMObject \
libLLVMBitReader \
+ libLLVMScalarOpts \
+ libLLVMTransformUtils \
+ libLLVMAnalysis \
+ libLLVMTarget \
libLLVMCore \
- libLLVMSupport
+ libLLVMMC \
+ libLLVMSupport \
include $(CLEAR_VARS)
diff --git a/tools/dsymutil/CMakeLists.txt b/tools/dsymutil/CMakeLists.txt
index 5e1f37f..59b37a9 100644
--- a/tools/dsymutil/CMakeLists.txt
+++ b/tools/dsymutil/CMakeLists.txt
@@ -1,5 +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 c04b2fe..9fa3f78 100644
--- a/tools/dsymutil/DebugMap.cpp
+++ b/tools/dsymutil/DebugMap.cpp
@@ -23,9 +23,9 @@ 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;
@@ -45,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';
}
diff --git a/tools/dsymutil/DebugMap.h b/tools/dsymutil/DebugMap.h
index ff2b27e..ee48b09 100644
--- a/tools/dsymutil/DebugMap.h
+++ b/tools/dsymutil/DebugMap.h
@@ -83,7 +83,7 @@ public:
/// debug map.
DebugMapObject &addDebugMapObject(StringRef ObjectFilePath);
- const Triple &getTriple() { return BinaryTriple; }
+ const Triple &getTriple() const { return BinaryTriple; }
void print(raw_ostream &OS) const;
@@ -101,8 +101,10 @@ 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;
@@ -111,7 +113,7 @@ public:
/// \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.
@@ -123,6 +125,10 @@ public:
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;
diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp
index 3c0bc0b..c9c05cd 100644
--- a/tools/dsymutil/DwarfLinker.cpp
+++ b/tools/dsymutil/DwarfLinker.cpp
@@ -10,19 +10,55 @@
#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/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 {
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.
@@ -30,26 +66,900 @@ class CompileUnit {
public:
/// \brief Information gathered about a DIE in the object file.
struct DIEInfo {
- uint64_t Address; ///< Linked address of the described entity.
+ 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) : OrigUnit(OrigUnit) {
+ 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;
- std::vector<DIEInfo> Info; ///< DIE info indexed by DIE index.
+ 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(const 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.getCompileUnitDIE(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(
+ const 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
@@ -66,15 +976,21 @@ private:
/// first step when we start processing a DebugMapObject.
class DwarfLinker {
public:
- DwarfLinker(StringRef OutputFilename, bool Verbose)
- : OutputFilename(OutputFilename), Verbose(Verbose), BinHolder(Verbose) {}
+ 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 &);
+ void startDebugObject(DWARFContext &, DebugMapObject &);
/// \brief Called at the end of a debug object link.
void endDebugObject();
@@ -104,7 +1020,7 @@ private:
/// 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.
+ /// root DIE selection and during DIE cloning.
unsigned NextValidReloc;
bool findValidRelocsInDebugInfo(const object::ObjectFile &Obj,
@@ -160,6 +1076,114 @@ private:
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.
///
/// @{
@@ -170,20 +1194,37 @@ private:
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 DWARFDebugInfoEntryMinimal *DIE = nullptr) const;
+
+ bool createStreamer(Triple TheTriple, StringRef OutputFilename);
/// @}
private:
std::string OutputFilename;
- bool Verbose;
+ 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
@@ -215,16 +1256,34 @@ const DWARFDebugInfoEntryMinimal *DwarfLinker::resolveDIEReference(
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 DWARFDebugInfoEntryMinimal *DIE) const {
+ StringRef Context = "<debug map>";
if (CurrentDebugObject)
- errs() << Twine("while processing ") +
- CurrentDebugObject->getObjectFilename() + ":\n";
- errs() << Twine("warning: ") + Warning + "\n";
+ Context = CurrentDebugObject->getObjectFilename();
+ warn(Warning, Context);
- if (!Verbose || !DIE)
+ if (!Options.Verbose || !DIE)
return;
errs() << " in DIE:\n";
@@ -232,6 +1291,14 @@ void DwarfLinker::reportWarning(const Twine &Warning, const DWARFUnit *Unit,
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,
@@ -260,14 +1327,45 @@ static bool dieNeedsChildrenToBeMeaningful(uint32_t Tag) {
llvm_unreachable("Invalid Tag");
}
-void DwarfLinker::startDebugObject(DWARFContext &Dwarf) {
+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
@@ -378,14 +1476,15 @@ bool DwarfLinker::hasValidRelocation(uint32_t StartOffset, uint32_t EndOffset,
return false;
const auto &ValidReloc = ValidRelocs[NextValidReloc++];
- if (Verbose)
+ 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.Address =
- ValidReloc.Mapping->getValue().BinaryAddress + ValidReloc.Addend;
+ Info.AddrAdjust = int64_t(ValidReloc.Mapping->getValue().BinaryAddress) +
+ ValidReloc.Addend -
+ ValidReloc.Mapping->getValue().ObjectAddress;
Info.InDebugMap = true;
return true;
}
@@ -442,7 +1541,7 @@ unsigned DwarfLinker::shouldKeepVariableDIE(
(Flags & TF_InFunctionScope))
return Flags;
- if (Verbose)
+ if (Options.Verbose)
DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */);
return Flags | TF_Keep;
@@ -474,10 +1573,30 @@ unsigned DwarfLinker::shouldKeepSubprogramDIE(
!hasValidRelocation(LowPcOffset, LowPcEndOffset, MyInfo))
return Flags;
- if (Verbose)
+ if (Options.Verbose)
DIE.dump(outs(), const_cast<DWARFUnit *>(&OrigUnit), 0, 8 /* Indent */);
- return Flags | TF_Keep;
+ 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.
@@ -503,7 +1622,6 @@ unsigned DwarfLinker::shouldKeepDIE(const DWARFDebugInfoEntryMinimal &DIE,
return Flags;
}
-
/// \brief Mark the passed DIE as well as all the ones it depends on
/// as kept.
///
@@ -601,6 +1719,708 @@ void DwarfLinker::lookForDIEsToKeep(const DWARFDebugInfoEntryMinimal &DIE,
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.getCompileUnitDIE(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().getCompileUnitDIE();
+ 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()) {
@@ -608,10 +2428,17 @@ bool DwarfLinker::link(const DebugMap &Map) {
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 (Verbose)
+ if (Options.Verbose)
outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n";
auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename());
if (std::error_code EC = ErrOrObj.getError()) {
@@ -621,24 +2448,24 @@ bool DwarfLinker::link(const DebugMap &Map) {
// Look for relocations that correspond to debug map entries.
if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
- if (Verbose)
+ if (Options.Verbose)
outs() << "No valid relocations found. Skipping.\n";
continue;
}
// Setup access to the debug info.
DWARFContextInMemory DwarfContext(*ErrOrObj);
- startDebugObject(DwarfContext);
+ 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->getCompileUnitDIE(false);
- if (Verbose) {
+ if (Options.Verbose) {
outs() << "Input compilation unit:";
CUDie->dump(outs(), CU.get(), 0);
}
- Units.emplace_back(*CU);
+ Units.emplace_back(*CU, UnitID++);
gatherDIEParents(CUDie, 0, Units.back());
}
@@ -651,16 +2478,63 @@ bool DwarfLinker::link(const DebugMap &Map) {
lookForDIEsToKeep(*CurrentUnit.getOrigUnit().getCompileUnitDIE(), *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().getCompileUnitDIE();
+ 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();
}
- return true;
+ // 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, bool Verbose) {
- DwarfLinker Linker(OutputFilename, Verbose);
+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 c995291..99b0b44 100644
--- a/tools/dsymutil/LLVMBuild.txt
+++ b/tools/dsymutil/LLVMBuild.txt
@@ -19,4 +19,4 @@
type = Tool
name = llvm-dsymutil
parent = Tools
-required_libraries = DebugInfoDWARF Object Support
+required_libraries = AsmPrinter DebugInfoDWARF MC Object Support all-targets
diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp
index 7bb0011..bf64303 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);
@@ -149,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
@@ -159,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:
@@ -174,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.");
}
@@ -231,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 e8dc569..c4365e0 100644
--- a/tools/dsymutil/Makefile
+++ b/tools/dsymutil/Makefile
@@ -9,7 +9,7 @@
LEVEL := ../..
TOOLNAME := llvm-dsymutil
-LINK_COMPONENTS := DebugInfoDWARF 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 2b4fcfe..4fc91b0 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 9203bea..e9f7cd9 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/gold-plugin.cpp b/tools/gold/gold-plugin.cpp
index e3a57b5..93ce3bc 100644
--- a/tools/gold/gold-plugin.cpp
+++ b/tools/gold/gold-plugin.cpp
@@ -91,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;
@@ -124,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
@@ -295,8 +300,8 @@ static void diagnosticHandler(const DiagnosticInfo &DI, void *Context) {
case DS_Warning:
Level = LDPL_WARNING;
break;
- case DS_Remark:
case DS_Note:
+ case DS_Remark:
Level = LDPL_INFO;
break;
}
@@ -598,6 +603,7 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
Module &M = Obj.getModule();
+ M.materializeMetadata();
UpgradeDebugInfo(M);
SmallPtrSet<GlobalValue *, 8> Used;
@@ -711,10 +717,9 @@ getModuleForFile(LLVMContext &Context, claimed_file &F,
static void runLTOPasses(Module &M, TargetMachine &TM) {
if (const DataLayout *DL = TM.getDataLayout())
- M.setDataLayout(DL);
+ M.setDataLayout(*DL);
legacy::PassManager passes;
- passes.add(new DataLayoutPass());
passes.add(createTargetTransformInfoWrapperPass(TM.getTargetIRAnalysis()));
PassManagerBuilder PMB;
@@ -724,6 +729,7 @@ static void runLTOPasses(Module &M, TargetMachine &TM) {
PMB.VerifyOutput = true;
PMB.LoopVectorize = true;
PMB.SLPVectorize = true;
+ PMB.OptLevel = options::OptLevel;
PMB.populateLTOPassManager(passes);
passes.run(M);
}
@@ -754,9 +760,24 @@ 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);
@@ -764,7 +785,6 @@ static void codegen(Module &M) {
saveBCFile(output_name + ".opt.bc", M);
legacy::PassManager CodeGenPasses;
- CodeGenPasses.add(new DataLayoutPass());
SmallString<128> Filename;
int FD;
@@ -809,7 +829,7 @@ static ld_plugin_status allSymbolsReadHook(raw_fd_ostream *ApiFile) {
return LDPS_OK;
LLVMContext Context;
- Context.setDiagnosticHandler(diagnosticHandler);
+ Context.setDiagnosticHandler(diagnosticHandler, nullptr, true);
std::unique_ptr<Module> Combined(new Module("ld-temp.o", Context));
Linker L(Combined.get());
diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt
index 484ff40..dcbcf9d 100644
--- a/tools/llc/CMakeLists.txt
+++ b/tools/llc/CMakeLists.txt
@@ -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 efa1422..55a45dc 100644
--- a/tools/llc/llc.cpp
+++ b/tools/llc/llc.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/CodeGen/CommandFlags.h"
@@ -305,8 +306,7 @@ static int compileModule(char **argv, LLVMContext &Context) {
// Add the target data from the target machine, if it exists, or the module.
if (const DataLayout *DL = Target->getDataLayout())
- M->setDataLayout(DL);
- PM.add(new DataLayoutPass());
+ M->setDataLayout(*DL);
if (RelaxAll.getNumOccurrences() > 0 &&
FileType != TargetMachine::CGFT_ObjectFile)
diff --git a/tools/lli/Android.mk b/tools/lli/Android.mk
index d771e56..a67c969 100644
--- a/tools/lli/Android.mk
+++ b/tools/lli/Android.mk
@@ -9,6 +9,7 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../..
lli_SRC_FILES := \
lli.cpp \
+ OrcLazyJIT.cpp \
RemoteMemoryManager.cpp \
RemoteTarget.cpp \
RemoteTargetExternal.cpp \
diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt
index 463c853..f98275b 100644
--- a/tools/lli/CMakeLists.txt
+++ b/tools/lli/CMakeLists.txt
@@ -35,8 +35,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/OrcLazyJIT.cpp b/tools/lli/OrcLazyJIT.cpp
new file mode 100644
index 0000000..4a8d3b9
--- /dev/null
+++ b/tools/lli/OrcLazyJIT.cpp
@@ -0,0 +1,53 @@
+//===------ 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"
+
+using namespace llvm;
+
+std::unique_ptr<OrcLazyJIT::CompileCallbackMgr>
+OrcLazyJIT::createCallbackMgr(Triple T, LLVMContext &Context) {
+ switch (T.getArch()) {
+ default:
+ // Flag error.
+ Error = true;
+ return nullptr;
+
+ case Triple::x86_64: {
+ typedef orc::JITCompileCallbackManager<CompileLayerT,
+ orc::OrcX86_64> CCMgrT;
+ return make_unique<CCMgrT>(CompileLayer, Context, 0, 64);
+ }
+ }
+}
+
+int llvm::runOrcLazyJIT(std::unique_ptr<Module> M, int ArgC, char* ArgV[]) {
+ OrcLazyJIT J(std::unique_ptr<TargetMachine>(EngineBuilder().selectTarget()),
+ getGlobalContext());
+
+ if (!J.Ok()) {
+ errs() << "Could not construct JIT.\n";
+ return 1;
+ }
+
+ 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 = reinterpret_cast<MainFnPtr>(
+ static_cast<uintptr_t>(MainSym.getAddress()));
+
+ return Main(ArgC, ArgV);
+}
diff --git a/tools/lli/OrcLazyJIT.h b/tools/lli/OrcLazyJIT.h
new file mode 100644
index 0000000..76e1ac6
--- /dev/null
+++ b/tools/lli/OrcLazyJIT.h
@@ -0,0 +1,97 @@
+//===--- 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/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/LazyEmittingLayer.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.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 orc::LazyEmittingLayer<CompileLayerT> LazyEmitLayerT;
+ typedef orc::CompileOnDemandLayer<LazyEmitLayerT,
+ CompileCallbackMgr> CODLayerT;
+ typedef CODLayerT::ModuleSetHandleT ModuleHandleT;
+
+ OrcLazyJIT(std::unique_ptr<TargetMachine> TM, LLVMContext &Context)
+ : Error(false), TM(std::move(TM)),
+ Mang(this->TM->getDataLayout()),
+ ObjectLayer([](){ return llvm::make_unique<SectionMemoryManager>(); }),
+ CompileLayer(ObjectLayer, orc::SimpleCompiler(*this->TM)),
+ LazyEmitLayer(CompileLayer),
+ CCMgr(createCallbackMgr(Triple(this->TM->getTargetTriple()), Context)),
+ CODLayer(LazyEmitLayer, *CCMgr) { }
+
+ bool Ok() const { return !Error; }
+
+ 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());
+
+ std::vector<std::unique_ptr<Module>> S;
+ S.push_back(std::move(M));
+ return CODLayer.addModuleSet(std::move(S));
+ }
+
+ 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::unique_ptr<CompileCallbackMgr>
+ createCallbackMgr(Triple T, LLVMContext &Context);
+
+ std::string mangle(const std::string &Name) {
+ std::string MangledName;
+ {
+ raw_string_ostream MangledNameStream(MangledName);
+ Mang.getNameWithPrefix(MangledNameStream, Name);
+ }
+ return MangledName;
+ }
+
+ bool Error;
+ std::unique_ptr<TargetMachine> TM;
+ Mangler Mang;
+
+ ObjLayerT ObjectLayer;
+ CompileLayerT CompileLayer;
+ LazyEmitLayerT LazyEmitLayer;
+ std::unique_ptr<CompileCallbackMgr> CCMgr;
+ CODLayerT CODLayer;
+};
+
+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 47da8fb..0a16210 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/lli.cpp b/tools/lli/lli.cpp
index 9c2b781..47ce2c0 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"
@@ -42,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"
@@ -65,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("-"));
@@ -75,12 +80,19 @@ namespace {
cl::desc("Force interpretation: disable JIT"),
cl::init(false));
- cl::opt<bool> UseOrcMCJITReplacement("use-orcmcjit",
- cl::desc("Use the experimental "
- "OrcMCJITReplacement as a "
- "drop-in replacement for "
- "MCJIT."),
- cl::init(false));
+ 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
@@ -403,6 +415,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);
@@ -429,7 +444,7 @@ int main(int argc, char **argv, char * const *envp) {
builder.setEngineKind(ForceInterpreter
? EngineKind::Interpreter
: EngineKind::JIT);
- builder.setUseOrcMCJITReplacement(UseOrcMCJITReplacement);
+ builder.setUseOrcMCJITReplacement(UseJITKind == JITKind::OrcMCJITReplacement);
// If we are supposed to override the target triple, do so now.
if (!TargetTriple.empty())
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp
index 2f1eb3b..f813465 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"
diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt
index 50c84e6..d2ef45a 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 224035a..879b9ab 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/CodeCoverage.cpp b/tools/llvm-cov/CodeCoverage.cpp
index cf8ab33..0331a02 100644
--- a/tools/llvm-cov/CodeCoverage.cpp
+++ b/tools/llvm-cov/CodeCoverage.cpp
@@ -20,6 +20,7 @@
#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/InstrProfReader.h"
#include "llvm/Support/CommandLine.h"
@@ -28,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>
@@ -87,6 +89,7 @@ public:
LoadedSourceFiles;
bool CompareFilenamesOnly;
StringMap<std::string> RemappedFilenames;
+ llvm::Triple::ArchType CoverageArch;
};
}
@@ -193,7 +196,8 @@ CodeCoverageTool::createSourceFileView(StringRef SourceFile,
}
std::unique_ptr<CoverageMapping> CodeCoverageTool::load() {
- auto CoverageOrErr = CoverageMapping::load(ObjectFilename, PGOFilename);
+ 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();
@@ -242,6 +246,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"));
@@ -287,11 +294,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;
@@ -322,6 +337,16 @@ int CodeCoverageTool::run(Command Cmd, int argc, const char **argv) {
Filters.push_back(std::unique_ptr<CoverageFilter>(StatFilterer));
}
+ 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)
@@ -372,15 +397,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;
@@ -446,15 +466,10 @@ 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;
diff --git a/tools/llvm-cov/gcov.cpp b/tools/llvm-cov/gcov.cpp
index c0a48f8..4377a50 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.
diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp
index 86ec26d..bf66f58 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/Android.mk b/tools/llvm-cxxdump/Android.mk
index c3309e4..b45912c 100644
--- a/tools/llvm-vtabledump/Android.mk
+++ b/tools/llvm-cxxdump/Android.mk
@@ -3,11 +3,11 @@ LOCAL_PATH := $(call my-dir)
LLVM_ROOT_PATH := $(LOCAL_PATH)/../..
include $(LLVM_ROOT_PATH)/llvm.mk
-llvm_vtabledump_SRC_FILES := \
+llvm_cxxdump_SRC_FILES := \
Error.cpp \
- llvm-vtabledump.cpp
+ llvm-cxxdump.cpp
-llvm_vtabledump_STATIC_LIBRARIES := \
+llvm_cxxdump_STATIC_LIBRARIES := \
libLLVMARMAsmParser \
libLLVMARMInfo \
libLLVMARMDesc \
@@ -47,13 +47,13 @@ llvm_vtabledump_STATIC_LIBRARIES := \
include $(CLEAR_VARS)
-LOCAL_MODULE := llvm-vtabledump
+LOCAL_MODULE := llvm-cxxdump
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(llvm_vtabledump_SRC_FILES)
+LOCAL_SRC_FILES := $(llvm_cxxdump_SRC_FILES)
LOCAL_LDLIBS += -lpthread -lm -ldl
-LOCAL_STATIC_LIBRARIES := $(llvm_vtabledump_STATIC_LIBRARIES)
+LOCAL_STATIC_LIBRARIES := $(llvm_cxxdump_STATIC_LIBRARIES)
include $(LLVM_HOST_BUILD_MK)
include $(LLVM_GEN_INTRINSICS_MK)
diff --git a/tools/llvm-vtabledump/CMakeLists.txt b/tools/llvm-cxxdump/CMakeLists.txt
index 4fe205b..ada886e 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 c5de895..16fed96 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 fd8bb18..7caf6d6 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 6a3cbff..4e08815 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 596c64c..02e8e5f 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 a21acae..aeb977a 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,8 +349,7 @@ 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;
@@ -318,7 +370,8 @@ static void dumpVTables(const ObjectFile *Obj) {
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) {
StringRef CHDName = CHDPair.first;
@@ -344,7 +397,8 @@ 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) {
StringRef TDName = TDPair.first;
@@ -356,6 +410,60 @@ static void dumpVTables(const ObjectFile *Obj) {
/*UseHexEscapes=*/true)
<< '\n';
}
+ for (const std::pair<StringRef, ThrowInfo> &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 std::pair<StringRef, CatchableTypeArray> &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 std::pair<StringRef, CatchableType> &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 std::pair<std::pair<StringRef, uint64_t>, StringRef> &VTTPair :
VTTEntries) {
StringRef VTTName = VTTPair.first.first;
@@ -410,17 +518,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 +542,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 +558,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 62f7557..daa05cb 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-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp
index 8cbcdc5..8bfd319 100644
--- a/tools/llvm-extract/llvm-extract.cpp
+++ b/tools/llvm-extract/llvm-extract.cpp
@@ -247,7 +247,6 @@ 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.
legacy::PassManager Passes;
- Passes.add(new DataLayoutPass()); // Use correct DataLayout
std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp
index c3091a5..af1a59b 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 828b9bb..e52191a 100644
--- a/tools/llvm-link/llvm-link.cpp
+++ b/tools/llvm-link/llvm-link.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Linker/Linker.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/DiagnosticPrinter.h"
@@ -111,6 +112,12 @@ int main(int argc, char **argv) {
return 1;
}
+ if (verifyModule(*M)) {
+ errs() << argv[0] << ": input module '" << InputFilenames[i]
+ << "' is broken!\n";
+ return 1;
+ }
+
if (Verbose) errs() << "Linking in '" << InputFilenames[i] << "'\n";
if (L.linkInModule(M.get()))
diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp
index 32b3134..9cd6587 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),
@@ -79,8 +83,8 @@ struct ModuleInfo {
};
}
-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: ";
@@ -98,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 =
@@ -118,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;
@@ -146,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();
@@ -231,6 +240,8 @@ int main(int argc, char **argv) {
// 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)
@@ -245,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]
@@ -265,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/Android.mk b/tools/llvm-mc/Android.mk
index ad83637..e7e29ee 100644
--- a/tools/llvm-mc/Android.mk
+++ b/tools/llvm-mc/Android.mk
@@ -38,8 +38,8 @@ llvm_mc_STATIC_LIBRARIES := \
libLLVMAsmPrinter \
libLLVMCodeGen \
libLLVMTransformUtils \
- libLLVMAnalysis \
libLLVMTarget \
+ libLLVMAnalysis \
libLLVMMC \
libLLVMObject \
libLLVMBitReader \
diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp
index 91bacc0..4f9b6fc 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();
@@ -457,7 +458,7 @@ 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,
@@ -468,10 +469,11 @@ int main(int argc, char **argv) {
Str.reset(TheTarget->createNullStreamer(Ctx));
} else {
assert(FileType == OFT_ObjectFile && "Invalid file type!");
- MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx);
+ 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, FOS, CE,
+ *STI, RelaxAll,
+ /*DWARFMustBeAtTheEnd*/ false));
if (NoExecStack)
Str->InitSections(true);
}
diff --git a/tools/llvm-nm/Android.mk b/tools/llvm-nm/Android.mk
index e3b66f0..4510fa9 100644
--- a/tools/llvm-nm/Android.mk
+++ b/tools/llvm-nm/Android.mk
@@ -39,8 +39,8 @@ llvm_nm_STATIC_LIBRARIES := \
libLLVMX86Disassembler \
libLLVMCodeGen \
libLLVMTransformUtils \
- libLLVMAnalysis \
libLLVMTarget \
+ libLLVMAnalysis \
libLLVMObject \
libLLVMBitReader \
libLLVMMC \
diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp
index f911c72..b62b547 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;
@@ -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/Android.mk b/tools/llvm-objdump/Android.mk
index 3b5eafd..847f932 100644
--- a/tools/llvm-objdump/Android.mk
+++ b/tools/llvm-objdump/Android.mk
@@ -42,8 +42,8 @@ llvm_objdump_STATIC_LIBRARIES := \
libLLVMAsmPrinter \
libLLVMCodeGen \
libLLVMTransformUtils \
- libLLVMAnalysis \
libLLVMTarget \
+ libLLVMAnalysis \
libLLVMObject \
libLLVMMCParser \
libLLVMMC \
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp
index cae4356..86504e6 100644
--- a/tools/llvm-objdump/MachODump.cpp
+++ b/tools/llvm-objdump/MachODump.cpp
@@ -63,6 +63,9 @@ 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"));
@@ -96,6 +99,35 @@ cl::list<std::string>
cl::desc("Prints the specified segment,section for "
"Mach-O objects (requires -macho)"));
+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<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"),
cl::ZeroOrMore);
@@ -173,7 +205,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;
@@ -182,19 +214,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;
@@ -206,14 +238,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";
@@ -222,7 +254,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)
@@ -323,15 +355,17 @@ static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose,
continue;
}
outs() << format("%5u ", indirect_symbol);
- MachO::symtab_command Symtab = O->getSymtabLoadCommand();
- if (indirect_symbol < Symtab.nsyms) {
- symbol_iterator Sym = O->getSymbolByIndex(indirect_symbol);
- SymbolRef Symbol = *Sym;
- StringRef SymName;
- Symbol.getName(SymName);
- outs() << SymName;
- } else {
- outs() << "?";
+ 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";
}
@@ -504,6 +538,59 @@ static void PrintLinkOptHints(MachOObjectFile *O) {
}
}
+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,
@@ -749,103 +836,103 @@ static void DumpLiteralPointerSection(MachOObjectFile *O,
}
// First look for an external relocation entry for this literal pointer.
- bool reloc_found = false;
- for (unsigned j = 0, e = Relocs.size(); j != e; ++j) {
- if (Relocs[i].first == i) {
- symbol_iterator RelocSym = Relocs[j].second;
- StringRef SymName;
- RelocSym->getName(SymName);
- outs() << "external relocation entry for symbol:" << SymName << "\n";
- reloc_found = true;
- }
- }
- if (reloc_found == true)
+ 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.
- bool found = false;
- for (unsigned SectIdx = 0; SectIdx != LiteralSections.size(); SectIdx++) {
- uint64_t SectAddress = LiteralSections[SectIdx].getAddress();
- uint64_t SectSize = LiteralSections[SectIdx].getSize();
- if (lp >= SectAddress && lp < SectAddress + SectSize) {
- found = true;
-
- StringRef SectName;
- LiteralSections[SectIdx].getName(SectName);
- DataRefImpl Ref = LiteralSections[SectIdx].getRawDataRefImpl();
- StringRef SegmentName = O->getSectionFinalSegmentName(Ref);
- outs() << SegmentName << ":" << SectName << ":";
-
- uint32_t section_type;
- if (O->is64Bit()) {
- const MachO::section_64 Sec = O->getSection64(Ref);
- section_type = Sec.flags & MachO::SECTION_TYPE;
- } else {
- const MachO::section Sec = O->getSection(Ref);
- section_type = Sec.flags & MachO::SECTION_TYPE;
- }
+ 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;
+ }
- StringRef BytesStr;
- LiteralSections[SectIdx].getContents(BytesStr);
- const char *Contents = reinterpret_cast<const char *>(BytesStr.data());
-
- switch (section_type) {
- case MachO::S_CSTRING_LITERALS:
- for (uint64_t i = lp - SectAddress;
- i < SectSize && Contents[i] != '\0'; i++) {
- DumpCstringChar(Contents[i]);
- }
- outs() << "\n";
- break;
- case MachO::S_4BYTE_LITERALS:
- float f;
- memcpy(&f, Contents + (lp - SectAddress), sizeof(float));
- uint32_t l;
- memcpy(&l, Contents + (lp - SectAddress), sizeof(uint32_t));
- if (O->isLittleEndian() != sys::IsLittleEndianHost) {
- sys::swapByteOrder(f);
- sys::swapByteOrder(l);
- }
- DumpLiteral4(l, f);
- break;
- case MachO::S_8BYTE_LITERALS: {
- double d;
- memcpy(&d, Contents + (lp - SectAddress), sizeof(double));
- uint32_t l0, l1;
- memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
- memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
- sizeof(uint32_t));
- if (O->isLittleEndian() != sys::IsLittleEndianHost) {
- sys::swapByteOrder(f);
- sys::swapByteOrder(l0);
- sys::swapByteOrder(l1);
- }
- DumpLiteral8(O, l0, l1, d);
- break;
- }
- case MachO::S_16BYTE_LITERALS: {
- uint32_t l0, l1, l2, l3;
- memcpy(&l0, Contents + (lp - SectAddress), sizeof(uint32_t));
- memcpy(&l1, Contents + (lp - SectAddress) + sizeof(uint32_t),
- sizeof(uint32_t));
- memcpy(&l2, Contents + (lp - SectAddress) + 2 * sizeof(uint32_t),
- sizeof(uint32_t));
- memcpy(&l3, Contents + (lp - SectAddress) + 3 * sizeof(uint32_t),
- sizeof(uint32_t));
- if (O->isLittleEndian() != sys::IsLittleEndianHost) {
- sys::swapByteOrder(l0);
- sys::swapByteOrder(l1);
- sys::swapByteOrder(l2);
- sys::swapByteOrder(l3);
- }
- DumpLiteral16(l0, l1, l2, l3);
- break;
- }
- }
+ 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;
+ }
}
- if (found == false)
- outs() << format("0x%" PRIx64, lp) << " (not in a literal section)\n";
}
}
@@ -894,7 +981,7 @@ static void DumpRawSectionContents(MachOObjectFile *O, const char *sect,
if (O->is64Bit())
outs() << format("%016" PRIx64, addr) << "\t";
else
- outs() << format("%08" PRIx64, sect) << "\t";
+ 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) << " ";
@@ -981,6 +1068,10 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
DisassembleMachO(Filename, O, SegName, SectName);
continue;
}
+ if (SegName == "__TEXT" && SectName == "__info_plist") {
+ outs() << sect;
+ continue;
+ }
switch (section_type) {
case MachO::S_REGULAR:
DumpRawSectionContents(O, sect, sect_size, sect_addr);
@@ -989,20 +1080,20 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
outs() << "zerofill section and has no contents in the file\n";
break;
case MachO::S_CSTRING_LITERALS:
- DumpCstringSection(O, sect, sect_size, sect_addr, verbose);
+ DumpCstringSection(O, sect, sect_size, sect_addr, !NoLeadingAddr);
break;
case MachO::S_4BYTE_LITERALS:
- DumpLiteral4Section(O, sect, sect_size, sect_addr, verbose);
+ DumpLiteral4Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
break;
case MachO::S_8BYTE_LITERALS:
- DumpLiteral8Section(O, sect, sect_size, sect_addr, verbose);
+ DumpLiteral8Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
break;
case MachO::S_16BYTE_LITERALS:
- DumpLiteral16Section(O, sect, sect_size, sect_addr, verbose);
- break;
+ DumpLiteral16Section(O, sect, sect_size, sect_addr, !NoLeadingAddr);
+ break;
case MachO::S_LITERAL_POINTERS:
DumpLiteralPointerSection(O, Section, sect, sect_size, sect_addr,
- verbose);
+ !NoLeadingAddr);
break;
case MachO::S_MOD_INIT_FUNC_POINTERS:
case MachO::S_MOD_TERM_FUNC_POINTERS:
@@ -1026,6 +1117,24 @@ static void DumpSectionContents(StringRef Filename, MachOObjectFile *O,
}
}
+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
@@ -1072,7 +1181,7 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
// UniversalHeaders or ArchiveHeaders.
if (Disassemble || PrivateHeaders || ExportsTrie || Rebase || Bind ||
LazyBind || WeakBind || IndirectSymbols || DataInCode || LinkOptHints ||
- DumpSections.size() != 0) {
+ DylibsUsed || DylibId || DumpSections.size() != 0) {
outs() << Filename;
if (!ArchiveMemberName.empty())
outs() << '(' << ArchiveMemberName << ')';
@@ -1084,9 +1193,9 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
if (Disassemble)
DisassembleMachO(Filename, MachOOF, "__TEXT", "__text");
if (IndirectSymbols)
- PrintIndirectSymbols(MachOOF, true);
+ PrintIndirectSymbols(MachOOF, !NonVerbose);
if (DataInCode)
- PrintDataInCodeTable(MachOOF, true);
+ PrintDataInCodeTable(MachOOF, !NonVerbose);
if (LinkOptHints)
PrintLinkOptHints(MachOOF);
if (Relocations)
@@ -1096,7 +1205,13 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF,
if (SectionContents)
PrintSectionContents(MachOOF);
if (DumpSections.size() != 0)
- DumpSectionContents(Filename, MachOOF, true);
+ 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)
@@ -1433,7 +1548,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.
@@ -1608,8 +1723,8 @@ struct DisassembleInfo {
// 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;
@@ -1621,7 +1736,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();
@@ -1704,7 +1819,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
@@ -1770,56 +1886,60 @@ 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();
@@ -1844,27 +1964,25 @@ 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
@@ -1886,18 +2004,13 @@ 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->AddrMap);
if (add != nullptr) {
@@ -1906,95 +2019,86 @@ int SymbolizerGetOpInfo(void *DisInfo, uint64_t Pc, uint64_t Offset,
}
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) {
@@ -2279,8 +2383,9 @@ 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) {
offset = 0;
left = 0;
S = SectionRef();
@@ -2302,10 +2407,10 @@ const char *get_pointer_64(uint64_t Address, uint32_t &offset, uint32_t &left,
// 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) {
+static const char *get_symbol_64(uint32_t sect_offset, SectionRef S,
+ DisassembleInfo *info, uint64_t &n_value) {
n_value = 0;
- if (info->verbose == false)
+ if (!info->verbose)
return nullptr;
// See if there is an external relocation entry at the sect_offset.
@@ -2437,9 +2542,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;
@@ -2488,8 +2593,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;
@@ -2522,8 +2627,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;
@@ -2555,9 +2660,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;
@@ -2599,7 +2705,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".
@@ -2615,7 +2721,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);
@@ -2626,13 +2732,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)
@@ -2640,10 +2746,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;
@@ -2691,13 +2797,14 @@ 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;
@@ -3075,6 +3182,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);
@@ -3085,10 +3193,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;
@@ -3101,7 +3215,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;
@@ -3129,6 +3243,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();
@@ -3169,13 +3287,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";
@@ -3192,9 +3312,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++;
@@ -3213,8 +3331,7 @@ 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();
@@ -3267,19 +3384,19 @@ 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(), "");
outs() << "\n";
@@ -5429,8 +5546,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/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp
index 6e62aaa..7bec062 100644
--- a/tools/llvm-objdump/llvm-objdump.cpp
+++ b/tools/llvm-objdump/llvm-objdump.cpp
@@ -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) {
@@ -412,8 +399,7 @@ 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(), "");
outs() << CommentStream.str();
@@ -907,6 +893,9 @@ int main(int argc, char **argv) {
&& !(IndirectSymbols && MachOOpt)
&& !(DataInCode && MachOOpt)
&& !(LinkOptHints && MachOOpt)
+ && !(InfoPlist && MachOOpt)
+ && !(DylibsUsed && MachOOpt)
+ && !(DylibId && 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 19f842f..c1d5ff8 100644
--- a/tools/llvm-objdump/llvm-objdump.h
+++ b/tools/llvm-objdump/llvm-objdump.h
@@ -40,6 +40,11 @@ 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<std::string> DisSymName;
+extern cl::opt<bool> NonVerbose;
extern cl::opt<bool> Relocations;
extern cl::opt<bool> SectionHeaders;
extern cl::opt<bool> SectionContents;
@@ -49,7 +54,7 @@ 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);
diff --git a/tools/llvm-pdbdump/Android.mk b/tools/llvm-pdbdump/Android.mk
index 82a406a..313e9a4 100644
--- a/tools/llvm-pdbdump/Android.mk
+++ b/tools/llvm-pdbdump/Android.mk
@@ -4,10 +4,13 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../..
include $(LLVM_ROOT_PATH)/llvm.mk
llvm_pdbdump_SRC_FILES := \
+ llvm-pdbdump.cpp \
+ BuiltinDumper.cpp \
ClassDefinitionDumper.cpp \
CompilandDumper.cpp \
+ EnumDumper.cpp \
FunctionDumper.cpp \
- llvm-pdbdump.cpp \
+ LinePrinter.cpp \
TypedefDumper.cpp \
TypeDumper.cpp \
VariableDumper.cpp
diff --git a/tools/llvm-pdbdump/BuiltinDumper.cpp b/tools/llvm-pdbdump/BuiltinDumper.cpp
new file mode 100644
index 0000000..d808298
--- /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 0000000..8cf984a
--- /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
index 0519bf0..4dd339c 100644
--- a/tools/llvm-pdbdump/CMakeLists.txt
+++ b/tools/llvm-pdbdump/CMakeLists.txt
@@ -5,9 +5,12 @@ set(LLVM_LINK_COMPONENTS
add_llvm_tool(llvm-pdbdump
llvm-pdbdump.cpp
+ BuiltinDumper.cpp
ClassDefinitionDumper.cpp
CompilandDumper.cpp
+ EnumDumper.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
index edf6eb4..8abf3fa 100644
--- a/tools/llvm-pdbdump/ClassDefinitionDumper.cpp
+++ b/tools/llvm-pdbdump/ClassDefinitionDumper.cpp
@@ -8,7 +8,9 @@
//===----------------------------------------------------------------------===//
#include "ClassDefinitionDumper.h"
+#include "EnumDumper.h"
#include "FunctionDumper.h"
+#include "LinePrinter.h"
#include "llvm-pdbdump.h"
#include "TypedefDumper.h"
#include "VariableDumper.h"
@@ -27,14 +29,38 @@
using namespace llvm;
-ClassDefinitionDumper::ClassDefinitionDumper() : PDBSymDumper(true) {}
+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();
+ }
-void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class,
- raw_ostream &OS, int Indent) {
- OS << "class " << Class.getName() << " {";
+ Printer << " {";
auto Children = Class.findAllChildren();
if (Children->getChildCount() == 0) {
- OS << "}";
+ Printer << "}";
return;
}
@@ -58,9 +84,10 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class,
auto &AccessGroup = Groups.find((int)Access)->second;
if (auto Func = dyn_cast<PDBSymbolFunc>(Child.get())) {
- if (Func->isCompilerGenerated())
+ if (Func->isCompilerGenerated() && opts::ExcludeCompilerGenerated)
continue;
- if (Func->getLength() == 0 && !Func->isPureVirtual())
+ if (Func->getLength() == 0 && !Func->isPureVirtual() &&
+ !Func->isIntroVirtualFunction())
continue;
Child.release();
AccessGroup.Functions.push_back(std::unique_ptr<PDBSymbolFunc>(Func));
@@ -73,80 +100,91 @@ void ClassDefinitionDumper::start(const PDBSymbolTypeUDT &Class,
}
int Count = 0;
- Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0], OS, Indent);
+ Count += dumpAccessGroup((PDB_MemberAccess)0, Groups[0]);
Count += dumpAccessGroup(PDB_MemberAccess::Public,
- Groups[(int)PDB_MemberAccess::Public], OS, Indent);
- Count +=
- dumpAccessGroup(PDB_MemberAccess::Protected,
- Groups[(int)PDB_MemberAccess::Protected], OS, Indent);
+ 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], OS, Indent);
-
+ Groups[(int)PDB_MemberAccess::Private]);
if (Count > 0)
- OS << newline(Indent);
- OS << "}";
+ Printer.NewLine();
+ Printer << "}";
}
int ClassDefinitionDumper::dumpAccessGroup(PDB_MemberAccess Access,
- const SymbolGroup &Group,
- raw_ostream &OS, int Indent) {
+ const SymbolGroup &Group) {
if (Group.Functions.empty() && Group.Data.empty() && Group.Unknown.empty())
return 0;
int Count = 0;
- if (Access == PDB_MemberAccess::Private)
- OS << newline(Indent) << "private:";
- else if (Access == PDB_MemberAccess::Protected)
- OS << newline(Indent) << "protected:";
- else if (Access == PDB_MemberAccess::Public)
- OS << newline(Indent) << "public:";
+ 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(OS, Indent + 2, *this);
+ (*iter)->dump(*this);
}
for (auto iter = Group.Data.begin(), end = Group.Data.end(); iter != end;
++iter) {
++Count;
- (*iter)->dump(OS, Indent + 2, *this);
+ (*iter)->dump(*this);
}
for (auto iter = Group.Unknown.begin(), end = Group.Unknown.end();
iter != end; ++iter) {
++Count;
- (*iter)->dump(OS, Indent + 2, *this);
+ (*iter)->dump(*this);
}
+ Printer.Unindent();
return Count;
}
-void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol,
- raw_ostream &OS, int Indent) {}
+void ClassDefinitionDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {}
-void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS,
- int Indent) {
- VariableDumper Dumper;
- Dumper.start(Symbol, OS, Indent);
+void ClassDefinitionDumper::dump(const PDBSymbolData &Symbol) {
+ VariableDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void ClassDefinitionDumper::dump(const PDBSymbolFunc &Symbol, raw_ostream &OS,
- int Indent) {
- FunctionDumper Dumper;
- Dumper.start(Symbol, FunctionDumper::PointerType::None, OS, Indent);
+void ClassDefinitionDumper::dump(const 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,
- raw_ostream &OS, int Indent) {}
+void ClassDefinitionDumper::dump(const PDBSymbolTypeVTable &Symbol) {}
+
+void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
-void ClassDefinitionDumper::dump(const PDBSymbolTypeEnum &Symbol,
- raw_ostream &OS, int Indent) {
- OS << newline(Indent) << "enum " << Symbol.getName();
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol,
- raw_ostream &OS, int Indent) {
- OS << newline(Indent);
- TypedefDumper Dumper;
- Dumper.start(Symbol, OS, Indent);
+void ClassDefinitionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol,
- raw_ostream &OS, int Indent) {}
+void ClassDefinitionDumper::dump(const PDBSymbolTypeUDT &Symbol) {}
diff --git a/tools/llvm-pdbdump/ClassDefinitionDumper.h b/tools/llvm-pdbdump/ClassDefinitionDumper.h
index aaf0376..5b48ba8 100644
--- a/tools/llvm-pdbdump/ClassDefinitionDumper.h
+++ b/tools/llvm-pdbdump/ClassDefinitionDumper.h
@@ -20,26 +20,25 @@
namespace llvm {
+class LinePrinter;
+
class ClassDefinitionDumper : public PDBSymDumper {
public:
- ClassDefinitionDumper();
+ ClassDefinitionDumper(LinePrinter &P);
- void start(const PDBSymbolTypeUDT &Exe, raw_ostream &OS, int Indent);
+ void start(const PDBSymbolTypeUDT &Exe);
- void dump(const PDBSymbolTypeBaseClass &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolData &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeVTable &Symbol, raw_ostream &OS,
- int Indent) override;
+ 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) {
@@ -56,8 +55,7 @@ private:
};
typedef std::unordered_map<int, SymbolGroup> SymbolGroupByAccess;
- int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group,
- raw_ostream &OS, int Indent);
+ int dumpAccessGroup(PDB_MemberAccess Access, const SymbolGroup &Group);
};
}
diff --git a/tools/llvm-pdbdump/CompilandDumper.cpp b/tools/llvm-pdbdump/CompilandDumper.cpp
index 852ddfa..86bf32d 100644
--- a/tools/llvm-pdbdump/CompilandDumper.cpp
+++ b/tools/llvm-pdbdump/CompilandDumper.cpp
@@ -8,6 +8,7 @@
//===----------------------------------------------------------------------===//
#include "CompilandDumper.h"
+#include "LinePrinter.h"
#include "llvm-pdbdump.h"
#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
@@ -34,84 +35,106 @@
using namespace llvm;
-CompilandDumper::CompilandDumper() : PDBSymDumper(true) {}
+CompilandDumper::CompilandDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
-void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol,
- raw_ostream &OS, int Indent) {}
+void CompilandDumper::dump(const PDBSymbolCompilandDetails &Symbol) {}
-void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol, raw_ostream &OS,
- int Indent) {}
+void CompilandDumper::dump(const PDBSymbolCompilandEnv &Symbol) {}
-void CompilandDumper::start(const PDBSymbolCompiland &Symbol, raw_ostream &OS,
- int Indent, bool Children) {
+void CompilandDumper::start(const PDBSymbolCompiland &Symbol, bool Children) {
std::string FullName = Symbol.getName();
- OS << newline(Indent) << FullName;
+ 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(OS, Indent + 2, *this);
+ Child->dump(*this);
+ Printer.Unindent();
}
-void CompilandDumper::dump(const PDBSymbolData &Symbol, raw_ostream &OS,
- int Indent) {
- OS << newline(Indent);
+void CompilandDumper::dump(const PDBSymbolData &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+
switch (auto LocType = Symbol.getLocationType()) {
case PDB_LocType::Static:
- OS << "data: [";
- OS << format_hex(Symbol.getRelativeVirtualAddress(), 10);
- OS << "]";
+ Printer << "data: ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "]";
break;
case PDB_LocType::Constant:
- OS << "constant: [" << Symbol.getValue() << "]";
+ Printer << "constant: ";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get()
+ << "[" << Symbol.getValue() << "]";
break;
default:
- OS << "data(unexpected type=" << LocType << ")";
+ Printer << "data(unexpected type=" << LocType << ")";
}
- OS << " " << Symbol.getName();
+ Printer << " ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
}
-void CompilandDumper::dump(const PDBSymbolFunc &Symbol, raw_ostream &OS,
- int Indent) {
+void CompilandDumper::dump(const PDBSymbolFunc &Symbol) {
if (Symbol.getLength() == 0)
return;
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
- FunctionDumper Dumper;
- Dumper.start(Symbol, FunctionDumper::PointerType::None, OS, Indent);
+ Printer.NewLine();
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, FunctionDumper::PointerType::None);
}
-void CompilandDumper::dump(const PDBSymbolLabel &Symbol, raw_ostream &OS,
- int Indent) {
- OS << newline(Indent);
- OS << "label [" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "] "
- << Symbol.getName();
+void CompilandDumper::dump(const PDBSymbolLabel &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "label ";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(Symbol.getRelativeVirtualAddress(), 10) << "] ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
}
-void CompilandDumper::dump(const PDBSymbolThunk &Symbol, raw_ostream &OS,
- int Indent) {
- OS << newline(Indent) << "thunk ";
+void CompilandDumper::dump(const PDBSymbolThunk &Symbol) {
+ if (Printer.IsSymbolExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
+ Printer << "thunk ";
PDB_ThunkOrdinal Ordinal = Symbol.getThunkOrdinal();
uint32_t RVA = Symbol.getRelativeVirtualAddress();
if (Ordinal == PDB_ThunkOrdinal::TrampIncremental) {
- OS << format_hex(RVA, 10);
- OS << " -> " << format_hex(Symbol.getTargetRelativeVirtualAddress(), 10);
+ uint32_t Target = Symbol.getTargetRelativeVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(RVA, 10);
+ Printer << " -> ";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(Target, 10);
} else {
- OS << "[" << format_hex(RVA, 10);
- OS << " - " << format_hex(RVA + Symbol.getLength(), 10) << "]";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << "[" << format_hex(RVA, 10) << " - "
+ << format_hex(RVA + Symbol.getLength(), 10) << "]";
}
- OS << " (" << Ordinal << ") ";
+ Printer << " (";
+ WithColor(Printer, PDB_ColorItem::Register).get() << Ordinal;
+ Printer << ") ";
std::string Name = Symbol.getName();
if (!Name.empty())
- OS << Name;
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
}
-void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) {}
+void CompilandDumper::dump(const PDBSymbolTypeTypedef &Symbol) {}
-void CompilandDumper::dump(const PDBSymbolUnknown &Symbol, raw_ostream &OS,
- int Indent) {
- OS << newline(Indent);
- OS << "unknown (" << Symbol.getSymTag() << ")";
+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
index abcebc2..0d1d27c 100644
--- a/tools/llvm-pdbdump/CompilandDumper.h
+++ b/tools/llvm-pdbdump/CompilandDumper.h
@@ -14,25 +14,25 @@
namespace llvm {
+class LinePrinter;
+
class CompilandDumper : public PDBSymDumper {
public:
- CompilandDumper();
-
- void start(const PDBSymbolCompiland &Symbol, raw_ostream &OS, int Indent,
- bool Children);
-
- void dump(const PDBSymbolCompilandDetails &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolCompilandEnv &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolData &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolFunc &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolLabel &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolThunk &Symbol, raw_ostream &OS, int Indent) override;
- void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolUnknown &Symbol, raw_ostream &OS,
- int Indent) override;
+ 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;
};
}
diff --git a/tools/llvm-pdbdump/EnumDumper.cpp b/tools/llvm-pdbdump/EnumDumper.cpp
new file mode 100644
index 0000000..3514c39
--- /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 0000000..23de061
--- /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/FunctionDumper.cpp b/tools/llvm-pdbdump/FunctionDumper.cpp
index e659830..419f888 100644
--- a/tools/llvm-pdbdump/FunctionDumper.cpp
+++ b/tools/llvm-pdbdump/FunctionDumper.cpp
@@ -8,6 +8,8 @@
//===----------------------------------------------------------------------===//
#include "FunctionDumper.h"
+#include "BuiltinDumper.h"
+#include "LinePrinter.h"
#include "llvm-pdbdump.h"
#include "llvm/DebugInfo/PDB/IPDBSession.h"
@@ -16,7 +18,6 @@
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
-#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
@@ -29,7 +30,7 @@ using namespace llvm;
namespace {
template <class T>
-void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS,
+void dumpClassParentWithScopeOperator(const T &Symbol, LinePrinter &Printer,
llvm::FunctionDumper &Dumper) {
uint32_t ClassParentId = Symbol.getClassParentId();
auto ClassParent =
@@ -38,17 +39,19 @@ void dumpClassParentWithScopeOperator(const T &Symbol, llvm::raw_ostream &OS,
if (!ClassParent)
return;
- OS << ClassParent->getName() << "::";
+ WithColor(Printer, PDB_ColorItem::Type).get() << ClassParent->getName();
+ Printer << "::";
}
}
-FunctionDumper::FunctionDumper() : PDBSymDumper(true) {}
+FunctionDumper::FunctionDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
- PointerType Pointer, raw_ostream &OS) {
+ const char *Name, PointerType Pointer) {
auto ReturnType = Symbol.getReturnType();
- ReturnType->dump(OS, 0, *this);
- OS << " ";
+ ReturnType->dump(*this);
+ Printer << " ";
uint32_t ClassParentId = Symbol.getClassParentId();
auto ClassParent =
Symbol.getSession().getConcreteSymbolById<PDBSymbolTypeUDT>(
@@ -63,181 +66,189 @@ void FunctionDumper::start(const PDBSymbolTypeFunctionSig &Symbol,
if (Pointer == PointerType::None) {
if (ShouldDumpCallingConvention)
- OS << CC << " ";
- if (ClassParent)
- OS << "(" << ClassParent->getName() << "::)";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ Printer << "(";
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::)";
+ }
} else {
- OS << "(";
+ Printer << "(";
if (ShouldDumpCallingConvention)
- OS << CC << " ";
- OS << Symbol.getCallingConvention() << " ";
- if (ClassParent)
- OS << ClassParent->getName() << "::";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << CC << " ";
+ if (ClassParent) {
+ WithColor(Printer, PDB_ColorItem::Identifier).get()
+ << ClassParent->getName();
+ Printer << "::";
+ }
if (Pointer == PointerType::Reference)
- OS << "&";
+ Printer << "&";
else
- OS << "*";
- OS << ")";
+ Printer << "*";
+ if (Name)
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Name;
+ Printer << ")";
}
- OS << "(";
+ Printer << "(";
if (auto ChildEnum = Symbol.getArguments()) {
uint32_t Index = 0;
while (auto Arg = ChildEnum->getNext()) {
- Arg->dump(OS, 0, *this);
+ Arg->dump(*this);
if (++Index < ChildEnum->getChildCount())
- OS << ", ";
+ Printer << ", ";
}
}
- OS << ")";
+ Printer << ")";
if (Symbol.isConstType())
- OS << " const";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
if (Symbol.isVolatileType())
- OS << " volatile";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
}
-void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer,
- raw_ostream &OS, int Indent) {
+void FunctionDumper::start(const PDBSymbolFunc &Symbol, PointerType Pointer) {
uint32_t FuncStart = Symbol.getRelativeVirtualAddress();
uint32_t FuncEnd = FuncStart + Symbol.getLength();
- OS << newline(Indent);
-
- OS << "func [" << format_hex(FuncStart, 8);
- if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>())
- OS << "+" << DebugStart->getRelativeVirtualAddress() - FuncStart;
- OS << " - " << format_hex(FuncEnd, 8);
- if (auto DebugEnd = Symbol.findOneChild<PDBSymbolFuncDebugEnd>())
- OS << "-" << FuncEnd - DebugEnd->getRelativeVirtualAddress();
- OS << "] ";
+ Printer << "func [";
+ WithColor(Printer, PDB_ColorItem::Address).get() << format_hex(FuncStart, 10);
+ if (auto DebugStart = Symbol.findOneChild<PDBSymbolFuncDebugStart>()) {
+ uint32_t Prologue = DebugStart->getRelativeVirtualAddress() - 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>()) {
+ uint32_t Epilogue = FuncEnd - DebugEnd->getRelativeVirtualAddress();
+ WithColor(Printer, PDB_ColorItem::Offset).get() << "-" << Epilogue;
+ }
+ Printer << "] (";
- if (Symbol.hasFramePointer())
- OS << "(" << Symbol.getLocalBasePointerRegisterId() << ")";
- else
- OS << "(FPO)";
+ if (Symbol.hasFramePointer()) {
+ WithColor(Printer, PDB_ColorItem::Register).get()
+ << Symbol.getLocalBasePointerRegisterId();
+ } else {
+ WithColor(Printer, PDB_ColorItem::Register).get() << "FPO";
+ }
+ Printer << ") ";
- OS << " ";
if (Symbol.isVirtual() || Symbol.isPureVirtual())
- OS << "virtual ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "virtual ";
auto Signature = Symbol.getSignature();
if (!Signature) {
- OS << Symbol.getName();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
if (Pointer == PointerType::Pointer)
- OS << "*";
+ Printer << "*";
else if (Pointer == FunctionDumper::PointerType::Reference)
- OS << "&";
+ Printer << "&";
return;
}
auto ReturnType = Signature->getReturnType();
- ReturnType->dump(OS, 0, *this);
- OS << " ";
+ ReturnType->dump(*this);
+ Printer << " ";
auto ClassParent = Symbol.getClassParent();
PDB_CallingConv CC = Signature->getCallingConvention();
if (Pointer != FunctionDumper::PointerType::None)
- OS << "(";
+ Printer << "(";
if ((ClassParent && CC != PDB_CallingConv::Thiscall) ||
- (!ClassParent && CC != PDB_CallingConv::NearStdcall))
- OS << Signature->getCallingConvention() << " ";
- OS << Symbol.getName();
+ (!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)
- OS << "*";
+ Printer << "*";
else if (Pointer == FunctionDumper::PointerType::Reference)
- OS << "&";
- OS << ")";
+ Printer << "&";
+ Printer << ")";
}
- OS << "(";
+ Printer << "(";
if (auto Arguments = Symbol.getArguments()) {
uint32_t Index = 0;
while (auto Arg = Arguments->getNext()) {
auto ArgType = Arg->getType();
- ArgType->dump(OS, 0, *this);
- OS << " " << Arg->getName();
+ ArgType->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Arg->getName();
if (++Index < Arguments->getChildCount())
- OS << ", ";
+ Printer << ", ";
}
}
- OS << ")";
+ Printer << ")";
if (Symbol.isConstType())
- OS << " const";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " const";
if (Symbol.isVolatileType())
- OS << " volatile";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << " volatile";
if (Symbol.isPureVirtual())
- OS << " = 0";
+ Printer << " = 0";
}
-void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS,
- int Indent) {
+void FunctionDumper::dump(const PDBSymbolTypeArray &Symbol) {
uint32_t ElementTypeId = Symbol.getTypeId();
auto ElementType = Symbol.getSession().getSymbolById(ElementTypeId);
if (!ElementType)
return;
- ElementType->dump(OS, 0, *this);
- OS << "[" << Symbol.getLength() << "]";
+ ElementType->dump(*this);
+ Printer << "[";
+ WithColor(Printer, PDB_ColorItem::LiteralValue).get() << Symbol.getLength();
+ Printer << "]";
}
-void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) {
- PDB_BuiltinType Type = Symbol.getBuiltinType();
- OS << Type;
- if (Type == PDB_BuiltinType::UInt || Type == PDB_BuiltinType::Int)
- OS << (8 * Symbol.getLength()) << "_t";
+void FunctionDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) {
- dumpClassParentWithScopeOperator(Symbol, OS, *this);
- OS << Symbol.getName();
+void FunctionDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
}
-void FunctionDumper::dump(const PDBSymbolTypeFunctionArg &Symbol,
- raw_ostream &OS, int Indent) {
+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.
- Symbol.defaultDump(OS, Indent);
uint32_t TypeId = Symbol.getTypeId();
auto Type = Symbol.getSession().getSymbolById(TypeId);
if (!Type)
return;
- Type->dump(OS, 0, *this);
+ Type->dump(*this);
}
-void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) {
- dumpClassParentWithScopeOperator(Symbol, OS, *this);
- OS << Symbol.getName();
+void FunctionDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ dumpClassParentWithScopeOperator(Symbol, Printer, *this);
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
}
-void FunctionDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
- int Indent) {
+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;
+ FunctionDumper NestedDumper(Printer);
PointerType Pointer =
Symbol.isReference() ? PointerType::Reference : PointerType::Pointer;
- NestedDumper.start(*FuncSig, Pointer, OS);
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
} else {
if (Symbol.isConstType())
- OS << "const ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
if (Symbol.isVolatileType())
- OS << "volatile ";
- PointeeType->dump(OS, Indent, *this);
- OS << (Symbol.isReference() ? "&" : "*");
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ PointeeType->dump(*this);
+ Printer << (Symbol.isReference() ? "&" : "*");
}
}
-void FunctionDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) {
- OS << Symbol.getName();
+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
index f9338cb..19a0014 100644
--- a/tools/llvm-pdbdump/FunctionDumper.h
+++ b/tools/llvm-pdbdump/FunctionDumper.h
@@ -14,31 +14,28 @@
namespace llvm {
+class LinePrinter;
+
class FunctionDumper : public PDBSymDumper {
public:
- FunctionDumper();
+ FunctionDumper(LinePrinter &P);
enum class PointerType { None, Pointer, Reference };
- void start(const PDBSymbolTypeFunctionSig &Symbol, PointerType Pointer,
- raw_ostream &OS);
- void start(const PDBSymbolFunc &Symbol, PointerType Pointer, raw_ostream &OS,
- int Indent);
-
- void dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeFunctionArg &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) override;
+ 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;
};
}
diff --git a/tools/llvm-pdbdump/LinePrinter.cpp b/tools/llvm-pdbdump/LinePrinter.cpp
new file mode 100644
index 0000000..6bbc403
--- /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 0000000..c2a3ab6
--- /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/TypeDumper.cpp b/tools/llvm-pdbdump/TypeDumper.cpp
index 3131e9f..88c0bd6 100644
--- a/tools/llvm-pdbdump/TypeDumper.cpp
+++ b/tools/llvm-pdbdump/TypeDumper.cpp
@@ -9,88 +9,89 @@
#include "TypeDumper.h"
+#include "BuiltinDumper.h"
#include "ClassDefinitionDumper.h"
-#include "FunctionDumper.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/PDBSymbolTypeFunctionSig.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
using namespace llvm;
-TypeDumper::TypeDumper(bool Inline, bool ClassDefs)
- : PDBSymDumper(true), InlineDump(Inline), FullClassDefs(ClassDefs) {}
+TypeDumper::TypeDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
-void TypeDumper::start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent) {
+void TypeDumper::start(const PDBSymbolExe &Exe) {
auto Enums = Exe.findAllChildren<PDBSymbolTypeEnum>();
- OS << newline(Indent) << "Enums: (" << Enums->getChildCount() << " items)";
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Enums";
+ Printer << ": (" << Enums->getChildCount() << " items)";
+ Printer.Indent();
while (auto Enum = Enums->getNext())
- Enum->dump(OS, Indent + 2, *this);
-
- auto FuncSigs = Exe.findAllChildren<PDBSymbolTypeFunctionSig>();
- OS << newline(Indent);
- OS << "Function Signatures: (" << FuncSigs->getChildCount() << " items)";
- while (auto Sig = FuncSigs->getNext())
- Sig->dump(OS, Indent + 2, *this);
+ Enum->dump(*this);
+ Printer.Unindent();
auto Typedefs = Exe.findAllChildren<PDBSymbolTypeTypedef>();
- OS << newline(Indent) << "Typedefs: (" << Typedefs->getChildCount()
- << " items)";
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Typedefs";
+ Printer << ": (" << Typedefs->getChildCount() << " items)";
+ Printer.Indent();
while (auto Typedef = Typedefs->getNext())
- Typedef->dump(OS, Indent + 2, *this);
+ Typedef->dump(*this);
+ Printer.Unindent();
auto Classes = Exe.findAllChildren<PDBSymbolTypeUDT>();
- OS << newline(Indent) << "Classes: (" << Classes->getChildCount()
- << " items)";
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << "Classes";
+ Printer << ": (" << Classes->getChildCount() << " items)";
+ Printer.Indent();
while (auto Class = Classes->getNext())
- Class->dump(OS, Indent + 2, *this);
+ Class->dump(*this);
+ Printer.Unindent();
}
-void TypeDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) {
+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;
- if (!InlineDump)
- OS << newline(Indent);
-
- OS << "enum " << Symbol.getName();
-}
-
-void TypeDumper::dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS,
- int Indent) {
- if (!InlineDump)
- OS << newline(Indent);
-
- FunctionDumper Dumper;
- Dumper.start(Symbol, FunctionDumper::PointerType::None, OS);
+ Printer.NewLine();
+ EnumDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) {
- if (!InlineDump)
- OS << newline(Indent);
+void TypeDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
- TypedefDumper Dumper;
- Dumper.start(Symbol, OS, Indent);
+ Printer.NewLine();
+ TypedefDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) {
+void TypeDumper::dump(const PDBSymbolTypeUDT &Symbol) {
if (Symbol.getUnmodifiedTypeId() != 0)
return;
- if (!InlineDump)
- OS << newline(Indent);
+ if (Printer.IsTypeExcluded(Symbol.getName()))
+ return;
+
+ Printer.NewLine();
- if (FullClassDefs) {
- ClassDefinitionDumper Dumper;
- Dumper.start(Symbol, OS, Indent);
+ if (opts::NoClassDefs) {
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "class ";
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << Symbol.getName();
} else {
- OS << "class " << Symbol.getName();
+ ClassDefinitionDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
}
diff --git a/tools/llvm-pdbdump/TypeDumper.h b/tools/llvm-pdbdump/TypeDumper.h
index d96c24c..5c0832e 100644
--- a/tools/llvm-pdbdump/TypeDumper.h
+++ b/tools/llvm-pdbdump/TypeDumper.h
@@ -14,24 +14,20 @@
namespace llvm {
+class LinePrinter;
+
class TypeDumper : public PDBSymDumper {
public:
- TypeDumper(bool Inline, bool ClassDefs);
+ TypeDumper(LinePrinter &P);
- void start(const PDBSymbolExe &Exe, raw_ostream &OS, int Indent);
+ void start(const PDBSymbolExe &Exe);
- void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) override;
+ void dump(const PDBSymbolTypeEnum &Symbol) override;
+ void dump(const PDBSymbolTypeTypedef &Symbol) override;
+ void dump(const PDBSymbolTypeUDT &Symbol) override;
private:
- bool InlineDump;
- bool FullClassDefs;
+ LinePrinter &Printer;
};
}
diff --git a/tools/llvm-pdbdump/TypedefDumper.cpp b/tools/llvm-pdbdump/TypedefDumper.cpp
index 6eea6b6..a6b5c53 100644
--- a/tools/llvm-pdbdump/TypedefDumper.cpp
+++ b/tools/llvm-pdbdump/TypedefDumper.cpp
@@ -9,12 +9,13 @@
#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/PDBSymbolTypeBuiltin.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
@@ -23,39 +24,34 @@
using namespace llvm;
-TypedefDumper::TypedefDumper() : PDBSymDumper(true) {}
+TypedefDumper::TypedefDumper(LinePrinter &P) : PDBSymDumper(true), Printer(P) {}
-void TypedefDumper::start(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) {
- OS << "typedef ";
+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(OS, 0, *this);
- OS << " " << Symbol.getName();
+ TypeSymbol->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " "
+ << Symbol.getName();
}
-void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS,
- int Indent) {}
+void TypedefDumper::dump(const PDBSymbolTypeArray &Symbol) {}
-void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) {
- PDB_BuiltinType Type = Symbol.getBuiltinType();
- OS << Type;
- if (Type == PDB_BuiltinType::UInt || Type == PDB_BuiltinType::Int)
- OS << (8 * Symbol.getLength()) << "_t";
+void TypedefDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void TypedefDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) {
- OS << "enum " << Symbol.getName();
+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, raw_ostream &OS,
- int Indent) {
+void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol) {
if (Symbol.isConstType())
- OS << "const ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
if (Symbol.isVolatileType())
- OS << "volatile ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
uint32_t PointeeId = Symbol.getTypeId();
auto PointeeType = Symbol.getSession().getSymbolById(PointeeId);
if (!PointeeType)
@@ -64,21 +60,20 @@ void TypedefDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
FunctionDumper::PointerType Pointer = FunctionDumper::PointerType::Pointer;
if (Symbol.isReference())
Pointer = FunctionDumper::PointerType::Reference;
- FunctionDumper NestedDumper;
- NestedDumper.start(*FuncSig, Pointer, OS);
+ FunctionDumper NestedDumper(Printer);
+ NestedDumper.start(*FuncSig, nullptr, Pointer);
} else {
- PointeeType->dump(OS, Indent, *this);
- OS << ((Symbol.isReference()) ? "&" : "*");
+ PointeeType->dump(*this);
+ Printer << ((Symbol.isReference()) ? "&" : "*");
}
}
-void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol,
- raw_ostream &OS, int Indent) {
- FunctionDumper Dumper;
- Dumper.start(Symbol, FunctionDumper::PointerType::None, OS);
+void TypedefDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ FunctionDumper Dumper(Printer);
+ Dumper.start(Symbol, nullptr, FunctionDumper::PointerType::None);
}
-void TypedefDumper::dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) {
- OS << "class " << Symbol.getName();
+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
index e6211a8..8cd578c 100644
--- a/tools/llvm-pdbdump/TypedefDumper.h
+++ b/tools/llvm-pdbdump/TypedefDumper.h
@@ -14,24 +14,23 @@
namespace llvm {
+class LinePrinter;
+
class TypedefDumper : public PDBSymDumper {
public:
- TypedefDumper();
-
- void start(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS, int Indent);
-
- void dump(const PDBSymbolTypeArray &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) override;
+ 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;
};
}
diff --git a/tools/llvm-pdbdump/VariableDumper.cpp b/tools/llvm-pdbdump/VariableDumper.cpp
index 913cfee..030610c 100644
--- a/tools/llvm-pdbdump/VariableDumper.cpp
+++ b/tools/llvm-pdbdump/VariableDumper.cpp
@@ -9,13 +9,16 @@
#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/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
@@ -25,96 +28,143 @@
using namespace llvm;
-VariableDumper::VariableDumper() : PDBSymDumper(true) {}
+VariableDumper::VariableDumper(LinePrinter &P)
+ : PDBSymDumper(true), Printer(P) {}
-void VariableDumper::start(const PDBSymbolData &Var, raw_ostream &OS,
- int Indent) {
- OS << newline(Indent);
- OS << "data ";
+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:
- OS << "[" << format_hex(Var.getRelativeVirtualAddress(), 10) << "] ";
- OS << "static ";
- dumpSymbolTypeAndName(*VarType, Var.getName(), OS);
+ Printer.NewLine();
+ Printer << "data [";
+ WithColor(Printer, PDB_ColorItem::Address).get()
+ << format_hex(Var.getRelativeVirtualAddress(), 10);
+ Printer << "] ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "static ";
+ dumpSymbolTypeAndName(*VarType, Var.getName());
break;
case PDB_LocType::Constant:
- OS << "const ";
- dumpSymbolTypeAndName(*VarType, Var.getName(), OS);
- OS << "[" << Var.getValue() << "]";
+ 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:
- OS << "+" << format_hex(Var.getOffset(), 4) << " ";
- dumpSymbolTypeAndName(*VarType, Var.getName(), OS);
+ 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;
- OS << "unknown(" << LocType << ") " << Var.getName();
}
}
-void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) {
- OS << Symbol.getBuiltinType();
+void VariableDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ BuiltinDumper Dumper(Printer);
+ Dumper.start(Symbol);
}
-void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) {
- OS << Symbol.getName();
+void VariableDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
}
-void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol,
- raw_ostream &OS, int Indent) {}
+void VariableDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {}
-void VariableDumper::dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
- int Indent) {
+void VariableDumper::dump(const PDBSymbolTypePointer &Symbol) {
auto PointeeType = Symbol.getPointeeType();
if (!PointeeType)
return;
if (auto Func = dyn_cast<PDBSymbolFunc>(PointeeType.get())) {
- FunctionDumper NestedDumper;
+ FunctionDumper NestedDumper(Printer);
FunctionDumper::PointerType Pointer =
Symbol.isReference() ? FunctionDumper::PointerType::Reference
: FunctionDumper::PointerType::Pointer;
- NestedDumper.start(*Func, Pointer, OS, Indent);
+ NestedDumper.start(*Func, Pointer);
} else {
if (Symbol.isConstType())
- OS << "const ";
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "const ";
if (Symbol.isVolatileType())
- OS << "volatile ";
- PointeeType->dump(OS, Indent, *this);
- OS << (Symbol.isReference() ? "&" : "*");
+ WithColor(Printer, PDB_ColorItem::Keyword).get() << "volatile ";
+ PointeeType->dump(*this);
+ Printer << (Symbol.isReference() ? "&" : "*");
}
}
-void VariableDumper::dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) {
- OS << "typedef " << Symbol.getName();
+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, raw_ostream &OS,
- int Indent) {
- OS << Symbol.getName();
+void VariableDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ WithColor(Printer, PDB_ColorItem::Type).get() << Symbol.getName();
}
void VariableDumper::dumpSymbolTypeAndName(const PDBSymbol &Type,
- StringRef Name, raw_ostream &OS) {
+ 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 << "[" << NestedArray->getCount() << "]";
+ IndexStream << "[";
+ IndexStream << NestedArray->getCount();
+ IndexStream << "]";
ElementType = NestedArray->getElementType();
}
IndexStream << "[" << ArrayType->getCount() << "]";
- ElementType->dump(OS, 0, *this);
- OS << " " << Name << IndexStream.str();
+ ElementType->dump(*this);
+ WithColor(Printer, PDB_ColorItem::Identifier).get() << " " << Name;
+ Printer << IndexStream.str();
} else {
- Type.dump(OS, 0, *this);
- OS << " " << Name;
+ 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
index e6e71fa..db8d8ea 100644
--- a/tools/llvm-pdbdump/VariableDumper.h
+++ b/tools/llvm-pdbdump/VariableDumper.h
@@ -15,28 +15,26 @@
namespace llvm {
+class LinePrinter;
+
class VariableDumper : public PDBSymDumper {
public:
- VariableDumper();
-
- void start(const PDBSymbolData &Var, raw_ostream &OS, int Indent);
-
- void dump(const PDBSymbolTypeBuiltin &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeEnum &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeFunctionSig &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypePointer &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeTypedef &Symbol, raw_ostream &OS,
- int Indent) override;
- void dump(const PDBSymbolTypeUDT &Symbol, raw_ostream &OS,
- int Indent) override;
+ 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,
- raw_ostream &OS);
+ void dumpSymbolTypeAndName(const PDBSymbol &Type, StringRef Name);
+ bool tryDumpFunctionPointer(const PDBSymbol &Type, StringRef Name);
+
+ LinePrinter &Printer;
};
}
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.cpp b/tools/llvm-pdbdump/llvm-pdbdump.cpp
index e33e715..78535ec 100644
--- a/tools/llvm-pdbdump/llvm-pdbdump.cpp
+++ b/tools/llvm-pdbdump/llvm-pdbdump.cpp
@@ -15,7 +15,10 @@
#include "llvm-pdbdump.h"
#include "CompilandDumper.h"
+#include "FunctionDumper.h"
+#include "LinePrinter.h"
#include "TypeDumper.h"
+#include "VariableDumper.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringExtras.h"
@@ -25,7 +28,10 @@
#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"
@@ -50,53 +56,164 @@ cl::list<std::string> InputFilenames(cl::Positional,
cl::desc("<input PDB files>"),
cl::OneOrMore);
-cl::opt<bool> DumpCompilands("compilands", cl::desc("Display compilands"));
-cl::opt<bool> DumpSymbols("symbols",
- cl::desc("Display symbols (implies --compilands"));
-cl::opt<bool> DumpTypes("types", cl::desc("Display types"));
-cl::opt<bool> DumpClassDefs("class-definitions",
- cl::desc("Display full class definitions"));
+cl::OptionCategory TypeCategory("Symbol Type Options");
+cl::OptionCategory FilterCategory("Filtering 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> 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::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(
- llvm::createPDBReader(PDB_ReaderType::DIA, Path));
- if (!Session) {
- outs() << "Unable to create PDB reader. Check that a valid implementation";
- outs() << " is available for your platform.";
+ std::unique_ptr<IPDBSession> Session;
+ PDB_ErrorCode Error =
+ llvm::createPDBReader(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;
}
+ LinePrinter Printer(2, outs());
+
auto GlobalScope(Session->getGlobalScope());
std::string FileName(GlobalScope->getSymbolsFileName());
- outs() << "Summary for " << FileName;
+ WithColor(Printer, PDB_ColorItem::None).get() << "Summary for ";
+ WithColor(Printer, PDB_ColorItem::Path).get() << FileName;
+ Printer.Indent();
uint64_t FileSize = 0;
- if (!llvm::sys::fs::file_size(FileName, FileSize))
- outs() << newline(2) << "Size: " << FileSize << " bytes";
- else
- outs() << newline(2) << "Size: (Unable to obtain file size)";
-
- outs() << newline(2) << "Guid: " << GlobalScope->getGuid();
- outs() << newline(2) << "Age: " << GlobalScope->getAge();
- outs() << newline(2) << "Attributes: ";
+
+ 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::DumpTypes) {
- outs() << "\nDumping types";
- TypeDumper Dumper(false, opts::DumpClassDefs);
- Dumper.start(*GlobalScope, outs(), 2);
+ if (opts::Types) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---TYPES---";
+ Printer.Indent();
+ TypeDumper Dumper(Printer);
+ Dumper.start(*GlobalScope);
+ Printer.Unindent();
}
- if (opts::DumpSymbols || opts::DumpCompilands) {
- outs() << "\nDumping compilands";
+ if (opts::Symbols) {
+ Printer.NewLine();
+ WithColor(Printer, PDB_ColorItem::SectionHeader).get() << "---SYMBOLS---";
+ Printer.Indent();
auto Compilands = GlobalScope->findAllChildren<PDBSymbolCompiland>();
- CompilandDumper Dumper;
+ CompilandDumper Dumper(Printer);
while (auto Compiland = Compilands->getNext())
- Dumper.start(*Compiland, outs(), 2, opts::DumpSymbols);
+ 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();
}
outs().flush();
}
@@ -118,6 +235,20 @@ int main(int argc_, const char *argv_[]) {
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;
+ }
+ 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);
diff --git a/tools/llvm-pdbdump/llvm-pdbdump.h b/tools/llvm-pdbdump/llvm-pdbdump.h
index 74a1718..586a9ea 100644
--- a/tools/llvm-pdbdump/llvm-pdbdump.h
+++ b/tools/llvm-pdbdump/llvm-pdbdump.h
@@ -10,19 +10,23 @@
#ifndef LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
#define LLVM_TOOLS_LLVMPDBDUMP_LLVMPDBDUMP_H
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/raw_ostream.h"
-namespace llvm {
-struct newline {
- newline(int IndentWidth) : Width(IndentWidth) {}
- int Width;
-};
+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;
-inline raw_ostream &operator<<(raw_ostream &OS, const newline &Indent) {
- OS << "\n";
- OS.indent(Indent.Width);
- return OS;
-}
+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 0137e35..1bfdb18 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,8 +39,8 @@ static void exitWithError(const Twine &Message, StringRef Whence = "") {
enum ProfileKinds { instr, sample };
-void mergeInstrProfile(const 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.");
@@ -65,9 +66,9 @@ void mergeInstrProfile(const cl::list<std::string> &Inputs,
Writer.write(Output);
}
-void mergeSampleProfile(const 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())
@@ -97,7 +98,7 @@ void mergeSampleProfile(const cl::list<std::string> &Inputs,
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...>"));
@@ -130,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);
@@ -183,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())
@@ -201,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/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index e4b7601..39fb065 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -207,6 +207,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 },
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index f8f3086..32db723 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"
@@ -320,6 +321,19 @@ 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 (std::error_code EC = ObjOrErr.getError()) {
+ reportError(UBinary->getFileName(), EC.message());
+ continue;
+ }
+
+ if (MachOObjectFile *MachOObj = ObjOrErr.get().get())
+ dumpObject(MachOObj);
+ }
+}
/// @brief Opens \a File and dumps it.
static void dumpInput(StringRef File) {
@@ -339,6 +353,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-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 58bf206..9462015 100644
--- a/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -298,7 +298,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 +339,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 +397,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;
diff --git a/tools/llvm-shlib/CMakeLists.txt b/tools/llvm-shlib/CMakeLists.txt
index 9a8cd4a..08dafe1 100644
--- a/tools/llvm-shlib/CMakeLists.txt
+++ b/tools/llvm-shlib/CMakeLists.txt
@@ -90,7 +90,7 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # FIXME: It should be "GNU ld for el
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
endif()
-target_link_libraries(LLVM ${cmake_2_8_12_PRIVATE} ${LIB_NAMES})
+target_link_libraries(LLVM PRIVATE ${LIB_NAMES})
add_dependencies(LLVM libLLVMExports)
diff --git a/tools/llvm-stress/CMakeLists.txt b/tools/llvm-stress/CMakeLists.txt
index 106ced1..d5c10e1 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 05ceeb5..f5e718b 100644
--- a/tools/llvm-stress/llvm-stress.cpp
+++ b/tools/llvm-stress/llvm-stress.cpp
@@ -713,7 +713,6 @@ int main(int argc, char **argv) {
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/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp
index d554022..cb40472 100644
--- a/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -21,6 +21,7 @@
#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"
diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp
index 714b8e0..cc4169f 100644
--- a/tools/lto/lto.cpp
+++ b/tools/lto/lto.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#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"
@@ -22,9 +23,13 @@
#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),
@@ -84,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() {
@@ -280,54 +289,42 @@ 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) {
- if (!parsedOptions) {
- unwrap(cg)->parseCodeGenDebugOptions();
- lto_add_attrs(cg);
- parsedOptions = true;
- }
- return !unwrap(cg)->optimize(DisableOpt, DisableInline,
+ maybeParseOptions(cg);
+ return !unwrap(cg)->optimize(DisableInline,
DisableGVNLoadPRE, DisableLTOVectorization,
sLastErrorString);
}
const void *lto_codegen_compile_optimized(lto_code_gen_t cg, size_t *length) {
- if (!parsedOptions) {
- unwrap(cg)->parseCodeGenDebugOptions();
- lto_add_attrs(cg);
- parsedOptions = true;
- }
+ 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);
}
diff --git a/tools/opt/Android.mk b/tools/opt/Android.mk
index 7220575..814fabc 100644
--- a/tools/opt/Android.mk
+++ b/tools/opt/Android.mk
@@ -12,7 +12,6 @@ llvm_opt_SRC_FILES := \
BreakpointPrinter.cpp \
GraphPrinters.cpp \
NewPMDriver.cpp \
- Passes.cpp \
PassPrinters.cpp \
PrintSCC.cpp \
opt.cpp \
@@ -51,6 +50,7 @@ llvm_opt_STATIC_LIBRARIES := \
libLLVMVectorize \
libLLVMScalarOpts \
libLLVMTransformUtils \
+ libLLVMPasses \
libLLVMAnalysis \
libLLVMipo \
libLLVMipa \
diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt
index 1d3f08d..5f82522 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 b3589f8..b162ab6 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 cfa9c31..2422eb4 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 a73750d..9216d5c 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,6 +23,7 @@
#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"
@@ -40,16 +40,16 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
TargetMachine *TM, tool_output_file *Out,
StringRef PassPipeline, OutputKind OK,
VerifierKind VK) {
- Passes P(TM);
+ PassBuilder PB(TM);
FunctionAnalysisManager FAM(DebugPM);
CGSCCAnalysisManager CGAM(DebugPM);
ModuleAnalysisManager MAM(DebugPM);
// Register all the basic analyses with the managers.
- P.registerModuleAnalyses(MAM);
- P.registerCGSCCAnalyses(CGAM);
- P.registerFunctionAnalyses(FAM);
+ PB.registerModuleAnalyses(MAM);
+ PB.registerCGSCCAnalyses(CGAM);
+ PB.registerFunctionAnalyses(FAM);
// Cross register the analysis managers through their proxies.
MAM.registerPass(FunctionAnalysisManagerModuleProxy(FAM));
@@ -63,8 +63,8 @@ bool llvm::runPassPipeline(StringRef Arg0, LLVMContext &Context, Module &M,
if (VK > VK_NoVerifier)
MPM.addPass(VerifierPass());
- if (!P.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;
}
diff --git a/tools/opt/PassRegistry.def b/tools/opt/PassRegistry.def
deleted file mode 100644
index d768a3a..0000000
--- a/tools/opt/PassRegistry.def
+++ /dev/null
@@ -1,77 +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())
-MODULE_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
-#undef MODULE_ANALYSIS
-
-#ifndef MODULE_PASS
-#define MODULE_PASS(NAME, CREATE_PASS)
-#endif
-MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-MODULE_PASS("no-op-module", NoOpModulePass())
-MODULE_PASS("print", PrintModulePass(dbgs()))
-MODULE_PASS("print-cg", LazyCallGraphPrinterPass(dbgs()))
-MODULE_PASS("verify", VerifierPass())
-#undef MODULE_PASS
-
-#ifndef CGSCC_ANALYSIS
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS)
-#endif
-CGSCC_ANALYSIS("no-op-cgscc", NoOpCGSCCAnalysis())
-#undef CGSCC_ANALYSIS
-
-#ifndef CGSCC_PASS
-#define CGSCC_PASS(NAME, CREATE_PASS)
-#endif
-CGSCC_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-CGSCC_PASS("no-op-cgscc", NoOpCGSCCPass())
-#undef CGSCC_PASS
-
-#ifndef FUNCTION_ANALYSIS
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS)
-#endif
-FUNCTION_ANALYSIS("assumptions", AssumptionAnalysis())
-FUNCTION_ANALYSIS("domtree", DominatorTreeAnalysis())
-FUNCTION_ANALYSIS("loops", LoopAnalysis())
-FUNCTION_ANALYSIS("no-op-function", NoOpFunctionAnalysis())
-FUNCTION_ANALYSIS("targetlibinfo", TargetLibraryAnalysis())
-FUNCTION_ANALYSIS("targetir",
- TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())
-#undef FUNCTION_ANALYSIS
-
-#ifndef FUNCTION_PASS
-#define FUNCTION_PASS(NAME, CREATE_PASS)
-#endif
-FUNCTION_PASS("early-cse", EarlyCSEPass())
-FUNCTION_PASS("instcombine", InstCombinePass())
-FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
-FUNCTION_PASS("no-op-function", NoOpFunctionPass())
-FUNCTION_PASS("lower-expect", LowerExpectIntrinsicPass())
-FUNCTION_PASS("print", PrintFunctionPass(dbgs()))
-FUNCTION_PASS("print<assumptions>", AssumptionPrinterPass(dbgs()))
-FUNCTION_PASS("print<domtree>", DominatorTreePrinterPass(dbgs()))
-FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs()))
-FUNCTION_PASS("simplify-cfg", SimplifyCFGPass())
-FUNCTION_PASS("verify", VerifierPass())
-FUNCTION_PASS("verify<domtree>", DominatorTreeVerifierPass())
-#undef FUNCTION_PASS
diff --git a/tools/opt/Passes.cpp b/tools/opt/Passes.cpp
deleted file mode 100644
index e5ad5c0..0000000
--- a/tools/opt/Passes.cpp
+++ /dev/null
@@ -1,406 +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/AssumptionCache.h"
-#include "llvm/Analysis/CGSCCPassManager.h"
-#include "llvm/Analysis/LazyCallGraph.h"
-#include "llvm/Analysis/LoopInfo.h"
-#include "llvm/Analysis/TargetLibraryInfo.h"
-#include "llvm/Analysis/TargetTransformInfo.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/IR/IRPrintingPasses.h"
-#include "llvm/IR/PassManager.h"
-#include "llvm/IR/Verifier.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Target/TargetMachine.h"
-#include "llvm/Transforms/InstCombine/InstCombine.h"
-#include "llvm/Transforms/Scalar/EarlyCSE.h"
-#include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h"
-#include "llvm/Transforms/Scalar/SimplifyCFG.h"
-
-using namespace llvm;
-
-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 Passes::registerModuleAnalyses(ModuleAnalysisManager &MAM) {
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- MAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-void Passes::registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM) {
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
- CGAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-void Passes::registerFunctionAnalyses(FunctionAnalysisManager &FAM) {
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
- FAM.registerPass(CREATE_PASS);
-#include "PassRegistry.def"
-}
-
-#ifndef NDEBUG
-static bool isModulePassName(StringRef Name) {
-#define MODULE_PASS(NAME, CREATE_PASS) if (Name == NAME) return true;
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">" || Name == "invalidate<" NAME ">") \
- return true;
-#include "PassRegistry.def"
-
- return false;
-}
-#endif
-
-static bool isCGSCCPassName(StringRef Name) {
-#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;
-}
-
-bool Passes::parseModulePassName(ModulePassManager &MPM, StringRef Name) {
-#define MODULE_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- MPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define MODULE_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- MPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- MPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-bool Passes::parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name) {
-#define CGSCC_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- CGPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define CGSCC_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- CGPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- CGPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-bool Passes::parseFunctionPassName(FunctionPassManager &FPM, StringRef Name) {
-#define FUNCTION_PASS(NAME, CREATE_PASS) \
- if (Name == NAME) { \
- FPM.addPass(CREATE_PASS); \
- return true; \
- }
-#define FUNCTION_ANALYSIS(NAME, CREATE_PASS) \
- if (Name == "require<" NAME ">") { \
- FPM.addPass(RequireAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- } \
- if (Name == "invalidate<" NAME ">") { \
- FPM.addPass(InvalidateAnalysisPass<decltype(CREATE_PASS)>()); \
- return true; \
- }
-#include "PassRegistry.def"
-
- return false;
-}
-
-bool Passes::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);
- }
-}
-
-bool Passes::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);
- }
-}
-
-bool Passes::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 Passes::parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
- bool VerifyEachPass, bool DebugLogging) {
- // By default, try to parse the pipeline as-if it were within an implicit
- // 'module(...)' pass pipeline. If this will parse at all, it needs to
- // consume the entire string.
- if (parseModulePassPipeline(MPM, PipelineText, VerifyEachPass, DebugLogging))
- return PipelineText.empty();
-
- // This isn't parsable as a module pipeline, look for the end of a pass name
- // and directly drop down to that layer.
- StringRef FirstName =
- PipelineText.substr(0, PipelineText.find_first_of(",)"));
- 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 d3cb628..0000000
--- a/tools/opt/Passes.h
+++ /dev/null
@@ -1,105 +0,0 @@
-//===- Passes.h - Utilities for manipulating all 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 registering passes, producing common pass manager
-/// configurations, and parsing of pass pipelines.
-///
-//===----------------------------------------------------------------------===//
-
-#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 {
-class TargetMachine;
-
-/// \brief This class provides access to all of LLVM's passes.
-///
-/// It's members provide the baseline state available to passes during their
-/// construction. The \c PassRegistry.def file specifies how to construct all
-/// of the built-in passes, and those may reference these members during
-/// construction.
-class Passes {
- TargetMachine *TM;
-
-public:
- explicit Passes(TargetMachine *TM = nullptr) : TM(TM) {}
-
- /// \brief Registers all available module analysis passes.
- ///
- /// This is an interface that can be used to populate a \c
- /// ModuleAnalysisManager with all registered module analyses. Callers can
- /// still manually register any additional analyses.
- void registerModuleAnalyses(ModuleAnalysisManager &MAM);
-
- /// \brief Registers all available CGSCC analysis passes.
- ///
- /// This is an interface that can be used to populate a \c CGSCCAnalysisManager
- /// with all registered CGSCC analyses. Callers can still manually register any
- /// additional analyses.
- void registerCGSCCAnalyses(CGSCCAnalysisManager &CGAM);
-
- /// \brief Registers all available function analysis passes.
- ///
- /// This is an interface that can be used to populate a \c
- /// FunctionAnalysisManager with all registered function analyses. Callers can
- /// still manually register any additional analyses.
- void registerFunctionAnalyses(FunctionAnalysisManager &FAM);
-
- /// \brief Parse a textual pass pipeline description into a \c ModulePassManager.
- ///
- /// The format of the textual pass pipeline description looks something like:
- ///
- /// module(function(instcombine,sroa),dce,cgscc(inliner,function(...)),...)
- ///
- /// Pass managers have ()s describing the nest structure of passes. All passes
- /// are comma separated. As a special shortcut, if the very first pass is not
- /// a module pass (as a module pass manager is), this will automatically form
- /// the shortest stack of pass managers that allow inserting that first pass.
- /// So, assuming function passes 'fpassN', CGSCC passes 'cgpassN', and loop passes
- /// 'lpassN', all of these are valid:
- ///
- /// fpass1,fpass2,fpass3
- /// cgpass1,cgpass2,cgpass3
- /// lpass1,lpass2,lpass3
- ///
- /// And they are equivalent to the following (resp.):
- ///
- /// module(function(fpass1,fpass2,fpass3))
- /// module(cgscc(cgpass1,cgpass2,cgpass3))
- /// module(function(loop(lpass1,lpass2,lpass3)))
- ///
- /// This shortcut is especially useful for debugging and testing small pass
- /// combinations. Note that these shortcuts don't introduce any other magic. If
- /// the sequence of passes aren't all the exact same kind of pass, it will be
- /// an error. You cannot mix different levels implicitly, you must explicitly
- /// form a pass manager in which to nest passes.
- bool parsePassPipeline(ModulePassManager &MPM, StringRef PipelineText,
- bool VerifyEachPass = true, bool DebugLogging = false);
-
-private:
- bool parseModulePassName(ModulePassManager &MPM, StringRef Name);
- bool parseCGSCCPassName(CGSCCPassManager &CGPM, StringRef Name);
- bool parseFunctionPassName(FunctionPassManager &FPM, StringRef Name);
- bool parseFunctionPassPipeline(FunctionPassManager &FPM,
- StringRef &PipelineText, bool VerifyEachPass,
- bool DebugLogging);
- bool parseCGSCCPassPipeline(CGSCCPassManager &CGPM, StringRef &PipelineText,
- bool VerifyEachPass, bool DebugLogging);
- bool parseModulePassPipeline(ModulePassManager &MPM, StringRef &PipelineText,
- bool VerifyEachPass, bool DebugLogging);
-};
-
-}
-
-#endif
diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp
index d952525..c1e120a 100644
--- a/tools/opt/opt.cpp
+++ b/tools/opt/opt.cpp
@@ -185,10 +185,8 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
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,
@@ -198,8 +196,7 @@ static inline void addPass(legacy::PassManagerBase &PM, Pass *P) {
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;
@@ -234,7 +231,6 @@ static void AddOptimizationPasses(legacy::PassManagerBase &MPM,
static void AddStandardLinkPasses(legacy::PassManagerBase &PM) {
PassManagerBuilder Builder;
Builder.VerifyInput = true;
- Builder.StripDebug = StripDebug;
if (DisableOptimizations)
Builder.OptLevel = 0;
@@ -247,7 +243,7 @@ static void AddStandardLinkPasses(legacy::PassManagerBase &PM) {
// CodeGen-related helper functions.
//
-CodeGenOpt::Level GetCodeGenOptLevel() {
+static CodeGenOpt::Level GetCodeGenOptLevel() {
if (OptLevelO1)
return CodeGenOpt::Less;
if (OptLevelO2)
@@ -419,15 +415,11 @@ int main(int argc, char **argv) {
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());
-
// Add internal analysis passes from the target machine.
Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis()
: TargetIRAnalysis()));
@@ -435,8 +427,6 @@ int main(int argc, char **argv) {
std::unique_ptr<legacy::FunctionPassManager> FPasses;
if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) {
FPasses.reset(new legacy::FunctionPassManager(M.get()));
- if (DL)
- FPasses->add(new DataLayoutPass());
FPasses->add(createTargetTransformInfoWrapperPass(
TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis()));
}
@@ -565,10 +555,8 @@ 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) {
diff --git a/tools/verify-uselistorder/verify-uselistorder.cpp b/tools/verify-uselistorder/verify-uselistorder.cpp
index a653608..ef3d5b3 100644
--- a/tools/verify-uselistorder/verify-uselistorder.cpp
+++ b/tools/verify-uselistorder/verify-uselistorder.cpp
@@ -47,6 +47,7 @@
#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>
diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp
index 8322b2f..6939bc4 100644
--- a/tools/yaml2obj/yaml2coff.cpp
+++ b/tools/yaml2obj/yaml2coff.cpp
@@ -282,7 +282,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/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp
index 375cd89..af4d868 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)