diff options
Diffstat (limited to 'tools')
116 files changed, 5792 insertions, 1263 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 69182856..9b80ee5 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -31,6 +31,9 @@ add_subdirectory(llvm-objdump) add_subdirectory(llvm-readobj) add_subdirectory(llvm-rtdyld) add_subdirectory(llvm-dwarfdump) +if( LLVM_USE_INTEL_JITEVENTS ) + add_subdirectory(llvm-jitlistener) +endif( LLVM_USE_INTEL_JITEVENTS ) add_subdirectory(bugpoint) add_subdirectory(bugpoint-passes) @@ -38,19 +41,25 @@ add_subdirectory(llvm-bcanalyzer) add_subdirectory(llvm-stress) add_subdirectory(llvm-mcmarkup) +add_subdirectory(llvm-symbolizer) + +add_subdirectory(obj2yaml) + if( NOT WIN32 ) add_subdirectory(lto) endif() if( LLVM_ENABLE_PIC ) # TODO: support other systems: - if( CMAKE_SYSTEM_NAME STREQUAL "Linux" ) + if( (CMAKE_SYSTEM_NAME STREQUAL "Linux") + OR (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ) add_subdirectory(gold) endif() endif() add_llvm_external_project(clang) add_llvm_external_project(lld) +add_llvm_external_project(lldb) add_llvm_external_project(polly) set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 64164792..25aa177 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-ranlib llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index a29e49f..b8f21d2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -34,7 +34,13 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \ bugpoint llvm-bcanalyzer \ llvm-diff macho-dump llvm-objdump llvm-readobj \ llvm-rtdyld llvm-dwarfdump llvm-cov \ - llvm-size llvm-stress llvm-mcmarkup + llvm-size llvm-stress llvm-mcmarkup \ + llvm-symbolizer obj2yaml + +# If Intel JIT Events support is configured, build an extra tool to test it. +ifeq ($(USE_INTEL_JITEVENTS), 1) + PARALLEL_DIRS += llvm-jitlistener +endif # Let users override the set of tools to build from the command line. ifdef ONLY_TOOLS diff --git a/tools/bugpoint-passes/CMakeLists.txt b/tools/bugpoint-passes/CMakeLists.txt index b2f1bb5..05f190a 100644 --- a/tools/bugpoint-passes/CMakeLists.txt +++ b/tools/bugpoint-passes/CMakeLists.txt @@ -1,3 +1,7 @@ +if( NOT LLVM_BUILD_TOOLS ) + set(EXCLUDE_FROM_ALL ON) +endif() + add_llvm_loadable_module( BugpointPasses TestPasses.cpp ) diff --git a/tools/bugpoint-passes/TestPasses.cpp b/tools/bugpoint-passes/TestPasses.cpp index 1535b03..118c98a 100644 --- a/tools/bugpoint-passes/TestPasses.cpp +++ b/tools/bugpoint-passes/TestPasses.cpp @@ -12,12 +12,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/BasicBlock.h" -#include "llvm/Constant.h" -#include "llvm/Instructions.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Type.h" +#include "llvm/InstVisitor.h" #include "llvm/Pass.h" -#include "llvm/Type.h" -#include "llvm/Support/InstVisitor.h" using namespace llvm; diff --git a/tools/bugpoint/BugDriver.cpp b/tools/bugpoint/BugDriver.cpp index 21636ea..e49a96b 100644 --- a/tools/bugpoint/BugDriver.cpp +++ b/tools/bugpoint/BugDriver.cpp @@ -15,15 +15,15 @@ #include "BugDriver.h" #include "ToolRunner.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Linker.h" -#include "llvm/Module.h" #include "llvm/Pass.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Host.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Host.h" #include <memory> using namespace llvm; diff --git a/tools/bugpoint/BugDriver.h b/tools/bugpoint/BugDriver.h index cc78489..2b621ec 100644 --- a/tools/bugpoint/BugDriver.h +++ b/tools/bugpoint/BugDriver.h @@ -18,8 +18,8 @@ #include "llvm/ADT/ValueMap.h" #include "llvm/Transforms/Utils/ValueMapper.h" -#include <vector> #include <string> +#include <vector> namespace llvm { diff --git a/tools/bugpoint/CMakeLists.txt b/tools/bugpoint/CMakeLists.txt index ee2235b..0000d97 100644 --- a/tools/bugpoint/CMakeLists.txt +++ b/tools/bugpoint/CMakeLists.txt @@ -1,5 +1,5 @@ set(LLVM_LINK_COMPONENTS asmparser instrumentation scalaropts ipo - linker bitreader bitwriter vectorize) + linker bitreader bitwriter irreader vectorize objcarcopts) add_llvm_tool(bugpoint BugDriver.cpp @@ -12,3 +12,4 @@ add_llvm_tool(bugpoint ToolRunner.cpp bugpoint.cpp ) +set_target_properties(bugpoint PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index aed16f4..ed211a6 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -12,22 +12,22 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "ToolRunner.h" #include "ListReducer.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" -#include "llvm/Module.h" -#include "llvm/Pass.h" -#include "llvm/PassManager.h" -#include "llvm/ValueSymbolTable.h" +#include "ToolRunner.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/ValueSymbolTable.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Support/FileUtilities.h" -#include "llvm/Support/CommandLine.h" #include <set> using namespace llvm; diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 218a559..da36045 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -230,7 +230,7 @@ bool BugDriver::initializeExecutionEnvironment() { } if (!SafeInterpreter) { SafeInterpreterSel = AutoPick; - Message = "Sorry, I can't automatically select an interpreter!\n"; + Message = "Sorry, I can't automatically select a safe interpreter!\n"; } break; case RunLLC: diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index b40b4f1..bb27767 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -13,25 +13,25 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "llvm/Constants.h" -#include "llvm/DataLayout.h" -#include "llvm/DerivedTypes.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/Pass.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Assembly/Writer.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/CodeExtractor.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/CodeExtractor.h" #include <set> using namespace llvm; diff --git a/tools/bugpoint/LLVMBuild.txt b/tools/bugpoint/LLVMBuild.txt index 549d9d0..0164355 100644 --- a/tools/bugpoint/LLVMBuild.txt +++ b/tools/bugpoint/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = bugpoint parent = Tools -required_libraries = AsmParser BitReader BitWriter IPO Instrumentation Linker Scalar +required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Linker Scalar ObjCARC diff --git a/tools/bugpoint/ListReducer.h b/tools/bugpoint/ListReducer.h index bd1c5da..8083e2d 100644 --- a/tools/bugpoint/ListReducer.h +++ b/tools/bugpoint/ListReducer.h @@ -15,11 +15,11 @@ #ifndef BUGPOINT_LIST_REDUCER_H #define BUGPOINT_LIST_REDUCER_H -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" -#include <vector> -#include <cstdlib> +#include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <cstdlib> +#include <vector> namespace llvm { diff --git a/tools/bugpoint/Makefile b/tools/bugpoint/Makefile index 34f4bdd..2049321 100644 --- a/tools/bugpoint/Makefile +++ b/tools/bugpoint/Makefile @@ -10,6 +10,6 @@ LEVEL := ../.. TOOLNAME := bugpoint LINK_COMPONENTS := asmparser instrumentation scalaropts ipo linker bitreader \ - bitwriter vectorize + bitwriter irreader vectorize objcarcopts include $(LEVEL)/Makefile.common diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index 82a3a86..c676a05 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -15,17 +15,17 @@ #include "BugDriver.h" #include "ListReducer.h" #include "ToolRunner.h" -#include "llvm/Constants.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Instructions.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Config/config.h" // for HAVE_LINK_R +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Linker.h" -#include "llvm/Module.h" #include "llvm/Pass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" -#include "llvm/Config/config.h" // for HAVE_LINK_R +#include "llvm/Transforms/Utils/Cloning.h" using namespace llvm; namespace llvm { diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index c56911a..87dc9f3 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -16,18 +16,18 @@ //===----------------------------------------------------------------------===// #include "BugDriver.h" -#include "llvm/DataLayout.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Support/FileUtilities.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Module.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/SystemUtils.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/ToolOutputFile.h" #define DONT_GET_PLUGIN_LOADER_OPTION #include "llvm/Support/PluginLoader.h" diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index d975d68..735061d 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -13,12 +13,12 @@ #define DEBUG_TYPE "toolrunner" #include "ToolRunner.h" -#include "llvm/Support/Program.h" +#include "llvm/Config/config.h" // for HAVE_LINK_R #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Config/config.h" // for HAVE_LINK_R #include <fstream> #include <sstream> using namespace llvm; @@ -531,12 +531,12 @@ LLC *AbstractInterpreter::createLLC(const char *Argv0, return 0; } - Message = "Found llc: " + LLCPath + "\n"; GCC *gcc = GCC::create(Message, GCCBinary, GCCArgs); if (!gcc) { errs() << Message << "\n"; exit(1); } + Message = "Found llc: " + LLCPath + "\n"; return new LLC(LLCPath, gcc, Args, UseIntegratedAssembler); } diff --git a/tools/bugpoint/ToolRunner.h b/tools/bugpoint/ToolRunner.h index 7b93394..bb83ce4 100644 --- a/tools/bugpoint/ToolRunner.h +++ b/tools/bugpoint/ToolRunner.h @@ -20,8 +20,8 @@ #include "llvm/ADT/Triple.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/SystemUtils.h" #include "llvm/Support/Path.h" +#include "llvm/Support/SystemUtils.h" #include <exception> #include <vector> diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 8f15b02..5e8fdd1 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -15,18 +15,18 @@ #include "BugDriver.h" #include "ToolRunner.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/LinkAllIR.h" #include "llvm/LinkAllPasses.h" -#include "llvm/LLVMContext.h" #include "llvm/PassManager.h" -#include "llvm/Support/PassNameParser.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Valgrind.h" -#include "llvm/LinkAllVMCore.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" //Enable this macro to debug bugpoint itself. @@ -120,6 +120,7 @@ int main(int argc, char **argv) { PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); initializeScalarOpts(Registry); + initializeObjCARCOpts(Registry); initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index b0a0dd2..40f5fd6 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -14,17 +14,14 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "plugin-api.h" - #include "llvm-c/lto.h" - #include "llvm/ADT/OwningPtr.h" -#include "llvm/Support/system_error.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Errno.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" - +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> #include <cstring> diff --git a/tools/llc/CMakeLists.txt b/tools/llc/CMakeLists.txt index 683f298..e5a5550 100644 --- a/tools/llc/CMakeLists.txt +++ b/tools/llc/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser irreader) add_llvm_tool(llc llc.cpp diff --git a/tools/llc/LLVMBuild.txt b/tools/llc/LLVMBuild.txt index 8c8794f..45cdc64 100644 --- a/tools/llc/LLVMBuild.txt +++ b/tools/llc/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llc parent = Tools -required_libraries = AsmParser BitReader all-targets +required_libraries = AsmParser BitReader IRReader all-targets diff --git a/tools/llc/Makefile b/tools/llc/Makefile index b32d557..c24f378 100644 --- a/tools/llc/Makefile +++ b/tools/llc/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llc -LINK_COMPONENTS := all-targets bitreader asmparser +LINK_COMPONENTS := all-targets bitreader asmparser irreader include $(LEVEL)/Makefile.common diff --git a/tools/llc/llc.cpp b/tools/llc/llc.cpp index 4d4a74c..1dce9d7 100644 --- a/tools/llc/llc.cpp +++ b/tools/llc/llc.cpp @@ -13,29 +13,30 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/DataLayout.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/Pass.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/ADT/Triple.h" #include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Support/IRReader.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/CodeGen/LinkAllAsmWriterComponents.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/MC/SubtargetFeature.h" +#include "llvm/Pass.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include <memory> @@ -51,6 +52,11 @@ InputFilename(cl::Positional, cl::desc("<input bitcode>"), cl::init("-")); static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); +static cl::opt<unsigned> +TimeCompilations("time-compilations", cl::Hidden, cl::init(1u), + cl::value_desc("N"), + cl::desc("Repeat compilation N times for timing")); + // Determine optimization level. static cl::opt<char> OptLevel("O", @@ -71,6 +77,8 @@ DisableSimplifyLibCalls("disable-simplify-libcalls", cl::desc("Disable simplify-libcalls"), cl::init(false)); +static int compileModule(char**, LLVMContext&); + // GetFileNameRoot - Helper function to get the basename of a filename. static inline std::string GetFileNameRoot(const std::string &InputFilename) { @@ -181,6 +189,15 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n"); + // Compile the module TimeCompilations times to give better compile time + // metrics. + for (unsigned I = TimeCompilations; I; --I) + if (int RetVal = compileModule(argv, Context)) + return RetVal; + return 0; +} + +static int compileModule(char **argv, LLVMContext &Context) { // Load the module to be compiled... SMDiagnostic Err; std::auto_ptr<Module> M; @@ -303,10 +320,8 @@ int main(int argc, char **argv) { TLI->disableAllFunctions(); PM.add(TLI); - if (target.get()) { - PM.add(new TargetTransformInfo(target->getScalarTargetTransformInfo(), - target->getVectorTargetTransformInfo())); - } + // Add intenal analysis passes from the target machine. + Target.addAnalysisPasses(PM); // Add the target data from the target machine, if it exists, or the module. if (const DataLayout *TD = Target.getDataLayout()) diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index ed479f5..aaa6598 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,5 +1,5 @@ -set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native) +set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native) if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS @@ -11,7 +11,9 @@ endif( LLVM_USE_OPROFILE ) if( LLVM_USE_INTEL_JITEVENTS ) set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} + DebugInfo IntelJITEvents + Object ) endif( LLVM_USE_INTEL_JITEVENTS ) diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt index 36ceb39..5823792 100644 --- a/tools/lli/LLVMBuild.txt +++ b/tools/lli/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = lli parent = Tools -required_libraries = AsmParser BitReader Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native +required_libraries = AsmParser BitReader IRReader Interpreter JIT MCJIT NativeCodeGen SelectionDAG Native diff --git a/tools/lli/Makefile b/tools/lli/Makefile index 31f3ab8..a653058 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -12,12 +12,12 @@ TOOLNAME := lli include $(LEVEL)/Makefile.config -LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser selectiondag native +LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native # If Intel JIT Events support is confiured, link against the LLVM Intel JIT # Events interface library ifeq ($(USE_INTEL_JITEVENTS), 1) - LINK_COMPONENTS += inteljitevents + LINK_COMPONENTS += debuginfo inteljitevents object endif # If oprofile support is confiured, link against the LLVM oprofile interface diff --git a/tools/lli/RecordingMemoryManager.cpp b/tools/lli/RecordingMemoryManager.cpp index 9e1cff5..e4d992d 100644 --- a/tools/lli/RecordingMemoryManager.cpp +++ b/tools/lli/RecordingMemoryManager.cpp @@ -15,29 +15,57 @@ #include "RecordingMemoryManager.h" using namespace llvm; +RecordingMemoryManager::~RecordingMemoryManager() { + for (SmallVectorImpl<Allocation>::iterator + I = AllocatedCodeMem.begin(), E = AllocatedCodeMem.end(); + I != E; ++I) + sys::Memory::releaseMappedMemory(I->first); + for (SmallVectorImpl<Allocation>::iterator + I = AllocatedDataMem.begin(), E = AllocatedDataMem.end(); + I != E; ++I) + sys::Memory::releaseMappedMemory(I->first); +} + uint8_t *RecordingMemoryManager:: allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { // The recording memory manager is just a local copy of the remote target. // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here. - void *Addr = malloc(Size); - assert(Addr && "malloc() failure!"); - sys::MemoryBlock Block(Addr, Size); + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); AllocatedCodeMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Addr; + return (uint8_t*)Block.base(); } uint8_t *RecordingMemoryManager:: -allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID) { +allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, bool IsReadOnly) { // The recording memory manager is just a local copy of the remote target. // The alignment requirement is just stored here for later use. Regular - // heap storage is sufficient here. - void *Addr = malloc(Size); - assert(Addr && "malloc() failure!"); - sys::MemoryBlock Block(Addr, Size); + // heap storage is sufficient here, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); AllocatedDataMem.push_back(Allocation(Block, Alignment)); - return (uint8_t*)Addr; + return (uint8_t*)Block.base(); +} + +sys::MemoryBlock RecordingMemoryManager::allocateSection(uintptr_t Size) { + error_code ec; + sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, + &Near, + sys::Memory::MF_READ | + sys::Memory::MF_WRITE, + ec); + assert(!ec && MB.base()); + + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + // Save this address as the basis for our next request + Near = MB; + return MB; } + void RecordingMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } void RecordingMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } void RecordingMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } @@ -81,7 +109,20 @@ void RecordingMemoryManager::endExceptionTable(const Function *F, uint8_t *Table void RecordingMemoryManager::deallocateExceptionTable(void *ET) { llvm_unreachable("Unexpected!"); } + +static int jit_noop() { + return 0; +} + void *RecordingMemoryManager::getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure) { + // We should not invoke parent's ctors/dtors from generated main()! + // On Mingw and Cygwin, the symbol __main is resolved to + // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors + // (and register wrong callee's dtors with atexit(3)). + // We expect ExecutionEngine::runStaticConstructorsDestructors() + // is called before ExecutionEngine::runFunctionAsMain() is called. + if (Name == "__main") return (void*)(intptr_t)&jit_noop; + return NULL; } diff --git a/tools/lli/RecordingMemoryManager.h b/tools/lli/RecordingMemoryManager.h index 1590235..991f535 100644 --- a/tools/lli/RecordingMemoryManager.h +++ b/tools/lli/RecordingMemoryManager.h @@ -31,9 +31,15 @@ private: SmallVector<Allocation, 16> AllocatedDataMem; SmallVector<Allocation, 16> AllocatedCodeMem; + // FIXME: This is part of a work around to keep sections near one another + // when MCJIT performs relocations after code emission but before + // the generated code is moved to the remote target. + sys::MemoryBlock Near; + sys::MemoryBlock allocateSection(uintptr_t Size); + public: RecordingMemoryManager() {} - virtual ~RecordingMemoryManager() {} + virtual ~RecordingMemoryManager(); typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator; typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator; @@ -47,10 +53,13 @@ public: unsigned SectionID); uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); + unsigned SectionID, bool IsReadOnly); void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true); + + bool applyPermissions(std::string *ErrMsg) { return false; } + // The following obsolete JITMemoryManager calls are stubbed out for // this model. void setMemoryWritable(); diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h index d05d3c6..b2a6d0e 100644 --- a/tools/lli/RemoteTarget.h +++ b/tools/lli/RemoteTarget.h @@ -15,8 +15,8 @@ #ifndef REMOTEPROCESS_H #define REMOTEPROCESS_H -#include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" #include <stdlib.h> diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index d41a595..297763f 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -14,11 +14,9 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "lli" +#include "llvm/IR/LLVMContext.h" #include "RecordingMemoryManager.h" #include "RemoteTarget.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/Type.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/CodeGen/LinkAllCodegenComponents.h" @@ -28,33 +26,27 @@ #include "llvm/ExecutionEngine/JITEventListener.h" #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Format.h" #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/Memory.h" -#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" #include <cerrno> -#ifdef __linux__ -// These includes used by LLIMCJITMemoryManager::getPointerToNamedFunction() -// for Glibc trickery. Look comments in this function for more information. -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#include <fcntl.h> -#include <unistd.h> -#endif - #ifdef __CYGWIN__ #include <cygwin/version.h> #if defined(CYGWIN_VERSION_DLL_MAJOR) && CYGWIN_VERSION_DLL_MAJOR<1007 @@ -217,211 +209,6 @@ static void do_shutdown() { #endif } -// Memory manager for MCJIT -class LLIMCJITMemoryManager : public JITMemoryManager { -public: - SmallVector<sys::MemoryBlock, 16> AllocatedDataMem; - SmallVector<sys::MemoryBlock, 16> AllocatedCodeMem; - SmallVector<sys::MemoryBlock, 16> FreeCodeMem; - - LLIMCJITMemoryManager() { } - ~LLIMCJITMemoryManager(); - - virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - virtual void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); - - // Invalidate instruction cache for code sections. Some platforms with - // separate data cache and instruction cache require explicit cache flush, - // otherwise JIT code manipulations (like resolved relocations) will get to - // the data cache but not to the instruction cache. - virtual void invalidateInstructionCache(); - - // The RTDyldMemoryManager doesn't use the following functions, so we don't - // need implement them. - virtual void setMemoryWritable() { - llvm_unreachable("Unexpected call!"); - } - virtual void setMemoryExecutable() { - llvm_unreachable("Unexpected call!"); - } - virtual void setPoisonMemory(bool poison) { - llvm_unreachable("Unexpected call!"); - } - virtual void AllocateGOT() { - llvm_unreachable("Unexpected call!"); - } - virtual uint8_t *getGOTBase() const { - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual uint8_t *startFunctionBody(const Function *F, - uintptr_t &ActualSize){ - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment) { - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) { - llvm_unreachable("Unexpected call!"); - } - virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual void deallocateFunctionBody(void *Body) { - llvm_unreachable("Unexpected call!"); - } - virtual uint8_t* startExceptionTable(const Function* F, - uintptr_t &ActualSize) { - llvm_unreachable("Unexpected call!"); - return 0; - } - virtual void endExceptionTable(const Function *F, uint8_t *TableStart, - uint8_t *TableEnd, uint8_t* FrameRegister) { - llvm_unreachable("Unexpected call!"); - } - virtual void deallocateExceptionTable(void *ET) { - llvm_unreachable("Unexpected call!"); - } -}; - -uint8_t *LLIMCJITMemoryManager::allocateDataSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID) { - if (!Alignment) - Alignment = 16; - // Ensure that enough memory is requested to allow aligning. - size_t NumElementsAligned = 1 + (Size + Alignment - 1)/Alignment; - uint8_t *Addr = (uint8_t*)calloc(NumElementsAligned, Alignment); - - // Honour the alignment requirement. - uint8_t *AlignedAddr = (uint8_t*)RoundUpToAlignment((uint64_t)Addr, Alignment); - - // Store the original address from calloc so we can free it later. - AllocatedDataMem.push_back(sys::MemoryBlock(Addr, NumElementsAligned*Alignment)); - return AlignedAddr; -} - -uint8_t *LLIMCJITMemoryManager::allocateCodeSection(uintptr_t Size, - unsigned Alignment, - unsigned SectionID) { - if (!Alignment) - Alignment = 16; - unsigned NeedAllocate = Alignment * ((Size + Alignment - 1)/Alignment + 1); - uintptr_t Addr = 0; - // Look in the list of free code memory regions and use a block there if one - // is available. - for (int i = 0, e = FreeCodeMem.size(); i != e; ++i) { - sys::MemoryBlock &MB = FreeCodeMem[i]; - if (MB.size() >= NeedAllocate) { - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - // Store cutted free memory block. - FreeCodeMem[i] = sys::MemoryBlock((void*)(Addr + Size), - EndOfBlock - Addr - Size); - return (uint8_t*)Addr; - } - } - - // No pre-allocated free block was large enough. Allocate a new memory region. - sys::MemoryBlock MB = sys::Memory::AllocateRWX(NeedAllocate, 0, 0); - - AllocatedCodeMem.push_back(MB); - Addr = (uintptr_t)MB.base(); - uintptr_t EndOfBlock = Addr + MB.size(); - // Align the address. - Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); - // The AllocateRWX may allocate much more memory than we need. In this case, - // we store the unused memory as a free memory block. - unsigned FreeSize = EndOfBlock-Addr-Size; - if (FreeSize > 16) - FreeCodeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); - - // Return aligned address - return (uint8_t*)Addr; -} - -void LLIMCJITMemoryManager::invalidateInstructionCache() { - for (int i = 0, e = AllocatedCodeMem.size(); i != e; ++i) - sys::Memory::InvalidateInstructionCache(AllocatedCodeMem[i].base(), - AllocatedCodeMem[i].size()); -} - -static int jit_noop() { - return 0; -} - -void *LLIMCJITMemoryManager::getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure) { -#if defined(__linux__) - //===--------------------------------------------------------------------===// - // Function stubs that are invoked instead of certain library calls - // - // Force the following functions to be linked in to anything that uses the - // JIT. This is a hack designed to work around the all-too-clever Glibc - // strategy of making these functions work differently when inlined vs. when - // not inlined, and hiding their real definitions in a separate archive file - // that the dynamic linker can't see. For more info, search for - // 'libc_nonshared.a' on Google, or read http://llvm.org/PR274. - if (Name == "stat") return (void*)(intptr_t)&stat; - if (Name == "fstat") return (void*)(intptr_t)&fstat; - if (Name == "lstat") return (void*)(intptr_t)&lstat; - if (Name == "stat64") return (void*)(intptr_t)&stat64; - if (Name == "fstat64") return (void*)(intptr_t)&fstat64; - if (Name == "lstat64") return (void*)(intptr_t)&lstat64; - if (Name == "atexit") return (void*)(intptr_t)&atexit; - if (Name == "mknod") return (void*)(intptr_t)&mknod; -#endif // __linux__ - - // We should not invoke parent's ctors/dtors from generated main()! - // On Mingw and Cygwin, the symbol __main is resolved to - // callee's(eg. tools/lli) one, to invoke wrong duplicated ctors - // (and register wrong callee's dtors with atexit(3)). - // We expect ExecutionEngine::runStaticConstructorsDestructors() - // is called before ExecutionEngine::runFunctionAsMain() is called. - if (Name == "__main") return (void*)(intptr_t)&jit_noop; - - const char *NameStr = Name.c_str(); - void *Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr); - if (Ptr) return Ptr; - - // If it wasn't found and if it starts with an underscore ('_') character, - // try again without the underscore. - if (NameStr[0] == '_') { - Ptr = sys::DynamicLibrary::SearchForAddressOfSymbol(NameStr+1); - if (Ptr) return Ptr; - } - - if (AbortOnFailure) - report_fatal_error("Program used external function '" + Name + - "' which could not be resolved!"); - return 0; -} - -LLIMCJITMemoryManager::~LLIMCJITMemoryManager() { - for (unsigned i = 0, e = AllocatedCodeMem.size(); i != e; ++i) - sys::Memory::ReleaseRWX(AllocatedCodeMem[i]); - for (unsigned i = 0, e = AllocatedDataMem.size(); i != e; ++i) - free(AllocatedDataMem[i].base()); -} - - void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { // Lay out our sections in order, with all the code sections first, then // all the data sections. @@ -561,7 +348,7 @@ int main(int argc, char **argv, char * const *envp) { if (RemoteMCJIT) JMM = new RecordingMemoryManager(); else - JMM = new LLIMCJITMemoryManager(); + JMM = new SectionMemoryManager(); builder.setJITMemoryManager(JMM); } else { if (RemoteMCJIT) { @@ -662,8 +449,13 @@ int main(int argc, char **argv, char * const *envp) { // MCJIT itself. FIXME. // // Run static constructors. - if (!RemoteMCJIT) - EE->runStaticConstructorsDestructors(false); + if (!RemoteMCJIT) { + if (UseMCJIT && !ForceInterpreter) { + // Give MCJIT a chance to apply relocations and set page permissions. + EE->finalizeObject(); + } + EE->runStaticConstructorsDestructors(false); + } if (NoLazyCompilation) { for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { @@ -710,7 +502,7 @@ int main(int argc, char **argv, char * const *envp) { (void)EE->getPointerToFunction(EntryFn); // Clear instruction cache before code will be executed. if (JMM) - static_cast<LLIMCJITMemoryManager*>(JMM)->invalidateInstructionCache(); + static_cast<SectionMemoryManager*>(JMM)->invalidateInstructionCache(); // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index a8a5013a..86eb8e2 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,20 +12,20 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Bitcode/Archive.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstdlib> -#include <memory> #include <fstream> +#include <memory> using namespace llvm; // Option for compatibility with AIX, not used but must allow it to be present. diff --git a/tools/llvm-as/llvm-as.cpp b/tools/llvm-as/llvm-as.cpp index 1def9a4..273c427 100644 --- a/tools/llvm-as/llvm-as.cpp +++ b/tools/llvm-as/llvm-as.cpp @@ -15,18 +15,18 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/Assembly/Parser.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Analysis/Verifier.h" +#include "llvm/Assembly/Parser.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/Signals.h" #include <memory> using namespace llvm; diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 8109ca4..99479a4 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -37,12 +37,11 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" - -#include <map> #include <algorithm> +#include <map> using namespace llvm; static cl::opt<std::string> @@ -99,16 +98,17 @@ static const char *GetBlockName(unsigned BlockID, if (CurStreamType != LLVMIRBitstream) return 0; switch (BlockID) { - default: return 0; - case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; - case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; - case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID"; - case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; - case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; - case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; - case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; - case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; - case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; + default: return 0; + case bitc::MODULE_BLOCK_ID: return "MODULE_BLOCK"; + case bitc::PARAMATTR_BLOCK_ID: return "PARAMATTR_BLOCK"; + case bitc::PARAMATTR_GROUP_BLOCK_ID: return "PARAMATTR_GROUP_BLOCK_ID"; + case bitc::TYPE_BLOCK_ID_NEW: return "TYPE_BLOCK_ID"; + case bitc::CONSTANTS_BLOCK_ID: return "CONSTANTS_BLOCK"; + case bitc::FUNCTION_BLOCK_ID: return "FUNCTION_BLOCK"; + case bitc::VALUE_SYMTAB_BLOCK_ID: return "VALUE_SYMTAB"; + case bitc::METADATA_BLOCK_ID: return "METADATA_BLOCK"; + case bitc::METADATA_ATTACHMENT_ID: return "METADATA_ATTACHMENT_BLOCK"; + case bitc::USELIST_BLOCK_ID: return "USELIST_BLOCK_ID"; } } @@ -150,7 +150,7 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::MODULE_CODE_DATALAYOUT: return "DATALAYOUT"; case bitc::MODULE_CODE_ASM: return "ASM"; case bitc::MODULE_CODE_SECTIONNAME: return "SECTIONNAME"; - case bitc::MODULE_CODE_DEPLIB: return "DEPLIB"; + case bitc::MODULE_CODE_DEPLIB: return "DEPLIB"; // FIXME: Remove in 4.0 case bitc::MODULE_CODE_GLOBALVAR: return "GLOBALVAR"; case bitc::MODULE_CODE_FUNCTION: return "FUNCTION"; case bitc::MODULE_CODE_ALIAS: return "ALIAS"; @@ -160,7 +160,9 @@ static const char *GetCodeName(unsigned CodeID, unsigned BlockID, case bitc::PARAMATTR_BLOCK_ID: switch (CodeID) { default: return 0; - case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY"; + case bitc::PARAMATTR_CODE_ENTRY_OLD: return "ENTRY"; + case bitc::PARAMATTR_CODE_ENTRY: return "ENTRY"; + case bitc::PARAMATTR_GRP_CODE_ENTRY: return "ENTRY"; } case bitc::TYPE_BLOCK_ID_NEW: switch (CodeID) { @@ -319,10 +321,10 @@ static bool Error(const std::string &Err) { } /// ParseBlock - Read a block, updating statistics, etc. -static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { +static bool ParseBlock(BitstreamCursor &Stream, unsigned BlockID, + unsigned IndentLevel) { std::string Indent(IndentLevel*2, ' '); uint64_t BlockBitStart = Stream.GetCurrentBitNo(); - unsigned BlockID = Stream.ReadSubBlockID(); // Get the statistics for this BlockID. PerBlockIDStats &BlockStats = BlockIDStats[BlockID]; @@ -355,7 +357,7 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { outs() << " BlockID=" << BlockID; outs() << " NumWords=" << NumWords - << " BlockCodeSize=" << Stream.GetAbbrevIDWidth() << ">\n"; + << " BlockCodeSize=" << Stream.getAbbrevIDWidth() << ">\n"; } SmallVector<uint64_t, 64> Record; @@ -367,12 +369,13 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { uint64_t RecordStartBit = Stream.GetCurrentBitNo(); - // Read the code for this record. - unsigned AbbrevID = Stream.ReadCode(); - switch (AbbrevID) { - case bitc::END_BLOCK: { - if (Stream.ReadBlockEnd()) - return Error("Error at end of block"); + BitstreamEntry Entry = + Stream.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); + + switch (Entry.Kind) { + case BitstreamEntry::Error: + return Error("malformed bitcode file"); + case BitstreamEntry::EndBlock: { uint64_t BlockBitEnd = Stream.GetCurrentBitNo(); BlockStats.NumBits += BlockBitEnd-BlockBitStart; if (Dump) { @@ -384,80 +387,81 @@ static bool ParseBlock(BitstreamCursor &Stream, unsigned IndentLevel) { } return false; } - case bitc::ENTER_SUBBLOCK: { + + case BitstreamEntry::SubBlock: { uint64_t SubBlockBitStart = Stream.GetCurrentBitNo(); - if (ParseBlock(Stream, IndentLevel+1)) + if (ParseBlock(Stream, Entry.ID, IndentLevel+1)) return true; ++BlockStats.NumSubBlocks; uint64_t SubBlockBitEnd = Stream.GetCurrentBitNo(); - + // Don't include subblock sizes in the size of this block. BlockBitStart += SubBlockBitEnd-SubBlockBitStart; + continue; + } + case BitstreamEntry::Record: + // The interesting case. break; } - case bitc::DEFINE_ABBREV: + + if (Entry.ID == bitc::DEFINE_ABBREV) { Stream.ReadAbbrevRecord(); ++BlockStats.NumAbbrevs; - break; - default: - Record.clear(); - - ++BlockStats.NumRecords; - if (AbbrevID != bitc::UNABBREV_RECORD) - ++BlockStats.NumAbbreviatedRecords; - - const char *BlobStart = 0; - unsigned BlobLen = 0; - unsigned Code = Stream.ReadRecord(AbbrevID, Record, BlobStart, BlobLen); - - - - // Increment the # occurrences of this code. - if (BlockStats.CodeFreq.size() <= Code) - BlockStats.CodeFreq.resize(Code+1); - BlockStats.CodeFreq[Code].NumInstances++; - BlockStats.CodeFreq[Code].TotalBits += - Stream.GetCurrentBitNo()-RecordStartBit; - if (AbbrevID != bitc::UNABBREV_RECORD) - BlockStats.CodeFreq[Code].NumAbbrev++; + continue; + } + + Record.clear(); + + ++BlockStats.NumRecords; + + StringRef Blob; + unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob); + + // Increment the # occurrences of this code. + if (BlockStats.CodeFreq.size() <= Code) + BlockStats.CodeFreq.resize(Code+1); + BlockStats.CodeFreq[Code].NumInstances++; + BlockStats.CodeFreq[Code].TotalBits += + Stream.GetCurrentBitNo()-RecordStartBit; + if (Entry.ID != bitc::UNABBREV_RECORD) { + BlockStats.CodeFreq[Code].NumAbbrev++; + ++BlockStats.NumAbbreviatedRecords; + } - if (Dump) { - outs() << Indent << " <"; - if (const char *CodeName = - GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) - outs() << CodeName; - else - outs() << "UnknownCode" << Code; - if (NonSymbolic && + if (Dump) { + outs() << Indent << " <"; + if (const char *CodeName = GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) - outs() << " codeid=" << Code; - if (AbbrevID != bitc::UNABBREV_RECORD) - outs() << " abbrevid=" << AbbrevID; - - for (unsigned i = 0, e = Record.size(); i != e; ++i) - outs() << " op" << i << "=" << (int64_t)Record[i]; - - outs() << "/>"; - - if (BlobStart) { - outs() << " blob data = "; - bool BlobIsPrintable = true; - for (unsigned i = 0; i != BlobLen; ++i) - if (!isprint(BlobStart[i])) { - BlobIsPrintable = false; - break; - } - - if (BlobIsPrintable) - outs() << "'" << std::string(BlobStart, BlobStart+BlobLen) <<"'"; - else - outs() << "unprintable, " << BlobLen << " bytes."; - } - - outs() << "\n"; + outs() << CodeName; + else + outs() << "UnknownCode" << Code; + if (NonSymbolic && + GetCodeName(Code, BlockID, *Stream.getBitStreamReader())) + outs() << " codeid=" << Code; + if (Entry.ID != bitc::UNABBREV_RECORD) + outs() << " abbrevid=" << Entry.ID; + + for (unsigned i = 0, e = Record.size(); i != e; ++i) + outs() << " op" << i << "=" << (int64_t)Record[i]; + + outs() << "/>"; + + if (Blob.data()) { + outs() << " blob data = "; + bool BlobIsPrintable = true; + for (unsigned i = 0, e = Blob.size(); i != e; ++i) + if (!isprint(static_cast<unsigned char>(Blob[i]))) { + BlobIsPrintable = false; + break; + } + + if (BlobIsPrintable) + outs() << "'" << Blob << "'"; + else + outs() << "unprintable, " << Blob.size() << " bytes."; } - break; + outs() << "\n"; } } } @@ -520,7 +524,9 @@ static int AnalyzeBitcode() { if (Code != bitc::ENTER_SUBBLOCK) return Error("Invalid record at top-level"); - if (ParseBlock(Stream, 0)) + unsigned BlockID = Stream.ReadSubBlockID(); + + if (ParseBlock(Stream, BlockID, 0)) return true; ++NumTopBlocks; } diff --git a/tools/llvm-diff/CMakeLists.txt b/tools/llvm-diff/CMakeLists.txt index c59d69e..0df8b9e 100644 --- a/tools/llvm-diff/CMakeLists.txt +++ b/tools/llvm-diff/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS support asmparser bitreader) +set(LLVM_LINK_COMPONENTS support asmparser bitreader irreader) add_llvm_tool(llvm-diff llvm-diff.cpp diff --git a/tools/llvm-diff/DiffConsumer.cpp b/tools/llvm-diff/DiffConsumer.cpp index 91c1699..9078013 100644 --- a/tools/llvm-diff/DiffConsumer.cpp +++ b/tools/llvm-diff/DiffConsumer.cpp @@ -12,9 +12,8 @@ //===----------------------------------------------------------------------===// #include "DiffConsumer.h" - -#include "llvm/Module.h" -#include "llvm/Instructions.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; diff --git a/tools/llvm-diff/DiffConsumer.h b/tools/llvm-diff/DiffConsumer.h index 98e369b..6c2209f 100644 --- a/tools/llvm-diff/DiffConsumer.h +++ b/tools/llvm-diff/DiffConsumer.h @@ -15,12 +15,11 @@ #define _LLVM_DIFFCONSUMER_H_ #include "DiffLog.h" - -#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" namespace llvm { class Module; diff --git a/tools/llvm-diff/DiffLog.cpp b/tools/llvm-diff/DiffLog.cpp index 9cc0c88..caf779b 100644 --- a/tools/llvm-diff/DiffLog.cpp +++ b/tools/llvm-diff/DiffLog.cpp @@ -13,10 +13,9 @@ #include "DiffLog.h" #include "DiffConsumer.h" - -#include "llvm/Instructions.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/Instructions.h" using namespace llvm; diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index 0c1e30c..4b11315 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -13,22 +13,20 @@ //===----------------------------------------------------------------------===// #include "DifferenceEngine.h" - -#include "llvm/Constants.h" -#include "llvm/Function.h" -#include "llvm/Instructions.h" -#include "llvm/Module.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" -#include "llvm/Support/CallSite.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/type_traits.h" - #include <utility> using namespace llvm; diff --git a/tools/llvm-diff/DifferenceEngine.h b/tools/llvm-diff/DifferenceEngine.h index 0246d8f..73bf6eb 100644 --- a/tools/llvm-diff/DifferenceEngine.h +++ b/tools/llvm-diff/DifferenceEngine.h @@ -15,11 +15,10 @@ #ifndef _LLVM_DIFFERENCE_ENGINE_H_ #define _LLVM_DIFFERENCE_ENGINE_H_ +#include "DiffConsumer.h" +#include "DiffLog.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include "DiffLog.h" -#include "DiffConsumer.h" - #include <utility> namespace llvm { diff --git a/tools/llvm-diff/LLVMBuild.txt b/tools/llvm-diff/LLVMBuild.txt index fa06a03..5adfdc2 100644 --- a/tools/llvm-diff/LLVMBuild.txt +++ b/tools/llvm-diff/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-diff parent = Tools -required_libraries = AsmParser BitReader +required_libraries = AsmParser BitReader IRReader diff --git a/tools/llvm-diff/Makefile b/tools/llvm-diff/Makefile index f7fa715..bd97a6a 100644 --- a/tools/llvm-diff/Makefile +++ b/tools/llvm-diff/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-diff -LINK_COMPONENTS := asmparser bitreader +LINK_COMPONENTS := asmparser bitreader irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index 45957b3..6eca1e2 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -13,19 +13,17 @@ #include "DiffLog.h" #include "DifferenceEngine.h" - -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/Type.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/SourceMgr.h" - +#include "llvm/Support/raw_ostream.h" #include <string> #include <utility> diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 41f023d..2baa91d 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -16,21 +16,21 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/DebugInfo.h" -#include "llvm/Module.h" -#include "llvm/Type.h" -#include "llvm/IntrinsicInst.h" -#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Assembly/AssemblyAnnotationWriter.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataStream.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/system_error.h" using namespace llvm; diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index e73300a..8094856 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -12,11 +12,11 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/RelocVisitor.h" -#include "llvm/DebugInfo/DIContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" @@ -52,6 +52,25 @@ static cl::opt<bool> PrintInlining("inlining", cl::init(false), cl::desc("Print all inlined frames for a given address")); +static cl::opt<DIDumpType> +DumpType("debug-dump", cl::init(DIDT_All), + cl::desc("Dump of debug sections:"), + cl::values( + clEnumValN(DIDT_All, "all", "Dump all debug sections"), + clEnumValN(DIDT_Abbrev, "abbrev", ".debug_abbrev"), + clEnumValN(DIDT_AbbrevDwo, "abbrev.dwo", ".debug_abbrev.dwo"), + clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"), + clEnumValN(DIDT_Info, "info", ".debug_info"), + clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), + clEnumValN(DIDT_Line, "line", ".debug_line"), + clEnumValN(DIDT_Frames, "frames", ".debug_frame"), + clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), + clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), + clEnumValN(DIDT_Str, "str", ".debug_str"), + clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), + clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"), + clEnumValEnd)); + static void PrintDILineInfo(DILineInfo dli) { if (PrintFunctions) outs() << (dli.getFunctionName() ? dli.getFunctionName() : "<unknown>") @@ -69,105 +88,18 @@ static void DumpInput(const StringRef &Filename) { } OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); - - StringRef DebugInfoSection; - RelocAddrMap RelocMap; - StringRef DebugAbbrevSection; - StringRef DebugLineSection; - StringRef DebugArangesSection; - StringRef DebugStringSection; - StringRef DebugRangesSection; - - error_code ec; - for (section_iterator i = Obj->begin_sections(), - e = Obj->end_sections(); - i != e; i.increment(ec)) { - StringRef name; - i->getName(name); - StringRef data; - i->getContents(data); - - if (name.startswith("__DWARF,")) - name = name.substr(8); // Skip "__DWARF," prefix. - name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. - if (name == "debug_info") - DebugInfoSection = data; - else if (name == "debug_abbrev") - DebugAbbrevSection = data; - else if (name == "debug_line") - DebugLineSection = data; - else if (name == "debug_aranges") - DebugArangesSection = data; - else if (name == "debug_str") - DebugStringSection = data; - else if (name == "debug_ranges") - DebugRangesSection = data; - // Any more debug info sections go here. - else - continue; - - // TODO: For now only handle relocations for the debug_info section. - if (name != "debug_info") - continue; - - if (i->begin_relocations() != i->end_relocations()) { - uint64_t SectionSize; - i->getSize(SectionSize); - for (relocation_iterator reloc_i = i->begin_relocations(), - reloc_e = i->end_relocations(); - reloc_i != reloc_e; reloc_i.increment(ec)) { - uint64_t Address; - reloc_i->getAddress(Address); - uint64_t Type; - reloc_i->getType(Type); - - RelocVisitor V(Obj->getFileFormatName()); - // The section address is always 0 for debug sections. - RelocToApply R(V.visit(Type, *reloc_i)); - if (V.error()) { - SmallString<32> Name; - error_code ec(reloc_i->getTypeName(Name)); - if (ec) { - errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n"; - } - errs() << "error: failed to compute relocation: " - << Name << "\n"; - continue; - } - - if (Address + R.Width > SectionSize) { - errs() << "error: " << R.Width << "-byte relocation starting " - << Address << " bytes into section " << name << " which is " - << SectionSize << " bytes long.\n"; - continue; - } - if (R.Width > 8) { - errs() << "error: can't handle a relocation of more than 8 bytes at " - "a time.\n"; - continue; - } - DEBUG(dbgs() << "Writing " << format("%p", R.Value) - << " at " << format("%p", Address) - << " with width " << format("%d", R.Width) - << "\n"); - RelocMap[Address] = std::make_pair(R.Width, R.Value); - } - } + if (!Obj) { + errs() << Filename << ": Unknown object file format\n"; + return; } - OwningPtr<DIContext> dictx(DIContext::getDWARFContext(/*FIXME*/true, - DebugInfoSection, - DebugAbbrevSection, - DebugArangesSection, - DebugLineSection, - DebugStringSection, - DebugRangesSection, - RelocMap)); + OwningPtr<DIContext> DICtx(DIContext::getDWARFContext(Obj.get())); + if (Address == -1ULL) { outs() << Filename << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; // Dump the complete DWARF structure. - dictx->dump(outs()); + DICtx->dump(outs(), DumpType); } else { // Print line info for the specified address. int SpecFlags = DILineInfoSpecifier::FileLineInfo | @@ -176,7 +108,7 @@ static void DumpInput(const StringRef &Filename) { SpecFlags |= DILineInfoSpecifier::FunctionName; if (PrintInlining) { DIInliningInfo InliningInfo = - dictx->getInliningInfoForAddress(Address, SpecFlags); + DICtx->getInliningInfoForAddress(Address, SpecFlags); uint32_t n = InliningInfo.getNumberOfFrames(); if (n == 0) { // Print one empty debug line info in any case. @@ -188,7 +120,7 @@ static void DumpInput(const StringRef &Filename) { } } } else { - DILineInfo dli = dictx->getLineInfoForAddress(Address, SpecFlags); + DILineInfo dli = DICtx->getLineInfoForAddress(Address, SpecFlags); PrintDILineInfo(dli); } } diff --git a/tools/llvm-extract/CMakeLists.txt b/tools/llvm-extract/CMakeLists.txt index a4e3266..3163c4b 100644 --- a/tools/llvm-extract/CMakeLists.txt +++ b/tools/llvm-extract/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter) +set(LLVM_LINK_COMPONENTS asmparser ipo bitreader bitwriter irreader) add_llvm_tool(llvm-extract llvm-extract.cpp diff --git a/tools/llvm-extract/LLVMBuild.txt b/tools/llvm-extract/LLVMBuild.txt index 1b1a4c3..70e3507 100644 --- a/tools/llvm-extract/LLVMBuild.txt +++ b/tools/llvm-extract/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-extract parent = Tools -required_libraries = AsmParser BitReader BitWriter IPO +required_libraries = AsmParser BitReader BitWriter IRReader IPO diff --git a/tools/llvm-extract/Makefile b/tools/llvm-extract/Makefile index a1e93f5..d371c54 100644 --- a/tools/llvm-extract/Makefile +++ b/tools/llvm-extract/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-extract -LINK_COMPONENTS := ipo bitreader bitwriter asmparser +LINK_COMPONENTS := ipo bitreader bitwriter asmparser irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index ac82d98..fd0a381 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -12,23 +12,24 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/Assembly/PrintModulePass.h" #include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/DataLayout.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/SystemUtils.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/Regex.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SetVector.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Transforms/IPO.h" #include <memory> using namespace llvm; diff --git a/tools/llvm-jitlistener/CMakeLists.txt b/tools/llvm-jitlistener/CMakeLists.txt new file mode 100644 index 0000000..c9704fb --- /dev/null +++ b/tools/llvm-jitlistener/CMakeLists.txt @@ -0,0 +1,22 @@ +# This tool is excluded from the CMake build if Intel JIT events are disabled.
+
+link_directories( ${LLVM_INTEL_JITEVENTS_LIBDIR} )
+include_directories( ${LLVM_INTEL_JITEVENTS_INCDIR} )
+
+set(LLVM_LINK_COMPONENTS
+ asmparser
+ bitreader
+ debuginfo
+ inteljitevents
+ interpreter
+ irreader
+ jit
+ mcjit
+ nativecodegen
+ object
+ selectiondag
+ )
+
+add_llvm_tool(llvm-jitlistener
+ llvm-jitlistener.cpp
+ )
diff --git a/tools/llvm-jitlistener/LLVMBuild.txt b/tools/llvm-jitlistener/LLVMBuild.txt new file mode 100644 index 0000000..1ce78ac --- /dev/null +++ b/tools/llvm-jitlistener/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-jitlistener/LLVMBuild.txt -------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-jitlistener +parent = Tools +required_libraries = AsmParser BitReader IRReader Interpreter JIT MCJIT NativeCodeGen Object SelectionDAG Native diff --git a/tools/llvm-jitlistener/Makefile b/tools/llvm-jitlistener/Makefile new file mode 100644 index 0000000..b132227 --- /dev/null +++ b/tools/llvm-jitlistener/Makefile @@ -0,0 +1,27 @@ +##===- tools/llvm-jitlistener/Makefile ---------------------*- Makefile -*-===##
+#
+# The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+TOOLNAME := llvm-jitlistener
+
+include $(LEVEL)/Makefile.config
+
+LINK_COMPONENTS := mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag Object
+
+# If Intel JIT Events support is configured, link against the LLVM Intel JIT
+# Events interface library. If not, this tool will do nothing useful, but it
+# will build correctly.
+ifeq ($(USE_INTEL_JITEVENTS), 1)
+ LINK_COMPONENTS += debuginfo inteljitevents
+endif
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LLVM_SRC_ROOT)/Makefile.rules
diff --git a/tools/llvm-jitlistener/llvm-jitlistener.cpp b/tools/llvm-jitlistener/llvm-jitlistener.cpp new file mode 100644 index 0000000..dbaf075 --- /dev/null +++ b/tools/llvm-jitlistener/llvm-jitlistener.cpp @@ -0,0 +1,207 @@ +//===-- llvm-jitlistener.cpp - Utility for testing MCJIT event listener ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a used by lit tests to verify the MCJIT JITEventListener +// interface. It registers a mock JIT event listener, generates a module from +// an input IR file and dumps the reported event information to stdout. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LLVMContext.h" +#include "../../lib/ExecutionEngine/IntelJITEvents/IntelJITEventsWrapper.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetSelect.h" +#include <string> + +using namespace llvm; + +namespace { + +typedef std::vector<std::pair<std::string, unsigned int> > SourceLocations; +typedef std::map<uint64_t, SourceLocations> NativeCodeMap; + +NativeCodeMap ReportedDebugFuncs; + +int NotifyEvent(iJIT_JVM_EVENT EventType, void *EventSpecificData) { + switch (EventType) { + case iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED: { + if (!EventSpecificData) { + errs() << + "Error: The JIT event listener did not provide a event data."; + return -1; + } + iJIT_Method_Load* msg = static_cast<iJIT_Method_Load*>(EventSpecificData); + + ReportedDebugFuncs[msg->method_id]; + + outs() << "Method load [" << msg->method_id << "]: " << msg->method_name + << ", Size = " << msg->method_size << "\n"; + + for(unsigned int i = 0; i < msg->line_number_size; ++i) { + if (!msg->line_number_table) { + errs() << "A function with a non-zero line count had no line table."; + return -1; + } + std::pair<std::string, unsigned int> loc( + std::string(msg->source_file_name), + msg->line_number_table[i].LineNumber); + ReportedDebugFuncs[msg->method_id].push_back(loc); + outs() << " Line info @ " << msg->line_number_table[i].Offset + << ": " << msg->source_file_name + << ", line " << msg->line_number_table[i].LineNumber << "\n"; + } + outs() << "\n"; + } + break; + case iJVM_EVENT_TYPE_METHOD_UNLOAD_START: { + if (!EventSpecificData) { + errs() << + "Error: The JIT event listener did not provide a event data."; + return -1; + } + unsigned int UnloadId + = *reinterpret_cast<unsigned int*>(EventSpecificData); + assert(1 == ReportedDebugFuncs.erase(UnloadId)); + outs() << "Method unload [" << UnloadId << "]\n"; + } + break; + default: + break; + } + return 0; +} + +iJIT_IsProfilingActiveFlags IsProfilingActive(void) { + // for testing, pretend we have an Intel Parallel Amplifier XE 2011 + // instance attached + return iJIT_SAMPLING_ON; +} + +unsigned int GetNewMethodID(void) { + static unsigned int id = 0; + return ++id; +} + +class JitEventListenerTest { +protected: + void InitEE(const std::string &IRFile) { + LLVMContext &Context = getGlobalContext(); + + // If we have a native target, initialize it to ensure it is linked in and + // usable by the JIT. + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + + // Parse the bitcode... + SMDiagnostic Err; + TheModule = ParseIRFile(IRFile, Err, Context); + if (!TheModule) { + errs() << Err.getMessage(); + return; + } + + // FIXME: This is using the default legacy JITMemoryManager because it + // supports poison memory. At some point, we'll need to update this to + // use an MCJIT-specific memory manager. It might be nice to have the + // poison memory option there too. + JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager(); + if (!MemMgr) { + errs() << "Unable to create memory manager."; + return; + } + + // Tell the memory manager to poison freed memory so that accessing freed + // memory is more easily tested. + MemMgr->setPoisonMemory(true); + + // Override the triple to generate ELF on Windows since that's supported + Triple Tuple(TheModule->getTargetTriple()); + if (Tuple.getTriple().empty()) + Tuple.setTriple(sys::getProcessTriple()); + + if (Tuple.isOSWindows() && Triple::ELF != Tuple.getEnvironment()) { + Tuple.setEnvironment(Triple::ELF); + TheModule->setTargetTriple(Tuple.getTriple()); + } + + // Compile the IR + std::string Error; + TheJIT.reset(EngineBuilder(TheModule) + .setEngineKind(EngineKind::JIT) + .setErrorStr(&Error) + .setJITMemoryManager(MemMgr) + .setUseMCJIT(true) + .create()); + if (Error.empty() == false) + errs() << Error; + } + + void DestroyEE() { + TheJIT.reset(); + } + + LLVMContext Context; // Global ownership + Module *TheModule; // Owned by ExecutionEngine. + JITMemoryManager *JMM; // Owned by ExecutionEngine. + OwningPtr<ExecutionEngine> TheJIT; + +public: + void ProcessInput(const std::string &Filename) { + InitEE(Filename); + + llvm::OwningPtr<llvm::JITEventListener> Listener(JITEventListener::createIntelJITEventListener( + new IntelJITEventsWrapper(NotifyEvent, 0, + IsProfilingActive, 0, 0, + GetNewMethodID))); + + TheJIT->RegisterJITEventListener(Listener.get()); + + TheJIT->finalizeObject(); + + // Destroy the JIT engine instead of unregistering to get unload events. + DestroyEE(); + } +}; + + + +} // end anonymous namespace + +static cl::opt<std::string> +InputFilename(cl::Positional, cl::desc("<input IR file>"), + cl::Required); + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "llvm jit event listener test utility\n"); + + JitEventListenerTest Test; + + Test.ProcessInput(InputFilename); + + return 0; +} diff --git a/tools/llvm-link/CMakeLists.txt b/tools/llvm-link/CMakeLists.txt index 11933f7..4df5356 100644 --- a/tools/llvm-link/CMakeLists.txt +++ b/tools/llvm-link/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser) +set(LLVM_LINK_COMPONENTS linker bitreader bitwriter asmparser irreader) add_llvm_tool(llvm-link llvm-link.cpp diff --git a/tools/llvm-link/LLVMBuild.txt b/tools/llvm-link/LLVMBuild.txt index 6399ded..2e386f3 100644 --- a/tools/llvm-link/LLVMBuild.txt +++ b/tools/llvm-link/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-link parent = Tools -required_libraries = AsmParser BitReader BitWriter Linker +required_libraries = AsmParser BitReader BitWriter IRReader Linker diff --git a/tools/llvm-link/Makefile b/tools/llvm-link/Makefile index 2553db0..ed30d2d 100644 --- a/tools/llvm-link/Makefile +++ b/tools/llvm-link/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-link -LINK_COMPONENTS := linker bitreader bitwriter asmparser +LINK_COMPONENTS := linker bitreader bitwriter asmparser irreader # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 378a833..83665cc 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -13,18 +13,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Linker.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/SystemUtils.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/ToolOutputFile.h" #include <memory> using namespace llvm; @@ -111,9 +112,6 @@ int main(int argc, char **argv) { } } - // TODO: Iterate over the -l list and link in any modules containing - // global symbols that have not been resolved so far. - if (DumpAsm) errs() << "Here's the assembly:\n" << *Composite; std::string ErrorInfo; diff --git a/tools/llvm-mc/Disassembler.cpp b/tools/llvm-mc/Disassembler.cpp index 5f2fdb8..06c7721 100644 --- a/tools/llvm-mc/Disassembler.cpp +++ b/tools/llvm-mc/Disassembler.cpp @@ -13,16 +13,12 @@ //===----------------------------------------------------------------------===// #include "Disassembler.h" -#include "../../lib/MC/MCDisassembler/EDDisassembler.h" -#include "../../lib/MC/MCDisassembler/EDInst.h" -#include "../../lib/MC/MCDisassembler/EDOperand.h" -#include "../../lib/MC/MCDisassembler/EDToken.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MemoryObject.h" #include "llvm/Support/SourceMgr.h" @@ -169,175 +165,3 @@ int Disassembler::disassemble(const Target &T, return ErrorOccurred; } - -static int byteArrayReader(uint8_t *B, uint64_t A, void *Arg) { - ByteArrayTy &ByteArray = *((ByteArrayTy*)Arg); - - if (A >= ByteArray.size()) - return -1; - - *B = ByteArray[A].first; - - return 0; -} - -static int verboseEvaluator(uint64_t *V, unsigned R, void *Arg) { - EDDisassembler &disassembler = *(EDDisassembler *)((void **)Arg)[0]; - raw_ostream &Out = *(raw_ostream *)((void **)Arg)[1]; - - if (const char *regName = disassembler.nameWithRegisterID(R)) - Out << "[" << regName << "/" << R << "]"; - - if (disassembler.registerIsStackPointer(R)) - Out << "(sp)"; - if (disassembler.registerIsProgramCounter(R)) - Out << "(pc)"; - - *V = 0; - return 0; -} - -int Disassembler::disassembleEnhanced(const std::string &TS, - MemoryBuffer &Buffer, - SourceMgr &SM, - raw_ostream &Out) { - ByteArrayTy ByteArray; - StringRef Str = Buffer.getBuffer(); - - if (ByteArrayFromString(ByteArray, Str, SM)) { - return -1; - } - - Triple T(TS); - EDDisassembler::AssemblySyntax AS; - - switch (T.getArch()) { - default: - errs() << "error: no default assembly syntax for " << TS.c_str() << "\n"; - return -1; - case Triple::arm: - case Triple::thumb: - AS = EDDisassembler::kEDAssemblySyntaxARMUAL; - break; - case Triple::x86: - case Triple::x86_64: - AS = EDDisassembler::kEDAssemblySyntaxX86ATT; - break; - } - - OwningPtr<EDDisassembler> - disassembler(EDDisassembler::getDisassembler(TS.c_str(), AS)); - - if (disassembler == 0) { - errs() << "error: couldn't get disassembler for " << TS << '\n'; - return -1; - } - - while (ByteArray.size()) { - OwningPtr<EDInst> - inst(disassembler->createInst(byteArrayReader, 0, &ByteArray)); - - if (inst == 0) { - errs() << "error: Didn't get an instruction\n"; - return -1; - } - - ByteArray.erase (ByteArray.begin(), ByteArray.begin() + inst->byteSize()); - - unsigned numTokens = inst->numTokens(); - if ((int)numTokens < 0) { - errs() << "error: couldn't count the instruction's tokens\n"; - return -1; - } - - for (unsigned tokenIndex = 0; tokenIndex != numTokens; ++tokenIndex) { - EDToken *token; - - if (inst->getToken(token, tokenIndex)) { - errs() << "error: Couldn't get token\n"; - return -1; - } - - const char *buf; - if (token->getString(buf)) { - errs() << "error: Couldn't get string for token\n"; - return -1; - } - - Out << '['; - int operandIndex = token->operandID(); - - if (operandIndex >= 0) - Out << operandIndex << "-"; - - switch (token->type()) { - case EDToken::kTokenWhitespace: Out << "w"; break; - case EDToken::kTokenPunctuation: Out << "p"; break; - case EDToken::kTokenOpcode: Out << "o"; break; - case EDToken::kTokenLiteral: Out << "l"; break; - case EDToken::kTokenRegister: Out << "r"; break; - } - - Out << ":" << buf; - - if (token->type() == EDToken::kTokenLiteral) { - Out << "="; - if (token->literalSign()) - Out << "-"; - uint64_t absoluteValue; - if (token->literalAbsoluteValue(absoluteValue)) { - errs() << "error: Couldn't get the value of a literal token\n"; - return -1; - } - Out << absoluteValue; - } else if (token->type() == EDToken::kTokenRegister) { - Out << "="; - unsigned regID; - if (token->registerID(regID)) { - errs() << "error: Couldn't get the ID of a register token\n"; - return -1; - } - Out << "r" << regID; - } - - Out << "]"; - } - - Out << " "; - - if (inst->isBranch()) - Out << "<br> "; - if (inst->isMove()) - Out << "<mov> "; - - unsigned numOperands = inst->numOperands(); - - if ((int)numOperands < 0) { - errs() << "error: Couldn't count operands\n"; - return -1; - } - - for (unsigned operandIndex = 0; operandIndex != numOperands; - ++operandIndex) { - Out << operandIndex << ":"; - - EDOperand *operand; - if (inst->getOperand(operand, operandIndex)) { - errs() << "error: couldn't get operand\n"; - return -1; - } - - uint64_t evaluatedResult; - void *Arg[] = { disassembler.get(), &Out }; - if (operand->evaluate(evaluatedResult, verboseEvaluator, Arg)) { - errs() << "error: Couldn't evaluate an operand\n"; - return -1; - } - Out << "=" << evaluatedResult << " "; - } - - Out << '\n'; - } - - return 0; -} diff --git a/tools/llvm-mc/Disassembler.h b/tools/llvm-mc/Disassembler.h index 17d622f..5615da8 100644 --- a/tools/llvm-mc/Disassembler.h +++ b/tools/llvm-mc/Disassembler.h @@ -35,11 +35,6 @@ public: MemoryBuffer &Buffer, SourceMgr &SM, raw_ostream &Out); - - static int disassembleEnhanced(const std::string &tripleString, - MemoryBuffer &buffer, - SourceMgr &SM, - raw_ostream &Out); }; } // namespace llvm diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index f7c3748..243899b 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -12,36 +12,35 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCParser/AsmLexer.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "Disassembler.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCParser/AsmLexer.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/ADT/OwningPtr.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileUtilities.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/Host.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/Host.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/system_error.h" -#include "Disassembler.h" using namespace llvm; static cl::opt<std::string> @@ -69,6 +68,9 @@ static cl::opt<bool> RelaxAll("mc-relax-all", cl::desc("Relax all fixups")); static cl::opt<bool> +DisableCFI("disable-cfi", cl::desc("Do not use .cfi_* directives")); + +static cl::opt<bool> NoExecStack("mc-no-exec-stack", cl::desc("File doesn't need an exec stack")); enum OutputFileType { @@ -154,12 +156,20 @@ static cl::opt<bool> GenDwarfForAssembly("g", cl::desc("Generate dwarf debugging info for assembly " "source files")); +static cl::opt<std::string> +DebugCompilationDir("fdebug-compilation-dir", + cl::desc("Specifies the debug info's compilation dir")); + +static cl::opt<std::string> +MainFileName("main-file-name", + cl::desc("Specifies the name we should consider the input file")); + enum ActionType { AC_AsLex, AC_Assemble, AC_Disassemble, - AC_EDisassemble, - AC_MDisassemble + AC_MDisassemble, + AC_HDisassemble }; static cl::opt<ActionType> @@ -171,10 +181,11 @@ Action(cl::desc("Action to perform:"), "Assemble a .s file (default)"), clEnumValN(AC_Disassemble, "disassemble", "Disassemble strings of hex bytes"), - clEnumValN(AC_EDisassemble, "edis", - "Enhanced disassembly of strings of hex bytes"), clEnumValN(AC_MDisassemble, "mdis", "Marked up disassembly of strings of hex bytes"), + clEnumValN(AC_HDisassemble, "hdis", + "Disassemble strings of hex bytes printing " + "immediates as hex"), clEnumValEnd)); static const Target *GetTarget(const char *ProgName) { @@ -224,6 +235,13 @@ static void setDwarfDebugFlags(int argc, char **argv) { } } +static std::string DwarfDebugProducer; +static void setDwarfDebugProducer(void) { + if(!getenv("DEBUG_PRODUCER")) + return; + DwarfDebugProducer += getenv("DEBUG_PRODUCER"); +} + static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) { AsmLexer Lexer(MAI); @@ -251,9 +269,6 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) case AsmToken::Real: Out->os() << "real: " << Lexer.getTok().getString(); break; - case AsmToken::Register: - Out->os() << "register: " << Lexer.getTok().getRegVal(); - break; case AsmToken::String: Out->os() << "string: " << Lexer.getTok().getString(); break; @@ -344,6 +359,8 @@ int main(int argc, char **argv) { TripleName = Triple::normalize(TripleName); setDwarfDebugFlags(argc, argv); + setDwarfDebugProducer(); + const char *ProgName = argv[0]; const Target *TheTarget = GetTarget(ProgName); if (!TheTarget) @@ -365,7 +382,6 @@ int main(int argc, char **argv) { // it later. SrcMgr.setIncludeDirs(IncludeDirs); - llvm::OwningPtr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TripleName)); assert(MAI && "Unable to create target asm info!"); @@ -382,8 +398,14 @@ int main(int argc, char **argv) { Ctx.setAllowTemporaryLabels(false); Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); - if (!DwarfDebugFlags.empty()) + if (!DwarfDebugFlags.empty()) Ctx.setDwarfDebugFlags(StringRef(DwarfDebugFlags)); + if (!DwarfDebugProducer.empty()) + Ctx.setDwarfDebugProducer(StringRef(DwarfDebugProducer)); + if (!DebugCompilationDir.empty()) + Ctx.setCompilationDir(DebugCompilationDir); + if (!MainFileName.empty()) + Ctx.setMainFileName(MainFileName); // Package up features to be passed to target/subtarget std::string FeaturesStr; @@ -405,7 +427,7 @@ int main(int argc, char **argv) { OwningPtr<MCSubtargetInfo> STI(TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); - MCInstPrinter *IP; + MCInstPrinter *IP = NULL; if (FileType == OFT_AssemblyFile) { IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); @@ -415,9 +437,10 @@ int main(int argc, char **argv) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); } + bool UseCFI = !DisableCFI; Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, /*useLoc*/ true, - /*useCFI*/ true, + UseCFI, /*useDwarfDirectory*/ true, IP, CE, MAB, ShowInst)); @@ -433,6 +456,7 @@ int main(int argc, char **argv) { } int Res = 1; + bool disassemble = false; switch (Action) { case AC_AsLex: Res = AsLexInput(SrcMgr, *MAI, Out.get()); @@ -441,16 +465,22 @@ int main(int argc, char **argv) { Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI); break; case AC_MDisassemble: + assert(IP && "Expected assembly output"); IP->setUseMarkup(1); - // Fall through to do disassembly. - case AC_Disassemble: - Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, - *Buffer, SrcMgr, Out->os()); + disassemble = true; break; - case AC_EDisassemble: - Res = Disassembler::disassembleEnhanced(TripleName, *Buffer, SrcMgr, Out->os()); + case AC_HDisassemble: + assert(IP && "Expected assembly output"); + IP->setPrintImmHex(1); + disassemble = true; + break; + case AC_Disassemble: + disassemble = true; break; } + if (disassemble) + Res = Disassembler::disassemble(*TheTarget, TripleName, *STI, *Str, + *Buffer, SrcMgr, Out->os()); // Keep output if no errors. if (Res == 0) Out->keep(); diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 0543e83..a24aae6 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -16,21 +16,21 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Bitcode/Archive.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> #include <cctype> @@ -113,6 +113,10 @@ namespace { cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden, cl::desc("Exclude aliases from output")); + cl::opt<bool> ArchiveMap("print-armap", + cl::desc("Print the archive map")); + cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), + cl::aliasopt(ArchiveMap)); bool PrintAddress = true; bool MultipleFiles = false; @@ -146,6 +150,8 @@ namespace { 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; @@ -156,12 +162,21 @@ namespace { 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; } static bool CompareSymbolName(const NMSymbol &a, const NMSymbol &b) { - return a.Name < b.Name; + 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; } StringRef CurrentFilename; @@ -346,12 +361,32 @@ static void DumpSymbolNamesFromFile(std::string &Filename) { return; if (object::Archive *a = dyn_cast<object::Archive>(arch.get())) { + if (ArchiveMap) { + outs() << "Archive map" << "\n"; + for (object::Archive::symbol_iterator i = a->begin_symbols(), + e = a->end_symbols(); i != e; ++i) { + object::Archive::child_iterator c; + StringRef symname; + StringRef filename; + if (error(i->getMember(c))) + return; + if (error(i->getName(symname))) + return; + if (error(c->getName(filename))) + return; + outs() << symname << " in " << filename << "\n"; + } + outs() << "\n"; + } + for (object::Archive::child_iterator i = a->begin_children(), e = a->end_children(); i != e; ++i) { OwningPtr<Binary> child; if (i->getAsBinary(child)) { // Try opening it as a bitcode file. - OwningPtr<MemoryBuffer> buff(i->getBuffer()); + OwningPtr<MemoryBuffer> buff; + if (error(i->getMemoryBuffer(buff))) + return; Module *Result = 0; if (buff) Result = ParseBitcodeFile(buff.get(), Context, &ErrorMessage); diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index f3b2e1f..0c49d0b 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -9,6 +9,8 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-objdump llvm-objdump.cpp + COFFDump.cpp + ELFDump.cpp MachODump.cpp MCFunction.cpp ) diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp new file mode 100644 index 0000000..2ada683 --- /dev/null +++ b/tools/llvm-objdump/COFFDump.cpp @@ -0,0 +1,355 @@ +//===-- COFFDump.cpp - COFF-specific dumper ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF-specific dumper for llvm-objdump. +/// It outputs the Win64 EH data structures as plain text. +/// The encoding of the unwind codes is decribed in MSDN: +/// http://msdn.microsoft.com/en-us/library/ck9asaa9.aspx +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Win64EH.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include <algorithm> +#include <cstring> + +using namespace llvm; +using namespace object; +using namespace llvm::Win64EH; + +// Returns the name of the unwind code. +static StringRef getUnwindCodeTypeName(uint8_t Code) { + switch(Code) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: return "UOP_PushNonVol"; + case UOP_AllocLarge: return "UOP_AllocLarge"; + case UOP_AllocSmall: return "UOP_AllocSmall"; + case UOP_SetFPReg: return "UOP_SetFPReg"; + case UOP_SaveNonVol: return "UOP_SaveNonVol"; + case UOP_SaveNonVolBig: return "UOP_SaveNonVolBig"; + case UOP_SaveXMM128: return "UOP_SaveXMM128"; + case UOP_SaveXMM128Big: return "UOP_SaveXMM128Big"; + case UOP_PushMachFrame: return "UOP_PushMachFrame"; + } +} + +// Returns the name of a referenced register. +static StringRef getUnwindRegisterName(uint8_t Reg) { + switch(Reg) { + default: llvm_unreachable("Invalid register"); + case 0: return "RAX"; + case 1: return "RCX"; + case 2: return "RDX"; + case 3: return "RBX"; + case 4: return "RSP"; + case 5: return "RBP"; + case 6: return "RSI"; + case 7: return "RDI"; + case 8: return "R8"; + case 9: return "R9"; + case 10: return "R10"; + case 11: return "R11"; + case 12: return "R12"; + case 13: return "R13"; + case 14: return "R14"; + case 15: return "R15"; + } +} + +// Calculates the number of array slots required for the unwind code. +static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { + switch (UnwindCode.getUnwindOp()) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: + case UOP_AllocSmall: + case UOP_SetFPReg: + case UOP_PushMachFrame: + return 1; + case UOP_SaveNonVol: + case UOP_SaveXMM128: + return 2; + case UOP_SaveNonVolBig: + case UOP_SaveXMM128Big: + return 3; + case UOP_AllocLarge: + return (UnwindCode.getOpInfo() == 0) ? 2 : 3; + } +} + +// Prints one unwind code. Because an unwind code can occupy up to 3 slots in +// the unwind codes array, this function requires that the correct number of +// slots is provided. +static void printUnwindCode(ArrayRef<UnwindCode> UCs) { + assert(UCs.size() >= getNumUsedSlots(UCs[0])); + outs() << format(" 0x%02x: ", unsigned(UCs[0].u.CodeOffset)) + << getUnwindCodeTypeName(UCs[0].getUnwindOp()); + switch (UCs[0].getUnwindOp()) { + case UOP_PushNonVol: + outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()); + break; + case UOP_AllocLarge: + if (UCs[0].getOpInfo() == 0) { + outs() << " " << UCs[1].FrameOffset; + } else { + outs() << " " << UCs[1].FrameOffset + + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); + } + break; + case UOP_AllocSmall: + outs() << " " << ((UCs[0].getOpInfo() + 1) * 8); + break; + case UOP_SetFPReg: + outs() << " "; + break; + case UOP_SaveNonVol: + outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(" [0x%04x]", 8 * UCs[1].FrameOffset); + break; + case UOP_SaveNonVolBig: + outs() << " " << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(" [0x%08x]", UCs[1].FrameOffset + + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); + break; + case UOP_SaveXMM128: + outs() << " XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(" [0x%04x]", 16 * UCs[1].FrameOffset); + break; + case UOP_SaveXMM128Big: + outs() << " XMM" << UCs[0].getOpInfo() + << format(" [0x%08x]", UCs[1].FrameOffset + + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16)); + break; + case UOP_PushMachFrame: + outs() << " " << (UCs[0].getOpInfo() ? "w/o" : "w") + << " error code"; + break; + } + outs() << "\n"; +} + +static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) { + for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ) { + unsigned UsedSlots = getNumUsedSlots(*I); + if (UsedSlots > UCs.size()) { + outs() << "Unwind data corrupted: Encountered unwind op " + << getUnwindCodeTypeName((*I).getUnwindOp()) + << " which requires " << UsedSlots + << " slots, but only " << UCs.size() + << " remaining in buffer"; + return ; + } + printUnwindCode(ArrayRef<UnwindCode>(I, E)); + I += UsedSlots; + } +} + +// Given a symbol sym this functions returns the address and section of it. +static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, + const SymbolRef &Sym, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddr) { + if (error_code ec = Sym.getAddress(ResolvedAddr)) return ec; + section_iterator iter(Obj->begin_sections()); + if (error_code ec = Sym.getSection(iter)) return ec; + ResolvedSection = Obj->getCOFFSection(iter); + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the symbol used for the relocation at the offset. +static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, SymbolRef &Sym) { + for (std::vector<RelocationRef>::const_iterator I = Rels.begin(), + E = Rels.end(); + I != E; ++I) { + uint64_t Ofs; + if (error_code ec = I->getOffset(Ofs)) return ec; + if (Ofs == Offset) { + if (error_code ec = I->getSymbol(Sym)) return ec; + break; + } + } + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function resolves the symbol used for the relocation at the offset and +// returns the section content and the address inside the content pointed to +// by the symbol. +static error_code getSectionContents(const COFFObjectFile *Obj, + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + ArrayRef<uint8_t> &Contents, + uint64_t &Addr) { + SymbolRef Sym; + if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; + const coff_section *Section; + if (error_code ec = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return ec; + if (error_code ec = Obj->getSectionContents(Section, Contents)) return ec; + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the name of the symbol used for the relocation at the +// offset. +static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, + uint64_t Offset, StringRef &Name) { + SymbolRef Sym; + if (error_code ec = resolveSymbol(Rels, Offset, Sym)) return ec; + if (error_code ec = Sym.getName(Name)) return ec; + return object_error::success; +} + +static void printCOFFSymbolAddress(llvm::raw_ostream &Out, + const std::vector<RelocationRef> &Rels, + uint64_t Offset, uint32_t Disp) { + StringRef Sym; + if (error_code ec = resolveSymbolName(Rels, Offset, Sym)) { + error(ec); + return ; + } + Out << Sym; + if (Disp > 0) + Out << format(" + 0x%04x", Disp); +} + +void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { + const coff_file_header *Header; + if (error(Obj->getHeader(Header))) return; + + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + errs() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + const coff_section *Pdata = 0; + + error_code ec; + for (section_iterator SI = Obj->begin_sections(), + SE = Obj->end_sections(); + SI != SE; SI.increment(ec)) { + if (error(ec)) return; + + StringRef Name; + if (error(SI->getName(Name))) continue; + + if (Name != ".pdata") continue; + + Pdata = Obj->getCOFFSection(SI); + std::vector<RelocationRef> Rels; + for (relocation_iterator RI = SI->begin_relocations(), + RE = SI->end_relocations(); + RI != RE; RI.increment(ec)) { + if (error(ec)) break; + Rels.push_back(*RI); + } + + // Sort relocations by address. + std::sort(Rels.begin(), Rels.end(), RelocAddressLess); + + ArrayRef<uint8_t> Contents; + if (error(Obj->getSectionContents(Pdata, Contents))) continue; + if (Contents.empty()) continue; + + ArrayRef<RuntimeFunction> RFs( + reinterpret_cast<const RuntimeFunction *>(Contents.data()), + Contents.size() / sizeof(RuntimeFunction)); + for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { + const uint64_t SectionOffset = std::distance(RFs.begin(), I) + * sizeof(RuntimeFunction); + + outs() << "Function Table:\n"; + + outs() << " Start Address: "; + printCOFFSymbolAddress(outs(), Rels, SectionOffset + + /*offsetof(RuntimeFunction, StartAddress)*/ 0, + I->StartAddress); + outs() << "\n"; + + outs() << " End Address: "; + printCOFFSymbolAddress(outs(), Rels, SectionOffset + + /*offsetof(RuntimeFunction, EndAddress)*/ 4, + I->EndAddress); + outs() << "\n"; + + outs() << " Unwind Info Address: "; + printCOFFSymbolAddress(outs(), Rels, SectionOffset + + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, + I->UnwindInfoOffset); + outs() << "\n"; + + ArrayRef<uint8_t> XContents; + uint64_t UnwindInfoOffset = 0; + if (error(getSectionContents(Obj, Rels, SectionOffset + + /*offsetof(RuntimeFunction, UnwindInfoOffset)*/ 8, + XContents, UnwindInfoOffset))) continue; + if (XContents.empty()) continue; + + UnwindInfoOffset += I->UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) continue; + + const Win64EH::UnwindInfo *UI = + reinterpret_cast<const Win64EH::UnwindInfo *> + (XContents.data() + UnwindInfoOffset); + + // The casts to int are required in order to output the value as number. + // Without the casts the value would be interpreted as char data (which + // results in garbage output). + outs() << " Version: " << static_cast<int>(UI->getVersion()) << "\n"; + outs() << " Flags: " << static_cast<int>(UI->getFlags()); + if (UI->getFlags()) { + if (UI->getFlags() & UNW_ExceptionHandler) + outs() << " UNW_ExceptionHandler"; + if (UI->getFlags() & UNW_TerminateHandler) + outs() << " UNW_TerminateHandler"; + if (UI->getFlags() & UNW_ChainInfo) + outs() << " UNW_ChainInfo"; + } + outs() << "\n"; + outs() << " Size of prolog: " + << static_cast<int>(UI->PrologSize) << "\n"; + outs() << " Number of Codes: " + << static_cast<int>(UI->NumCodes) << "\n"; + // Maybe this should move to output of UOP_SetFPReg? + if (UI->getFrameRegister()) { + outs() << " Frame register: " + << getUnwindRegisterName(UI->getFrameRegister()) + << "\n"; + outs() << " Frame offset: " + << 16 * UI->getFrameOffset() + << "\n"; + } else { + outs() << " No frame pointer used\n"; + } + if (UI->getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + // FIXME: Output exception handler data + } else if (UI->getFlags() & UNW_ChainInfo) { + // FIXME: Output chained unwind info + } + + if (UI->NumCodes) + outs() << " Unwind Codes:\n"; + + printAllUnwindCodes(ArrayRef<UnwindCode>(&UI->UnwindCodes[0], + UI->NumCodes)); + + outs() << "\n\n"; + outs().flush(); + } + } +} diff --git a/tools/llvm-objdump/ELFDump.cpp b/tools/llvm-objdump/ELFDump.cpp new file mode 100644 index 0000000..bd15231 --- /dev/null +++ b/tools/llvm-objdump/ELFDump.cpp @@ -0,0 +1,100 @@ +//===-- ELFDump.cpp - ELF-specific dumper -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the ELF-specific dumper for llvm-objdump. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-objdump.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; + +template<class ELFT> +void printProgramHeaders( + const ELFObjectFile<ELFT> *o) { + typedef ELFObjectFile<ELFT> ELFO; + outs() << "Program Header:\n"; + for (typename ELFO::Elf_Phdr_Iter pi = o->begin_program_headers(), + pe = o->end_program_headers(); + pi != pe; ++pi) { + switch (pi->p_type) { + case ELF::PT_LOAD: + outs() << " LOAD "; + break; + case ELF::PT_GNU_STACK: + outs() << " STACK "; + break; + case ELF::PT_GNU_EH_FRAME: + outs() << "EH_FRAME "; + break; + case ELF::PT_INTERP: + outs() << " INTERP "; + break; + case ELF::PT_DYNAMIC: + outs() << " DYNAMIC "; + break; + case ELF::PT_PHDR: + outs() << " PHDR "; + break; + case ELF::PT_TLS: + outs() << " TLS "; + break; + default: + outs() << " UNKNOWN "; + } + + const char *Fmt = ELFT::Is64Bits ? "0x%016" PRIx64 " " : "0x%08" PRIx64 " "; + + outs() << "off " + << format(Fmt, (uint64_t)pi->p_offset) + << "vaddr " + << format(Fmt, (uint64_t)pi->p_vaddr) + << "paddr " + << format(Fmt, (uint64_t)pi->p_paddr) + << format("align 2**%u\n", CountTrailingZeros_64(pi->p_align)) + << " filesz " + << format(Fmt, (uint64_t)pi->p_filesz) + << "memsz " + << format(Fmt, (uint64_t)pi->p_memsz) + << "flags " + << ((pi->p_flags & ELF::PF_R) ? "r" : "-") + << ((pi->p_flags & ELF::PF_W) ? "w" : "-") + << ((pi->p_flags & ELF::PF_X) ? "x" : "-") + << "\n"; + } + outs() << "\n"; +} + +void llvm::printELFFileHeader(const object::ObjectFile *Obj) { + // Little-endian 32-bit + if (const ELFObjectFile<ELFType<support::little, 4, false> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::little, 4, false> > >(Obj)) + printProgramHeaders(ELFObj); + + // Big-endian 32-bit + if (const ELFObjectFile<ELFType<support::big, 4, false> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::big, 4, false> > >(Obj)) + printProgramHeaders(ELFObj); + + // Little-endian 64-bit + if (const ELFObjectFile<ELFType<support::little, 8, true> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::little, 8, true> > >(Obj)) + printProgramHeaders(ELFObj); + + // Big-endian 64-bit + if (const ELFObjectFile<ELFType<support::big, 8, true> > *ELFObj = + dyn_cast<ELFObjectFile<ELFType<support::big, 8, true> > >(Obj)) + printProgramHeaders(ELFObj); +} diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 1feea42..c324ff1 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -13,11 +13,9 @@ #include "llvm-objdump.h" #include "MCFunction.h" -#include "llvm/Support/MachO.h" -#include "llvm/Object/MachO.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/DebugInfo/DIContext.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" @@ -28,10 +26,12 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/MachO.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" @@ -309,16 +309,10 @@ void llvm::DisassembleInputMachO(StringRef Filename) { raw_ostream &DebugOut = nulls(); #endif - StringRef DebugAbbrevSection, DebugInfoSection, DebugArangesSection, - DebugLineSection, DebugStrSection; OwningPtr<DIContext> diContext; - OwningPtr<MachOObjectFile> DSYMObj; - MachOObject *DbgInfoObj = MachOObj; + ObjectFile *DbgObj = MachOOF.get(); // Try to find debug info and set up the DIContext for it. if (UseDbg) { - ArrayRef<SectionRef> DebugSections = Sections; - std::vector<SectionRef> DSYMSections; - // A separate DSym file path was specified, parse it as a macho file, // get the sections and supply it to the section name parsing machinery. if (!DSYMFile.empty()) { @@ -327,42 +321,11 @@ void llvm::DisassembleInputMachO(StringRef Filename) { errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; return; } - DSYMObj.reset(static_cast<MachOObjectFile*>( - ObjectFile::createMachOObjectFile(Buf.take()))); - const macho::Header &Header = DSYMObj->getObject()->getHeader(); - - std::vector<SymbolRef> Symbols; - SmallVector<uint64_t, 8> FoundFns; - getSectionsAndSymbols(Header, DSYMObj.get(), 0, DSYMSections, Symbols, - FoundFns); - DebugSections = DSYMSections; - DbgInfoObj = DSYMObj.get()->getObject(); - } - - // Find the named debug info sections. - for (unsigned SectIdx = 0; SectIdx != DebugSections.size(); SectIdx++) { - StringRef SectName; - if (!DebugSections[SectIdx].getName(SectName)) { - if (SectName.equals("__DWARF,__debug_abbrev")) - DebugSections[SectIdx].getContents(DebugAbbrevSection); - else if (SectName.equals("__DWARF,__debug_info")) - DebugSections[SectIdx].getContents(DebugInfoSection); - else if (SectName.equals("__DWARF,__debug_aranges")) - DebugSections[SectIdx].getContents(DebugArangesSection); - else if (SectName.equals("__DWARF,__debug_line")) - DebugSections[SectIdx].getContents(DebugLineSection); - else if (SectName.equals("__DWARF,__debug_str")) - DebugSections[SectIdx].getContents(DebugStrSection); - } + DbgObj = ObjectFile::createMachOObjectFile(Buf.take()); } - // Setup the DIContext. - diContext.reset(DIContext::getDWARFContext(DbgInfoObj->isLittleEndian(), - DebugInfoSection, - DebugAbbrevSection, - DebugArangesSection, - DebugLineSection, - DebugStrSection)); + // Setup the DIContext + diContext.reset(DIContext::getDWARFContext(DbgObj)); } FunctionMapTy FunctionMap; @@ -371,9 +334,15 @@ void llvm::DisassembleInputMachO(StringRef Filename) { for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { StringRef SectName; if (Sections[SectIdx].getName(SectName) || - SectName.compare("__TEXT,__text")) + SectName != "__text") continue; // Skip non-text sections + StringRef SegmentName; + DataRefImpl DR = Sections[SectIdx].getRawDataRefImpl(); + if (MachOOF->getSectionFinalSegmentName(DR, SegmentName) || + SegmentName != "__TEXT") + continue; + // Insert the functions from the function starts segment into our map. uint64_t VMAddr; Sections[SectIdx].getAddress(VMAddr); diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 13ea4e3..7832cf0 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -11,17 +11,17 @@ // dumps out a plethora of information about an object file depending on the // flags. // +// The flags and output of this program should be near identical to those of +// binutils objdump. +// //===----------------------------------------------------------------------===// #include "llvm-objdump.h" #include "MCFunction.h" -#include "llvm/Object/Archive.h" -#include "llvm/Object/COFF.h" -#include "llvm/Object/ObjectFile.h" #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -29,6 +29,10 @@ #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -72,9 +76,9 @@ static cl::opt<bool> SymbolTable("t", cl::desc("Display the symbol table")); static cl::opt<bool> -MachO("macho", cl::desc("Use MachO specific object file parser")); +MachOOpt("macho", cl::desc("Use MachO specific object file parser")); static cl::alias -MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachO)); +MachOm("m", cl::desc("Alias for --macho"), cl::aliasopt(MachOOpt)); cl::opt<std::string> llvm::TripleName("triple", cl::desc("Target triple to disassemble for, " @@ -100,9 +104,28 @@ MAttrs("mattr", cl::desc("Target specific attributes"), cl::value_desc("a1,+a2,-a3,...")); +static cl::opt<bool> +NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling instructions, " + "do not print the instruction bytes.")); + +static cl::opt<bool> +UnwindInfo("unwind-info", cl::desc("Display unwind information")); + +static cl::alias +UnwindInfoShort("u", cl::desc("Alias for --unwind-info"), + cl::aliasopt(UnwindInfo)); + +static cl::opt<bool> +PrivateHeaders("private-headers", + cl::desc("Display format specific file headers")); + +static cl::alias +PrivateHeadersShort("p", cl::desc("Alias for --private-headers"), + cl::aliasopt(PrivateHeaders)); + static StringRef ToolName; -static bool error(error_code ec) { +bool llvm::error(error_code ec) { if (!ec) return false; outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; @@ -161,7 +184,7 @@ void llvm::DumpBytes(StringRef bytes) { outs() << output; } -static bool RelocAddressLess(RelocationRef a, RelocationRef b) { +bool llvm::RelocAddressLess(RelocationRef a, RelocationRef b) { uint64_t a_addr, b_addr; if (error(a.getAddress(a_addr))) return false; if (error(b.getAddress(b_addr))) return false; @@ -205,6 +228,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (!error(i->containsSymbol(*si, contains)) && contains) { uint64_t Address; if (error(si->getAddress(Address))) break; + if (Address == UnknownAddressOrSize) continue; Address -= SectionAddr; StringRef Name; @@ -230,9 +254,18 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Sort relocations by address. std::sort(Rels.begin(), Rels.end(), RelocAddressLess); + StringRef SegmentName = ""; + if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(Obj)) { + DataRefImpl DR = i->getRawDataRefImpl(); + if (error(MachO->getSectionFinalSegmentName(DR, SegmentName))) + break; + } StringRef name; if (error(i->getName(name))) break; - outs() << "Disassembly of section " << name << ':'; + outs() << "Disassembly of section "; + if (!SegmentName.empty()) + outs() << SegmentName << ","; + outs() << name << ':'; // If the section has no symbols just insert a dummy one and disassemble // the whole section. @@ -321,8 +354,11 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, DebugOut, nulls())) { - outs() << format("%8" PRIx64 ":\t", SectionAddr + Index); - DumpBytes(StringRef(Bytes.data() + Index, Size)); + outs() << format("%8" PRIx64 ":", SectionAddr + Index); + if (!NoShowRawInsn) { + outs() << "\t"; + DumpBytes(StringRef(Bytes.data() + Index, Size)); + } IP->printInst(&Inst, outs(), ""); outs() << "\n"; } else { @@ -409,7 +445,7 @@ static void PrintSectionHeaders(const ObjectFile *o) { if (error(si->isBSS(BSS))) return; std::string Type = (std::string(Text ? "TEXT " : "") + (Data ? "DATA " : "") + (BSS ? "BSS" : "")); - outs() << format("%3d %-13s %09" PRIx64 " %017" PRIx64 " %s\n", + outs() << format("%3d %-13s %08" PRIx64 " %016" PRIx64 " %s\n", i, Name.str().c_str(), Size, Address, Type.c_str()); ++i; } @@ -446,7 +482,7 @@ static void PrintSectionContents(const ObjectFile *o) { // Print ascii. outs() << " "; for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { - if (std::isprint(Contents[addr + i] & 0xFF)) + if (std::isprint(static_cast<unsigned char>(Contents[addr + i]) & 0xFF)) outs() << Contents[addr + i]; else outs() << "."; @@ -539,7 +575,10 @@ static void PrintSymbolTable(const ObjectFile *o) { else if (Type == SymbolRef::ST_Function) FileFunc = 'F'; - outs() << format("%08" PRIx64, Address) << " " + const char *Fmt = o->getBytesInAddress() > 4 ? "%016" PRIx64 : + "%08" PRIx64; + + outs() << format(Fmt, Address) << " " << GlobLoc // Local -> 'l', Global -> 'g', Neither -> ' ' << (Weak ? 'w' : ' ') // Weak? << ' ' // Constructor. Not supported yet. @@ -553,6 +592,13 @@ static void PrintSymbolTable(const ObjectFile *o) { else if (Section == o->end_sections()) outs() << "*UND*"; else { + if (const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(o)) { + StringRef SegmentName; + DataRefImpl DR = Section->getRawDataRefImpl(); + if (error(MachO->getSectionFinalSegmentName(DR, SegmentName))) + SegmentName = ""; + outs() << SegmentName << ","; + } StringRef SectionName; if (error(Section->getName(SectionName))) SectionName = ""; @@ -566,6 +612,19 @@ static void PrintSymbolTable(const ObjectFile *o) { } } +static void PrintUnwindInfo(const ObjectFile *o) { + outs() << "Unwind info:\n\n"; + + if (const COFFObjectFile *coff = dyn_cast<COFFObjectFile>(o)) { + printCOFFUnwindInfo(coff); + } else { + // TODO: Extract DWARF dump tool to objdump. + errs() << "This operation is only currently supported " + "for COFF object files.\n"; + return; + } +} + static void DumpObject(const ObjectFile *o) { outs() << '\n'; outs() << o->getFileName() @@ -581,6 +640,10 @@ static void DumpObject(const ObjectFile *o) { PrintSectionContents(o); if (SymbolTable) PrintSymbolTable(o); + if (UnwindInfo) + PrintUnwindInfo(o); + if (PrivateHeaders && o->isELF()) + printELFFileHeader(o); } /// @brief Dump each object file in \a a; @@ -611,7 +674,7 @@ static void DumpInput(StringRef file) { return; } - if (MachO && Disassemble) { + if (MachOOpt && Disassemble) { DisassembleInputMachO(file); return; } @@ -659,7 +722,9 @@ int main(int argc, char **argv) { && !Relocations && !SectionHeaders && !SectionContents - && !SymbolTable) { + && !SymbolTable + && !UnwindInfo + && !PrivateHeaders) { cl::PrintHelpMessage(); return 2; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index aa71b77..ca7bced 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -17,12 +17,23 @@ namespace llvm { +namespace object { + class COFFObjectFile; + class ObjectFile; + class RelocationRef; +} +class error_code; + extern cl::opt<std::string> TripleName; extern cl::opt<std::string> ArchName; // Various helper functions. +bool error(error_code ec); +bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void DumpBytes(StringRef bytes); void DisassembleInputMachO(StringRef Filename); +void printCOFFUnwindInfo(const object::COFFObjectFile* o); +void printELFFileHeader(const object::ObjectFile *o); class StringRefMemoryObject : public MemoryObject { virtual void anchor(); diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp index 81e9503..b2c3f06 100644 --- a/tools/llvm-prof/llvm-prof.cpp +++ b/tools/llvm-prof/llvm-prof.cpp @@ -13,23 +13,23 @@ // //===----------------------------------------------------------------------===// -#include "llvm/InstrTypes.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/Assembly/AssemblyAnnotationWriter.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Analysis/Passes.h" #include "llvm/Analysis/ProfileInfo.h" #include "llvm/Analysis/ProfileInfoLoader.h" -#include "llvm/Analysis/Passes.h" +#include "llvm/Assembly/AssemblyAnnotationWriter.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Module.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Format.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> #include <iomanip> diff --git a/tools/llvm-ranlib/llvm-ranlib.cpp b/tools/llvm-ranlib/llvm-ranlib.cpp index d2f5f0f..fe9d3e2 100644 --- a/tools/llvm-ranlib/llvm-ranlib.cpp +++ b/tools/llvm-ranlib/llvm-ranlib.cpp @@ -11,16 +11,16 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Bitcode/Archive.h" +#include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include <memory> using namespace llvm; diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index be80469..3d20def 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -1,5 +1,15 @@ -set(LLVM_LINK_COMPONENTS archive bitreader object) +set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + archive + bitreader + object) add_llvm_tool(llvm-readobj llvm-readobj.cpp + ObjDumper.cpp + COFFDumper.cpp + ELFDumper.cpp + MachODumper.cpp + Error.cpp + StreamWriter.cpp ) diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp new file mode 100644 index 0000000..be4e76c --- /dev/null +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -0,0 +1,1014 @@ +//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the COFF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/Win64EH.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +#include <algorithm> +#include <cstring> +#include <time.h> + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::Win64EH; + +namespace { + +class COFFDumper : public ObjDumper { +public: + COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { + cacheRelocations(); + } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + void printX64UnwindInfo(); + + void printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels); + + void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); + + void cacheRelocations(); + + error_code getSectionContents( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + ArrayRef<uint8_t> &Contents, + uint64_t &Addr); + + error_code getSection( + const std::vector<RelocationRef> &Rels, + uint64_t Offset, + const coff_section **Section, + uint64_t *AddrPtr); + + typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; + + const llvm::object::COFFObjectFile *Obj; + RelocMapTy RelocMap; + std::vector<RelocationRef> EmptyRelocs; +}; + +} // namespace + + +namespace llvm { + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); + if (!COFFObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new COFFDumper(COFFObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +// Returns the name of the unwind code. +static StringRef getUnwindCodeTypeName(uint8_t Code) { + switch(Code) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: return "PUSH_NONVOL"; + case UOP_AllocLarge: return "ALLOC_LARGE"; + case UOP_AllocSmall: return "ALLOC_SMALL"; + case UOP_SetFPReg: return "SET_FPREG"; + case UOP_SaveNonVol: return "SAVE_NONVOL"; + case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; + case UOP_SaveXMM128: return "SAVE_XMM128"; + case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; + case UOP_PushMachFrame: return "PUSH_MACHFRAME"; + } +} + +// Returns the name of a referenced register. +static StringRef getUnwindRegisterName(uint8_t Reg) { + switch(Reg) { + default: llvm_unreachable("Invalid register"); + case 0: return "RAX"; + case 1: return "RCX"; + case 2: return "RDX"; + case 3: return "RBX"; + case 4: return "RSP"; + case 5: return "RBP"; + case 6: return "RSI"; + case 7: return "RDI"; + case 8: return "R8"; + case 9: return "R9"; + case 10: return "R10"; + case 11: return "R11"; + case 12: return "R12"; + case 13: return "R13"; + case 14: return "R14"; + case 15: return "R15"; + } +} + +// Calculates the number of array slots required for the unwind code. +static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { + switch (UnwindCode.getUnwindOp()) { + default: llvm_unreachable("Invalid unwind code"); + case UOP_PushNonVol: + case UOP_AllocSmall: + case UOP_SetFPReg: + case UOP_PushMachFrame: + return 1; + case UOP_SaveNonVol: + case UOP_SaveXMM128: + return 2; + case UOP_SaveNonVolBig: + case UOP_SaveXMM128Big: + return 3; + case UOP_AllocLarge: + return (UnwindCode.getOpInfo() == 0) ? 2 : 3; + } +} + +// Given a symbol sym this functions returns the address and section of it. +static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, + const SymbolRef &Sym, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddr) { + if (error_code EC = Sym.getAddress(ResolvedAddr)) + return EC; + + section_iterator iter(Obj->begin_sections()); + if (error_code EC = Sym.getSection(iter)) + return EC; + + ResolvedSection = Obj->getCOFFSection(iter); + return object_error::success; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the symbol used for the relocation at the offset. +static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, SymbolRef &Sym) { + for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(), + RelE = Rels.end(); + RelI != RelE; ++RelI) { + uint64_t Ofs; + if (error_code EC = RelI->getOffset(Ofs)) + return EC; + + if (Ofs == Offset) { + if (error_code EC = RelI->getSymbol(Sym)) + return EC; + return readobj_error::success; + } + } + + return readobj_error::unknown_symbol; +} + +// Given a vector of relocations for a section and an offset into this section +// the function returns the name of the symbol used for the relocation at the +// offset. +static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, + uint64_t Offset, StringRef &Name) { + SymbolRef Sym; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; + if (error_code EC = Sym.getName(Name)) return EC; + return object_error::success; +} + +static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2) +}; + +static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI ) +}; + +static const EnumEntry<COFF::SectionCharacteristics> +ImageSectionCharacteristics[] = { + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE ) +}; + +static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = { + { "Null" , COFF::IMAGE_SYM_TYPE_NULL }, + { "Void" , COFF::IMAGE_SYM_TYPE_VOID }, + { "Char" , COFF::IMAGE_SYM_TYPE_CHAR }, + { "Short" , COFF::IMAGE_SYM_TYPE_SHORT }, + { "Int" , COFF::IMAGE_SYM_TYPE_INT }, + { "Long" , COFF::IMAGE_SYM_TYPE_LONG }, + { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT }, + { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE }, + { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT }, + { "Union" , COFF::IMAGE_SYM_TYPE_UNION }, + { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM }, + { "MOE" , COFF::IMAGE_SYM_TYPE_MOE }, + { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE }, + { "Word" , COFF::IMAGE_SYM_TYPE_WORD }, + { "UInt" , COFF::IMAGE_SYM_TYPE_UINT }, + { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD } +}; + +static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = { + { "Null" , COFF::IMAGE_SYM_DTYPE_NULL }, + { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER }, + { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION }, + { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY } +}; + +static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = { + { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION }, + { "Null" , COFF::IMAGE_SYM_CLASS_NULL }, + { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC }, + { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL }, + { "Static" , COFF::IMAGE_SYM_CLASS_STATIC }, + { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER }, + { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF }, + { "Label" , COFF::IMAGE_SYM_CLASS_LABEL }, + { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL }, + { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT }, + { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT }, + { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG }, + { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION }, + { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG }, + { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION }, + { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC }, + { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG }, + { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM }, + { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM }, + { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD }, + { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK }, + { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION }, + { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT }, + { "File" , COFF::IMAGE_SYM_CLASS_FILE }, + { "Section" , COFF::IMAGE_SYM_CLASS_SECTION }, + { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL }, + { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN } +}; + +static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = { + { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES }, + { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY }, + { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE }, + { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH }, + { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE }, + { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST }, + { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST } +}; + +static const EnumEntry<COFF::WeakExternalCharacteristics> +WeakExternalCharacteristics[] = { + { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, + { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, + { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } +}; + +static const EnumEntry<unsigned> UnwindFlags[] = { + { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, + { "TerminateHandler", Win64EH::UNW_TerminateHandler }, + { "ChainInfo" , Win64EH::UNW_ChainInfo } +}; + +static const EnumEntry<unsigned> UnwindOpInfo[] = { + { "RAX", 0 }, + { "RCX", 1 }, + { "RDX", 2 }, + { "RBX", 3 }, + { "RSP", 4 }, + { "RBP", 5 }, + { "RSI", 6 }, + { "RDI", 7 }, + { "R8", 8 }, + { "R9", 9 }, + { "R10", 10 }, + { "R11", 11 }, + { "R12", 12 }, + { "R13", 13 }, + { "R14", 14 }, + { "R15", 15 } +}; + +// Some additional COFF structures not defined by llvm::object. +namespace { + struct coff_aux_function_definition { + support::ulittle32_t TagIndex; + support::ulittle32_t TotalSize; + support::ulittle32_t PointerToLineNumber; + support::ulittle32_t PointerToNextFunction; + uint8_t Unused[2]; + }; + + struct coff_aux_weak_external_definition { + support::ulittle32_t TagIndex; + support::ulittle32_t Characteristics; + uint8_t Unused[10]; + }; + + struct coff_aux_file_record { + char FileName[18]; + }; + + struct coff_aux_clr_token { + support::ulittle8_t AuxType; + support::ulittle8_t Reserved; + support::ulittle32_t SymbolTableIndex; + uint8_t Unused[12]; + }; +} // namespace + +static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { + return static_cast<const char*>(UI.getLanguageSpecificData()) + - reinterpret_cast<const char*>(&UI); +} + +static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) { + if (UCs.size() < 3) + return 0; + + return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); +} + +template<typename T> +static error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, const T* &Aux) { + ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); + Aux = reinterpret_cast<const T*>(AuxData.data()); + return readobj_error::success; +} + +static std::string formatSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, uint32_t Disp) { + std::string Buffer; + raw_string_ostream Str(Buffer); + + StringRef Sym; + if (resolveSymbolName(Rels, Offset, Sym)) { + Str << format(" (0x%X)", Offset); + return Str.str(); + } + + Str << Sym; + if (Disp > 0) { + Str << format(" +0x%X (0x%X)", Disp, Offset); + } else { + Str << format(" (0x%X)", Offset); + } + + return Str.str(); +} + +// Given a vector of relocations for a section and an offset into this section +// the function resolves the symbol used for the relocation at the offset and +// returns the section content and the address inside the content pointed to +// by the symbol. +error_code COFFDumper::getSectionContents( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + ArrayRef<uint8_t> &Contents, uint64_t &Addr) { + + SymbolRef Sym; + const coff_section *Section; + + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + if (error_code EC = Obj->getSectionContents(Section, Contents)) + return EC; + + return object_error::success; +} + +error_code COFFDumper::getSection( + const std::vector<RelocationRef> &Rels, uint64_t Offset, + const coff_section **SectionPtr, uint64_t *AddrPtr) { + + SymbolRef Sym; + if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + return EC; + + const coff_section *Section; + uint64_t Addr; + if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + return EC; + + if (SectionPtr) + *SectionPtr = Section; + if (AddrPtr) + *AddrPtr = Addr; + + return object_error::success; +} + +void COFFDumper::cacheRelocations() { + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) + break; + + const coff_section *Section = Obj->getCOFFSection(SecI); + + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) + break; + + RelocMap[Section].push_back(*RelI); + } + + // Sort relocations by address. + std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), + relocAddressLess); + } +} + +void COFFDumper::printFileHeaders() { + const coff_file_header *Header = 0; + if (error(Obj->getHeader(Header))) + return; + + time_t TDS = Header->TimeDateStamp; + char FormattedTime[20] = { }; + strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); + + { + DictScope D(W, "ImageFileHeader"); + W.printEnum ("Machine", Header->Machine, + makeArrayRef(ImageFileMachineType)); + W.printNumber("SectionCount", Header->NumberOfSections); + W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp); + W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable); + W.printNumber("SymbolCount", Header->NumberOfSymbols); + W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader); + W.printFlags ("Characteristics", Header->Characteristics, + makeArrayRef(ImageFileCharacteristics)); + } +} + +void COFFDumper::printSections() { + error_code EC; + + ListScope SectionsD(W, "Sections"); + int SectionNumber = 0; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) + break; + + ++SectionNumber; + const coff_section *Section = Obj->getCOFFSection(SecI); + + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope D(W, "Section"); + W.printNumber("Number", SectionNumber); + W.printBinary("Name", Name, Section->Name); + W.printHex ("VirtualSize", Section->VirtualSize); + W.printHex ("VirtualAddress", Section->VirtualAddress); + W.printNumber("RawDataSize", Section->SizeOfRawData); + W.printHex ("PointerToRawData", Section->PointerToRawData); + W.printHex ("PointerToRelocations", Section->PointerToRelocations); + W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers); + W.printNumber("RelocationCount", Section->NumberOfRelocations); + W.printNumber("LineNumberCount", Section->NumberOfLinenumbers); + W.printFlags ("Characteristics", Section->Characteristics, + makeArrayRef(ImageSectionCharacteristics), + COFF::SectionCharacteristics(0x00F00000)); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +void COFFDumper::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + int SectionNumber = 0; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + ++SectionNumber; + if (error(EC)) + break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void COFFDumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + uint64_t Offset; + uint64_t RelocType; + SmallString<32> RelocName; + SymbolRef Symbol; + StringRef SymbolName; + StringRef Contents; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getType(RelocType))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + if (error(SecI->getContents(Contents))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << "\n"; +} + +void COFFDumper::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +void COFFDumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void COFFDumper::printSymbol(symbol_iterator SymI) { + DictScope D(W, "Symbol"); + + const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); + const coff_section *Section; + if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { + W.startLine() << "Invalid section number: " << EC.message() << "\n"; + W.flush(); + return; + } + + StringRef SymbolName; + if (Obj->getSymbolName(Symbol, SymbolName)) + SymbolName = ""; + + StringRef SectionName; + if (Section && Obj->getSectionName(Section, SectionName)) + SectionName = ""; + + W.printString("Name", SymbolName); + W.printNumber("Value", Symbol->Value); + W.printNumber("Section", SectionName, Symbol->SectionNumber); + W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType)); + W.printEnum ("ComplexType", Symbol->getComplexType(), + makeArrayRef(ImageSymDType)); + W.printEnum ("StorageClass", Symbol->StorageClass, + makeArrayRef(ImageSymClass)); + W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); + + for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { + if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && + Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && + Symbol->SectionNumber > 0) { + const coff_aux_function_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxFunctionDef"); + W.printNumber("TagIndex", Aux->TagIndex); + W.printNumber("TotalSize", Aux->TotalSize); + W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); + W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); + + } else if ( + Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || + (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && + Symbol->SectionNumber == 0 && + Symbol->Value == 0)) { + const coff_aux_weak_external_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + const coff_symbol *Linked; + StringRef LinkedName; + error_code EC; + if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || + (EC = Obj->getSymbolName(Linked, LinkedName))) { + LinkedName = ""; + error(EC); + } + + DictScope AS(W, "AuxWeakExternal"); + W.printNumber("Linked", LinkedName, Aux->TagIndex); + W.printEnum ("Search", Aux->Characteristics, + makeArrayRef(WeakExternalCharacteristics)); + W.printBinary("Unused", Aux->Unused); + + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { + const coff_aux_file_record *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC) { + const coff_aux_section_definition *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxSectionDef"); + W.printNumber("Length", Aux->Length); + W.printNumber("RelocationCount", Aux->NumberOfRelocations); + W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); + W.printHex("Checksum", Aux->CheckSum); + W.printNumber("Number", Aux->Number); + W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); + W.printBinary("Unused", makeArrayRef(Aux->Unused)); + + if (Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT + && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + const coff_section *Assoc; + StringRef AssocName; + error_code EC; + if ((EC = Obj->getSection(Aux->Number, Assoc)) || + (EC = Obj->getSectionName(Assoc, AssocName))) { + AssocName = ""; + error(EC); + } + + W.printNumber("AssocSection", AssocName, Aux->Number); + } + } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { + const coff_aux_clr_token *Aux; + if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) + break; + + DictScope AS(W, "AuxCLRToken"); + W.printNumber("AuxType", Aux->AuxType); + W.printNumber("Reserved", Aux->Reserved); + W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); + W.printBinary("Unused", Aux->Unused); + + } else { + W.startLine() << "<unhandled auxiliary record>\n"; + } + } +} + +void COFFDumper::printUnwindInfo() { + const coff_file_header *Header; + if (error(Obj->getHeader(Header))) + return; + + ListScope D(W, "UnwindInformation"); + if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { + W.startLine() << "Unsupported image machine type " + "(currently only AMD64 is supported).\n"; + return; + } + + printX64UnwindInfo(); +} + +void COFFDumper::printX64UnwindInfo() { + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + if (Name != ".pdata" && !Name.startswith(".pdata$")) + continue; + + const coff_section *PData = Obj->getCOFFSection(SecI); + + ArrayRef<uint8_t> Contents; + if (error(Obj->getSectionContents(PData, Contents)) || + Contents.empty()) + continue; + + ArrayRef<RuntimeFunction> RFs( + reinterpret_cast<const RuntimeFunction *>(Contents.data()), + Contents.size() / sizeof(RuntimeFunction)); + + for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { + const uint64_t OffsetInSection = std::distance(RFs.begin(), I) + * sizeof(RuntimeFunction); + + printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); + } + } +} + +void COFFDumper::printRuntimeFunction( + const RuntimeFunction& RTF, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + + DictScope D(W, "RuntimeFunction"); + W.printString("StartAddress", + formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); + W.printString("EndAddress", + formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); + W.printString("UnwindInfoAddress", + formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); + + const coff_section* XData = 0; + uint64_t UnwindInfoOffset = 0; + if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) + return; + + ArrayRef<uint8_t> XContents; + if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) + return; + + UnwindInfoOffset += RTF.UnwindInfoOffset; + if (UnwindInfoOffset > XContents.size()) + return; + + const Win64EH::UnwindInfo *UI = + reinterpret_cast<const Win64EH::UnwindInfo *>( + XContents.data() + UnwindInfoOffset); + + printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); +} + +void COFFDumper::printUnwindInfo( + const Win64EH::UnwindInfo& UI, + uint64_t OffsetInSection, + const std::vector<RelocationRef> &Rels) { + DictScope D(W, "UnwindInfo"); + W.printNumber("Version", UI.getVersion()); + W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); + W.printNumber("PrologSize", UI.PrologSize); + if (UI.getFrameRegister() != 0) { + W.printEnum("FrameRegister", UI.getFrameRegister(), + makeArrayRef(UnwindOpInfo)); + W.printHex("FrameOffset", UI.getFrameOffset()); + } else { + W.printString("FrameRegister", StringRef("-")); + W.printString("FrameOffset", StringRef("-")); + } + + W.printNumber("UnwindCodeCount", UI.NumCodes); + { + ListScope CodesD(W, "UnwindCodes"); + ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes); + for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { + unsigned UsedSlots = getNumUsedSlots(*I); + if (UsedSlots > UCs.size()) { + errs() << "Corrupt unwind data"; + return; + } + printUnwindCode(UI, ArrayRef<UnwindCode>(I, E)); + I += UsedSlots - 1; + } + } + + uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); + if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { + W.printString("Handler", formatSymbol(Rels, LSDAOffset, + UI.getLanguageSpecificHandlerOffset())); + } else if (UI.getFlags() & UNW_ChainInfo) { + const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); + if (Chained) { + DictScope D(W, "Chained"); + W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, + Chained->StartAddress)); + W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, + Chained->EndAddress)); + W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, + Chained->UnwindInfoOffset)); + } + } +} + +// Prints one unwind code. Because an unwind code can occupy up to 3 slots in +// the unwind codes array, this function requires that the correct number of +// slots is provided. +void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, + ArrayRef<UnwindCode> UCs) { + assert(UCs.size() >= getNumUsedSlots(UCs[0])); + + W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) + << getUnwindCodeTypeName(UCs[0].getUnwindOp()); + + uint32_t AllocSize = 0; + + switch (UCs[0].getUnwindOp()) { + case UOP_PushNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); + break; + + case UOP_AllocLarge: + if (UCs[0].getOpInfo() == 0) { + AllocSize = UCs[1].FrameOffset * 8; + } else { + AllocSize = getLargeSlotValue(UCs); + } + outs() << " size=" << AllocSize; + break; + case UOP_AllocSmall: + outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); + break; + case UOP_SetFPReg: + if (UI.getFrameRegister() == 0) { + outs() << " reg=<invalid>"; + } else { + outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) + << format(", offset=0x%X", UI.getFrameOffset() * 16); + } + break; + case UOP_SaveNonVol: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 8); + break; + case UOP_SaveNonVolBig: + outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_SaveXMM128: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", UCs[1].FrameOffset * 16); + break; + case UOP_SaveXMM128Big: + outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) + << format(", offset=0x%X", getLargeSlotValue(UCs)); + break; + case UOP_PushMachFrame: + outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); + break; + } + + outs() << "\n"; +} diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp new file mode 100644 index 0000000..9e111dd --- /dev/null +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -0,0 +1,800 @@ +//===-- ELFDumper.cpp - ELF-specific dumper ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the ELF-specific dumper for llvm-readobj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; +using namespace llvm::object; +using namespace ELF; + + +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: return #enum; + +namespace { + +template<typename ELFT> +class ELFDumper : public ObjDumper { +public: + ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + + virtual void printDynamicTable() LLVM_OVERRIDE; + virtual void printNeededLibraries() LLVM_OVERRIDE; + +private: + typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + + void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const ELFObjectFile<ELFT> *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + typedef ELFType<support::little, 4, false> Little32ELF; + typedef ELFType<support::big, 4, false> Big32ELF; + typedef ELFType<support::little, 4, true > Little64ELF; + typedef ELFType<support::big, 8, true > Big64ELF; + + typedef ELFObjectFile<Little32ELF> LittleELF32Obj; + typedef ELFObjectFile<Big32ELF > BigELF32Obj; + typedef ELFObjectFile<Little64ELF> LittleELF64Obj; + typedef ELFObjectFile<Big64ELF > BigELF64Obj; + + // Little-endian 32-bit + if (const LittleELF32Obj *ELFObj = dyn_cast<LittleELF32Obj>(Obj)) { + Result.reset(new ELFDumper<Little32ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 32-bit + if (const BigELF32Obj *ELFObj = dyn_cast<BigELF32Obj>(Obj)) { + Result.reset(new ELFDumper<Big32ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Little-endian 64-bit + if (const LittleELF64Obj *ELFObj = dyn_cast<LittleELF64Obj>(Obj)) { + Result.reset(new ELFDumper<Little64ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + // Big-endian 64-bit + if (const BigELF64Obj *ELFObj = dyn_cast<BigELF64Obj>(Obj)) { + Result.reset(new ELFDumper<Big64ELF>(ELFObj, Writer)); + return readobj_error::success; + } + + return readobj_error::unsupported_obj_file_format; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> ElfClass[] = { + { "None", ELF::ELFCLASSNONE }, + { "32-bit", ELF::ELFCLASS32 }, + { "64-bit", ELF::ELFCLASS64 }, +}; + +static const EnumEntry<unsigned> ElfDataEncoding[] = { + { "None", ELF::ELFDATANONE }, + { "LittleEndian", ELF::ELFDATA2LSB }, + { "BigEndian", ELF::ELFDATA2MSB }, +}; + +static const EnumEntry<unsigned> ElfObjectFileType[] = { + { "None", ELF::ET_NONE }, + { "Relocatable", ELF::ET_REL }, + { "Executable", ELF::ET_EXEC }, + { "SharedObject", ELF::ET_DYN }, + { "Core", ELF::ET_CORE }, +}; + +static const EnumEntry<unsigned> ElfOSABI[] = { + { "SystemV", ELF::ELFOSABI_NONE }, + { "HPUX", ELF::ELFOSABI_HPUX }, + { "NetBSD", ELF::ELFOSABI_NETBSD }, + { "GNU/Linux", ELF::ELFOSABI_LINUX }, + { "GNU/Hurd", ELF::ELFOSABI_HURD }, + { "Solaris", ELF::ELFOSABI_SOLARIS }, + { "AIX", ELF::ELFOSABI_AIX }, + { "IRIX", ELF::ELFOSABI_IRIX }, + { "FreeBSD", ELF::ELFOSABI_FREEBSD }, + { "TRU64", ELF::ELFOSABI_TRU64 }, + { "Modesto", ELF::ELFOSABI_MODESTO }, + { "OpenBSD", ELF::ELFOSABI_OPENBSD }, + { "OpenVMS", ELF::ELFOSABI_OPENVMS }, + { "NSK", ELF::ELFOSABI_NSK }, + { "AROS", ELF::ELFOSABI_AROS }, + { "FenixOS", ELF::ELFOSABI_FENIXOS }, + { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI }, + { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX }, + { "ARM", ELF::ELFOSABI_ARM }, + { "Standalone" , ELF::ELFOSABI_STANDALONE } +}; + +static const EnumEntry<unsigned> ElfMachineType[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EM_NONE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_RS3_LE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PARISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VPP500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARC32PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_960 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PPC64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_S390 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V800 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR20 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RH32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RCE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALPHA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SPARCV9 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_300H ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8S ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_H8_500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IA_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS_X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COLDFIRE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC12 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PCP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NCPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDR1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STARCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ME16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST100 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TINYJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_X86_64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP10 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PDP11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FX66 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST9PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC11 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_68HC05 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SVX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST19 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRIS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_JAVELIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FIREPATH ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ZSP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMIX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HUANY ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PRISM ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_FR30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D10V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_D30V ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_V850 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32R ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10300 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MN10200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_PJ ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPENRISC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XTENSA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TMM_GPP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NS32K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TPC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SNP1K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ST200 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IP2K ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_F2MC16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MSP430 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_BLACKFIN ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C33 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SEP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARCA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_UNICORE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_EXCESS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DXP ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ALTERA_NIOS2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XGATE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_C166 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M16C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSPIC30F ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_M32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TSK3000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RS08 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SHARC ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SCORE7 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_DSP24 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE3 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_LATTICEMICO32), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SE_C17 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C6000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C2000 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TI_C5500 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MMDSP_PLUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CYPRESS_M8C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_R32C ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TRIMEDIA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_HEXAGON ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_8051 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STXP7X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_NDS32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG1X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MAXQ30 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_XIMO16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MANIK ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CRAYNV2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_METAG ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MCST_ELBRUS ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ECOG16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CR16 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ETPU ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_SLE9X ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_L10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_K10M ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AARCH64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_AVR32 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MICROBLAZE ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_1ST ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_COREA_2ND ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_ARC_COMPACT2 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_OPEN8 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE ) +}; + +static const EnumEntry<unsigned> ElfSymbolBindings[] = { + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK } +}; + +static const EnumEntry<unsigned> ElfSymbolTypes[] = { + { "None", ELF::STT_NOTYPE }, + { "Object", ELF::STT_OBJECT }, + { "Function", ELF::STT_FUNC }, + { "Section", ELF::STT_SECTION }, + { "File", ELF::STT_FILE }, + { "Common", ELF::STT_COMMON }, + { "TLS", ELF::STT_TLS }, + { "GNU_IFunc", ELF::STT_GNU_IFUNC } +}; + +static const char *getElfSectionType(unsigned Arch, unsigned Type) { + switch (Arch) { + case Triple::arm: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); + } + case Triple::hexagon: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); + } + case Triple::x86_64: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); + } + case Triple::mips: + case Triple::mipsel: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); + } + } + + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NULL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PROGBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_STRTAB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_RELA ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNAMIC ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOTE ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_NOBITS ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_REL ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SHLIB ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_DYNSYM ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_INIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_FINI_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_PREINIT_ARRAY ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GROUP ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_HASH ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verdef ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_verneed ); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_GNU_versym ); + default: return ""; + } +} + +static const EnumEntry<unsigned> ElfSectionFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_INFO_LINK ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_LINK_ORDER ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_OS_NONCONFORMING), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_GROUP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) +}; + + +template<class ELFT> +void ELFDumper<ELFT>::printFileHeaders() { + error_code EC; + typedef ELFObjectFile<ELFT> ELFO; + + const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader(); + + { + DictScope D(W, "ElfHeader"); + { + DictScope D(W, "Ident"); + W.printBinary("Magic", makeArrayRef(Header->e_ident).slice(ELF::EI_MAG0, + 4)); + W.printEnum ("Class", Header->e_ident[ELF::EI_CLASS], + makeArrayRef(ElfClass)); + W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA], + makeArrayRef(ElfDataEncoding)); + W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]); + W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], + makeArrayRef(ElfOSABI)); + W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]); + W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD)); + } + + W.printEnum ("Type", Header->e_type, makeArrayRef(ElfObjectFileType)); + W.printEnum ("Machine", Header->e_machine, makeArrayRef(ElfMachineType)); + W.printNumber("Version", Header->e_version); + W.printHex ("Entry", Header->e_entry); + W.printHex ("ProgramHeaderOffset", Header->e_phoff); + W.printHex ("SectionHeaderOffset", Header->e_shoff); + W.printFlags ("Flags", Header->e_flags); + W.printNumber("HeaderSize", Header->e_ehsize); + W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); + W.printNumber("ProgramHeaderCount", Header->e_phnum); + W.printNumber("SectionHeaderEntrySize", Header->e_shentsize); + W.printNumber("SectionHeaderCount", Header->e_shnum); + W.printNumber("StringTableSectionIndex", Header->e_shstrndx); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSections() { + ListScope SectionsD(W, "Sections"); + + int SectionIndex = -1; + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionIndex; + + const Elf_Shdr *Section = Obj->getElfSection(SecI); + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printNumber("Name", Name, Section->sh_name); + W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type), + Section->sh_type); + W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags)); + W.printHex ("Address", Section->sh_addr); + W.printHex ("Offset", Section->sh_offset); + W.printNumber("Size", Section->sh_size); + W.printNumber("Link", Section->sh_link); + W.printNumber("Info", Section->sh_info); + W.printNumber("AddressAlignment", Section->sh_addralign); + W.printNumber("EntrySize", Section->sh_entsize); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + int SectionNumber = -1; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionNumber; + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printRelocation(section_iterator Sec, + relocation_iterator RelI) { + uint64_t Offset; + SmallString<32> RelocName; + int64_t Info; + StringRef SymbolName; + SymbolRef Symbol; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getAdditionalInfo(Info))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << W.hex(Info) + << "\n"; +} + +template<class ELFT> +void ELFDumper<ELFT>::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_dynamic_symbols(), + SymE = Obj->end_dynamic_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI, true); + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printSymbol(symbol_iterator SymI, bool IsDynamic) { + error_code EC; + + const Elf_Sym *Symbol = Obj->getElfSymbol(SymI); + const Elf_Shdr *Section = Obj->getSection(Symbol); + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + StringRef SectionName; + if (Section && Obj->getSectionName(Section, SectionName)) + SectionName = ""; + + std::string FullSymbolName(SymbolName); + if (IsDynamic) { + StringRef Version; + bool IsDefault; + if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) + return; + if (!Version.empty()) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; + } + } + + DictScope D(W, "Symbol"); + W.printNumber("Name", FullSymbolName, Symbol->st_name); + W.printHex ("Value", Symbol->st_value); + W.printNumber("Size", Symbol->st_size); + W.printEnum ("Binding", Symbol->getBinding(), + makeArrayRef(ElfSymbolBindings)); + W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + W.printNumber("Other", Symbol->st_other); + W.printHex ("Section", SectionName, Symbol->st_shndx); +} + +#define LLVM_READOBJ_TYPE_CASE(name) \ + case DT_##name: return #name + +static const char *getTypeString(uint64_t Type) { + switch (Type) { + LLVM_READOBJ_TYPE_CASE(BIND_NOW); + LLVM_READOBJ_TYPE_CASE(DEBUG); + LLVM_READOBJ_TYPE_CASE(FINI); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAY); + LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(FLAGS); + LLVM_READOBJ_TYPE_CASE(HASH); + LLVM_READOBJ_TYPE_CASE(INIT); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY); + LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ); + LLVM_READOBJ_TYPE_CASE(JMPREL); + LLVM_READOBJ_TYPE_CASE(NEEDED); + LLVM_READOBJ_TYPE_CASE(NULL); + LLVM_READOBJ_TYPE_CASE(PLTGOT); + LLVM_READOBJ_TYPE_CASE(PLTREL); + LLVM_READOBJ_TYPE_CASE(PLTRELSZ); + LLVM_READOBJ_TYPE_CASE(REL); + LLVM_READOBJ_TYPE_CASE(RELA); + LLVM_READOBJ_TYPE_CASE(RELENT); + LLVM_READOBJ_TYPE_CASE(RELSZ); + LLVM_READOBJ_TYPE_CASE(RELAENT); + LLVM_READOBJ_TYPE_CASE(RELASZ); + LLVM_READOBJ_TYPE_CASE(RPATH); + LLVM_READOBJ_TYPE_CASE(RUNPATH); + LLVM_READOBJ_TYPE_CASE(SONAME); + LLVM_READOBJ_TYPE_CASE(STRSZ); + LLVM_READOBJ_TYPE_CASE(STRTAB); + LLVM_READOBJ_TYPE_CASE(SYMBOLIC); + LLVM_READOBJ_TYPE_CASE(SYMENT); + LLVM_READOBJ_TYPE_CASE(SYMTAB); + LLVM_READOBJ_TYPE_CASE(TEXTREL); + default: return "unknown"; + } +} + +#undef LLVM_READOBJ_TYPE_CASE + +template<class ELFT> +static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, + uint64_t Value, bool Is64, raw_ostream &OS) { + switch (Type) { + case DT_PLTREL: + if (Value == DT_REL) { + OS << "REL"; + break; + } else if (Value == DT_RELA) { + OS << "RELA"; + break; + } + // Fallthrough. + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + case DT_DEBUG: + case DT_NULL: + OS << format("0x%" PRIX64, Value); + break; + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_RELSZ: + case DT_RELENT: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_PREINIT_ARRAYSZ: + OS << Value << " (bytes)"; + break; + case DT_NEEDED: + OS << "SharedLibrary (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + case DT_SONAME: + OS << "LibrarySoname (" + << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + break; + } +} + +template<class ELFT> +void ELFDumper<ELFT>::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} + +template<class ELFT> +void ELFDumper<ELFT>::printDynamicTable() { + typedef ELFObjectFile<ELFT> ELFO; + typedef typename ELFO::Elf_Dyn_iterator EDI; + EDI Start = Obj->begin_dynamic_table(), + End = Obj->end_dynamic_table(true); + + if (Start == End) + return; + + ptrdiff_t Total = std::distance(Start, End); + raw_ostream &OS = W.getOStream(); + W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; + + bool Is64 = Obj->getBytesInAddress() == 8; + + W.startLine() + << " Tag" << (Is64 ? " " : " ") << "Type" + << " " << "Name/Value\n"; + for (; Start != End; ++Start) { + W.startLine() + << " " + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) + << " " << format("%-21s", getTypeString(Start->getTag())); + printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + OS << "\n"; + } + + W.startLine() << "]\n"; +} + +static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) { + StringRef LPath, RPath; + L.getPath(LPath); + R.getPath(RPath); + return LPath < RPath; +} + +template<class ELFT> +void ELFDumper<ELFT>::printNeededLibraries() { + ListScope D(W, "NeededLibraries"); + + error_code EC; + + typedef std::vector<LibraryRef> LibsTy; + LibsTy Libs; + + for (library_iterator I = Obj->begin_libraries_needed(), + E = Obj->end_libraries_needed(); + I != E; I.increment(EC)) { + if (EC) + report_fatal_error("Needed libraries iteration failed"); + + Libs.push_back(*I); + } + + std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); + I != E; ++I) { + StringRef Path; + I->getPath(Path); + outs() << " " << Path << "\n"; + } +} diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp new file mode 100644 index 0000000..a6c6132 --- /dev/null +++ b/tools/llvm-readobj/Error.cpp @@ -0,0 +1,62 @@ +//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class _readobj_error_category : public _do_message { +public: + virtual const char* name() const; + virtual std::string message(int ev) const; + virtual error_condition default_error_condition(int ev) const; +}; +} // namespace + +const char *_readobj_error_category::name() const { + return "llvm.readobj"; +} + +std::string _readobj_error_category::message(int ev) const { + switch (ev) { + case readobj_error::success: return "Success"; + case readobj_error::file_not_found: + return "No such file."; + case readobj_error::unsupported_file_format: + return "The file was not recognized as a valid object file."; + case readobj_error::unrecognized_file_format: + return "Unrecognized file type."; + case readobj_error::unsupported_obj_file_format: + return "Unsupported object file format."; + case readobj_error::unknown_symbol: + return "Unknown symbol."; + default: + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); + } +} + +error_condition _readobj_error_category::default_error_condition(int ev) const { + if (ev == readobj_error::success) + return errc::success; + return errc::invalid_argument; +} + +namespace llvm { +const error_category &readobj_category() { + static _readobj_error_category o; + return o; +} +} // namespace llvm diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h new file mode 100644 index 0000000..cf68da8 --- /dev/null +++ b/tools/llvm-readobj/Error.h @@ -0,0 +1,48 @@ +//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the llvm-readobj tool. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ERROR_H +#define LLVM_READOBJ_ERROR_H + +#include "llvm/Support/system_error.h" + +namespace llvm { + +const error_category &readobj_category(); + +struct readobj_error { + enum _ { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol + }; + _ v_; + + readobj_error(_ v) : v_(v) {} + explicit readobj_error(int v) : v_(_(v)) {} + operator int() const {return v_;} +}; + +inline error_code make_error_code(readobj_error e) { + return error_code(static_cast<int>(e), readobj_category()); +} + +template <> struct is_error_code_enum<readobj_error> : true_type { }; +template <> struct is_error_code_enum<readobj_error::_> : true_type { }; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt index c9f934f..813c12b 100644 --- a/tools/llvm-readobj/LLVMBuild.txt +++ b/tools/llvm-readobj/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-readobj parent = Tools -required_libraries = Archive BitReader Object +required_libraries = all-targets Archive BitReader Object diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp new file mode 100644 index 0000000..798c941 --- /dev/null +++ b/tools/llvm-readobj/MachODumper.cpp @@ -0,0 +1,438 @@ +//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the MachO-specific dumper for llvm-readobj. +// +//===----------------------------------------------------------------------===// + +#include "llvm-readobj.h" +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" + +using namespace llvm; +using namespace object; + +namespace { + +class MachODumper : public ObjDumper { +public: + MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer) + : ObjDumper(Writer) + , Obj(Obj) { } + + virtual void printFileHeaders() LLVM_OVERRIDE; + virtual void printSections() LLVM_OVERRIDE; + virtual void printRelocations() LLVM_OVERRIDE; + virtual void printSymbols() LLVM_OVERRIDE; + virtual void printDynamicSymbols() LLVM_OVERRIDE; + virtual void printUnwindInfo() LLVM_OVERRIDE; + +private: + void printSymbol(symbol_iterator SymI); + + void printRelocation(section_iterator SecI, relocation_iterator RelI); + + const llvm::object::MachOObjectFile *Obj; +}; + +} // namespace + + +namespace llvm { + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result) { + const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); + if (!MachOObj) + return readobj_error::unsupported_obj_file_format; + + Result.reset(new MachODumper(MachOObj, Writer)); + return readobj_error::success; +} + +} // namespace llvm + + +static const EnumEntry<unsigned> MachOSectionTypes[] = { + { "Regular" , 0x00 }, + { "ZeroFill" , 0x01 }, + { "CStringLiterals" , 0x02 }, + { "4ByteLiterals" , 0x03 }, + { "8ByteLiterals" , 0x04 }, + { "LiteralPointers" , 0x05 }, + { "NonLazySymbolPointers" , 0x06 }, + { "LazySymbolPointers" , 0x07 }, + { "SymbolStubs" , 0x08 }, + { "ModInitFuncs" , 0x09 }, + { "ModTermFuncs" , 0x0A }, + { "Coalesced" , 0x0B }, + { "GBZeroFill" , 0x0C }, + { "Interposing" , 0x0D }, + { "16ByteLiterals" , 0x0E }, + { "DTraceDOF" , 0x0F }, + { "LazyDylibSymbolPoints" , 0x10 }, + { "ThreadLocalRegular" , 0x11 }, + { "ThreadLocalZerofill" , 0x12 }, + { "ThreadLocalVariables" , 0x13 }, + { "ThreadLocalVariablePointers" , 0x14 }, + { "ThreadLocalInitFunctionPointers", 0x15 } +}; + +static const EnumEntry<unsigned> MachOSectionAttributes[] = { + { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, + { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, + { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, + { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, + { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, + { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, + { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, + { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, + { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, + { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, +}; + +static const EnumEntry<unsigned> MachOSymbolRefTypes[] = { + { "UndefinedNonLazy", 0 }, + { "ReferenceFlagUndefinedLazy", 1 }, + { "ReferenceFlagDefined", 2 }, + { "ReferenceFlagPrivateDefined", 3 }, + { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, + { "ReferenceFlagPrivateUndefinedLazy", 5 } +}; + +static const EnumEntry<unsigned> MachOSymbolFlags[] = { + { "ReferencedDynamically", 0x10 }, + { "NoDeadStrip", 0x20 }, + { "WeakRef", 0x40 }, + { "WeakDef", 0x80 } +}; + +static const EnumEntry<unsigned> MachOSymbolTypes[] = { + { "Undef", 0x0 }, + { "External", 0x1 }, + { "Abs", 0x2 }, + { "Indirect", 0xA }, + { "PreboundUndef", 0xC }, + { "Section", 0xE }, + { "PrivateExternal", 0x10 } +}; + +namespace { + enum { + N_STAB = 0xE0 + }; + + struct MachOSection { + ArrayRef<char> Name; + ArrayRef<char> SegmentName; + uint64_t Address; + uint64_t Size; + uint32_t Offset; + uint32_t Alignment; + uint32_t RelocationTableOffset; + uint32_t NumRelocationTableEntries; + uint32_t Flags; + uint32_t Reserved1; + uint32_t Reserved2; + }; + + struct MachOSymbol { + uint32_t StringIndex; + uint8_t Type; + uint8_t SectionIndex; + uint16_t Flags; + uint64_t Value; + }; +} + +static StringRef parseSegmentOrSectionName(ArrayRef<char> P) { + if (P[15] == 0) + // Null terminated. + return StringRef(P.data()); + // Not null terminated, so this is a 16 char string. + return StringRef(P.data(), 16); +} + +static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (LCI.Command.Type == macho::LCT_Segment64) + return true; + assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); + return false; +} + +static void getSection(const MachOObject *MachOObj, + DataRefImpl DRI, + MachOSection &Section) { + LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); + if (is64BitLoadCommand(MachOObj, DRI)) { + InMemoryStruct<macho::Section64> Sect; + MachOObj->ReadSection64(LCI, DRI.d.b, Sect); + + Section.Name = ArrayRef<char>(Sect->Name); + Section.SegmentName = ArrayRef<char>(Sect->SegmentName); + Section.Address = Sect->Address; + Section.Size = Sect->Size; + Section.Offset = Sect->Offset; + Section.Alignment = Sect->Align; + Section.RelocationTableOffset = Sect->RelocationTableOffset; + Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; + Section.Flags = Sect->Flags; + Section.Reserved1 = Sect->Reserved1; + Section.Reserved2 = Sect->Reserved2; + } else { + InMemoryStruct<macho::Section> Sect; + MachOObj->ReadSection(LCI, DRI.d.b, Sect); + + Section.Name = Sect->Name; + Section.SegmentName = Sect->SegmentName; + Section.Address = Sect->Address; + Section.Size = Sect->Size; + Section.Offset = Sect->Offset; + Section.Alignment = Sect->Align; + Section.RelocationTableOffset = Sect->RelocationTableOffset; + Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; + Section.Flags = Sect->Flags; + Section.Reserved1 = Sect->Reserved1; + Section.Reserved2 = Sect->Reserved2; + } +} + +static void getSymbolTableEntry(const MachOObject *MachO, + DataRefImpl DRI, + InMemoryStruct<macho::SymbolTableEntry> &Res) { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); + MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + MachO->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); +} + +static void getSymbol64TableEntry(const MachOObject *MachO, + DataRefImpl DRI, + InMemoryStruct<macho::Symbol64TableEntry> &Res) { + InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; + LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); + MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); + MachO->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); +} + +static void getSymbol(const MachOObject *MachOObj, + DataRefImpl DRI, + MachOSymbol &Symbol) { + if (MachOObj->is64Bit()) { + InMemoryStruct<macho::Symbol64TableEntry> Entry; + getSymbol64TableEntry(MachOObj, DRI, Entry); + Symbol.StringIndex = Entry->StringIndex; + Symbol.Type = Entry->Type; + Symbol.SectionIndex = Entry->SectionIndex; + Symbol.Flags = Entry->Flags; + Symbol.Value = Entry->Value; + } else { + InMemoryStruct<macho::SymbolTableEntry> Entry; + getSymbolTableEntry(MachOObj, DRI, Entry); + Symbol.StringIndex = Entry->StringIndex; + Symbol.Type = Entry->Type; + Symbol.SectionIndex = Entry->SectionIndex; + Symbol.Flags = Entry->Flags; + Symbol.Value = Entry->Value; + } +} + +void MachODumper::printFileHeaders() { + W.startLine() << "FileHeaders not implemented.\n"; +} + +void MachODumper::printSections() { + ListScope Group(W, "Sections"); + + int SectionIndex = -1; + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + ++SectionIndex; + + const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); + + MachOSection Section; + getSection(MachO, SecI->getRawDataRefImpl(), Section); + StringRef Name; + if (error(SecI->getName(Name))) + Name = ""; + + DictScope SectionD(W, "Section"); + W.printNumber("Index", SectionIndex); + W.printBinary("Name", Name, Section.Name); + W.printBinary("Segment", parseSegmentOrSectionName(Section.SegmentName), + Section.SegmentName); + W.printHex ("Address", Section.Address); + W.printHex ("Size", Section.Size); + W.printNumber("Offset", Section.Offset); + W.printNumber("Alignment", Section.Alignment); + W.printHex ("RelocationOffset", Section.RelocationTableOffset); + W.printNumber("RelocationCount", Section.NumRelocationTableEntries); + W.printEnum ("Type", Section.Flags & 0xFF, + makeArrayRef(MachOSectionAttributes)); + W.printFlags ("Attributes", Section.Flags >> 8, + makeArrayRef(MachOSectionAttributes)); + W.printHex ("Reserved1", Section.Reserved1); + W.printHex ("Reserved2", Section.Reserved2); + + if (opts::SectionRelocations) { + ListScope D(W, "Relocations"); + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + printRelocation(SecI, RelI); + } + } + + if (opts::SectionSymbols) { + ListScope D(W, "Symbols"); + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + bool Contained = false; + if (SecI->containsSymbol(*SymI, Contained) || !Contained) + continue; + + printSymbol(SymI); + } + } + + if (opts::SectionData) { + StringRef Data; + if (error(SecI->getContents(Data))) break; + + W.printBinaryBlock("SectionData", Data); + } + } +} + +void MachODumper::printRelocations() { + ListScope D(W, "Relocations"); + + error_code EC; + for (section_iterator SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; SecI.increment(EC)) { + if (error(EC)) break; + + StringRef Name; + if (error(SecI->getName(Name))) + continue; + + bool PrintedGroup = false; + for (relocation_iterator RelI = SecI->begin_relocations(), + RelE = SecI->end_relocations(); + RelI != RelE; RelI.increment(EC)) { + if (error(EC)) break; + + if (!PrintedGroup) { + W.startLine() << "Section " << Name << " {\n"; + W.indent(); + PrintedGroup = true; + } + + printRelocation(SecI, RelI); + } + + if (PrintedGroup) { + W.unindent(); + W.startLine() << "}\n"; + } + } +} + +void MachODumper::printRelocation(section_iterator SecI, + relocation_iterator RelI) { + uint64_t Offset; + SmallString<32> RelocName; + int64_t Info; + StringRef SymbolName; + SymbolRef Symbol; + if (error(RelI->getOffset(Offset))) return; + if (error(RelI->getTypeName(RelocName))) return; + if (error(RelI->getAdditionalInfo(Info))) return; + if (error(RelI->getSymbol(Symbol))) return; + if (error(Symbol.getName(SymbolName))) return; + + raw_ostream& OS = W.startLine(); + OS << W.hex(Offset) + << " " << RelocName + << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << W.hex(Info) + << "\n"; +} + +void MachODumper::printSymbols() { + ListScope Group(W, "Symbols"); + + error_code EC; + for (symbol_iterator SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; SymI.increment(EC)) { + if (error(EC)) break; + + printSymbol(SymI); + } +} + +void MachODumper::printDynamicSymbols() { + ListScope Group(W, "DynamicSymbols"); +} + +void MachODumper::printSymbol(symbol_iterator SymI) { + error_code EC; + + StringRef SymbolName; + if (SymI->getName(SymbolName)) + SymbolName = ""; + + const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); + + MachOSymbol Symbol; + getSymbol(MachO, SymI->getRawDataRefImpl(), Symbol); + + StringRef SectionName; + section_iterator SecI(Obj->end_sections()); + if (error(SymI->getSection(SecI)) || + error(SecI->getName(SectionName))) + SectionName = ""; + + DictScope D(W, "Symbol"); + W.printNumber("Name", SymbolName, Symbol.StringIndex); + if (Symbol.Type & N_STAB) { + W.printHex ("Type", "SymDebugTable", Symbol.Type); + } else { + W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); + } + W.printHex ("Section", SectionName, Symbol.SectionIndex); + W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), + makeArrayRef(MachOSymbolRefTypes)); + W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), + makeArrayRef(MachOSymbolFlags)); + W.printHex ("Value", Symbol.Value); +} + +void MachODumper::printUnwindInfo() { + W.startLine() << "UnwindInfo not implemented.\n"; +} diff --git a/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile index a7a7de3..1bb7295 100644 --- a/tools/llvm-readobj/Makefile +++ b/tools/llvm-readobj/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-readobj -LINK_COMPONENTS := archive bitreader object +LINK_COMPONENTS := archive bitreader object all-targets # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp new file mode 100644 index 0000000..61f5117 --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.cpp @@ -0,0 +1,33 @@ +//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements ObjDumper. +/// +//===----------------------------------------------------------------------===// + +#include "ObjDumper.h" + +#include "Error.h" +#include "StreamWriter.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +ObjDumper::ObjDumper(StreamWriter& Writer) + : W(Writer) { +} + +ObjDumper::~ObjDumper() { +} + +} // namespace llvm diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h new file mode 100644 index 0000000..8d191cb --- /dev/null +++ b/tools/llvm-readobj/ObjDumper.h @@ -0,0 +1,60 @@ +//===-- ObjDumper.h -------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_OBJDUMPER_H +#define LLVM_READOBJ_OBJDUMPER_H + +namespace llvm { + +namespace object { + class ObjectFile; +} + +class error_code; + +template<typename T> +class OwningPtr; + +class StreamWriter; + +class ObjDumper { +public: + ObjDumper(StreamWriter& Writer); + virtual ~ObjDumper(); + + virtual void printFileHeaders() = 0; + virtual void printSections() = 0; + virtual void printRelocations() = 0; + virtual void printSymbols() = 0; + virtual void printDynamicSymbols() = 0; + virtual void printUnwindInfo() = 0; + + // Only implemented for ELF at this time. + virtual void printDynamicTable() { } + virtual void printNeededLibraries() { } + +protected: + StreamWriter& W; +}; + +error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter& Writer, + OwningPtr<ObjDumper> &Result); + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/StreamWriter.cpp b/tools/llvm-readobj/StreamWriter.cpp new file mode 100644 index 0000000..8718112 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.cpp @@ -0,0 +1,79 @@ +#include "StreamWriter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" +#include <cctype> + +using namespace llvm::support; + +namespace llvm { + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value) { + uint64_t N = Value.Value; + // Zero is a special case. + if (N == 0) + return OS << "0x0"; + + char NumberBuffer[20]; + char *EndPtr = NumberBuffer + sizeof(NumberBuffer); + char *CurPtr = EndPtr; + + while (N) { + uintptr_t X = N % 16; + *--CurPtr = (X < 10 ? '0' + X : 'A' + X - 10); + N /= 16; + } + + OS << "0x"; + return OS.write(CurPtr, EndPtr - CurPtr); +} + +void StreamWriter::printBinaryImpl(StringRef Label, StringRef Str, + ArrayRef<uint8_t> Data, bool Block) { + if (Data.size() > 16) + Block = true; + + if (Block) { + startLine() << Label; + if (Str.size() > 0) + OS << ": " << Str; + OS << " (\n"; + for (size_t addr = 0, end = Data.size(); addr < end; addr += 16) { + startLine() << format(" %04" PRIX64 ": ", uint64_t(addr)); + // Dump line of hex. + for (size_t i = 0; i < 16; ++i) { + if (i != 0 && i % 4 == 0) + OS << ' '; + if (addr + i < end) + OS << hexdigit((Data[addr + i] >> 4) & 0xF, false) + << hexdigit(Data[addr + i] & 0xF, false); + else + OS << " "; + } + // Print ascii. + OS << " |"; + for (std::size_t i = 0; i < 16 && addr + i < end; ++i) { + if (std::isprint(Data[addr + i] & 0xFF)) + OS << Data[addr + i]; + else + OS << "."; + } + OS << "|\n"; + } + + startLine() << ")\n"; + } else { + startLine() << Label << ":"; + if (Str.size() > 0) + OS << " " << Str; + OS << " ("; + for (size_t i = 0; i < Data.size(); ++i) { + if (i > 0) + OS << " "; + + OS << format("%02X", static_cast<int>(Data[i])); + } + OS << ")\n"; + } +} + +} // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h new file mode 100644 index 0000000..129f6e7 --- /dev/null +++ b/tools/llvm-readobj/StreamWriter.h @@ -0,0 +1,282 @@ +//===-- StreamWriter.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_STREAMWRITER_H +#define LLVM_READOBJ_STREAMWRITER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; +using namespace llvm::support; + +namespace llvm { + +template<typename T> +struct EnumEntry { + StringRef Name; + T Value; +}; + +struct HexNumber { + // To avoid sign-extension we have to explicitly cast to the appropriate + // unsigned type. The overloads are here so that every type that is implicitly + // convertible to an integer (including enums and endian helpers) can be used + // without requiring type traits or call-site changes. + HexNumber(int8_t Value) : Value(static_cast<uint8_t >(Value)) { } + HexNumber(int16_t Value) : Value(static_cast<uint16_t>(Value)) { } + HexNumber(int32_t Value) : Value(static_cast<uint32_t>(Value)) { } + HexNumber(int64_t Value) : Value(static_cast<uint64_t>(Value)) { } + HexNumber(uint8_t Value) : Value(Value) { } + HexNumber(uint16_t Value) : Value(Value) { } + HexNumber(uint32_t Value) : Value(Value) { } + HexNumber(uint64_t Value) : Value(Value) { } + uint64_t Value; +}; + +raw_ostream &operator<<(raw_ostream &OS, const HexNumber& Value); + +class StreamWriter { +public: + StreamWriter(raw_ostream &OS) + : OS(OS) + , IndentLevel(0) { + } + + void flush() { + OS.flush(); + } + + void indent(int Levels = 1) { + IndentLevel += Levels; + } + + void unindent(int Levels = 1) { + IndentLevel = std::max(0, IndentLevel - Levels); + } + + void printIndent() { + for (int i = 0; i < IndentLevel; ++i) + OS << " "; + } + + template<typename T> + HexNumber hex(T Value) { + return HexNumber(Value); + } + + template<typename T, typename TEnum> + void printEnum(StringRef Label, T Value, + ArrayRef<EnumEntry<TEnum> > EnumValues) { + StringRef Name; + bool Found = false; + for (size_t i = 0; i < EnumValues.size(); ++i) { + if (EnumValues[i].Value == Value) { + Name = EnumValues[i].Name; + Found = true; + break; + } + } + + if (Found) { + startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n"; + } else { + startLine() << Label << ": " << hex(Value) << "\n"; + } + } + + template<typename T, typename TFlag> + void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag> > Flags, + TFlag EnumMask = TFlag(0)) { + typedef EnumEntry<TFlag> FlagEntry; + typedef SmallVector<FlagEntry, 10> FlagVector; + FlagVector SetFlags; + + for (typename ArrayRef<FlagEntry>::const_iterator I = Flags.begin(), + E = Flags.end(); I != E; ++I) { + if (I->Value == 0) + continue; + + bool IsEnum = (I->Value & EnumMask) != 0; + if ((!IsEnum && (Value & I->Value) == I->Value) || + (IsEnum && (Value & EnumMask) == I->Value)) { + SetFlags.push_back(*I); + } + } + + std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>); + + startLine() << Label << " [ (" << hex(Value) << ")\n"; + for (typename FlagVector::const_iterator I = SetFlags.begin(), + E = SetFlags.end(); + I != E; ++I) { + startLine() << " " << I->Name << " (" << hex(I->Value) << ")\n"; + } + startLine() << "]\n"; + } + + template<typename T> + void printFlags(StringRef Label, T Value) { + startLine() << Label << " [ (" << hex(Value) << ")\n"; + uint64_t Flag = 1; + uint64_t Curr = Value; + while (Curr > 0) { + if (Curr & 1) + startLine() << " " << hex(Flag) << "\n"; + Curr >>= 1; + Flag <<= 1; + } + startLine() << "]\n"; + } + + void printNumber(StringRef Label, uint64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, uint8_t Value) { + startLine() << Label << ": " << unsigned(Value) << "\n"; + } + + void printNumber(StringRef Label, int64_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int32_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int16_t Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printNumber(StringRef Label, int8_t Value) { + startLine() << Label << ": " << int(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, T Value) { + startLine() << Label << ": " << hex(Value) << "\n"; + } + + template<typename T> + void printHex(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n"; + } + + void printString(StringRef Label, StringRef Value) { + startLine() << Label << ": " << Value << "\n"; + } + + void printString(StringRef Label, const std::string &Value) { + startLine() << Label << ": " << Value << "\n"; + } + + template<typename T> + void printNumber(StringRef Label, StringRef Str, T Value) { + startLine() << Label << ": " << Str << " (" << Value << ")\n"; + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, Str, Value, false); + } + + void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, Str, V, false); + } + + void printBinary(StringRef Label, ArrayRef<uint8_t> Value) { + printBinaryImpl(Label, StringRef(), Value, false); + } + + void printBinary(StringRef Label, ArrayRef<char> Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinary(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, false); + } + + void printBinaryBlock(StringRef Label, StringRef Value) { + ArrayRef<uint8_t> V(reinterpret_cast<const uint8_t*>(Value.data()), + Value.size()); + printBinaryImpl(Label, StringRef(), V, true); + } + + raw_ostream& startLine() { + printIndent(); + return OS; + } + + raw_ostream& getOStream() { + return OS; + } + +private: + template<typename T> + static bool flagName(const EnumEntry<T>& lhs, const EnumEntry<T>& rhs) { + return lhs.Name < rhs.Name; + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value, + bool Block); + + raw_ostream &OS; + int IndentLevel; +}; + +struct DictScope { + DictScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " {\n"; + W.indent(); + } + + ~DictScope() { + W.unindent(); + W.startLine() << "}\n"; + } + + StreamWriter& W; +}; + +struct ListScope { + ListScope(StreamWriter& W, StringRef N) : W(W) { + W.startLine() << N << " [\n"; + W.indent(); + } + + ~ListScope() { + W.unindent(); + W.startLine() << "]\n"; + } + + StreamWriter& W; +}; + +} // namespace llvm + +#endif diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 3be1289..67c9a98 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -7,212 +7,277 @@ // //===----------------------------------------------------------------------===// // -// This program is a utility that works like traditional Unix "readelf", -// except that it can handle any type of object file recognized by lib/Object. +// This is a tool similar to readelf, except it works on multiple object file +// formats. The main purpose of this tool is to provide detailed output suitable +// for FileCheck. // -// It makes use of the generic ObjectFile interface. +// Flags should be similar to readelf where supported, but the output format +// does not need to be identical. The point is to not make users learn yet +// another set of flags. // -// Caution: This utility is new, experimental, unsupported, and incomplete. +// Output should be specialized for each format where appropriate. // //===----------------------------------------------------------------------===// +#include "llvm-readobj.h" + +#include "Error.h" +#include "ObjDumper.h" +#include "StreamWriter.h" + +#include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Object/ELF.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/Format.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/system_error.h" + +#include <string> + using namespace llvm; using namespace llvm::object; -static cl::opt<std::string> -InputFilename(cl::Positional, cl::desc("<input object>"), cl::init("")); +namespace opts { + cl::list<std::string> InputFilenames(cl::Positional, + cl::desc("<input object files>"), + cl::ZeroOrMore); -void DumpSymbolHeader() { - outs() << format(" %-32s", (const char*)"Name") - << format(" %-4s", (const char*)"Type") - << format(" %-16s", (const char*)"Address") - << format(" %-16s", (const char*)"Size") - << format(" %-16s", (const char*)"FileOffset") - << format(" %-26s", (const char*)"Flags") - << "\n"; + // -file-headers, -h + cl::opt<bool> FileHeaders("file-headers", + cl::desc("Display file headers ")); + cl::alias FileHeadersShort("h", + cl::desc("Alias for --file-headers"), + cl::aliasopt(FileHeaders)); + + // -sections, -s + cl::opt<bool> Sections("sections", + cl::desc("Display all sections.")); + cl::alias SectionsShort("s", + cl::desc("Alias for --sections"), + cl::aliasopt(Sections)); + + // -section-relocations, -sr + cl::opt<bool> SectionRelocations("section-relocations", + cl::desc("Display relocations for each section shown.")); + cl::alias SectionRelocationsShort("sr", + cl::desc("Alias for --section-relocations"), + cl::aliasopt(SectionRelocations)); + + // -section-symbols, -st + cl::opt<bool> SectionSymbols("section-symbols", + cl::desc("Display symbols for each section shown.")); + cl::alias SectionSymbolsShort("st", + cl::desc("Alias for --section-symbols"), + cl::aliasopt(SectionSymbols)); + + // -section-data, -sd + cl::opt<bool> SectionData("section-data", + cl::desc("Display section data for each section shown.")); + cl::alias SectionDataShort("sd", + cl::desc("Alias for --section-data"), + cl::aliasopt(SectionData)); + + // -relocations, -r + cl::opt<bool> Relocations("relocations", + cl::desc("Display the relocation entries in the file")); + cl::alias RelocationsShort("r", + cl::desc("Alias for --relocations"), + cl::aliasopt(Relocations)); + + // -symbols, -t + cl::opt<bool> Symbols("symbols", + cl::desc("Display the symbol table")); + cl::alias SymbolsShort("t", + cl::desc("Alias for --symbols"), + cl::aliasopt(Symbols)); + + // -dyn-symbols, -dt + cl::opt<bool> DynamicSymbols("dyn-symbols", + cl::desc("Display the dynamic symbol table")); + cl::alias DynamicSymbolsShort("dt", + cl::desc("Alias for --dyn-symbols"), + cl::aliasopt(DynamicSymbols)); + + // -unwind, -u + cl::opt<bool> UnwindInfo("unwind", + cl::desc("Display unwind information")); + cl::alias UnwindInfoShort("u", + cl::desc("Alias for --unwind"), + cl::aliasopt(UnwindInfo)); + + // -dynamic-table + cl::opt<bool> DynamicTable("dynamic-table", + cl::desc("Display the ELF .dynamic section table")); + + // -needed-libs + cl::opt<bool> NeededLibraries("needed-libs", + cl::desc("Display the needed libraries")); +} // namespace opts + +namespace llvm { + +bool error(error_code EC) { + if (!EC) + return false; + + outs() << "\nError reading file: " << EC.message() << ".\n"; + outs().flush(); + return true; } -const char *GetTypeStr(SymbolRef::Type Type) { - switch (Type) { - case SymbolRef::ST_Unknown: return "?"; - case SymbolRef::ST_Data: return "DATA"; - case SymbolRef::ST_Debug: return "DBG"; - case SymbolRef::ST_File: return "FILE"; - case SymbolRef::ST_Function: return "FUNC"; - case SymbolRef::ST_Other: return "-"; - } - return "INV"; +bool relocAddressLess(RelocationRef a, RelocationRef b) { + uint64_t a_addr, b_addr; + if (error(a.getAddress(a_addr))) return false; + if (error(b.getAddress(b_addr))) return false; + return a_addr < b_addr; } -std::string GetFlagStr(uint32_t Flags) { - std::string result; - if (Flags & SymbolRef::SF_Undefined) - result += "undef,"; - if (Flags & SymbolRef::SF_Global) - result += "global,"; - if (Flags & SymbolRef::SF_Weak) - result += "weak,"; - if (Flags & SymbolRef::SF_Absolute) - result += "absolute,"; - if (Flags & SymbolRef::SF_ThreadLocal) - result += "threadlocal,"; - if (Flags & SymbolRef::SF_Common) - result += "common,"; - if (Flags & SymbolRef::SF_FormatSpecific) - result += "formatspecific,"; - - // Remove trailing comma - if (result.size() > 0) { - result.erase(result.size() - 1); - } - return result; +} // namespace llvm + + +static void reportError(StringRef Input, error_code EC) { + if (Input == "-") + Input = "<stdin>"; + + errs() << Input << ": " << EC.message() << "\n"; + errs().flush(); } -void DumpSymbol(const SymbolRef &Sym, const ObjectFile *obj, bool IsDynamic) { - StringRef Name; - SymbolRef::Type Type; - uint32_t Flags; - uint64_t Address; - uint64_t Size; - uint64_t FileOffset; - Sym.getName(Name); - Sym.getAddress(Address); - Sym.getSize(Size); - Sym.getFileOffset(FileOffset); - Sym.getType(Type); - Sym.getFlags(Flags); - std::string FullName = Name; - - // If this is a dynamic symbol from an ELF object, append - // the symbol's version to the name. - if (IsDynamic && obj->isELF()) { - StringRef Version; - bool IsDefault; - GetELFSymbolVersion(obj, Sym, Version, IsDefault); - if (!Version.empty()) { - FullName += (IsDefault ? "@@" : "@"); - FullName += Version; - } - } +static void reportError(StringRef Input, StringRef Message) { + if (Input == "-") + Input = "<stdin>"; - // format() can't handle StringRefs - outs() << format(" %-32s", FullName.c_str()) - << format(" %-4s", GetTypeStr(Type)) - << format(" %16" PRIx64, Address) - << format(" %16" PRIx64, Size) - << format(" %16" PRIx64, FileOffset) - << " " << GetFlagStr(Flags) - << "\n"; + errs() << Input << ": " << Message << "\n"; } +/// @brief Creates an format-specific object file dumper. +static error_code createDumper(const ObjectFile *Obj, + StreamWriter &Writer, + OwningPtr<ObjDumper> &Result) { + if (!Obj) + return readobj_error::unsupported_file_format; -// Iterate through the normal symbols in the ObjectFile -void DumpSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Symbols:\n"; - symbol_iterator it = obj->begin_symbols(); - symbol_iterator ie = obj->end_symbols(); - while (it != ie) { - DumpSymbol(*it, obj, false); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; - } - outs() << " Total: " << count << "\n\n"; + if (Obj->isCOFF()) + return createCOFFDumper(Obj, Writer, Result); + if (Obj->isELF()) + return createELFDumper(Obj, Writer, Result); + if (Obj->isMachO()) + return createMachODumper(Obj, Writer, Result); + + return readobj_error::unsupported_obj_file_format; } -// Iterate through the dynamic symbols in the ObjectFile. -void DumpDynamicSymbols(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - outs() << "Dynamic Symbols:\n"; - symbol_iterator it = obj->begin_dynamic_symbols(); - symbol_iterator ie = obj->end_dynamic_symbols(); - while (it != ie) { - DumpSymbol(*it, obj, true); - it.increment(ec); - if (ec) - report_fatal_error("Symbol iteration failed"); - ++count; + +/// @brief Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj) { + StreamWriter Writer(outs()); + OwningPtr<ObjDumper> Dumper; + if (error_code EC = createDumper(Obj, Writer, Dumper)) { + reportError(Obj->getFileName(), EC); + return; } - outs() << " Total: " << count << "\n\n"; -} -void DumpLibrary(const LibraryRef &lib) { - StringRef path; - lib.getPath(path); - outs() << " " << path << "\n"; + outs() << '\n'; + outs() << "File: " << Obj->getFileName() << "\n"; + outs() << "Format: " << Obj->getFileFormatName() << "\n"; + outs() << "Arch: " + << Triple::getArchTypeName((llvm::Triple::ArchType)Obj->getArch()) + << "\n"; + outs() << "AddressSize: " << (8*Obj->getBytesInAddress()) << "bit\n"; + if (Obj->isELF()) + outs() << "LoadName: " << Obj->getLoadName() << "\n"; + + if (opts::FileHeaders) + Dumper->printFileHeaders(); + if (opts::Sections) + Dumper->printSections(); + if (opts::Relocations) + Dumper->printRelocations(); + if (opts::Symbols) + Dumper->printSymbols(); + if (opts::DynamicSymbols) + Dumper->printDynamicSymbols(); + if (opts::UnwindInfo) + Dumper->printUnwindInfo(); + if (opts::DynamicTable) + Dumper->printDynamicTable(); + if (opts::NeededLibraries) + Dumper->printNeededLibraries(); } -// Iterate through needed libraries -void DumpLibrariesNeeded(const ObjectFile *obj) { - error_code ec; - uint32_t count = 0; - library_iterator it = obj->begin_libraries_needed(); - library_iterator ie = obj->end_libraries_needed(); - outs() << "Libraries needed:\n"; - while (it != ie) { - DumpLibrary(*it); - it.increment(ec); - if (ec) - report_fatal_error("Needed libraries iteration failed"); - ++count; + +/// @brief Dumps each object file in \a Arc; +static void dumpArchive(const Archive *Arc) { + for (Archive::child_iterator ArcI = Arc->begin_children(), + ArcE = Arc->end_children(); + ArcI != ArcE; ++ArcI) { + OwningPtr<Binary> child; + if (error_code EC = ArcI->getAsBinary(child)) { + // Ignore non-object files. + if (EC != object_error::invalid_file_type) + reportError(Arc->getFileName(), EC.message()); + continue; + } + + if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get())) + dumpObject(Obj); + else + reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } - outs() << " Total: " << count << "\n\n"; } -void DumpHeaders(const ObjectFile *obj) { - outs() << "File Format : " << obj->getFileFormatName() << "\n"; - outs() << "Arch : " - << Triple::getArchTypeName((llvm::Triple::ArchType)obj->getArch()) - << "\n"; - outs() << "Address Size: " << (8*obj->getBytesInAddress()) << " bits\n"; - outs() << "Load Name : " << obj->getLoadName() << "\n"; - outs() << "\n"; + +/// @brief Opens \a File and dumps it. +static void dumpInput(StringRef File) { + // If file isn't stdin, check that it exists. + if (File != "-" && !sys::fs::exists(File)) { + reportError(File, readobj_error::file_not_found); + return; + } + + // Attempt to open the binary. + OwningPtr<Binary> Binary; + if (error_code EC = createBinary(File, Binary)) { + reportError(File, EC); + return; + } + + if (Archive *Arc = dyn_cast<Archive>(Binary.get())) + dumpArchive(Arc); + else if (ObjectFile *Obj = dyn_cast<ObjectFile>(Binary.get())) + dumpObject(Obj); + else + reportError(File, readobj_error::unrecognized_file_format); } -int main(int argc, char** argv) { - error_code ec; + +int main(int argc, const char *argv[]) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; - cl::ParseCommandLineOptions(argc, argv, - "LLVM Object Reader\n"); + // Initialize targets. + llvm::InitializeAllTargetInfos(); - if (InputFilename.empty()) { - errs() << "Please specify an input filename\n"; - return 1; - } + // Register the target printer for --version. + cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); - // Open the object file - OwningPtr<MemoryBuffer> File; - if (MemoryBuffer::getFile(InputFilename, File)) { - errs() << InputFilename << ": Open failed\n"; - return 1; - } + cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); - ObjectFile *obj = ObjectFile::createObjectFile(File.take()); - if (!obj) { - errs() << InputFilename << ": Object type not recognized\n"; - } + // Default to stdin if no filename is specified. + if (opts::InputFilenames.size() == 0) + opts::InputFilenames.push_back("-"); + + std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), + dumpInput); - DumpHeaders(obj); - DumpSymbols(obj); - DumpDynamicSymbols(obj); - DumpLibrariesNeeded(obj); return 0; } - diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h new file mode 100644 index 0000000..be18268 --- /dev/null +++ b/tools/llvm-readobj/llvm-readobj.h @@ -0,0 +1,45 @@ +//===-- llvm-readobj.h ----------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_READ_OBJ_H +#define LLVM_TOOLS_READ_OBJ_H + +#include "llvm/Support/CommandLine.h" +#include <string> + +namespace llvm { + namespace object { + class RelocationRef; + } + + class error_code; + + // Various helper functions. + bool error(error_code ec); + bool relocAddressLess(object::RelocationRef A, + object::RelocationRef B); +} // namespace llvm + +namespace opts { + extern llvm::cl::list<std::string> InputFilenames; + extern llvm::cl::opt<bool> FileHeaders; + extern llvm::cl::opt<bool> Sections; + extern llvm::cl::opt<bool> SectionRelocations; + extern llvm::cl::opt<bool> SectionSymbols; + extern llvm::cl::opt<bool> SectionData; + extern llvm::cl::opt<bool> Relocations; + extern llvm::cl::opt<bool> Symbols; + extern llvm::cl::opt<bool> DynamicSymbols; + extern llvm::cl::opt<bool> UnwindInfo; +} // namespace opts + +#define LLVM_READOBJ_ENUM_ENT(ns, enum) \ + { #enum, ns::enum } + +#endif diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt index 17e2c3e..8d161d3 100644 --- a/tools/llvm-rtdyld/CMakeLists.txt +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} support MC object RuntimeDyld JIT debuginfo) add_llvm_tool(llvm-rtdyld llvm-rtdyld.cpp diff --git a/tools/llvm-rtdyld/Makefile b/tools/llvm-rtdyld/Makefile index 30fbee0..fabdd68 100644 --- a/tools/llvm-rtdyld/Makefile +++ b/tools/llvm-rtdyld/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-rtdyld -LINK_COMPONENTS := all-targets support MC object RuntimeDyld JIT +LINK_COMPONENTS := all-targets support MC object RuntimeDyld JIT debuginfo # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 7b5bd03..4d8d345 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -11,11 +11,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ExecutionEngine/RuntimeDyld.h" -#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/DebugInfo/DIContext.h" #include "llvm/ExecutionEngine/ObjectBuffer.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/Object/MachOObject.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ManagedStatic.h" @@ -31,7 +32,8 @@ InputFileList(cl::Positional, cl::ZeroOrMore, cl::desc("<input file>")); enum ActionType { - AC_Execute + AC_Execute, + AC_PrintLineInfo }; static cl::opt<ActionType> @@ -39,6 +41,8 @@ Action(cl::desc("Action to perform:"), cl::init(AC_Execute), cl::values(clEnumValN(AC_Execute, "execute", "Load, link, and execute the inputs."), + clEnumValN(AC_PrintLineInfo, "printline", + "Load, link, and print line information for each function."), clEnumValEnd)); static cl::opt<std::string> @@ -58,13 +62,15 @@ public: uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID); uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); + unsigned SectionID, bool IsReadOnly); virtual void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true) { return 0; } + bool applyPermissions(std::string *ErrMsg) { return false; } + // Invalidate instruction cache for sections with execute permissions. // Some platforms with separate data cache and instruction cache require // explicit cache flush, otherwise JIT code manipulations (like resolved @@ -82,7 +88,8 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID) { + unsigned SectionID, + bool IsReadOnly) { sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); DataMemory.push_back(MB); return (uint8_t*)MB.base(); @@ -111,6 +118,66 @@ static int Error(const Twine &Msg) { /* *** */ +static int printLineInfoForInput() { + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Instantiate a dynamic linker. + TrivialMemoryManager *MemMgr = new TrivialMemoryManager; + RuntimeDyld Dyld(MemMgr); + + // Load the input memory buffer. + OwningPtr<MemoryBuffer> InputBuffer; + OwningPtr<ObjectImage> LoadedObject; + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], + InputBuffer)) + return Error("unable to read input: '" + ec.message() + "'"); + + // Load the object file + LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.take()))); + if (!LoadedObject) { + return Error(Dyld.getErrorString()); + } + + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + OwningPtr<DIContext> Context(DIContext::getDWARFContext(LoadedObject->getObjectFile())); + + // Use symbol info to iterate functions in the object. + error_code ec; + for (object::symbol_iterator I = LoadedObject->begin_symbols(), + E = LoadedObject->end_symbols(); + I != E && !ec; + I.increment(ec)) { + object::SymbolRef::Type SymType; + if (I->getType(SymType)) continue; + if (SymType == object::SymbolRef::ST_Function) { + StringRef Name; + uint64_t Addr; + uint64_t Size; + if (I->getName(Name)) continue; + if (I->getAddress(Addr)) continue; + if (I->getSize(Size)) continue; + + outs() << "Function: " << Name << ", Size = " << Size << "\n"; + + DILineInfoTable Lines = Context->getLineInfoForAddressRange(Addr, Size); + DILineInfoTable::iterator Begin = Lines.begin(); + DILineInfoTable::iterator End = Lines.end(); + for (DILineInfoTable::iterator It = Begin; It != End; ++It) { + outs() << " Line info @ " << It->first - Addr << ": " + << It->second.getFileName() + << ", line:" << It->second.getLine() << "\n"; + } + } + } + } + + return 0; +} + static int executeInput() { // Instantiate a dynamic linker. TrivialMemoryManager *MemMgr = new TrivialMemoryManager; @@ -177,5 +244,7 @@ int main(int argc, char **argv) { switch (Action) { case AC_Execute: return executeInput(); + case AC_PrintLineInfo: + return printLineInfoForInput(); } } diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index 462da40..3de6605 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -23,8 +23,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> #include <string> diff --git a/tools/llvm-stress/Makefile b/tools/llvm-stress/Makefile index 90d57c3..8767cbe 100644 --- a/tools/llvm-stress/Makefile +++ b/tools/llvm-stress/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. TOOLNAME := llvm-stress LINK_COMPONENTS := object -LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts ipo # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS = 1 diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index 8473d94..fbda1b7 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -11,25 +11,25 @@ // different components in LLVM. // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/Constants.h" -#include "llvm/Instruction.h" -#include "llvm/CallGraphSCCPass.h" -#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/Verifier.h" -#include "llvm/Support/PassNameParser.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Module.h" +#include "llvm/PassManager.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/ToolOutputFile.h" -#include <memory> -#include <sstream> +#include <algorithm> #include <set> +#include <sstream> #include <vector> -#include <algorithm> using namespace llvm; static cl::opt<unsigned> SeedCL("seed", @@ -379,9 +379,7 @@ struct ConstModifier: public Modifier { RandomBits[i] = Ran->Rand64(); APInt RandomInt(Ty->getPrimitiveSizeInBits(), makeArrayRef(RandomBits)); - - bool isIEEE = !Ty->isX86_FP80Ty() && !Ty->isPPC_FP128Ty(); - APFloat RandomFloat(RandomInt, isIEEE); + APFloat RandomFloat(Ty->getFltSemantics(), RandomInt); if (Ran->Rand() & 1) return PT->push_back(ConstantFP::getNullValue(Ty)); @@ -624,15 +622,15 @@ void FillFunction(Function *F, Random &R) { // List of modifiers which add new random instructions. std::vector<Modifier*> Modifiers; - std::auto_ptr<Modifier> LM(new LoadModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> SM(new StoreModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> EE(new ExtractElementModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> SHM(new ShuffModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> IE(new InsertElementModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> BM(new BinModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> CM(new CastModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> SLM(new SelectModifier(BB, &PT, &R)); - std::auto_ptr<Modifier> PM(new CmpModifier(BB, &PT, &R)); + OwningPtr<Modifier> LM(new LoadModifier(BB, &PT, &R)); + OwningPtr<Modifier> SM(new StoreModifier(BB, &PT, &R)); + OwningPtr<Modifier> EE(new ExtractElementModifier(BB, &PT, &R)); + OwningPtr<Modifier> SHM(new ShuffModifier(BB, &PT, &R)); + OwningPtr<Modifier> IE(new InsertElementModifier(BB, &PT, &R)); + OwningPtr<Modifier> BM(new BinModifier(BB, &PT, &R)); + OwningPtr<Modifier> CM(new CastModifier(BB, &PT, &R)); + OwningPtr<Modifier> SLM(new SelectModifier(BB, &PT, &R)); + OwningPtr<Modifier> PM(new CmpModifier(BB, &PT, &R)); Modifiers.push_back(LM.get()); Modifiers.push_back(SM.get()); Modifiers.push_back(EE.get()); @@ -686,7 +684,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm codegen stress-tester\n"); llvm_shutdown_obj Y; - std::auto_ptr<Module> M(new Module("/tmp/autogen.bc", getGlobalContext())); + OwningPtr<Module> M(new Module("/tmp/autogen.bc", getGlobalContext())); Function *F = GenEmptyFunction(M.get()); // Pick an initial seed value diff --git a/tools/llvm-symbolizer/CMakeLists.txt b/tools/llvm-symbolizer/CMakeLists.txt new file mode 100644 index 0000000..5967b89 --- /dev/null +++ b/tools/llvm-symbolizer/CMakeLists.txt @@ -0,0 +1,14 @@ +# FIXME: As we plan to execute llvm-symbolizer binary from compiler-rt +# libraries, it has to be compiled for all supported targets (x86_64, i386 etc). +# This means that we need LLVM libraries to be compiled for these +# targets as well. Currently, there is no support for such a build strategy. + +set(LLVM_LINK_COMPONENTS + DebugInfo + Object + ) + +add_llvm_tool(llvm-symbolizer + LLVMSymbolize.cpp + llvm-symbolizer.cpp + ) diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp new file mode 100644 index 0000000..29d91a0 --- /dev/null +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -0,0 +1,292 @@ +//===-- LLVMSymbolize.cpp -------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation for LLVM symbolization library. +// +//===----------------------------------------------------------------------===// + +#include "LLVMSymbolize.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Object/MachO.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Path.h" + +#include <sstream> + +namespace llvm { +namespace symbolize { + +static bool error(error_code ec) { + if (!ec) + return false; + errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; + return true; +} + +static uint32_t +getDILineInfoSpecifierFlags(const LLVMSymbolizer::Options &Opts) { + uint32_t Flags = llvm::DILineInfoSpecifier::FileLineInfo | + llvm::DILineInfoSpecifier::AbsoluteFilePath; + if (Opts.PrintFunctions) + Flags |= llvm::DILineInfoSpecifier::FunctionName; + return Flags; +} + +static void patchFunctionNameInDILineInfo(const std::string &NewFunctionName, + DILineInfo &LineInfo) { + std::string FileName = LineInfo.getFileName(); + LineInfo = DILineInfo(StringRef(FileName), StringRef(NewFunctionName), + LineInfo.getLine(), LineInfo.getColumn()); +} + +ModuleInfo::ModuleInfo(ObjectFile *Obj, DIContext *DICtx) + : Module(Obj), DebugInfoContext(DICtx) { + error_code ec; + for (symbol_iterator si = Module->begin_symbols(), se = Module->end_symbols(); + si != se; si.increment(ec)) { + if (error(ec)) + return; + SymbolRef::Type SymbolType; + if (error(si->getType(SymbolType))) + continue; + if (SymbolType != SymbolRef::ST_Function && + SymbolType != SymbolRef::ST_Data) + continue; + uint64_t SymbolAddress; + if (error(si->getAddress(SymbolAddress)) || + SymbolAddress == UnknownAddressOrSize) + continue; + uint64_t SymbolSize; + if (error(si->getSize(SymbolSize)) || SymbolSize == UnknownAddressOrSize) + continue; + StringRef SymbolName; + if (error(si->getName(SymbolName))) + continue; + // FIXME: If a function has alias, there are two entries in symbol table + // with same address size. Make sure we choose the correct one. + SymbolMapTy &M = SymbolType == SymbolRef::ST_Function ? Functions : Objects; + SymbolDesc SD = { SymbolAddress, SymbolAddress + SymbolSize }; + M.insert(std::make_pair(SD, SymbolName)); + } +} + +bool ModuleInfo::getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, + std::string &Name, uint64_t &Addr, + uint64_t &Size) const { + const SymbolMapTy &M = Type == SymbolRef::ST_Function ? Functions : Objects; + SymbolDesc SD = { Address, Address + 1 }; + SymbolMapTy::const_iterator it = M.find(SD); + if (it == M.end()) + return false; + if (Address < it->first.Addr || Address >= it->first.AddrEnd) + return false; + Name = it->second.str(); + Addr = it->first.Addr; + Size = it->first.AddrEnd - it->first.Addr; + return true; +} + +DILineInfo ModuleInfo::symbolizeCode( + uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { + DILineInfo LineInfo; + if (DebugInfoContext) { + LineInfo = DebugInfoContext->getLineInfoForAddress( + ModuleOffset, getDILineInfoSpecifierFlags(Opts)); + } + // Override function name from symbol table if necessary. + if (Opts.PrintFunctions && Opts.UseSymbolTable) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, + FunctionName, Start, Size)) { + patchFunctionNameInDILineInfo(FunctionName, LineInfo); + } + } + return LineInfo; +} + +DIInliningInfo ModuleInfo::symbolizeInlinedCode( + uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const { + DIInliningInfo InlinedContext; + if (DebugInfoContext) { + InlinedContext = DebugInfoContext->getInliningInfoForAddress( + ModuleOffset, getDILineInfoSpecifierFlags(Opts)); + } + // Make sure there is at least one frame in context. + if (InlinedContext.getNumberOfFrames() == 0) { + InlinedContext.addFrame(DILineInfo()); + } + // Override the function name in lower frame with name from symbol table. + if (Opts.PrintFunctions && Opts.UseSymbolTable) { + DIInliningInfo PatchedInlinedContext; + for (uint32_t i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) { + DILineInfo LineInfo = InlinedContext.getFrame(i); + if (i == n - 1) { + std::string FunctionName; + uint64_t Start, Size; + if (getNameFromSymbolTable(SymbolRef::ST_Function, ModuleOffset, + FunctionName, Start, Size)) { + patchFunctionNameInDILineInfo(FunctionName, LineInfo); + } + } + PatchedInlinedContext.addFrame(LineInfo); + } + InlinedContext = PatchedInlinedContext; + } + return InlinedContext; +} + +bool ModuleInfo::symbolizeData(uint64_t ModuleOffset, std::string &Name, + uint64_t &Start, uint64_t &Size) const { + return getNameFromSymbolTable(SymbolRef::ST_Data, ModuleOffset, Name, Start, + Size); +} + +const char LLVMSymbolizer::kBadString[] = "??"; + +std::string LLVMSymbolizer::symbolizeCode(const std::string &ModuleName, + uint64_t ModuleOffset) { + ModuleInfo *Info = getOrCreateModuleInfo(ModuleName); + if (Info == 0) + return printDILineInfo(DILineInfo()); + if (Opts.PrintInlining) { + DIInliningInfo InlinedContext = + Info->symbolizeInlinedCode(ModuleOffset, Opts); + uint32_t FramesNum = InlinedContext.getNumberOfFrames(); + assert(FramesNum > 0); + std::string Result; + for (uint32_t i = 0; i < FramesNum; i++) { + DILineInfo LineInfo = InlinedContext.getFrame(i); + Result += printDILineInfo(LineInfo); + } + return Result; + } + DILineInfo LineInfo = Info->symbolizeCode(ModuleOffset, Opts); + return printDILineInfo(LineInfo); +} + +std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, + uint64_t ModuleOffset) { + std::string Name = kBadString; + uint64_t Start = 0; + uint64_t Size = 0; + if (Opts.UseSymbolTable) { + if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { + if (Info->symbolizeData(ModuleOffset, Name, Start, Size)) + DemangleName(Name); + } + } + std::stringstream ss; + ss << Name << "\n" << Start << " " << Size << "\n"; + return ss.str(); +} + +void LLVMSymbolizer::flush() { + DeleteContainerSeconds(Modules); +} + +// Returns true if the object endianness is known. +static bool getObjectEndianness(const ObjectFile *Obj, bool &IsLittleEndian) { + // FIXME: Implement this when libLLVMObject allows to do it easily. + IsLittleEndian = true; + return true; +} + +static ObjectFile *getObjectFile(const std::string &Path) { + OwningPtr<MemoryBuffer> Buff; + if (error_code ec = MemoryBuffer::getFile(Path, Buff)) + error(ec); + return ObjectFile::createObjectFile(Buff.take()); +} + +static std::string getDarwinDWARFResourceForModule(const std::string &Path) { + StringRef Basename = sys::path::filename(Path); + const std::string &DSymDirectory = Path + ".dSYM"; + SmallString<16> ResourceName = StringRef(DSymDirectory); + sys::path::append(ResourceName, "Contents", "Resources", "DWARF"); + sys::path::append(ResourceName, Basename); + return ResourceName.str(); +} + +ModuleInfo * +LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) { + ModuleMapTy::iterator I = Modules.find(ModuleName); + if (I != Modules.end()) + return I->second; + + ObjectFile *Obj = getObjectFile(ModuleName); + if (Obj == 0) { + // Module name doesn't point to a valid object file. + Modules.insert(make_pair(ModuleName, (ModuleInfo *)0)); + return 0; + } + + DIContext *Context = 0; + bool IsLittleEndian; + if (getObjectEndianness(Obj, IsLittleEndian)) { + // On Darwin we may find DWARF in separate object file in + // resource directory. + ObjectFile *DbgObj = Obj; + if (isa<MachOObjectFile>(Obj)) { + const std::string &ResourceName = + getDarwinDWARFResourceForModule(ModuleName); + ObjectFile *ResourceObj = getObjectFile(ResourceName); + if (ResourceObj != 0) + DbgObj = ResourceObj; + } + Context = DIContext::getDWARFContext(DbgObj); + assert(Context); + } + + ModuleInfo *Info = new ModuleInfo(Obj, Context); + Modules.insert(make_pair(ModuleName, Info)); + return Info; +} + +std::string LLVMSymbolizer::printDILineInfo(DILineInfo LineInfo) const { + // By default, DILineInfo contains "<invalid>" for function/filename it + // cannot fetch. We replace it to "??" to make our output closer to addr2line. + static const std::string kDILineInfoBadString = "<invalid>"; + std::stringstream Result; + if (Opts.PrintFunctions) { + std::string FunctionName = LineInfo.getFunctionName(); + if (FunctionName == kDILineInfoBadString) + FunctionName = kBadString; + DemangleName(FunctionName); + Result << FunctionName << "\n"; + } + std::string Filename = LineInfo.getFileName(); + if (Filename == kDILineInfoBadString) + Filename = kBadString; + Result << Filename << ":" << LineInfo.getLine() << ":" << LineInfo.getColumn() + << "\n"; + return Result.str(); +} + +#if !defined(_MSC_VER) +// Assume that __cxa_demangle is provided by libcxxabi (except for Windows). +extern "C" char *__cxa_demangle(const char *mangled_name, char *output_buffer, + size_t *length, int *status); +#endif + +void LLVMSymbolizer::DemangleName(std::string &Name) const { +#if !defined(_MSC_VER) + if (!Opts.Demangle) + return; + int status = 0; + char *DemangledName = __cxa_demangle(Name.c_str(), 0, 0, &status); + if (status != 0) + return; + Name = DemangledName; + free(DemangledName); +#endif +} + +} // namespace symbolize +} // namespace llvm diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h new file mode 100644 index 0000000..0733dfb --- /dev/null +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -0,0 +1,98 @@ +//===-- LLVMSymbolize.h ----------------------------------------- C++ -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Header for LLVM symbolization library. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_SYMBOLIZE_H +#define LLVM_SYMBOLIZE_H + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/DebugInfo/DIContext.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include <map> +#include <string> + +namespace llvm { + +using namespace object; + +namespace symbolize { + +class ModuleInfo; + +class LLVMSymbolizer { +public: + struct Options { + bool UseSymbolTable : 1; + bool PrintFunctions : 1; + bool PrintInlining : 1; + bool Demangle : 1; + Options(bool UseSymbolTable = true, bool PrintFunctions = true, + bool PrintInlining = true, bool Demangle = true) + : UseSymbolTable(UseSymbolTable), PrintFunctions(PrintFunctions), + PrintInlining(PrintInlining), Demangle(Demangle) { + } + }; + + LLVMSymbolizer(const Options &Opts = Options()) : Opts(Opts) {} + + // Returns the result of symbolization for module name/offset as + // a string (possibly containing newlines). + std::string + symbolizeCode(const std::string &ModuleName, uint64_t ModuleOffset); + std::string + symbolizeData(const std::string &ModuleName, uint64_t ModuleOffset); + void flush(); +private: + ModuleInfo *getOrCreateModuleInfo(const std::string &ModuleName); + std::string printDILineInfo(DILineInfo LineInfo) const; + void DemangleName(std::string &Name) const; + + typedef std::map<std::string, ModuleInfo *> ModuleMapTy; + ModuleMapTy Modules; + Options Opts; + static const char kBadString[]; +}; + +class ModuleInfo { +public: + ModuleInfo(ObjectFile *Obj, DIContext *DICtx); + + DILineInfo symbolizeCode(uint64_t ModuleOffset, + const LLVMSymbolizer::Options &Opts) const; + DIInliningInfo symbolizeInlinedCode( + uint64_t ModuleOffset, const LLVMSymbolizer::Options &Opts) const; + bool symbolizeData(uint64_t ModuleOffset, std::string &Name, uint64_t &Start, + uint64_t &Size) const; + +private: + bool getNameFromSymbolTable(SymbolRef::Type Type, uint64_t Address, + std::string &Name, uint64_t &Addr, + uint64_t &Size) const; + OwningPtr<ObjectFile> Module; + OwningPtr<DIContext> DebugInfoContext; + + struct SymbolDesc { + uint64_t Addr; + uint64_t AddrEnd; + friend bool operator<(const SymbolDesc &s1, const SymbolDesc &s2) { + return s1.AddrEnd <= s2.Addr; + } + }; + typedef std::map<SymbolDesc, StringRef> SymbolMapTy; + SymbolMapTy Functions; + SymbolMapTy Objects; +}; + +} // namespace symbolize +} // namespace llvm + +#endif // LLVM_SYMBOLIZE_H diff --git a/tools/llvm-symbolizer/Makefile b/tools/llvm-symbolizer/Makefile new file mode 100644 index 0000000..5ac83a5 --- /dev/null +++ b/tools/llvm-symbolizer/Makefile @@ -0,0 +1,17 @@ +##===- tools/llvm-symbolizer/Makefile ----------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-symbolizer +LINK_COMPONENTS := DebugInfo Object + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/llvm-symbolizer/llvm-symbolizer.cpp b/tools/llvm-symbolizer/llvm-symbolizer.cpp new file mode 100644 index 0000000..0cafffa --- /dev/null +++ b/tools/llvm-symbolizer/llvm-symbolizer.cpp @@ -0,0 +1,119 @@ +//===-- llvm-symbolizer.cpp - Simple addr2line-like symbolizer ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This utility works much like "addr2line". It is able of transforming +// tuples (module name, module offset) to code locations (function name, +// file, line number, column number). It is targeted for compiler-rt tools +// (especially AddressSanitizer and ThreadSanitizer) that can use it +// to symbolize stack traces in their error reports. +// +//===----------------------------------------------------------------------===// + +#include "LLVMSymbolize.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdio> +#include <cstring> +#include <string> + +using namespace llvm; +using namespace symbolize; + +static cl::opt<bool> +ClUseSymbolTable("use-symbol-table", cl::init(true), + cl::desc("Prefer names in symbol table to names " + "in debug info")); + +static cl::opt<bool> +ClPrintFunctions("functions", cl::init(true), + cl::desc("Print function names as well as line " + "information for a given address")); + +static cl::opt<bool> +ClPrintInlining("inlining", cl::init(true), + cl::desc("Print all inlined frames for a given address")); + +static cl::opt<bool> +ClDemangle("demangle", cl::init(true), cl::desc("Demangle function names")); + +static bool parseCommand(bool &IsData, std::string &ModuleName, + uint64_t &ModuleOffset) { + const char *kDataCmd = "DATA "; + const char *kCodeCmd = "CODE "; + const int kMaxInputStringLength = 1024; + const char kDelimiters[] = " \n"; + char InputString[kMaxInputStringLength]; + if (!fgets(InputString, sizeof(InputString), stdin)) + return false; + IsData = false; + ModuleName = ""; + std::string ModuleOffsetStr = ""; + char *pos = InputString; + if (strncmp(pos, kDataCmd, strlen(kDataCmd)) == 0) { + IsData = true; + pos += strlen(kDataCmd); + } else if (strncmp(pos, kCodeCmd, strlen(kCodeCmd)) == 0) { + IsData = false; + pos += strlen(kCodeCmd); + } else { + // If no cmd, assume it's CODE. + IsData = false; + } + // Skip delimiters and parse input filename. + pos += strspn(pos, kDelimiters); + if (*pos == '"' || *pos == '\'') { + char quote = *pos; + pos++; + char *end = strchr(pos, quote); + if (end == 0) + return false; + ModuleName = std::string(pos, end - pos); + pos = end + 1; + } else { + int name_length = strcspn(pos, kDelimiters); + ModuleName = std::string(pos, name_length); + pos += name_length; + } + // Skip delimiters and parse module offset. + pos += strspn(pos, kDelimiters); + int offset_length = strcspn(pos, kDelimiters); + ModuleOffsetStr = std::string(pos, offset_length); + if (StringRef(ModuleOffsetStr).getAsInteger(0, ModuleOffset)) + return false; + return true; +} + +int main(int argc, char **argv) { + // Print stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "llvm symbolizer for compiler-rt\n"); + LLVMSymbolizer::Options Opts(ClUseSymbolTable, ClPrintFunctions, + ClPrintInlining, ClDemangle); + LLVMSymbolizer Symbolizer(Opts); + + bool IsData = false; + std::string ModuleName; + uint64_t ModuleOffset; + while (parseCommand(IsData, ModuleName, ModuleOffset)) { + std::string Result = + IsData ? Symbolizer.symbolizeData(ModuleName, ModuleOffset) + : Symbolizer.symbolizeCode(ModuleName, ModuleOffset); + outs() << Result << "\n"; + outs().flush(); + } + return 0; +} diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 9112976..5820b14 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -6,10 +6,13 @@ add_definitions( -DLLVM_VERSION_INFO=\"${PACKAGE_VERSION}\" ) set(SOURCES LTOCodeGenerator.cpp + LTODisassembler.cpp lto.cpp LTOModule.cpp ) +set(LLVM_COMMON_DEPENDS intrinsics_gen) + if( NOT WIN32 AND LLVM_ENABLE_PIC ) set(bsl ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS ON) diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp index b1c4f43..e7c83f9 100644 --- a/tools/lto/LTOCodeGenerator.cpp +++ b/tools/lto/LTOCodeGenerator.cpp @@ -14,39 +14,44 @@ #include "LTOCodeGenerator.h" #include "LTOModule.h" -#include "llvm/Constants.h" -#include "llvm/DataLayout.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Linker.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Analysis/Passes.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/Config/config.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Linker.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetMachine.h" -#include "llvm/Target/TargetRegisterInfo.h" -#include "llvm/Transforms/IPO.h" -#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FormattedStream.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/system_error.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/Target/Mangler.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/ObjCARC.h" using namespace llvm; static cl::opt<bool> +DisableOpt("disable-opt", cl::init(false), + cl::desc("Do not run any optimization passes")); + +static cl::opt<bool> DisableInline("disable-inlining", cl::init(false), cl::desc("Do not run the inliner pass")); @@ -371,26 +376,33 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, // Add an appropriate DataLayout instance for this module... passes.add(new DataLayout(*_target->getDataLayout())); - passes.add(new TargetTransformInfo(_target->getScalarTargetTransformInfo(), - _target->getVectorTargetTransformInfo())); + _target->addAnalysisPasses(passes); // Enabling internalize here would use its AllButMain variant. It // keeps only main if it exists and does nothing for libraries. Instead // we create the pass ourselves with the symbol list provided by the linker. - PassManagerBuilder().populateLTOPassManager(passes, /*Internalize=*/false, + if (!DisableOpt) { + PassManagerBuilder().populateLTOPassManager(passes, + /*Internalize=*/false, !DisableInline, DisableGVNLoadPRE); + } // Make sure everything is still good. passes.add(createVerifierPass()); - FunctionPassManager *codeGenPasses = new FunctionPassManager(mergedModule); + PassManager codeGenPasses; - codeGenPasses->add(new DataLayout(*_target->getDataLayout())); + codeGenPasses.add(new DataLayout(*_target->getDataLayout())); + _target->addAnalysisPasses(codeGenPasses); formatted_raw_ostream Out(out); - if (_target->addPassesToEmitFile(*codeGenPasses, Out, + // If the bitcode files contain ARC code and were compiled with optimization, + // the ObjCARCContractPass must be run, so do it unconditionally here. + codeGenPasses.add(createObjCARCContractPass()); + + if (_target->addPassesToEmitFile(codeGenPasses, Out, TargetMachine::CGFT_ObjectFile)) { errMsg = "target file type not supported"; return true; @@ -400,15 +412,7 @@ bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, passes.run(*mergedModule); // Run the code generator, and write assembly file - codeGenPasses->doInitialization(); - - for (Module::iterator - it = mergedModule->begin(), e = mergedModule->end(); it != e; ++it) - if (!it->isDeclaration()) - codeGenPasses->run(*it); - - codeGenPasses->doFinalization(); - delete codeGenPasses; + codeGenPasses.run(*mergedModule); return false; // success } diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h index 3081b7d..601dbfa 100644 --- a/tools/lto/LTOCodeGenerator.h +++ b/tools/lto/LTOCodeGenerator.h @@ -14,10 +14,10 @@ #ifndef LTO_CODE_GENERATOR_H #define LTO_CODE_GENERATOR_H -#include "llvm/Linker.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm-c/lto.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Linker.h" #include <string> namespace llvm { diff --git a/tools/lto/LTODisassembler.cpp b/tools/lto/LTODisassembler.cpp new file mode 100644 index 0000000..186aceb --- /dev/null +++ b/tools/lto/LTODisassembler.cpp @@ -0,0 +1,26 @@ +//===-- LTODisassembler.cpp - LTO Disassembler interface ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This function provides utility methods used by clients of libLTO that want +// to use the disassembler. +// +//===----------------------------------------------------------------------===// + +#include "llvm-c/lto.h" +#include "llvm/Support/TargetSelect.h" + +using namespace llvm; + +void lto_initialize_disassembler() { + // Initialize targets and assembly printers/parsers. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllDisassemblers(); +} diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index ffdcbe6..ff67769 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -13,19 +13,20 @@ //===----------------------------------------------------------------------===// #include "LTOModule.h" -#include "llvm/Constants.h" -#include "llvm/LLVMContext.h" -#include "llvm/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" +#include "llvm/MC/MCParser/MCAsmParser.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetAsmParser.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/Target/TargetRegisterInfo.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" @@ -34,8 +35,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/system_error.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/Triple.h" +#include "llvm/Target/TargetRegisterInfo.h" using namespace llvm; static cl::opt<bool> @@ -320,8 +320,9 @@ MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { } /// objcClassNameFromExpression - Get string that the data pointer points to. -bool LTOModule::objcClassNameFromExpression(Constant *c, std::string &name) { - if (ConstantExpr *ce = dyn_cast<ConstantExpr>(c)) { +bool +LTOModule::objcClassNameFromExpression(const Constant *c, std::string &name) { + if (const ConstantExpr *ce = dyn_cast<ConstantExpr>(c)) { Constant *op = ce->getOperand(0); if (GlobalVariable *gvn = dyn_cast<GlobalVariable>(op)) { Constant *cn = gvn->getInitializer(); @@ -337,8 +338,8 @@ bool LTOModule::objcClassNameFromExpression(Constant *c, std::string &name) { } /// addObjCClass - Parse i386/ppc ObjC class data structure. -void LTOModule::addObjCClass(GlobalVariable *clgv) { - ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); +void LTOModule::addObjCClass(const GlobalVariable *clgv) { + const ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); if (!c) return; // second slot in __OBJC,__class is pointer to superclass name @@ -374,8 +375,8 @@ void LTOModule::addObjCClass(GlobalVariable *clgv) { } /// addObjCCategory - Parse i386/ppc ObjC category data structure. -void LTOModule::addObjCCategory(GlobalVariable *clgv) { - ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); +void LTOModule::addObjCCategory(const GlobalVariable *clgv) { + const ConstantStruct *c = dyn_cast<ConstantStruct>(clgv->getInitializer()); if (!c) return; // second slot in __OBJC,__category is pointer to target class name @@ -399,7 +400,7 @@ void LTOModule::addObjCCategory(GlobalVariable *clgv) { } /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. -void LTOModule::addObjCClassRef(GlobalVariable *clgv) { +void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { std::string targetclassName; if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) return; @@ -419,7 +420,7 @@ void LTOModule::addObjCClassRef(GlobalVariable *clgv) { } /// addDefinedDataSymbol - Add a data symbol as defined to the list. -void LTOModule::addDefinedDataSymbol(GlobalValue *v) { +void LTOModule::addDefinedDataSymbol(const GlobalValue *v) { // Add to list of defined symbols. addDefinedSymbol(v, false); @@ -448,34 +449,34 @@ void LTOModule::addDefinedDataSymbol(GlobalValue *v) { // special case if this data blob is an ObjC class definition if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { - if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { addObjCClass(gv); } } // special case if this data blob is an ObjC category definition else if (v->getSection().compare(0, 18, "__OBJC,__category,") == 0) { - if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { addObjCCategory(gv); } } // special case if this data blob is the list of referenced classes else if (v->getSection().compare(0, 18, "__OBJC,__cls_refs,") == 0) { - if (GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { + if (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { addObjCClassRef(gv); } } } /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. -void LTOModule::addDefinedFunctionSymbol(Function *f) { +void LTOModule::addDefinedFunctionSymbol(const Function *f) { // add to list of defined symbols addDefinedSymbol(f, true); } /// addDefinedSymbol - Add a defined symbol to the list. -void LTOModule::addDefinedSymbol(GlobalValue *def, bool isFunction) { +void LTOModule::addDefinedSymbol(const GlobalValue *def, bool isFunction) { // ignore all llvm.* symbols if (def->getName().startswith("llvm.")) return; @@ -492,7 +493,7 @@ void LTOModule::addDefinedSymbol(GlobalValue *def, bool isFunction) { if (isFunction) { attr |= LTO_SYMBOL_PERMISSIONS_CODE; } else { - GlobalVariable *gv = dyn_cast<GlobalVariable>(def); + const GlobalVariable *gv = dyn_cast<GlobalVariable>(def); if (gv && gv->isConstant()) attr |= LTO_SYMBOL_PERMISSIONS_RODATA; else @@ -607,7 +608,8 @@ void LTOModule::addAsmGlobalSymbolUndef(const char *name) { /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet to a /// list to be resolved later. -void LTOModule::addPotentialUndefinedSymbol(GlobalValue *decl, bool isFunc) { +void +LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) { // ignore all llvm.* symbols if (decl->getName().startswith("llvm.")) return; @@ -731,7 +733,8 @@ namespace { return Symbols.end(); } - RecordStreamer(MCContext &Context) : MCStreamer(Context) {} + RecordStreamer(MCContext &Context) + : MCStreamer(SK_RecordStreamer, Context) {} virtual void EmitInstruction(const MCInst &Inst) { // Scan for values. @@ -743,6 +746,9 @@ namespace { Symbol->setSection(*getCurrentSection()); markDefined(*Symbol); } + virtual void EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); + } virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { // FIXME: should we handle aliases? markDefined(*Symbol); @@ -760,8 +766,13 @@ namespace { markDefined(*Symbol); } + virtual void EmitBundleAlignMode(unsigned AlignPow2) {} + virtual void EmitBundleLock(bool AlignToEnd) {} + virtual void EmitBundleUnlock() {} + // Noop calls. virtual void ChangeSection(const MCSection *Section) {} + virtual void InitToTextSection() {} virtual void InitSections() {} virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} virtual void EmitThumbFunc(MCSymbol *Func) {} @@ -794,6 +805,10 @@ namespace { const MCSymbol *Label, unsigned PointerSize) {} virtual void FinishImpl() {} + + static bool classof(const MCStreamer *S) { + return S->getKind() == SK_RecordStreamer; + } }; } // end anonymous namespace diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h index 8e52206..83f3a7d 100644 --- a/tools/lto/LTOModule.h +++ b/tools/lto/LTOModule.h @@ -14,15 +14,15 @@ #ifndef LTO_MODULE_H #define LTO_MODULE_H -#include "llvm/Module.h" +#include "llvm-c/lto.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/IR/Module.h" #include "llvm/MC/MCContext.h" #include "llvm/Target/Mangler.h" #include "llvm/Target/TargetMachine.h" -#include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringMap.h" -#include "llvm-c/lto.h" -#include <vector> #include <string> +#include <vector> // Forward references to llvm classes. namespace llvm { @@ -44,7 +44,7 @@ private: const char *name; uint32_t attributes; bool isFunction; - llvm::GlobalValue *symbol; + const llvm::GlobalValue *symbol; }; llvm::OwningPtr<llvm::Module> _module; @@ -138,16 +138,16 @@ private: /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet /// to a list to be resolved later. - void addPotentialUndefinedSymbol(llvm::GlobalValue *dcl, bool isFunc); + void addPotentialUndefinedSymbol(const llvm::GlobalValue *dcl, bool isFunc); /// addDefinedSymbol - Add a defined symbol to the list. - void addDefinedSymbol(llvm::GlobalValue *def, bool isFunction); + void addDefinedSymbol(const llvm::GlobalValue *def, bool isFunction); /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. - void addDefinedFunctionSymbol(llvm::Function *f); + void addDefinedFunctionSymbol(const llvm::Function *f); /// addDefinedDataSymbol - Add a data symbol as defined to the list. - void addDefinedDataSymbol(llvm::GlobalValue *v); + void addDefinedDataSymbol(const llvm::GlobalValue *v); /// addAsmGlobalSymbols - Add global symbols from module-level ASM to the /// defined or undefined lists. @@ -162,17 +162,17 @@ private: void addAsmGlobalSymbolUndef(const char *); /// addObjCClass - Parse i386/ppc ObjC class data structure. - void addObjCClass(llvm::GlobalVariable *clgv); + void addObjCClass(const llvm::GlobalVariable *clgv); /// addObjCCategory - Parse i386/ppc ObjC category data structure. - void addObjCCategory(llvm::GlobalVariable *clgv); + void addObjCCategory(const llvm::GlobalVariable *clgv); /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. - void addObjCClassRef(llvm::GlobalVariable *clgv); + void addObjCClassRef(const llvm::GlobalVariable *clgv); /// objcClassNameFromExpression - Get string that the data pointer points /// to. - bool objcClassNameFromExpression(llvm::Constant* c, std::string &name); + bool objcClassNameFromExpression(const llvm::Constant* c, std::string &name); /// isTargetMatch - Returns 'true' if the memory buffer is for the specified /// target triple. diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 3610fed..ab2e16e 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -51,7 +51,7 @@ ifeq ($(HOST_OS),Darwin) endif # If we're doing an Apple-style build, add the LTO object path. - ifeq ($(RC_BUILDIT),YES) + ifeq ($(RC_XBS),YES) TempFile := $(shell mkdir -p ${OBJROOT}/dSYMs ; mktemp ${OBJROOT}/dSYMs/llvm-lto.XXXXXX) LLVMLibsOptions := $(LLVMLibsOptions) \ -Wl,-object_path_lto -Wl,$(TempFile) diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index a7e633d..11ad532 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,10 +13,9 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" -#include "llvm-c/Core.h" - -#include "LTOModule.h" #include "LTOCodeGenerator.h" +#include "LTOModule.h" +#include "llvm-c/Core.h" // Holds most recent error string. diff --git a/tools/lto/lto.exports b/tools/lto/lto.exports index 4940bb1..46d0d74 100644 --- a/tools/lto/lto.exports +++ b/tools/lto/lto.exports @@ -1,5 +1,6 @@ lto_get_error_message lto_get_version +lto_initialize_disassembler lto_module_create lto_module_create_from_fd lto_module_create_from_fd_at_offset @@ -28,6 +29,7 @@ lto_codegen_set_assembler_path lto_codegen_set_cpu lto_codegen_compile_to_file LLVMCreateDisasm +LLVMCreateDisasmCPU LLVMDisasmDispose LLVMDisasmInstruction LLVMSetDisasmOptions diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 20deda9..3bd3ecc 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -337,7 +337,7 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj, InMemoryStruct<macho::LinkeditDataLoadCommand> LLC; Obj.ReadLinkeditDataLoadCommand(LCI, LLC); if (!LLC) - return Error("unable to read segment load command"); + return Error("unable to read data-in-code load command"); outs() << " ('dataoff', " << LLC->DataOffset << ")\n" << " ('datasize', " << LLC->DataSize << ")\n" @@ -361,6 +361,31 @@ static int DumpDataInCodeDataCommand(MachOObject &Obj, return 0; } +static int DumpLinkerOptionsCommand(MachOObject &Obj, + const MachOObject::LoadCommandInfo &LCI) { + InMemoryStruct<macho::LinkerOptionsLoadCommand> LOLC; + Obj.ReadLinkerOptionsLoadCommand(LCI, LOLC); + if (!LOLC) + return Error("unable to read linker options load command"); + + outs() << " ('count', " << LOLC->Count << ")\n" + << " ('_strings', [\n"; + + uint64_t DataSize = LOLC->Size - sizeof(macho::LinkerOptionsLoadCommand); + StringRef Data = Obj.getData( + LCI.Offset + sizeof(macho::LinkerOptionsLoadCommand), DataSize); + for (unsigned i = 0; i != LOLC->Count; ++i) { + std::pair<StringRef,StringRef> Split = Data.split('\0'); + outs() << "\t\""; + outs().write_escaped(Split.first); + outs() << "\",\n"; + Data = Split.second; + } + outs() <<" ])\n"; + + return 0; +} + static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { const MachOObject::LoadCommandInfo &LCI = Obj.getLoadCommandInfo(Index); @@ -390,6 +415,9 @@ static int DumpLoadCommand(MachOObject &Obj, unsigned Index) { case macho::LCT_DataInCode: Res = DumpDataInCodeDataCommand(Obj, LCI); break; + case macho::LCT_LinkerOptions: + Res = DumpLinkerOptionsCommand(Obj, LCI); + break; default: Warning("unknown load command: " + Twine(LCI.Command.Type)); break; diff --git a/tools/obj2yaml/CMakeLists.txt b/tools/obj2yaml/CMakeLists.txt new file mode 100644 index 0000000..d64bf1b --- /dev/null +++ b/tools/obj2yaml/CMakeLists.txt @@ -0,0 +1,7 @@ +set(LLVM_LINK_COMPONENTS archive object) + +add_llvm_utility(obj2yaml + obj2yaml.cpp coff2yaml.cpp + ) + +target_link_libraries(obj2yaml LLVMSupport) diff --git a/tools/obj2yaml/Makefile b/tools/obj2yaml/Makefile new file mode 100644 index 0000000..95f393d --- /dev/null +++ b/tools/obj2yaml/Makefile @@ -0,0 +1,20 @@ +##===- utils/obj2yaml/Makefile ----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../.. +TOOLNAME = obj2yaml +LINK_COMPONENTS := object + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +# Don't install this utility +NO_INSTALL = 1 + +include $(LEVEL)/Makefile.common diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp new file mode 100644 index 0000000..f0241d9 --- /dev/null +++ b/tools/obj2yaml/coff2yaml.cpp @@ -0,0 +1,361 @@ +//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/Object/COFF.h" + + +template <typename One, typename Two> +struct pod_pair { // I'd much rather use std::pair, but it's not a POD + One first; + Two second; +}; + +#define STRING_PAIR(x) {llvm::COFF::x, #x} +static const pod_pair<llvm::COFF::MachineTypes, const char *> +MachineTypePairs [] = { + STRING_PAIR(IMAGE_FILE_MACHINE_UNKNOWN), + STRING_PAIR(IMAGE_FILE_MACHINE_AM33), + STRING_PAIR(IMAGE_FILE_MACHINE_AMD64), + STRING_PAIR(IMAGE_FILE_MACHINE_ARM), + STRING_PAIR(IMAGE_FILE_MACHINE_ARMV7), + STRING_PAIR(IMAGE_FILE_MACHINE_EBC), + STRING_PAIR(IMAGE_FILE_MACHINE_I386), + STRING_PAIR(IMAGE_FILE_MACHINE_IA64), + STRING_PAIR(IMAGE_FILE_MACHINE_M32R), + STRING_PAIR(IMAGE_FILE_MACHINE_MIPS16), + STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU), + STRING_PAIR(IMAGE_FILE_MACHINE_MIPSFPU16), + STRING_PAIR(IMAGE_FILE_MACHINE_POWERPC), + STRING_PAIR(IMAGE_FILE_MACHINE_POWERPCFP), + STRING_PAIR(IMAGE_FILE_MACHINE_R4000), + STRING_PAIR(IMAGE_FILE_MACHINE_SH3), + STRING_PAIR(IMAGE_FILE_MACHINE_SH3DSP), + STRING_PAIR(IMAGE_FILE_MACHINE_SH4), + STRING_PAIR(IMAGE_FILE_MACHINE_SH5), + STRING_PAIR(IMAGE_FILE_MACHINE_THUMB), + STRING_PAIR(IMAGE_FILE_MACHINE_WCEMIPSV2) +}; + +static const pod_pair<llvm::COFF::SectionCharacteristics, const char *> +SectionCharacteristicsPairs1 [] = { + STRING_PAIR(IMAGE_SCN_TYPE_NO_PAD), + STRING_PAIR(IMAGE_SCN_CNT_CODE), + STRING_PAIR(IMAGE_SCN_CNT_INITIALIZED_DATA), + STRING_PAIR(IMAGE_SCN_CNT_UNINITIALIZED_DATA), + STRING_PAIR(IMAGE_SCN_LNK_OTHER), + STRING_PAIR(IMAGE_SCN_LNK_INFO), + STRING_PAIR(IMAGE_SCN_LNK_REMOVE), + STRING_PAIR(IMAGE_SCN_LNK_COMDAT), + STRING_PAIR(IMAGE_SCN_GPREL), + STRING_PAIR(IMAGE_SCN_MEM_PURGEABLE), + STRING_PAIR(IMAGE_SCN_MEM_16BIT), + STRING_PAIR(IMAGE_SCN_MEM_LOCKED), + STRING_PAIR(IMAGE_SCN_MEM_PRELOAD) +}; + +static const pod_pair<llvm::COFF::SectionCharacteristics, const char *> +SectionCharacteristicsPairsAlignment [] = { + STRING_PAIR(IMAGE_SCN_ALIGN_1BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_2BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_4BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_8BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_16BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_32BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_64BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_128BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_256BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_512BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_1024BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_2048BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_4096BYTES), + STRING_PAIR(IMAGE_SCN_ALIGN_8192BYTES) +}; + +static const pod_pair<llvm::COFF::SectionCharacteristics, const char *> +SectionCharacteristicsPairs2 [] = { + STRING_PAIR(IMAGE_SCN_LNK_NRELOC_OVFL), + STRING_PAIR(IMAGE_SCN_MEM_DISCARDABLE), + STRING_PAIR(IMAGE_SCN_MEM_NOT_CACHED), + STRING_PAIR(IMAGE_SCN_MEM_NOT_PAGED), + STRING_PAIR(IMAGE_SCN_MEM_SHARED), + STRING_PAIR(IMAGE_SCN_MEM_EXECUTE), + STRING_PAIR(IMAGE_SCN_MEM_READ), + STRING_PAIR(IMAGE_SCN_MEM_WRITE) +}; + +static const pod_pair<llvm::COFF::SymbolBaseType, const char *> +SymbolBaseTypePairs [] = { + STRING_PAIR(IMAGE_SYM_TYPE_NULL), + STRING_PAIR(IMAGE_SYM_TYPE_VOID), + STRING_PAIR(IMAGE_SYM_TYPE_CHAR), + STRING_PAIR(IMAGE_SYM_TYPE_SHORT), + STRING_PAIR(IMAGE_SYM_TYPE_INT), + STRING_PAIR(IMAGE_SYM_TYPE_LONG), + STRING_PAIR(IMAGE_SYM_TYPE_FLOAT), + STRING_PAIR(IMAGE_SYM_TYPE_DOUBLE), + STRING_PAIR(IMAGE_SYM_TYPE_STRUCT), + STRING_PAIR(IMAGE_SYM_TYPE_UNION), + STRING_PAIR(IMAGE_SYM_TYPE_ENUM), + STRING_PAIR(IMAGE_SYM_TYPE_MOE), + STRING_PAIR(IMAGE_SYM_TYPE_BYTE), + STRING_PAIR(IMAGE_SYM_TYPE_WORD), + STRING_PAIR(IMAGE_SYM_TYPE_UINT), + STRING_PAIR(IMAGE_SYM_TYPE_DWORD) +}; + +static const pod_pair<llvm::COFF::SymbolComplexType, const char *> +SymbolComplexTypePairs [] = { + STRING_PAIR(IMAGE_SYM_DTYPE_NULL), + STRING_PAIR(IMAGE_SYM_DTYPE_POINTER), + STRING_PAIR(IMAGE_SYM_DTYPE_FUNCTION), + STRING_PAIR(IMAGE_SYM_DTYPE_ARRAY), +}; + +static const pod_pair<llvm::COFF::SymbolStorageClass, const char *> +SymbolStorageClassPairs [] = { + STRING_PAIR(IMAGE_SYM_CLASS_END_OF_FUNCTION), + STRING_PAIR(IMAGE_SYM_CLASS_NULL), + STRING_PAIR(IMAGE_SYM_CLASS_AUTOMATIC), + STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL), + STRING_PAIR(IMAGE_SYM_CLASS_STATIC), + STRING_PAIR(IMAGE_SYM_CLASS_REGISTER), + STRING_PAIR(IMAGE_SYM_CLASS_EXTERNAL_DEF), + STRING_PAIR(IMAGE_SYM_CLASS_LABEL), + STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_LABEL), + STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_STRUCT), + STRING_PAIR(IMAGE_SYM_CLASS_ARGUMENT), + STRING_PAIR(IMAGE_SYM_CLASS_STRUCT_TAG), + STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_UNION), + STRING_PAIR(IMAGE_SYM_CLASS_UNION_TAG), + STRING_PAIR(IMAGE_SYM_CLASS_TYPE_DEFINITION), + STRING_PAIR(IMAGE_SYM_CLASS_UNDEFINED_STATIC), + STRING_PAIR(IMAGE_SYM_CLASS_ENUM_TAG), + STRING_PAIR(IMAGE_SYM_CLASS_MEMBER_OF_ENUM), + STRING_PAIR(IMAGE_SYM_CLASS_REGISTER_PARAM), + STRING_PAIR(IMAGE_SYM_CLASS_BIT_FIELD), + STRING_PAIR(IMAGE_SYM_CLASS_BLOCK), + STRING_PAIR(IMAGE_SYM_CLASS_FUNCTION), + STRING_PAIR(IMAGE_SYM_CLASS_END_OF_STRUCT), + STRING_PAIR(IMAGE_SYM_CLASS_FILE), + STRING_PAIR(IMAGE_SYM_CLASS_SECTION), + STRING_PAIR(IMAGE_SYM_CLASS_WEAK_EXTERNAL), + STRING_PAIR(IMAGE_SYM_CLASS_CLR_TOKEN), +}; + +static const pod_pair<llvm::COFF::RelocationTypeX86, const char *> +RelocationTypeX86Pairs [] = { + STRING_PAIR(IMAGE_REL_I386_ABSOLUTE), + STRING_PAIR(IMAGE_REL_I386_DIR16), + STRING_PAIR(IMAGE_REL_I386_REL16), + STRING_PAIR(IMAGE_REL_I386_DIR32), + STRING_PAIR(IMAGE_REL_I386_DIR32NB), + STRING_PAIR(IMAGE_REL_I386_SEG12), + STRING_PAIR(IMAGE_REL_I386_SECTION), + STRING_PAIR(IMAGE_REL_I386_SECREL), + STRING_PAIR(IMAGE_REL_I386_TOKEN), + STRING_PAIR(IMAGE_REL_I386_SECREL7), + STRING_PAIR(IMAGE_REL_I386_REL32), + STRING_PAIR(IMAGE_REL_AMD64_ABSOLUTE), + STRING_PAIR(IMAGE_REL_AMD64_ADDR64), + STRING_PAIR(IMAGE_REL_AMD64_ADDR32), + STRING_PAIR(IMAGE_REL_AMD64_ADDR32NB), + STRING_PAIR(IMAGE_REL_AMD64_REL32), + STRING_PAIR(IMAGE_REL_AMD64_REL32_1), + STRING_PAIR(IMAGE_REL_AMD64_REL32_2), + STRING_PAIR(IMAGE_REL_AMD64_REL32_3), + STRING_PAIR(IMAGE_REL_AMD64_REL32_4), + STRING_PAIR(IMAGE_REL_AMD64_REL32_5), + STRING_PAIR(IMAGE_REL_AMD64_SECTION), + STRING_PAIR(IMAGE_REL_AMD64_SECREL), + STRING_PAIR(IMAGE_REL_AMD64_SECREL7), + STRING_PAIR(IMAGE_REL_AMD64_TOKEN), + STRING_PAIR(IMAGE_REL_AMD64_SREL32), + STRING_PAIR(IMAGE_REL_AMD64_PAIR), + STRING_PAIR(IMAGE_REL_AMD64_SSPAN32) +}; + +static const pod_pair<llvm::COFF::RelocationTypesARM, const char *> +RelocationTypesARMPairs [] = { + STRING_PAIR(IMAGE_REL_ARM_ABSOLUTE), + STRING_PAIR(IMAGE_REL_ARM_ADDR32), + STRING_PAIR(IMAGE_REL_ARM_ADDR32NB), + STRING_PAIR(IMAGE_REL_ARM_BRANCH24), + STRING_PAIR(IMAGE_REL_ARM_BRANCH11), + STRING_PAIR(IMAGE_REL_ARM_TOKEN), + STRING_PAIR(IMAGE_REL_ARM_BLX24), + STRING_PAIR(IMAGE_REL_ARM_BLX11), + STRING_PAIR(IMAGE_REL_ARM_SECTION), + STRING_PAIR(IMAGE_REL_ARM_SECREL), + STRING_PAIR(IMAGE_REL_ARM_MOV32A), + STRING_PAIR(IMAGE_REL_ARM_MOV32T), + STRING_PAIR(IMAGE_REL_ARM_BRANCH20T), + STRING_PAIR(IMAGE_REL_ARM_BRANCH24T), + STRING_PAIR(IMAGE_REL_ARM_BLX23T) +}; +#undef STRING_PAIR + + +static const char endl = '\n'; + +namespace yaml { // COFF-specific yaml-writing specific routines + +static llvm::raw_ostream &writeName(llvm::raw_ostream &Out, + const char *Name, std::size_t NameSize) { + for (std::size_t i = 0; i < NameSize; ++i) { + if (!Name[i]) break; + Out << Name[i]; + } + return Out; +} + +// Given an array of pod_pair<enum, const char *>, write all enums that match +template <typename T, std::size_t N> +static llvm::raw_ostream &writeBitMask(llvm::raw_ostream &Out, + const pod_pair<T, const char *> (&Arr)[N], unsigned long Val) { + for (std::size_t i = 0; i < N; ++i) + if (Val & Arr[i].first) + Out << Arr[i].second << ", "; + return Out; +} + +} // end of yaml namespace + +// Given an array of pod_pair<enum, const char *>, look up a value +template <typename T, std::size_t N> +const char *nameLookup(const pod_pair<T, const char *> (&Arr)[N], + unsigned long Val, const char *NotFound = NULL) { + T n = static_cast<T>(Val); + for (std::size_t i = 0; i < N; ++i) + if (n == Arr[i].first) + return Arr[i].second; + return NotFound; +} + + +static llvm::raw_ostream &yamlCOFFHeader( + const llvm::object::coff_file_header *Header,llvm::raw_ostream &Out) { + + Out << "header: !Header" << endl; + Out << " Machine: "; + Out << nameLookup(MachineTypePairs, Header->Machine, "# Unknown_MachineTypes") + << " # ("; + return yaml::writeHexNumber(Out, Header->Machine) << ")" << endl << endl; +} + + +static llvm::raw_ostream &yamlCOFFSections(llvm::object::COFFObjectFile &Obj, + std::size_t NumSections, llvm::raw_ostream &Out) { + llvm::error_code ec; + Out << "sections:" << endl; + for (llvm::object::section_iterator iter = Obj.begin_sections(); + iter != Obj.end_sections(); iter.increment(ec)) { + const llvm::object::coff_section *sect = Obj.getCOFFSection(iter); + + Out << " - !Section" << endl; + Out << " Name: "; + yaml::writeName(Out, sect->Name, sizeof(sect->Name)) << endl; + + Out << " Characteristics: ["; + yaml::writeBitMask(Out, SectionCharacteristicsPairs1, sect->Characteristics); + Out << nameLookup(SectionCharacteristicsPairsAlignment, + sect->Characteristics & 0x00F00000, "# Unrecognized_IMAGE_SCN_ALIGN") + << ", "; + yaml::writeBitMask(Out, SectionCharacteristicsPairs2, sect->Characteristics); + Out << "] # "; + yaml::writeHexNumber(Out, sect->Characteristics) << endl; + + llvm::ArrayRef<uint8_t> sectionData; + Obj.getSectionContents(sect, sectionData); + Out << " SectionData: "; + yaml::writeHexStream(Out, sectionData) << endl; + if (iter->begin_relocations() != iter->end_relocations()) + Out << " Relocations:\n"; + for (llvm::object::relocation_iterator rIter = iter->begin_relocations(); + rIter != iter->end_relocations(); rIter.increment(ec)) { + const llvm::object::coff_relocation *reloc = Obj.getCOFFRelocation(rIter); + + Out << " - !Relocation" << endl; + Out << " VirtualAddress: " ; + yaml::writeHexNumber(Out, reloc->VirtualAddress) << endl; + Out << " SymbolTableIndex: " << reloc->SymbolTableIndex << endl; + Out << " Type: " + << nameLookup(RelocationTypeX86Pairs, reloc->Type) << endl; + // TODO: Use the correct reloc type for the machine. + Out << endl; + } + + } + return Out; +} + +static llvm::raw_ostream& yamlCOFFSymbols(llvm::object::COFFObjectFile &Obj, + std::size_t NumSymbols, llvm::raw_ostream &Out) { + llvm::error_code ec; + Out << "symbols:" << endl; + for (llvm::object::symbol_iterator iter = Obj.begin_symbols(); + iter != Obj.end_symbols(); iter.increment(ec)) { + // Gather all the info that we need + llvm::StringRef str; + const llvm::object::coff_symbol *symbol = Obj.getCOFFSymbol(iter); + Obj.getSymbolName(symbol, str); + std::size_t simpleType = symbol->getBaseType(); + std::size_t complexType = symbol->getComplexType(); + std::size_t storageClass = symbol->StorageClass; + + Out << " - !Symbol" << endl; + Out << " Name: " << str << endl; + + Out << " Value: " << symbol->Value << endl; + Out << " SectionNumber: " << symbol->SectionNumber << endl; + + Out << " SimpleType: " + << nameLookup(SymbolBaseTypePairs, simpleType, + "# Unknown_SymbolBaseType") + << " # (" << simpleType << ")" << endl; + + Out << " ComplexType: " + << nameLookup(SymbolComplexTypePairs, complexType, + "# Unknown_SymbolComplexType") + << " # (" << complexType << ")" << endl; + + Out << " StorageClass: " + << nameLookup(SymbolStorageClassPairs, storageClass, + "# Unknown_StorageClass") + << " # (" << (int) storageClass << ")" << endl; + + if (symbol->NumberOfAuxSymbols > 0) { + llvm::ArrayRef<uint8_t> aux = Obj.getSymbolAuxData(symbol); + Out << " NumberOfAuxSymbols: " + << (int) symbol->NumberOfAuxSymbols << endl; + Out << " AuxillaryData: "; + yaml::writeHexStream(Out, aux); + } + + Out << endl; + } + + return Out; +} + + +llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj) { + llvm::error_code ec; + llvm::object::COFFObjectFile obj(TheObj, ec); + if (!ec) { + const llvm::object::coff_file_header *hd; + ec = obj.getHeader(hd); + if (!ec) { + yamlCOFFHeader(hd, Out); + yamlCOFFSections(obj, hd->NumberOfSections, Out); + yamlCOFFSymbols(obj, hd->NumberOfSymbols, Out); + } + } + return ec; +} diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp new file mode 100644 index 0000000..bdc461a --- /dev/null +++ b/tools/obj2yaml/obj2yaml.cpp @@ -0,0 +1,86 @@ +//===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "obj2yaml.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" + +const char endl = '\n'; + +namespace yaml { // generic yaml-writing specific routines + +unsigned char printable(unsigned char Ch) { + return Ch >= ' ' && Ch <= '~' ? Ch : '.'; +} + +llvm::raw_ostream &writeHexStream(llvm::raw_ostream &Out, + const llvm::ArrayRef<uint8_t> arr) { + const char *hex = "0123456789ABCDEF"; + Out << " !hex \""; + + typedef llvm::ArrayRef<uint8_t>::const_iterator iter_t; + const iter_t end = arr.end(); + for (iter_t iter = arr.begin(); iter != end; ++iter) + Out << hex[(*iter >> 4) & 0x0F] << hex[(*iter & 0x0F)]; + + Out << "\" # |"; + for (iter_t iter = arr.begin(); iter != end; ++iter) + Out << printable(*iter); + Out << "|" << endl; + + return Out; + } + +llvm::raw_ostream &writeHexNumber(llvm::raw_ostream &Out, unsigned long long N) { + if (N >= 10) + Out << "0x"; + Out.write_hex(N); + return Out; +} + +} + + +using namespace llvm; +enum ObjectFileType { coff }; + +cl::opt<ObjectFileType> InputFormat( + cl::desc("Choose input format"), + cl::values( + clEnumVal(coff, "process COFF object files"), + clEnumValEnd)); + +cl::opt<std::string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-")); + +int main(int argc, char * argv[]) { + cl::ParseCommandLineOptions(argc, argv); + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + +// Process the input file + OwningPtr<MemoryBuffer> buf; + +// TODO: If this is an archive, then burst it and dump each entry + if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, buf)) + llvm::errs() << "Error: '" << ec.message() << "' opening file '" + << InputFilename << "'" << endl; + else { + ec = coff2yaml(llvm::outs(), buf.take()); + if (ec) + llvm::errs() << "Error: " << ec.message() << " dumping COFF file" << endl; + } + + return 0; +} diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h new file mode 100644 index 0000000..0bc376a --- /dev/null +++ b/tools/obj2yaml/obj2yaml.h @@ -0,0 +1,34 @@ +//===------ utils/obj2yaml.hpp - obj2yaml conversion tool -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// This file declares some helper routines, and also the format-specific +// writers. To add a new format, add the declaration here, and, in a separate +// source file, implement it. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_UTILS_OBJ2YAML_H +#define LLVM_UTILS_OBJ2YAML_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" + +namespace yaml { // routines for writing YAML +// Write a hex stream: +// <Prefix> !hex: "<hex digits>" #|<ASCII chars>\n + llvm::raw_ostream &writeHexStream + (llvm::raw_ostream &Out, const llvm::ArrayRef<uint8_t> arr); + +// Writes a number in hex; prefix it by 0x if it is >= 10 + llvm::raw_ostream &writeHexNumber + (llvm::raw_ostream &Out, unsigned long long N); +} + +llvm::error_code coff2yaml(llvm::raw_ostream &Out, llvm::MemoryBuffer *TheObj); + +#endif diff --git a/tools/opt/AnalysisWrappers.cpp b/tools/opt/AnalysisWrappers.cpp index a2b57bb..55f544f 100644 --- a/tools/opt/AnalysisWrappers.cpp +++ b/tools/opt/AnalysisWrappers.cpp @@ -17,10 +17,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Module.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/Module.h" #include "llvm/Pass.h" #include "llvm/Support/CallSite.h" -#include "llvm/Analysis/CallGraph.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/tools/opt/CMakeLists.txt b/tools/opt/CMakeLists.txt index 32de6d4..9195911 100644 --- a/tools/opt/CMakeLists.txt +++ b/tools/opt/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter instrumentation scalaropts ipo vectorize) +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader asmparser bitwriter irreader instrumentation scalaropts objcarcopts ipo vectorize) add_llvm_tool(opt AnalysisWrappers.cpp @@ -6,3 +6,4 @@ add_llvm_tool(opt PrintSCC.cpp opt.cpp ) +set_target_properties(opt PROPERTIES ENABLE_EXPORTS 1) diff --git a/tools/opt/GraphPrinters.cpp b/tools/opt/GraphPrinters.cpp index 30361f5..f271966 100644 --- a/tools/opt/GraphPrinters.cpp +++ b/tools/opt/GraphPrinters.cpp @@ -14,81 +14,10 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/GraphWriter.h" -#include "llvm/Pass.h" -#include "llvm/Value.h" -#include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/Dominators.h" -#include "llvm/Support/ToolOutputFile.h" -using namespace llvm; - -template<typename GraphType> -static void WriteGraphToFile(raw_ostream &O, const std::string &GraphName, - const GraphType >) { - std::string Filename = GraphName + ".dot"; - O << "Writing '" << Filename << "'..."; - std::string ErrInfo; - tool_output_file F(Filename.c_str(), ErrInfo); - - if (ErrInfo.empty()) { - WriteGraph(F.os(), GT); - F.os().close(); - if (!F.os().has_error()) { - O << "\n"; - F.keep(); - return; - } - } - O << " error opening file for writing!\n"; - F.os().clear_error(); -} - - -//===----------------------------------------------------------------------===// -// Call Graph Printer -//===----------------------------------------------------------------------===// - -namespace llvm { - template<> - struct DOTGraphTraits<CallGraph*> : public DefaultDOTGraphTraits { - - DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} - - static std::string getGraphName(CallGraph *F) { - return "Call Graph"; - } - - static std::string getNodeLabel(CallGraphNode *Node, CallGraph *Graph) { - if (Node->getFunction()) - return ((Value*)Node->getFunction())->getName(); - return "external node"; - } - }; -} - - -namespace { - struct CallGraphPrinter : public ModulePass { - static char ID; // Pass ID, replacement for typeid - CallGraphPrinter() : ModulePass(ID) {} - - virtual bool runOnModule(Module &M) { - WriteGraphToFile(llvm::errs(), "callgraph", &getAnalysis<CallGraph>()); - return false; - } - - void print(raw_ostream &OS, const llvm::Module*) const {} - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.addRequired<CallGraph>(); - AU.setPreservesAll(); - } - }; -} +#include "llvm/Pass.h" -char CallGraphPrinter::ID = 0; -static RegisterPass<CallGraphPrinter> P2("dot-callgraph", - "Print Call Graph to 'dot' file"); +using namespace llvm; //===----------------------------------------------------------------------===// // DomInfoPrinter Pass diff --git a/tools/opt/LLVMBuild.txt b/tools/opt/LLVMBuild.txt index b174431..77b9446 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 IPO Instrumentation Scalar all-targets +required_libraries = AsmParser BitReader BitWriter IRReader IPO Instrumentation Scalar ObjCARC all-targets diff --git a/tools/opt/Makefile b/tools/opt/Makefile index ee7e1cf..a451005 100644 --- a/tools/opt/Makefile +++ b/tools/opt/Makefile @@ -9,6 +9,6 @@ LEVEL := ../.. TOOLNAME := opt -LINK_COMPONENTS := bitreader bitwriter asmparser instrumentation scalaropts ipo vectorize all-targets +LINK_COMPONENTS := bitreader bitwriter asmparser irreader instrumentation scalaropts objcarcopts ipo vectorize all-targets include $(LEVEL)/Makefile.common diff --git a/tools/opt/PrintSCC.cpp b/tools/opt/PrintSCC.cpp index 11efdcd..a502fa7 100644 --- a/tools/opt/PrintSCC.cpp +++ b/tools/opt/PrintSCC.cpp @@ -25,12 +25,12 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Pass.h" -#include "llvm/Module.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/Analysis/CallGraph.h" +#include "llvm/IR/Module.h" +#include "llvm/Pass.h" #include "llvm/Support/CFG.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/ADT/SCCIterator.h" using namespace llvm; namespace { diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index bac0d46..ba82bde 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -12,40 +12,41 @@ // //===----------------------------------------------------------------------===// -#include "llvm/LLVMContext.h" -#include "llvm/DataLayout.h" -#include "llvm/DebugInfo.h" -#include "llvm/Module.h" -#include "llvm/PassManager.h" -#include "llvm/CallGraphSCCPass.h" -#include "llvm/CodeGen/CommandFlags.h" -#include "llvm/Bitcode/ReaderWriter.h" -#include "llvm/Assembly/PrintModulePass.h" -#include "llvm/Analysis/Verifier.h" -#include "llvm/Analysis/LoopPass.h" -#include "llvm/Analysis/RegionPass.h" -#include "llvm/Analysis/CallGraph.h" -#include "llvm/Target/TargetLibraryInfo.h" -#include "llvm/Target/TargetMachine.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" -#include "llvm/Support/PassNameParser.h" -#include "llvm/Support/Signals.h" +#include "llvm/Analysis/CallGraph.h" +#include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/RegionPass.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Assembly/PrintModulePass.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/DebugInfo.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Module.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/LinkAllIR.h" +#include "llvm/LinkAllPasses.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/PassManager.h" #include "llvm/Support/Debug.h" -#include "llvm/Support/IRReader.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PassNameParser.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/SystemUtils.h" #include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/LinkAllPasses.h" -#include "llvm/LinkAllVMCore.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetLibraryInfo.h" +#include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" -#include <memory> #include <algorithm> +#include <memory> using namespace llvm; // The OptimizationList is automatically populated with registered Passes by the @@ -523,16 +524,11 @@ CodeGenOpt::Level GetCodeGenOptLevel() { } // Returns the TargetMachine instance or zero if no triple is provided. -static TargetMachine* GetTargetMachine(std::string TripleStr) { - if (TripleStr.empty()) - return 0; - - // Get the target specific parser. +static TargetMachine* GetTargetMachine(Triple TheTriple) { std::string Error; - Triple TheTriple(Triple::normalize(TargetTriple)); - const Target *TheTarget = TargetRegistry::lookupTarget(MArch, TheTriple, Error); + // Some modules don't specify a triple, and this is okay. if (!TheTarget) { return 0; } @@ -572,6 +568,7 @@ int main(int argc, char **argv) { PassRegistry &Registry = *PassRegistry::getPassRegistry(); initializeCore(Registry); initializeScalarOpts(Registry); + initializeObjCARCOpts(Registry); initializeVectorization(Registry); initializeIPO(Registry); initializeAnalysis(Registry); @@ -655,11 +652,15 @@ int main(int argc, char **argv) { if (TD) Passes.add(TD); - std::auto_ptr<TargetMachine> TM(GetTargetMachine(TargetTriple)); - if (TM.get()) { - Passes.add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(), - TM->getVectorTargetTransformInfo())); - } + Triple ModuleTriple(M->getTargetTriple()); + TargetMachine *Machine = 0; + if (ModuleTriple.getArch()) + Machine = GetTargetMachine(Triple(ModuleTriple)); + std::auto_ptr<TargetMachine> TM(Machine); + + // Add internal analysis passes from the target machine. + if (TM.get()) + TM->addAnalysisPasses(Passes); OwningPtr<FunctionPassManager> FPasses; if (OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || OptLevelO3) { |