diff options
author | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-02-11 20:01:10 -0800 |
commit | ce9904c6ea8fd669978a8eefb854b330eb9828ff (patch) | |
tree | 2418ee2e96ea220977c8fb74959192036ab5b133 /tools | |
parent | c27b10b198c1d9e9b51f2303994313ec2778edd7 (diff) | |
parent | dbb832b83351cec97b025b61c26536ef50c3181c (diff) | |
download | external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.zip external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.gz external_llvm-ce9904c6ea8fd669978a8eefb854b330eb9828ff.tar.bz2 |
Merge remote-tracking branch 'upstream/release_34' into merge-20140211
Conflicts:
lib/Linker/LinkModules.cpp
lib/Support/Unix/Signals.inc
Change-Id: Ia54f291fa5dc828052d2412736e8495c1282aa64
Diffstat (limited to 'tools')
96 files changed, 3828 insertions, 2919 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index e663781..12e10fd 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,59 +2,66 @@ # three small executables. This is done to minimize memory load in parallel # builds. Please retain this ordering. -if( NOT WIN32 OR MSYS OR CYGWIN ) - # We currently require 'sed' to build llvm-config, so don't try to build it - # on pure Win32. - add_subdirectory(llvm-config) -endif() +add_llvm_tool_subdirectory(llvm-config) -add_subdirectory(opt) -add_subdirectory(llvm-as) -add_subdirectory(llvm-dis) -add_subdirectory(llvm-mc) +add_llvm_tool_subdirectory(opt) +add_llvm_tool_subdirectory(llvm-as) +add_llvm_tool_subdirectory(llvm-dis) +add_llvm_tool_subdirectory(llvm-mc) -add_subdirectory(llc) -add_subdirectory(llvm-ar) -add_subdirectory(llvm-nm) -add_subdirectory(llvm-size) +add_llvm_tool_subdirectory(llc) +add_llvm_tool_subdirectory(llvm-ar) +add_llvm_tool_subdirectory(llvm-nm) +add_llvm_tool_subdirectory(llvm-size) -add_subdirectory(llvm-cov) -add_subdirectory(llvm-prof) -add_subdirectory(llvm-link) -add_subdirectory(lli) +add_llvm_tool_subdirectory(llvm-cov) +add_llvm_tool_subdirectory(llvm-link) +add_llvm_tool_subdirectory(lli) -add_subdirectory(llvm-extract) -add_subdirectory(llvm-diff) -add_subdirectory(macho-dump) -add_subdirectory(llvm-objdump) -add_subdirectory(llvm-readobj) -add_subdirectory(llvm-rtdyld) -add_subdirectory(llvm-dwarfdump) +add_llvm_tool_subdirectory(llvm-extract) +add_llvm_tool_subdirectory(llvm-diff) +add_llvm_tool_subdirectory(macho-dump) +add_llvm_tool_subdirectory(llvm-objdump) +add_llvm_tool_subdirectory(llvm-readobj) +add_llvm_tool_subdirectory(llvm-rtdyld) +add_llvm_tool_subdirectory(llvm-dwarfdump) if( LLVM_USE_INTEL_JITEVENTS ) - add_subdirectory(llvm-jitlistener) + add_llvm_tool_subdirectory(llvm-jitlistener) +else() + ignore_llvm_tool_subdirectory(llvm-jitlistener) endif( LLVM_USE_INTEL_JITEVENTS ) -add_subdirectory(bugpoint) -add_subdirectory(bugpoint-passes) -add_subdirectory(llvm-bcanalyzer) -add_subdirectory(llvm-stress) -add_subdirectory(llvm-mcmarkup) +add_llvm_tool_subdirectory(bugpoint) +add_llvm_tool_subdirectory(bugpoint-passes) +add_llvm_tool_subdirectory(llvm-bcanalyzer) +add_llvm_tool_subdirectory(llvm-stress) +add_llvm_tool_subdirectory(llvm-mcmarkup) + +add_llvm_tool_subdirectory(llvm-symbolizer) -add_subdirectory(llvm-symbolizer) +add_llvm_tool_subdirectory(llvm-c-test) -add_subdirectory(obj2yaml) -add_subdirectory(yaml2obj) +add_llvm_tool_subdirectory(obj2yaml) +add_llvm_tool_subdirectory(yaml2obj) -if( NOT WIN32 ) - add_subdirectory(lto) +if( NOT CYGWIN ) + add_llvm_tool_subdirectory(lto) + add_llvm_tool_subdirectory(llvm-lto) +else() + ignore_llvm_tool_subdirectory(lto) + ignore_llvm_tool_subdirectory(llvm-lto) endif() if( LLVM_ENABLE_PIC ) # TODO: support other systems: if( (CMAKE_SYSTEM_NAME STREQUAL "Linux") OR (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ) - add_subdirectory(gold) + add_llvm_tool_subdirectory(gold) + else() + ignore_llvm_tool_subdirectory(gold) endif() +else() + ignore_llvm_tool_subdirectory(gold) endif() add_llvm_external_project(clang) @@ -63,6 +70,10 @@ if( NOT LLVM_INCLUDE_TOOLS STREQUAL "bootstrap-only" ) add_llvm_external_project(lld) add_llvm_external_project(lldb) add_llvm_external_project(polly) + + # Automatically add remaining sub-directories containing a 'CMakeLists.txt' + # file as external projects. + add_llvm_implicit_external_projects() endif() set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS} PARENT_SCOPE) diff --git a/tools/LLVMBuild.txt b/tools/LLVMBuild.txt index 9ec89f3..93b8d98 100644 --- a/tools/LLVMBuild.txt +++ b/tools/LLVMBuild.txt @@ -16,7 +16,7 @@ ;===------------------------------------------------------------------------===; [common] -subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-mc llvm-nm llvm-objdump llvm-prof llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup +subdirectories = bugpoint llc lli llvm-ar llvm-as llvm-bcanalyzer llvm-cov llvm-diff llvm-dis llvm-dwarfdump llvm-extract llvm-jitlistener llvm-link llvm-lto llvm-mc llvm-nm llvm-objdump llvm-rtdyld llvm-size macho-dump opt llvm-mcmarkup [component_0] type = Group diff --git a/tools/Makefile b/tools/Makefile index b7375c9..be87254 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -27,15 +27,11 @@ OPTIONAL_DIRS := lldb # large and three small executables. This is done to minimize memory load # in parallel builds. Please retain this ordering. DIRS := llvm-config -PARALLEL_DIRS := opt llvm-as llvm-dis \ - llc llvm-ar llvm-nm \ - llvm-prof llvm-link \ - lli llvm-extract llvm-mc \ - bugpoint llvm-bcanalyzer \ - llvm-diff macho-dump llvm-objdump llvm-readobj \ - llvm-rtdyld llvm-dwarfdump llvm-cov \ - llvm-size llvm-stress llvm-mcmarkup \ - llvm-symbolizer obj2yaml yaml2obj +PARALLEL_DIRS := opt llvm-as llvm-dis llc llvm-ar llvm-nm llvm-link \ + lli llvm-extract llvm-mc bugpoint llvm-bcanalyzer llvm-diff \ + macho-dump llvm-objdump llvm-readobj llvm-rtdyld \ + llvm-dwarfdump llvm-cov llvm-size llvm-stress llvm-mcmarkup \ + llvm-symbolizer obj2yaml yaml2obj llvm-c-test # If Intel JIT Events support is configured, build an extra tool to test it. ifeq ($(USE_INTEL_JITEVENTS), 1) @@ -54,11 +50,10 @@ endif ifndef ONLY_TOOLS ifeq ($(ENABLE_PIC),1) # gold only builds if binutils is around. It requires "lto" to build before - # it so it is added to DIRS. + # it so it is added to DIRS. llvm-lto also requires lto + DIRS += lto llvm-lto ifdef BINUTILS_INCDIR - DIRS += lto gold - else - PARALLEL_DIRS += lto + DIRS += gold endif PARALLEL_DIRS += bugpoint-passes diff --git a/tools/bugpoint/CrashDebugger.cpp b/tools/bugpoint/CrashDebugger.cpp index c8b4f6f..b90fc61 100644 --- a/tools/bugpoint/CrashDebugger.cpp +++ b/tools/bugpoint/CrashDebugger.cpp @@ -195,10 +195,10 @@ namespace { } bool ReduceCrashingFunctions::TestFuncs(std::vector<Function*> &Funcs) { - - //if main isn't present, claim there is no problem - if (KeepMain && find(Funcs.begin(), Funcs.end(), - BD.getProgram()->getFunction("main")) == Funcs.end()) + // If main isn't present, claim there is no problem. + if (KeepMain && std::find(Funcs.begin(), Funcs.end(), + BD.getProgram()->getFunction("main")) == + Funcs.end()) return false; // Clone the program to try hacking it apart... diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 3d3dac3..c05c8d7 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -301,7 +301,6 @@ std::string BugDriver::executeProgram(const Module *Program, if (AI == 0) AI = Interpreter; assert(AI && "Interpreter should have been created already!"); bool CreatedBitcode = false; - std::string ErrMsg; if (BitcodeFile.empty()) { // Emit the program to a bitcode file... SmallString<128> UniqueFilename; diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index 107d0db..254d997 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -662,7 +662,7 @@ static bool IsARMArchitecture(std::vector<const char*> Args) { I = Args.begin(), E = Args.end(); I != E; ++I) { if (StringRef(*I).equals_lower("-arch")) { ++I; - if (I != E && StringRef(*I).substr(0, strlen("arm")).equals_lower("arm")) + if (I != E && StringRef(*I).startswith_lower("arm")) return true; } } diff --git a/tools/bugpoint/bugpoint.cpp b/tools/bugpoint/bugpoint.cpp index 5e8fdd1..9bc592e 100644 --- a/tools/bugpoint/bugpoint.cpp +++ b/tools/bugpoint/bugpoint.cpp @@ -49,8 +49,8 @@ TimeoutValue("timeout", cl::init(300), cl::value_desc("seconds"), static cl::opt<int> MemoryLimit("mlimit", cl::init(-1), cl::value_desc("MBytes"), - cl::desc("Maximum amount of memory to use. 0 disables check." - " Defaults to 100MB (800MB under valgrind).")); + cl::desc("Maximum amount of memory to use. 0 disables check." + " Defaults to 300MB (800MB under valgrind).")); static cl::opt<bool> UseValgrind("enable-valgrind", @@ -152,7 +152,7 @@ int main(int argc, char **argv) { if (sys::RunningOnValgrind() || UseValgrind) MemoryLimit = 800; else - MemoryLimit = 100; + MemoryLimit = 300; } BugDriver D(argv[0], FindBugs, TimeoutValue, MemoryLimit, diff --git a/tools/gold/README.txt b/tools/gold/README.txt index a906a90..286d9af 100644 --- a/tools/gold/README.txt +++ b/tools/gold/README.txt @@ -1,21 +1,13 @@ +The LLVM Gold LTO Plugin +======================== + This directory contains a plugin that is designed to work with binutils gold linker. At present time, this is not the default linker in binutils, and the default build of gold does not support plugins. -Obtaining binutils: - - cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login - {enter "anoncvs" as the password} - cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils - -This will create a src/ directory. Make a build/ directory and from -there configure binutils with "../src/configure --enable-gold --enable-plugins". -Then build binutils with "make all-gold". +See docs/GoldPlugin.html for complete build and usage instructions. -To build the LLVMgold plugin, configure LLVM with the option ---with-binutils-include=/path/to/binutils/src/include/ --enable-pic. To use the -plugin, run "ld-new --plugin /path/to/LLVMgold.so". -Without PIC libLTO and LLVMgold are not being built (because they would fail -link on x86-64 with a relocation error: PIC and non-PIC can't be combined). +NOTE: libLTO and LLVMgold aren't built without PIC because they would fail +to link on x86-64 with a relocation error: PIC and non-PIC can't be combined. As an alternative to passing --enable-pic, you can use 'make ENABLE_PIC=1' in your entire LLVM build. diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 7771709..0e3bad2 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -15,6 +15,7 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "plugin-api.h" #include "llvm-c/lto.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" @@ -67,6 +68,7 @@ namespace { std::list<claimed_file> Modules; std::vector<std::string> Cleanup; lto_code_gen_t code_gen = NULL; + StringSet<> CannotBeHidden; } namespace options { @@ -197,7 +199,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) { case LDPT_ADD_SYMBOLS: add_symbols = tv->tv_u.tv_add_symbols; break; - case LDPT_GET_SYMBOLS: + case LDPT_GET_SYMBOLS_V2: get_symbols = tv->tv_u.tv_get_symbols; break; case LDPT_ADD_INPUT_FILE: @@ -297,6 +299,9 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, sym.version = NULL; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; + bool CanBeHidden = scope == LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; + if (!CanBeHidden) + CannotBeHidden.insert(sym.name); switch (scope) { case LTO_SYMBOL_SCOPE_HIDDEN: sym.visibility = LDPV_HIDDEN; @@ -306,6 +311,7 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, break; case 0: // extern case LTO_SYMBOL_SCOPE_DEFAULT: + case LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN: sym.visibility = LDPV_DEFAULT; break; default: @@ -351,14 +357,27 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, } } - if (code_gen) - lto_codegen_add_module(code_gen, M); + if (code_gen) { + if (lto_codegen_add_module(code_gen, M)) { + (*message)(LDPL_ERROR, "Error linking module: %s", + lto_get_error_message()); + return LDPS_ERR; + } + } lto_module_dispose(M); return LDPS_OK; } +static bool mustPreserve(const claimed_file &F, int i) { + if (F.syms[i].resolution == LDPR_PREVAILING_DEF) + return true; + if (F.syms[i].resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) + return CannotBeHidden.count(F.syms[i].name); + return false; +} + /// all_symbols_read_hook - gold informs us that all symbols have been read. /// At this point, we use get_symbols to see if any of our definitions have /// been overridden by a native object file. Then, perform optimization and @@ -381,7 +400,7 @@ static ld_plugin_status all_symbols_read_hook(void) { continue; (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); for (unsigned i = 0, e = I->syms.size(); i != e; i++) { - if (I->syms[i].resolution == LDPR_PREVAILING_DEF) { + if (mustPreserve(*I, i)) { lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name); if (options::generate_api_file) @@ -417,12 +436,19 @@ static ld_plugin_status all_symbols_read_hook(void) { bool err = lto_codegen_write_merged_modules(code_gen, path.c_str()); if (err) (*message)(LDPL_FATAL, "Failed to write the output file."); - if (options::generate_bc_file == options::BC_ONLY) + if (options::generate_bc_file == options::BC_ONLY) { + lto_codegen_dispose(code_gen); exit(0); + } } - const char *objPath; - if (lto_codegen_compile_to_file(code_gen, &objPath)) { - (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); + + std::string ObjPath; + { + const char *Temp; + if (lto_codegen_compile_to_file(code_gen, &Temp)) { + (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); + } + ObjPath = Temp; } lto_codegen_dispose(code_gen); @@ -434,9 +460,9 @@ static ld_plugin_status all_symbols_read_hook(void) { } } - if ((*add_input_file)(objPath) != LDPS_OK) { + if ((*add_input_file)(ObjPath.c_str()) != LDPS_OK) { (*message)(LDPL_ERROR, "Unable to add .o file to the link."); - (*message)(LDPL_ERROR, "File left behind in: %s", objPath); + (*message)(LDPL_ERROR, "File left behind in: %s", ObjPath.c_str()); return LDPS_ERR; } @@ -447,7 +473,7 @@ static ld_plugin_status all_symbols_read_hook(void) { } if (options::obj_path.empty()) - Cleanup.push_back(objPath); + Cleanup.push_back(ObjPath); return LDPS_OK; } diff --git a/tools/lli/CMakeLists.txt b/tools/lli/CMakeLists.txt index 98f411d..5f8c7c9 100644 --- a/tools/lli/CMakeLists.txt +++ b/tools/lli/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_LINK_COMPONENTS mcjit jit interpreter nativecodegen bitreader asmparser irreader selectiondag native instrumentation) +add_subdirectory(ChildTarget) + if( LLVM_USE_OPROFILE ) set(LLVM_LINK_COMPONENTS ${LLVM_LINK_COMPONENTS} @@ -19,6 +21,7 @@ endif( LLVM_USE_INTEL_JITEVENTS ) add_llvm_tool(lli lli.cpp - RecordingMemoryManager.cpp + RemoteMemoryManager.cpp RemoteTarget.cpp + RemoteTargetExternal.cpp ) diff --git a/tools/lli/ChildTarget/CMakeLists.txt b/tools/lli/ChildTarget/CMakeLists.txt new file mode 100644 index 0000000..fd1ac24 --- /dev/null +++ b/tools/lli/ChildTarget/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_tool(lli-child-target + ChildTarget.cpp + ) diff --git a/tools/lli/ChildTarget/ChildTarget.cpp b/tools/lli/ChildTarget/ChildTarget.cpp new file mode 100644 index 0000000..55fcae9 --- /dev/null +++ b/tools/lli/ChildTarget/ChildTarget.cpp @@ -0,0 +1,242 @@ +#include "llvm/Config/config.h" + +#include "../RemoteTargetMessage.h" +#include <assert.h> +#include <map> +#include <stdint.h> +#include <string> +#include <vector> + +using namespace llvm; + +class LLIChildTarget { +public: + ~LLIChildTarget(); // OS-specific destructor + void initialize(); + LLIMessageType waitForIncomingMessage(); + void handleMessage(LLIMessageType messageType); + +private: + // Incoming message handlers + void handleAllocateSpace(); + void handleLoadSection(bool IsCode); + void handleExecute(); + void handleTerminate(); + + // Outgoing message handlers + void sendChildActive(); + void sendAllocationResult(uint64_t Addr); + void sendLoadComplete(); + void sendExecutionComplete(uint64_t Result); + + // OS-specific functions + void initializeConnection(); + int WriteBytes(const void *Data, size_t Size); + int ReadBytes(void *Data, size_t Size); + uint64_t allocate(uint32_t Alignment, uint32_t Size); + void makeSectionExecutable(uint64_t Addr, uint32_t Size); + void InvalidateInstructionCache(const void *Addr, size_t Len); + void releaseMemory(uint64_t Addr, uint32_t Size); + + // Store a map of allocated buffers to sizes. + typedef std::map<uint64_t, uint32_t> AllocMapType; + AllocMapType m_AllocatedBufferMap; + + // Communication handles (OS-specific) + void *ConnectionData; +}; + +int main() { + LLIChildTarget ThisChild; + ThisChild.initialize(); + LLIMessageType MsgType; + do { + MsgType = ThisChild.waitForIncomingMessage(); + ThisChild.handleMessage(MsgType); + } while (MsgType != LLI_Terminate && + MsgType != LLI_Error); + return 0; +} + +// Public methods +void LLIChildTarget::initialize() { + initializeConnection(); + sendChildActive(); +} + +LLIMessageType LLIChildTarget::waitForIncomingMessage() { + int32_t MsgType = -1; + if (ReadBytes(&MsgType, 4) > 0) + return (LLIMessageType)MsgType; + return LLI_Error; +} + +void LLIChildTarget::handleMessage(LLIMessageType messageType) { + switch (messageType) { + case LLI_AllocateSpace: + handleAllocateSpace(); + break; + case LLI_LoadCodeSection: + handleLoadSection(true); + break; + case LLI_LoadDataSection: + handleLoadSection(false); + break; + case LLI_Execute: + handleExecute(); + break; + case LLI_Terminate: + handleTerminate(); + break; + default: + // FIXME: Handle error! + break; + } +} + +// Incoming message handlers +void LLIChildTarget::handleAllocateSpace() { + // Read and verify the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + assert(DataSize == 8); + + // Read the message arguments. + uint32_t Alignment; + uint32_t AllocSize; + rc = ReadBytes(&Alignment, 4); + assert(rc == 4); + rc = ReadBytes(&AllocSize, 4); + assert(rc == 4); + + // Allocate the memory. + uint64_t Addr = allocate(Alignment, AllocSize); + + // Send AllocationResult message. + sendAllocationResult(Addr); +} + +void LLIChildTarget::handleLoadSection(bool IsCode) { + // Read the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + + // Read the target load address. + uint64_t Addr; + rc = ReadBytes(&Addr, 8); + assert(rc == 8); + + size_t BufferSize = DataSize - 8; + + // FIXME: Verify that this is in allocated space + + // Read section data into previously allocated buffer + rc = ReadBytes((void*)Addr, DataSize - 8); + assert(rc == (int)(BufferSize)); + + // If IsCode, mark memory executable + if (IsCode) + makeSectionExecutable(Addr, BufferSize); + + // Send MarkLoadComplete message. + sendLoadComplete(); +} + +void LLIChildTarget::handleExecute() { + // Read the message data size. + uint32_t DataSize; + int rc = ReadBytes(&DataSize, 4); + assert(rc == 4); + assert(DataSize == 8); + + // Read the target address. + uint64_t Addr; + rc = ReadBytes(&Addr, 8); + assert(rc == 8); + + // Call function + int Result; + int (*fn)(void) = (int(*)(void))Addr; + Result = fn(); + + // Send ExecutionResult message. + sendExecutionComplete((int64_t)Result); +} + +void LLIChildTarget::handleTerminate() { + // Release all allocated memory + AllocMapType::iterator Begin = m_AllocatedBufferMap.begin(); + AllocMapType::iterator End = m_AllocatedBufferMap.end(); + for (AllocMapType::iterator It = Begin; It != End; ++It) { + releaseMemory(It->first, It->second); + } + m_AllocatedBufferMap.clear(); +} + +// Outgoing message handlers +void LLIChildTarget::sendChildActive() { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_ChildActive; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 0; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); +} + +void LLIChildTarget::sendAllocationResult(uint64_t Addr) { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_AllocationResult; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); + + // Write the allocated address. + rc = WriteBytes(&Addr, 8); + assert(rc == 8); +} + +void LLIChildTarget::sendLoadComplete() { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_LoadComplete; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + // Write the data size. + uint32_t DataSize = 0; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); +} + +void LLIChildTarget::sendExecutionComplete(uint64_t Result) { + // Write the message type. + uint32_t MsgType = (uint32_t)LLI_ExecutionResult; + int rc = WriteBytes(&MsgType, 4); + assert(rc == 4); + + + // Write the data size. + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4); + + // Write the result. + rc = WriteBytes(&Result, 8); + assert(rc == 8); +} + +#ifdef LLVM_ON_UNIX +#include "Unix/ChildTarget.inc" +#endif + +#ifdef LLVM_ON_WIN32 +#include "Windows/ChildTarget.inc" +#endif diff --git a/tools/llvm-prof/LLVMBuild.txt b/tools/lli/ChildTarget/LLVMBuild.txt index d59127c..daf6df1 100644 --- a/tools/llvm-prof/LLVMBuild.txt +++ b/tools/lli/ChildTarget/LLVMBuild.txt @@ -1,4 +1,4 @@ -;===- ./tools/llvm-prof/LLVMBuild.txt --------------------------*- Conf -*--===; +;===- ./tools/lli/ChildTarget/LLVMBuild.txt --------------------*- Conf -*--===; ; ; The LLVM Compiler Infrastructure ; @@ -17,6 +17,5 @@ [component_0] type = Tool -name = llvm-prof -parent = Tools -required_libraries = Analysis BitReader +name = lli-child-target +parent = lli diff --git a/tools/lli/ChildTarget/Makefile b/tools/lli/ChildTarget/Makefile new file mode 100644 index 0000000..f77b144 --- /dev/null +++ b/tools/lli/ChildTarget/Makefile @@ -0,0 +1,17 @@ +##===- tools/lli/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 := lli-child-target + +include $(LEVEL)/Makefile.config + +LINK_COMPONENTS := + +include $(LLVM_SRC_ROOT)/Makefile.rules diff --git a/tools/lli/ChildTarget/Unix/ChildTarget.inc b/tools/lli/ChildTarget/Unix/ChildTarget.inc new file mode 100644 index 0000000..cc95810 --- /dev/null +++ b/tools/lli/ChildTarget/Unix/ChildTarget.inc @@ -0,0 +1,166 @@ +//===- ChildTarget.inc - Child process for external JIT execution for Unix -==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the Unix-specific parts of the ChildTarget class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#ifdef __APPLE__ +#include <mach/mach.h> +#endif + +#if defined(__mips__) +# if defined(__OpenBSD__) +# include <mips64/sysarch.h> +# else +# include <sys/cachectl.h> +# endif +#endif + +#ifdef __APPLE__ +extern "C" void sys_icache_invalidate(const void *Addr, size_t len); +#else +extern "C" void __clear_cache(void *, void*); +#endif + +namespace { + +struct ConnectionData_t { + int InputPipe; + int OutputPipe; + + ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} +}; + +} // namespace + +LLIChildTarget::~LLIChildTarget() { + delete static_cast<ConnectionData_t *>(ConnectionData); +} + +// OS-specific methods +void LLIChildTarget::initializeConnection() { + // Store the parent ends of the pipes + ConnectionData = (void*)new ConnectionData_t(STDIN_FILENO, STDOUT_FILENO); +} + +int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { + return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +} + +int LLIChildTarget::ReadBytes(void *Data, size_t Size) { + return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +} + +// The functions below duplicate functionality that is implemented in +// Support/Memory.cpp with the goal of avoiding a dependency on any +// llvm libraries. + +uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { + if (!Alignment) + Alignment = 16; + + static const size_t PageSize = getpagesize(); + const size_t NumPages = (Size+PageSize-1)/PageSize; + Size = NumPages*PageSize; + + int fd = -1; +#ifdef NEED_DEV_ZERO_FOR_MMAP + static int zero_fd = open("/dev/zero", O_RDWR); + if (zero_fd == -1) + return 0; + fd = zero_fd; +#endif + + int MMFlags = MAP_PRIVATE | +#ifdef HAVE_MMAP_ANONYMOUS + MAP_ANONYMOUS +#else + MAP_ANON +#endif + ; // Ends statement above + + uint64_t Addr = (uint64_t)::mmap(0, Size, PROT_READ | PROT_WRITE, MMFlags, fd, 0); + if (Addr == (uint64_t)MAP_FAILED) + return 0; + + // Align the address. + Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); + + m_AllocatedBufferMap[Addr] = Size; + + // Return aligned address + return Addr; +} + +void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { + // FIXME: We have to mark the memory as RWX because multiple code chunks may + // be on the same page. The RemoteTarget interface should be changed to + // work around that. + int Result = ::mprotect((void*)Addr, Size, PROT_READ | PROT_WRITE | PROT_EXEC); + if (Result != 0) + InvalidateInstructionCache((const void *)Addr, Size); +} + +/// InvalidateInstructionCache - Before the JIT can run a block of code +/// that has been emitted it must invalidate the instruction cache on some +/// platforms. +void LLIChildTarget::InvalidateInstructionCache(const void *Addr, + size_t Len) { + +// icache invalidation for PPC and ARM. +#if defined(__APPLE__) + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) || defined(__arm__) + sys_icache_invalidate(const_cast<void *>(Addr), Len); +# endif + +#else + +# if (defined(__POWERPC__) || defined (__ppc__) || \ + defined(_POWER) || defined(_ARCH_PPC)) && defined(__GNUC__) + const size_t LineSize = 32; + + const intptr_t Mask = ~(LineSize - 1); + const intptr_t StartLine = ((intptr_t) Addr) & Mask; + const intptr_t EndLine = ((intptr_t) Addr + Len + LineSize - 1) & Mask; + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("dcbf 0, %0" : : "r"(Line)); + asm volatile("sync"); + + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +# elif defined(__arm__) && defined(__GNUC__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + const char *Start = static_cast<const char *>(Addr); + const char *End = Start + Len; + __clear_cache(const_cast<char *>(Start), const_cast<char *>(End)); +# elif defined(__mips__) + const char *Start = static_cast<const char *>(Addr); + cacheflush(const_cast<char *>(Start), Len, BCACHE); +# endif + +#endif // end apple +} + +void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { + ::munmap((void*)Addr, Size); +} diff --git a/tools/lli/ChildTarget/Windows/ChildTarget.inc b/tools/lli/ChildTarget/Windows/ChildTarget.inc new file mode 100644 index 0000000..45db2b0 --- /dev/null +++ b/tools/lli/ChildTarget/Windows/ChildTarget.inc @@ -0,0 +1,44 @@ +//=- ChildTarget.inc - Child process for external JIT execution for Windows -=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Non-implementation of the Windows-specific parts of the ChildTarget class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +LLIChildTarget::~LLIChildTarget() { +} + +// The RemoteTargetExternal implementation should prevent us from ever getting +// here on Windows, but nothing prevents a user from running this directly. +void LLIChildTarget::initializeConnection() { + assert(0 && "lli-child-target is not implemented for Windows"); +} + +int LLIChildTarget::WriteBytes(const void *Data, size_t Size) { + return 0; +} + +int LLIChildTarget::ReadBytes(void *Data, size_t Size) { + return 0; +} + +uint64_t LLIChildTarget::allocate(uint32_t Alignment, uint32_t Size) { + return 0; +} + +void LLIChildTarget::makeSectionExecutable(uint64_t Addr, uint32_t Size) { +} + +void LLIChildTarget::InvalidateInstructionCache(const void *Addr, + size_t Len) { +} + +void LLIChildTarget::releaseMemory(uint64_t Addr, uint32_t Size) { +} diff --git a/tools/lli/LLVMBuild.txt b/tools/lli/LLVMBuild.txt index c96a9e8..aab2a20 100644 --- a/tools/lli/LLVMBuild.txt +++ b/tools/lli/LLVMBuild.txt @@ -15,6 +15,9 @@ ; ;===------------------------------------------------------------------------===; +[common] +subdirectories = ChildTarget + [component_0] type = Tool name = lli diff --git a/tools/lli/Makefile b/tools/lli/Makefile index 7a40427..eca5d83 100644 --- a/tools/lli/Makefile +++ b/tools/lli/Makefile @@ -10,6 +10,8 @@ LEVEL := ../.. TOOLNAME := lli +PARALLEL_DIRS := ChildTarget + include $(LEVEL)/Makefile.config LINK_COMPONENTS := mcjit jit instrumentation interpreter nativecodegen bitreader asmparser irreader selectiondag native diff --git a/tools/lli/RecordingMemoryManager.cpp b/tools/lli/RecordingMemoryManager.cpp deleted file mode 100644 index 1fa8176..0000000 --- a/tools/lli/RecordingMemoryManager.cpp +++ /dev/null @@ -1,117 +0,0 @@ -//===- RecordingMemoryManager.cpp - Recording memory manager --------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#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, 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*)Block.base(); -} - -uint8_t *RecordingMemoryManager:: -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, 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*)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!"); } -void RecordingMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } -uint8_t *RecordingMemoryManager::getGOTBase() const { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd) { - llvm_unreachable("Unexpected!"); -} -uint8_t *RecordingMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -uint8_t *RecordingMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { - llvm_unreachable("Unexpected!"); - return 0; -} -void RecordingMemoryManager::deallocateFunctionBody(void *Body) { - 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 deleted file mode 100644 index b2919c3..0000000 --- a/tools/lli/RecordingMemoryManager.h +++ /dev/null @@ -1,82 +0,0 @@ -//===- RecordingMemoryManager.h - LLI MCJIT recording memory manager ------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This memory manager allocates local storage and keeps a record of each -// allocation. Iterators are provided for all data and code allocations. -// -//===----------------------------------------------------------------------===// - -#ifndef RECORDINGMEMORYMANAGER_H -#define RECORDINGMEMORYMANAGER_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ExecutionEngine/JITMemoryManager.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Memory.h" -#include <utility> - -namespace llvm { - -class RecordingMemoryManager : public JITMemoryManager { -public: - typedef std::pair<sys::MemoryBlock, unsigned> Allocation; - -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(); - - typedef SmallVectorImpl<Allocation>::const_iterator const_data_iterator; - typedef SmallVectorImpl<Allocation>::const_iterator const_code_iterator; - - const_data_iterator data_begin() const { return AllocatedDataMem.begin(); } - const_data_iterator data_end() const { return AllocatedDataMem.end(); } - const_code_iterator code_begin() const { return AllocatedCodeMem.begin(); } - const_code_iterator code_end() const { return AllocatedCodeMem.end(); } - - uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); - - uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); - - void *getPointerToNamedFunction(const std::string &Name, - bool AbortOnFailure = true); - - bool finalizeMemory(std::string *ErrMsg) { return false; } - - // The following obsolete JITMemoryManager calls are stubbed out for - // this model. - void setMemoryWritable(); - void setMemoryExecutable(); - void setPoisonMemory(bool poison); - void AllocateGOT(); - uint8_t *getGOTBase() const; - uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); - uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, - unsigned Alignment); - void endFunctionBody(const Function *F, uint8_t *FunctionStart, - uint8_t *FunctionEnd); - uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); - uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); - void deallocateFunctionBody(void *Body); -}; - -} // end namespace llvm - -#endif diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp new file mode 100644 index 0000000..04fc40e --- /dev/null +++ b/tools/lli/RemoteMemoryManager.cpp @@ -0,0 +1,206 @@ +//===---- RemoteMemoryManager.cpp - Recording memory manager --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "lli" +#include "RemoteMemoryManager.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/ObjectImage.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +RemoteMemoryManager::~RemoteMemoryManager() { + for (SmallVector<Allocation, 2>::iterator + I = AllocatedSections.begin(), E = AllocatedSections.end(); + I != E; ++I) + sys::Memory::releaseMappedMemory(I->MB); +} + +uint8_t *RemoteMemoryManager:: +allocateCodeSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName) { + // 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, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, true) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, true) ); + return (uint8_t*)Block.base(); +} + +uint8_t *RemoteMemoryManager:: +allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + 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, but we're using mapped memory to work + // around a bug in MCJIT. + sys::MemoryBlock Block = allocateSection(Size); + // AllocatedSections will own this memory. + AllocatedSections.push_back( Allocation(Block, Alignment, false) ); + // UnmappedSections has the same information but does not own the memory. + UnmappedSections.push_back( Allocation(Block, Alignment, false) ); + return (uint8_t*)Block.base(); +} + +sys::MemoryBlock RemoteMemoryManager::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 RemoteMemoryManager::notifyObjectLoaded(ExecutionEngine *EE, + const ObjectImage *Obj) { + // The client should have called setRemoteTarget() before triggering any + // code generation. + assert(Target); + if (!Target) + return; + + // FIXME: Make this function thread safe. + + // Lay out our sections in order, with all the code sections first, then + // all the data sections. + uint64_t CurOffset = 0; + unsigned MaxAlign = Target->getPageAlignment(); + SmallVector<std::pair<Allocation, uint64_t>, 16> Offsets; + unsigned NumSections = UnmappedSections.size(); + // We're going to go through the list twice to separate code and data, but + // it's a very small list, so that's OK. + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "code region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + // Adjust to keep code and data aligned on seperate pages. + CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; + for (size_t i = 0, e = NumSections; i != e; ++i) { + Allocation &Section = UnmappedSections[i]; + if (!Section.IsCode) { + unsigned Size = Section.MB.size(); + unsigned Align = Section.Alignment; + DEBUG(dbgs() << "data region: size " << Size + << ", alignment " << Align << "\n"); + // Align the current offset up to whatever is needed for the next + // section. + CurOffset = (CurOffset + Align - 1) / Align * Align; + // Save off the address of the new section and allocate its space. + Offsets.push_back(std::pair<Allocation,uint64_t>(Section, CurOffset)); + CurOffset += Size; + } + } + + // Allocate space in the remote target. + uint64_t RemoteAddr; + if (Target->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) + report_fatal_error(Target->getErrorMsg()); + + // Map the section addresses so relocations will get updated in the local + // copies of the sections. + for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { + uint64_t Addr = RemoteAddr + Offsets[i].second; + EE->mapSectionAddress(const_cast<void*>(Offsets[i].first.MB.base()), Addr); + + DEBUG(dbgs() << " Mapping local: " << Offsets[i].first.MB.base() + << " to remote: 0x" << format("%llx", Addr) << "\n"); + + MappedSections[Addr] = Offsets[i].first; + } + + UnmappedSections.clear(); +} + +bool RemoteMemoryManager::finalizeMemory(std::string *ErrMsg) { + // FIXME: Make this function thread safe. + for (DenseMap<uint64_t, Allocation>::iterator + I = MappedSections.begin(), E = MappedSections.end(); + I != E; ++I) { + uint64_t RemoteAddr = I->first; + const Allocation &Section = I->second; + if (Section.IsCode) { + Target->loadCode(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading code: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } else { + Target->loadData(RemoteAddr, Section.MB.base(), Section.MB.size()); + + DEBUG(dbgs() << " loading data: " << Section.MB.base() + << " to remote: 0x" << format("%llx", RemoteAddr) << "\n"); + } + } + + MappedSections.clear(); + + return false; +} + +void RemoteMemoryManager::setMemoryWritable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setMemoryExecutable() { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::setPoisonMemory(bool poison) { llvm_unreachable("Unexpected!"); } +void RemoteMemoryManager::AllocateGOT() { llvm_unreachable("Unexpected!"); } +uint8_t *RemoteMemoryManager::getGOTBase() const { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::startFunctionBody(const Function *F, uintptr_t &ActualSize){ + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd) { + llvm_unreachable("Unexpected!"); +} +uint8_t *RemoteMemoryManager::allocateSpace(intptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +uint8_t *RemoteMemoryManager::allocateGlobal(uintptr_t Size, unsigned Alignment) { + llvm_unreachable("Unexpected!"); + return 0; +} +void RemoteMemoryManager::deallocateFunctionBody(void *Body) { + llvm_unreachable("Unexpected!"); +} diff --git a/tools/lli/RemoteMemoryManager.h b/tools/lli/RemoteMemoryManager.h new file mode 100644 index 0000000..5d0456f --- /dev/null +++ b/tools/lli/RemoteMemoryManager.h @@ -0,0 +1,114 @@ +//===- RemoteMemoryManager.h - LLI MCJIT recording memory manager ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This memory manager allocates local storage and keeps a record of each +// allocation. Iterators are provided for all data and code allocations. +// +//===----------------------------------------------------------------------===// + +#ifndef REMOTEMEMORYMANAGER_H +#define REMOTEMEMORYMANAGER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ExecutionEngine/JITMemoryManager.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Memory.h" +#include <utility> + +#include "RemoteTarget.h" + +namespace llvm { + +class RemoteMemoryManager : public JITMemoryManager { +public: + // Notice that this structure takes ownership of the memory allocated. + struct Allocation { + Allocation() {} + Allocation(sys::MemoryBlock mb, unsigned a, bool code) + : MB(mb), Alignment(a), IsCode(code) {} + + sys::MemoryBlock MB; + unsigned Alignment; + bool IsCode; + }; + +private: + // This vector contains Allocation objects for all sections which we have + // allocated. This vector effectively owns the memory associated with the + // allocations. + SmallVector<Allocation, 2> AllocatedSections; + + // This vector contains pointers to Allocation objects for any sections we + // have allocated locally but have not yet remapped for the remote target. + // When we receive notification of a completed module load, we will map + // these sections into the remote target. + SmallVector<Allocation, 2> UnmappedSections; + + // This map tracks the sections we have remapped for the remote target + // but have not yet copied to the target. + DenseMap<uint64_t, Allocation> MappedSections; + + // 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); + + RemoteTarget *Target; + +public: + RemoteMemoryManager() : Target(NULL) {} + virtual ~RemoteMemoryManager(); + + uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName); + + uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); + + // For now, remote symbol resolution is not support in lli. The MCJIT + // interface does support this, but clients must provide their own + // mechanism for finding remote symbol addresses. MCJIT will resolve + // symbols from Modules it contains. + uint64_t getSymbolAddress(const std::string &Name) { return 0; } + + void notifyObjectLoaded(ExecutionEngine *EE, const ObjectImage *Obj); + + bool finalizeMemory(std::string *ErrMsg); + + // For now, remote EH frame registration isn't supported. Remote symbol + // resolution is a prerequisite to supporting remote EH frame registration. + void registerEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + void deregisterEHFrames(uint8_t *Addr, uint64_t LoadAddr, size_t Size) {} + + // This is a non-interface function used by lli + void setRemoteTarget(RemoteTarget *T) { Target = T; } + + // The following obsolete JITMemoryManager calls are stubbed out for + // this model. + void setMemoryWritable(); + void setMemoryExecutable(); + void setPoisonMemory(bool poison); + void AllocateGOT(); + uint8_t *getGOTBase() const; + uint8_t *startFunctionBody(const Function *F, uintptr_t &ActualSize); + uint8_t *allocateStub(const GlobalValue* F, unsigned StubSize, + unsigned Alignment); + void endFunctionBody(const Function *F, uint8_t *FunctionStart, + uint8_t *FunctionEnd); + uint8_t *allocateSpace(intptr_t Size, unsigned Alignment); + uint8_t *allocateGlobal(uintptr_t Size, unsigned Alignment); + void deallocateFunctionBody(void *Body); +}; + +} // end namespace llvm + +#endif diff --git a/tools/lli/RemoteTarget.cpp b/tools/lli/RemoteTarget.cpp index 212bdfd..5c74e6e 100644 --- a/tools/lli/RemoteTarget.cpp +++ b/tools/lli/RemoteTarget.cpp @@ -13,13 +13,44 @@ //===----------------------------------------------------------------------===// #include "RemoteTarget.h" +#include "RemoteTargetExternal.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Memory.h" #include <stdlib.h> #include <string> + using namespace llvm; +// Static methods +RemoteTarget *RemoteTarget::createRemoteTarget() { + return new RemoteTarget; +} + +RemoteTarget *RemoteTarget::createExternalRemoteTarget(std::string &ChildName) { +#ifdef LLVM_ON_UNIX + return new RemoteTargetExternal(ChildName); +#else + return 0; +#endif +} + +bool RemoteTarget::hostSupportsExternalRemoteTarget() { +#ifdef LLVM_ON_UNIX + return true; +#else + return false; +#endif +} + + +//////////////////////////////////////////////////////////////////////////////// +// Simulated remote execution +// +// This implementation will simply move generated code and data to a new memory +// location in the current executable and let it run from there. +//////////////////////////////////////////////////////////////////////////////// + bool RemoteTarget::allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address) { sys::MemoryBlock *Prev = Allocations.size() ? &Allocations.back() : NULL; diff --git a/tools/lli/RemoteTarget.h b/tools/lli/RemoteTarget.h index b2a6d0e..c95fbd1 100644 --- a/tools/lli/RemoteTarget.h +++ b/tools/lli/RemoteTarget.h @@ -41,7 +41,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool allocateSpace(size_t Size, unsigned Alignment, uint64_t &Address); + virtual bool allocateSpace(size_t Size, + unsigned Alignment, + uint64_t &Address); /// Load data into the target address space. /// @@ -51,7 +53,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool loadData(uint64_t Address, const void *Data, size_t Size); + virtual bool loadData(uint64_t Address, + const void *Data, + size_t Size); /// Load code into the target address space and prepare it for execution. /// @@ -61,7 +65,9 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool loadCode(uint64_t Address, const void *Data, size_t Size); + virtual bool loadCode(uint64_t Address, + const void *Data, + size_t Size); /// Execute code in the target process. The called function is required /// to be of signature int "(*)(void)". @@ -72,24 +78,29 @@ public: /// /// @returns False on success. On failure, ErrorMsg is updated with /// descriptive text of the encountered error. - bool executeCode(uint64_t Address, int &RetVal); + virtual bool executeCode(uint64_t Address, + int &RetVal); /// Minimum alignment for memory permissions. Used to seperate code and /// data regions to make sure data doesn't get marked as code or vice /// versa. /// /// @returns Page alignment return value. Default of 4k. - unsigned getPageAlignment() { return 4096; } + virtual unsigned getPageAlignment() { return 4096; } /// Start the remote process. - void create(); + virtual void create(); /// Terminate the remote process. - void stop(); + virtual void stop(); RemoteTarget() : ErrorMsg(""), IsRunning(false) {} - ~RemoteTarget() { if (IsRunning) stop(); } + virtual ~RemoteTarget() { if (IsRunning) stop(); } + // Create an instance of the system-specific remote target class. + static RemoteTarget *createRemoteTarget(); + static RemoteTarget *createExternalRemoteTarget(std::string &ChildName); + static bool hostSupportsExternalRemoteTarget(); private: // Main processing function for the remote target process. Command messages // are received on file descriptor CmdFD and responses come back on OutFD. diff --git a/tools/lli/RemoteTargetExternal.cpp b/tools/lli/RemoteTargetExternal.cpp new file mode 100644 index 0000000..742a948 --- /dev/null +++ b/tools/lli/RemoteTargetExternal.cpp @@ -0,0 +1,162 @@ +//===---- RemoteTargetExternal.cpp - LLVM out-of-process JIT execution ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the RemoteTargetExternal class which executes JITed code +// in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Config/config.h" + +#include "RemoteTarget.h" +#include "RemoteTargetExternal.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Memory.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +using namespace llvm; + +bool RemoteTargetExternal::allocateSpace(size_t Size, unsigned Alignment, + uint64_t &Address) { + SendAllocateSpace(Alignment, Size); + Receive(LLI_AllocationResult, Address); + return false; +} + +bool RemoteTargetExternal::loadData(uint64_t Address, const void *Data, size_t Size) { + SendLoadSection(Address, Data, (uint32_t)Size, false); + Receive(LLI_LoadComplete); + return false; +} + +bool RemoteTargetExternal::loadCode(uint64_t Address, const void *Data, size_t Size) { + SendLoadSection(Address, Data, (uint32_t)Size, true); + Receive(LLI_LoadComplete); + return false; +} + +bool RemoteTargetExternal::executeCode(uint64_t Address, int &RetVal) { + SendExecute(Address); + + Receive(LLI_ExecutionResult, RetVal); + return false; +} + +void RemoteTargetExternal::stop() { + SendTerminate(); + Wait(); +} + +void RemoteTargetExternal::SendAllocateSpace(uint32_t Alignment, uint32_t Size) { + int rc; + uint32_t MsgType = (uint32_t)LLI_AllocateSpace; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Alignment, 4); + assert(rc == 4 && "Error writing alignment data."); + + rc = WriteBytes(&Size, 4); + assert(rc == 4 && "Error writing size data."); +} + +void RemoteTargetExternal::SendLoadSection(uint64_t Addr, + const void *Data, + uint32_t Size, + bool IsCode) { + int rc; + uint32_t MsgType = IsCode ? LLI_LoadCodeSection : LLI_LoadDataSection; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = Size + 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Addr, 8); + assert(rc == 8 && "Error writing data."); + + rc = WriteBytes(Data, Size); + assert(rc == (int)Size && "Error writing data."); +} + +void RemoteTargetExternal::SendExecute(uint64_t Addr) { + int rc; + uint32_t MsgType = (uint32_t)LLI_Execute; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + uint32_t DataSize = 8; + rc = WriteBytes(&DataSize, 4); + assert(rc == 4 && "Error writing data size."); + + rc = WriteBytes(&Addr, 8); + assert(rc == 8 && "Error writing data."); +} + +void RemoteTargetExternal::SendTerminate() { + int rc; + uint32_t MsgType = (uint32_t)LLI_Terminate; + rc = WriteBytes(&MsgType, 4); + assert(rc == 4 && "Error writing message type."); + + // No data or data size is sent with Terminate +} + + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType) { + int rc; + uint32_t MsgType; + rc = ReadBytes(&MsgType, 4); + assert(rc == 4 && "Error reading message type."); + assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + + uint32_t DataSize; + rc = ReadBytes(&DataSize, 4); + assert(rc == 4 && "Error reading data size."); + assert(DataSize == 0 && "Error: unexpected data size."); +} + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, int &Data) { + uint64_t Temp; + Receive(ExpectedMsgType, Temp); + Data = (int)(int64_t)Temp; +} + +void RemoteTargetExternal::Receive(LLIMessageType ExpectedMsgType, uint64_t &Data) { + int rc; + uint32_t MsgType; + rc = ReadBytes(&MsgType, 4); + assert(rc == 4 && "Error reading message type."); + assert(MsgType == (uint32_t)ExpectedMsgType && "Error: received unexpected message type."); + + uint32_t DataSize; + rc = ReadBytes(&DataSize, 4); + assert(rc == 4 && "Error reading data size."); + assert(DataSize == 8 && "Error: unexpected data size."); + + rc = ReadBytes(&Data, 8); + assert(DataSize == 8 && "Error: unexpected data."); +} + +#ifdef LLVM_ON_UNIX +#include "Unix/RemoteTargetExternal.inc" +#endif + +#ifdef LLVM_ON_WIN32 +#include "Windows/RemoteTargetExternal.inc" +#endif diff --git a/tools/lli/RemoteTargetExternal.h b/tools/lli/RemoteTargetExternal.h new file mode 100644 index 0000000..a4bfad2 --- /dev/null +++ b/tools/lli/RemoteTargetExternal.h @@ -0,0 +1,118 @@ +//===----- RemoteTargetExternal.h - LLVM out-of-process JIT execution -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the RemoteTargetExternal class which executes JITed code in a +// separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#ifndef LLI_REMOTETARGETEXTERNAL_H +#define LLI_REMOTETARGETEXTERNAL_H + +#include "llvm/Config/config.h" + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Memory.h" +#include <stdlib.h> +#include <string> + +#include "RemoteTarget.h" +#include "RemoteTargetMessage.h" + +namespace llvm { + +class RemoteTargetExternal : public RemoteTarget { +public: + /// Allocate space in the remote target address space. + /// + /// @param Size Amount of space, in bytes, to allocate. + /// @param Alignment Required minimum alignment for allocated space. + /// @param[out] Address Remote address of the allocated memory. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool allocateSpace(size_t Size, + unsigned Alignment, + uint64_t &Address); + + /// Load data into the target address space. + /// + /// @param Address Destination address in the target process. + /// @param Data Source address in the host process. + /// @param Size Number of bytes to copy. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool loadData(uint64_t Address, const void *Data, size_t Size); + + /// Load code into the target address space and prepare it for execution. + /// + /// @param Address Destination address in the target process. + /// @param Data Source address in the host process. + /// @param Size Number of bytes to copy. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool loadCode(uint64_t Address, const void *Data, size_t Size); + + /// Execute code in the target process. The called function is required + /// to be of signature int "(*)(void)". + /// + /// @param Address Address of the loaded function in the target + /// process. + /// @param[out] RetVal The integer return value of the called function. + /// + /// @returns False on success. On failure, ErrorMsg is updated with + /// descriptive text of the encountered error. + virtual bool executeCode(uint64_t Address, int &RetVal); + + /// Minimum alignment for memory permissions. Used to seperate code and + /// data regions to make sure data doesn't get marked as code or vice + /// versa. + /// + /// @returns Page alignment return value. Default of 4k. + virtual unsigned getPageAlignment() { return 4096; } + + /// Start the remote process. + virtual void create(); + + /// Terminate the remote process. + virtual void stop(); + + RemoteTargetExternal(std::string &Name) : RemoteTarget(), ChildName(Name) {} + virtual ~RemoteTargetExternal(); + +private: + std::string ChildName; + + // This will get filled in as a point to an OS-specific structure. + void *ConnectionData; + + void SendAllocateSpace(uint32_t Alignment, uint32_t Size); + void SendLoadSection(uint64_t Addr, + const void *Data, + uint32_t Size, + bool IsCode); + void SendExecute(uint64_t Addr); + void SendTerminate(); + + void Receive(LLIMessageType Msg); + void Receive(LLIMessageType Msg, int &Data); + void Receive(LLIMessageType Msg, uint64_t &Data); + + int WriteBytes(const void *Data, size_t Size); + int ReadBytes(void *Data, size_t Size); + void Wait(); +}; + +} // end namespace llvm + +#endif // LLI_REMOTETARGETEXTERNAL_H diff --git a/tools/lli/RemoteTargetMessage.h b/tools/lli/RemoteTargetMessage.h new file mode 100644 index 0000000..12cfa9a --- /dev/null +++ b/tools/lli/RemoteTargetMessage.h @@ -0,0 +1,45 @@ +//===---- RemoteTargetMessage.h - LLI out-of-process message protocol -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the LLIMessageType enum which is used for communication with a +// child process for remote execution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLI_REMOTETARGETMESSAGE_H +#define LLI_REMOTETARGETMESSAGE_H + +namespace llvm { + +// LLI messages from parent-to-child or vice versa follow an exceedingly simple +// protocol where the first four bytes represent the message type, the next +// four bytes represent the size of data for the command and following bytes +// represent the actual data. +// +// The protocol is not intended to be robust, secure or fault-tolerant. It is +// only here for testing purposes and is therefore intended to be the simplest +// implementation that will work. It is assumed that the parent and child +// share characteristics like endianness. + +enum LLIMessageType { + LLI_Error = -1, + LLI_ChildActive = 0, // Data = not used + LLI_AllocateSpace, // Data = struct { uint_32t Align, uint_32t Size } + LLI_AllocationResult, // Data = uint64_t AllocAddress (in Child memory space) + LLI_LoadCodeSection, // Data = uint32_t Addr, followed by section contests + LLI_LoadDataSection, // Data = uint32_t Addr, followed by section contents + LLI_LoadComplete, // Data = not used + LLI_Execute, // Data = Address of function to execute + LLI_ExecutionResult, // Data = uint64_t Result + LLI_Terminate // Data = not used +}; + +} // end namespace llvm + +#endif diff --git a/tools/lli/Unix/RemoteTargetExternal.inc b/tools/lli/Unix/RemoteTargetExternal.inc new file mode 100644 index 0000000..9c1a4cc --- /dev/null +++ b/tools/lli/Unix/RemoteTargetExternal.inc @@ -0,0 +1,96 @@ +//=- RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Unix --=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of the Unix-specific parts of the RemoteTargetExternal class +// which executes JITed code in a separate process from where it was built. +// +//===----------------------------------------------------------------------===// + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> + +namespace { + +struct ConnectionData_t { + int InputPipe; + int OutputPipe; + + ConnectionData_t(int in, int out) : InputPipe(in), OutputPipe(out) {} +}; + +} // namespace + +namespace llvm { + +void RemoteTargetExternal::create() { + int PipeFD[2][2]; + pid_t ChildPID; + + // Create two pipes. + if (pipe(PipeFD[0]) != 0 || pipe(PipeFD[1]) != 0) + perror("Error creating pipe: "); + + ChildPID = fork(); + + if (ChildPID == 0) { + // In the child... + + // Close the parent ends of the pipes + close(PipeFD[0][1]); + close(PipeFD[1][0]); + + // Use our pipes as stdin and stdout + if (PipeFD[0][0] != STDIN_FILENO) { + dup2(PipeFD[0][0], STDIN_FILENO); + close(PipeFD[0][0]); + } + if (PipeFD[1][1] != STDOUT_FILENO) { + dup2(PipeFD[1][1], STDOUT_FILENO); + close(PipeFD[1][1]); + } + + // Execute the child process. + char *args[1] = { NULL }; + int rc = execv(ChildName.c_str(), args); + if (rc != 0) + perror("Error executing child process: "); + } + else { + // In the parent... + + // Close the child ends of the pipes + close(PipeFD[0][0]); + close(PipeFD[1][1]); + + // Store the parent ends of the pipes + ConnectionData = (void*)new ConnectionData_t(PipeFD[1][0], PipeFD[0][1]); + + Receive(LLI_ChildActive); + } +} + +int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { + return write(((ConnectionData_t*)ConnectionData)->OutputPipe, Data, Size); +} + +int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { + return read(((ConnectionData_t*)ConnectionData)->InputPipe, Data, Size); +} + +void RemoteTargetExternal::Wait() { + wait(NULL); +} + +RemoteTargetExternal::~RemoteTargetExternal() { + delete static_cast<ConnectionData_t *>(ConnectionData); +} + +} // namespace llvm diff --git a/tools/lli/Windows/RemoteTargetExternal.inc b/tools/lli/Windows/RemoteTargetExternal.inc new file mode 100644 index 0000000..aef4627 --- /dev/null +++ b/tools/lli/Windows/RemoteTargetExternal.inc @@ -0,0 +1,35 @@ +//= RemoteTargetExternal.inc - LLVM out-of-process JIT execution for Windows =// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definition of the Windows-specific parts of the RemoteTargetExternal class +// which is meant to execute JITed code in a separate process from where it was +// built. To support this functionality on Windows, implement these functions. +// +//===----------------------------------------------------------------------===// + +namespace llvm { + +void RemoteTargetExternal::create() { +} + +int RemoteTargetExternal::WriteBytes(const void *Data, size_t Size) { + return 0; +} + +int RemoteTargetExternal::ReadBytes(void *Data, size_t Size) { + return 0; +} + +void RemoteTargetExternal::Wait() { +} + +RemoteTargetExternal::~RemoteTargetExternal() { +} + +} // namespace llvm diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 8d74b23..f317566 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -15,7 +15,7 @@ #define DEBUG_TYPE "lli" #include "llvm/IR/LLVMContext.h" -#include "RecordingMemoryManager.h" +#include "RemoteMemoryManager.h" #include "RemoteTarget.h" #include "llvm/ADT/Triple.h" #include "llvm/Bitcode/ReaderWriter.h" @@ -27,8 +27,10 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Module.h" #include "llvm/IR/Type.h" +#include "llvm/IR/TypeBuilder.h" #include "llvm/IRReader/IRReader.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -41,6 +43,7 @@ #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetSelect.h" @@ -83,6 +86,18 @@ namespace { cl::desc("Execute MCJIT'ed code in a separate process."), cl::init(false)); + // Manually specify the child process for remote execution. This overrides + // the simulated remote execution that allocates address space for child + // execution. The child process will be executed and will communicate with + // lli via stdin/stdout pipes. + cl::opt<std::string> + MCJITRemoteProcess("mcjit-remote-process", + cl::desc("Specify the filename of the process to launch " + "for remote MCJIT execution. If none is specified," + "\n\tremote execution will be simulated in-process."), + cl::value_desc("filename"), + cl::init("")); + // Determine optimization level. cl::opt<char> OptLevel("O", @@ -118,6 +133,11 @@ namespace { cl::value_desc("function"), cl::init("main")); + cl::list<std::string> + ExtraModules("extra-module", + cl::desc("Extra modules to be loaded"), + cl::value_desc("input bitcode")); + cl::opt<std::string> FakeArgv0("fake-argv0", cl::desc("Override the 'argv[0]' value passed into the executing" @@ -209,82 +229,46 @@ static void do_shutdown() { #endif } -void layoutRemoteTargetMemory(RemoteTarget *T, RecordingMemoryManager *JMM) { - // Lay out our sections in order, with all the code sections first, then - // all the data sections. - uint64_t CurOffset = 0; - unsigned MaxAlign = T->getPageAlignment(); - SmallVector<std::pair<const void*, uint64_t>, 16> Offsets; - SmallVector<unsigned, 16> Sizes; - for (RecordingMemoryManager::const_code_iterator I = JMM->code_begin(), - E = JMM->code_end(); - I != E; ++I) { - DEBUG(dbgs() << "code region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - // Adjust to keep code and data aligned on seperate pages. - CurOffset = (CurOffset + MaxAlign - 1) / MaxAlign * MaxAlign; - unsigned FirstDataIndex = Offsets.size(); - for (RecordingMemoryManager::const_data_iterator I = JMM->data_begin(), - E = JMM->data_end(); - I != E; ++I) { - DEBUG(dbgs() << "data region: size " << I->first.size() - << ", alignment " << I->second << "\n"); - // Align the current offset up to whatever is needed for the next - // section. - unsigned Align = I->second; - CurOffset = (CurOffset + Align - 1) / Align * Align; - // Save off the address of the new section and allocate its space. - Offsets.push_back(std::pair<const void*,uint64_t>(I->first.base(), CurOffset)); - Sizes.push_back(I->first.size()); - CurOffset += I->first.size(); - } - - // Allocate space in the remote target. - uint64_t RemoteAddr; - if (T->allocateSpace(CurOffset, MaxAlign, RemoteAddr)) - report_fatal_error(T->getErrorMsg()); - // Map the section addresses so relocations will get updated in the local - // copies of the sections. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - EE->mapSectionAddress(const_cast<void*>(Offsets[i].first), Addr); - - DEBUG(dbgs() << " Mapping local: " << Offsets[i].first - << " to remote: 0x" << format("%llx", Addr) << "\n"); - - } - - // Trigger application of relocations - EE->finalizeObject(); - - // Now load it all to the target. - for (unsigned i = 0, e = Offsets.size(); i != e; ++i) { - uint64_t Addr = RemoteAddr + Offsets[i].second; - - if (i < FirstDataIndex) { - T->loadCode(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading code: " << Offsets[i].first - << " to remote: 0x" << format("%llx", Addr) << "\n"); - } else { - T->loadData(Addr, Offsets[i].first, Sizes[i]); - - DEBUG(dbgs() << " loading data: " << Offsets[i].first - << " to remote: 0x" << format("%llx", Addr) << "\n"); - } - +// On Mingw and Cygwin, an external symbol named '__main' is called from the +// generated 'main' function to allow static intialization. To avoid linking +// problems with remote targets (because lli's remote target support does not +// currently handle external linking) we add a secondary module which defines +// an empty '__main' function. +static void addCygMingExtraModule(ExecutionEngine *EE, + LLVMContext &Context, + StringRef TargetTripleStr) { + IRBuilder<> Builder(Context); + Triple TargetTriple(TargetTripleStr); + + // Create a new module. + Module *M = new Module("CygMingHelper", Context); + M->setTargetTriple(TargetTripleStr); + + // Create an empty function named "__main". + Function *Result; + if (TargetTriple.isArch64Bit()) { + Result = Function::Create( + TypeBuilder<int64_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); + } else { + Result = Function::Create( + TypeBuilder<int32_t(void), false>::get(Context), + GlobalValue::ExternalLinkage, "__main", M); } + BasicBlock *BB = BasicBlock::Create(Context, "__main", Result); + Builder.SetInsertPoint(BB); + Value *ReturnVal; + if (TargetTriple.isArch64Bit()) + ReturnVal = ConstantInt::get(Context, APInt(64, 0)); + else + ReturnVal = ConstantInt::get(Context, APInt(32, 0)); + Builder.CreateRet(ReturnVal); + + // Add this new module to the ExecutionEngine. + EE->addModule(M); } + //===----------------------------------------------------------------------===// // main Driver function // @@ -357,7 +341,7 @@ int main(int argc, char **argv, char * const *envp) { if (UseMCJIT && !ForceInterpreter) { builder.setUseMCJIT(true); if (RemoteMCJIT) - RTDyldMM = new RecordingMemoryManager(); + RTDyldMM = new RemoteMemoryManager(); else RTDyldMM = new SectionMemoryManager(); builder.setMCJITMemoryManager(RTDyldMM); @@ -407,6 +391,22 @@ int main(int argc, char **argv, char * const *envp) { exit(1); } + // Load any additional modules specified on the command line. + for (unsigned i = 0, e = ExtraModules.size(); i != e; ++i) { + Module *XMod = ParseIRFile(ExtraModules[i], Err, Context); + if (!XMod) { + Err.print(argv[0], errs()); + return 1; + } + EE->addModule(XMod); + } + + // If the target is Cygwin/MingW and we are generating remote code, we + // need an extra module to help out with linking. + if (RemoteMCJIT && Triple(Mod->getTargetTriple()).isOSCygMing()) { + addCygMingExtraModule(EE, Context, Mod->getTargetTriple()); + } + // The following functions have no effect if their respective profiling // support wasn't enabled in the build configuration. EE->RegisterJITEventListener( @@ -445,68 +445,33 @@ int main(int argc, char **argv, char * const *envp) { return -1; } - // If the program doesn't explicitly call exit, we will need the Exit - // function later on to make an explicit call, so get the function now. - Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), - Type::getInt32Ty(Context), - NULL); - // Reset errno to zero on entry to main. errno = 0; - // Remote target MCJIT doesn't (yet) support static constructors. No reason - // it couldn't. This is a limitation of the LLI implemantation, not the - // MCJIT itself. FIXME. - // - // Run static constructors. - 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) { - Function *Fn = &*I; - if (Fn != EntryFn && !Fn->isDeclaration()) - EE->getPointerToFunction(Fn); - } - } - int Result; - if (RemoteMCJIT) { - RecordingMemoryManager *MM = static_cast<RecordingMemoryManager*>(RTDyldMM); - // Everything is prepared now, so lay out our program for the target - // address space, assign the section addresses to resolve any relocations, - // and send it to the target. - RemoteTarget Target; - Target.create(); - - // Ask for a pointer to the entry function. This triggers the actual - // compilation. - (void)EE->getPointerToFunction(EntryFn); - // Enough has been compiled to execute the entry function now, so - // layout the target memory. - layoutRemoteTargetMemory(&Target, MM); - - // Since we're executing in a (at least simulated) remote address space, - // we can't use the ExecutionEngine::runFunctionAsMain(). We have to - // grab the function address directly here and tell the remote target - // to execute the function. - // FIXME: argv and envp handling. - uint64_t Entry = (uint64_t)EE->getPointerToFunction(EntryFn); - - DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" - << format("%llx", Entry) << "\n"); + if (!RemoteMCJIT) { + // If the program doesn't explicitly call exit, we will need the Exit + // function later on to make an explicit call, so get the function now. + Constant *Exit = Mod->getOrInsertFunction("exit", Type::getVoidTy(Context), + Type::getInt32Ty(Context), + NULL); + + // Run static constructors. + if (UseMCJIT && !ForceInterpreter) { + // Give MCJIT a chance to apply relocations and set page permissions. + EE->finalizeObject(); + } + EE->runStaticConstructorsDestructors(false); - if (Target.executeCode(Entry, Result)) - errs() << "ERROR: " << Target.getErrorMsg() << "\n"; + if (!UseMCJIT && NoLazyCompilation) { + for (Module::iterator I = Mod->begin(), E = Mod->end(); I != E; ++I) { + Function *Fn = &*I; + if (Fn != EntryFn && !Fn->isDeclaration()) + EE->getPointerToFunction(Fn); + } + } - Target.stop(); - } else { // Trigger compilation separately so code regions that need to be // invalidated will be known. (void)EE->getPointerToFunction(EntryFn); @@ -516,11 +481,7 @@ int main(int argc, char **argv, char * const *envp) { // Run main. Result = EE->runFunctionAsMain(EntryFn, InputArgv, envp); - } - // Like static constructors, the remote target MCJIT support doesn't handle - // this yet. It could. FIXME. - if (!RemoteMCJIT) { // Run static destructors. EE->runStaticConstructorsDestructors(true); @@ -538,6 +499,67 @@ int main(int argc, char **argv, char * const *envp) { errs() << "ERROR: exit defined with wrong prototype!\n"; abort(); } + } else { + // else == "if (RemoteMCJIT)" + + // Remote target MCJIT doesn't (yet) support static constructors. No reason + // it couldn't. This is a limitation of the LLI implemantation, not the + // MCJIT itself. FIXME. + // + RemoteMemoryManager *MM = static_cast<RemoteMemoryManager*>(RTDyldMM); + // Everything is prepared now, so lay out our program for the target + // address space, assign the section addresses to resolve any relocations, + // and send it to the target. + + OwningPtr<RemoteTarget> Target; + if (!MCJITRemoteProcess.empty()) { // Remote execution on a child process + if (!RemoteTarget::hostSupportsExternalRemoteTarget()) { + errs() << "Warning: host does not support external remote targets.\n" + << " Defaulting to simulated remote execution\n"; + Target.reset(RemoteTarget::createRemoteTarget()); + } else { + std::string ChildEXE = sys::FindProgramByName(MCJITRemoteProcess); + if (ChildEXE == "") { + errs() << "Unable to find child target: '\''" << MCJITRemoteProcess << "\'\n"; + return -1; + } + Target.reset(RemoteTarget::createExternalRemoteTarget(ChildEXE)); + } + } else { + // No child process name provided, use simulated remote execution. + Target.reset(RemoteTarget::createRemoteTarget()); + } + + // Give the memory manager a pointer to our remote target interface object. + MM->setRemoteTarget(Target.get()); + + // Create the remote target. + Target->create(); + + // Since we're executing in a (at least simulated) remote address space, + // we can't use the ExecutionEngine::runFunctionAsMain(). We have to + // grab the function address directly here and tell the remote target + // to execute the function. + // + // Our memory manager will map generated code into the remote address + // space as it is loaded and copy the bits over during the finalizeMemory + // operation. + // + // FIXME: argv and envp handling. + uint64_t Entry = EE->getFunctionAddress(EntryFn->getName().str()); + + DEBUG(dbgs() << "Executing '" << EntryFn->getName() << "' at 0x" + << format("%llx", Entry) << "\n"); + + if (Target->executeCode(Entry, Result)) + errs() << "ERROR: " << Target->getErrorMsg() << "\n"; + + // Like static constructors, the remote target MCJIT support doesn't handle + // this yet. It could. FIXME. + + // Stop the remote target + Target->stop(); } + return Result; } diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 503999c..f15a1e2 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -4,4 +4,22 @@ add_llvm_tool(llvm-ar llvm-ar.cpp ) +# FIXME: this is duplicated from the clang CMakeLists.txt +# FIXME: bin/llvm-ranlib is not a valid build target with this setup (pr17024) + +if(UNIX) + set(LLVM_LINK_OR_COPY create_symlink) + set(llvm_ar_binary "llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") +else() + set(LLVM_LINK_OR_COPY copy) + set(llvm_ar_binary "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ar${CMAKE_EXECUTABLE_SUFFIX}") +endif() + +set(llvm_ranlib "${LLVM_BINARY_DIR}/bin/${CMAKE_CFG_INTDIR}/llvm-ranlib${CMAKE_EXECUTABLE_SUFFIX}") +add_custom_command(TARGET llvm-ar POST_BUILD + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_ranlib}") + +set_property(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${llvm_ranlib}) + # TODO: Support check-local. diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile index 15fb090..16a8283 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -9,6 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-ar +TOOLALIAS = llvm-ranlib LINK_COMPONENTS := bitreader support object # This tool has no plugins, optimize startup time. diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 6026fa7..d70db72 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -63,20 +63,13 @@ static void failIfError(error_code EC, Twine Context = "") { fail(Context + ": " + EC.message()); } -// Option for compatibility with AIX, not used but must allow it to be present. -static cl::opt<bool> -X32Option ("X32_64", cl::Hidden, - cl::desc("Ignored option for compatibility with AIX")); - -// llvm-ar operation code and modifier flags. This must come first. -static cl::opt<std::string> -Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]...")); - -// llvm-ar remaining positional arguments. +// llvm-ar/llvm-ranlib remaining positional arguments. static cl::list<std::string> RestOfArgs(cl::Positional, cl::OneOrMore, cl::desc("[relpos] [count] <archive-file> [members]...")); +std::string Options; + // MoreHelp - Provide additional help output explaining the operations and // modifiers of llvm-ar. This object instructs the CommandLine library // to print the text of the constructor when the --help option is given. @@ -156,6 +149,13 @@ static void getRelPos() { RestOfArgs.erase(RestOfArgs.begin()); } +static void getOptions() { + if(RestOfArgs.size() == 0) + show_help("Expected options"); + Options = RestOfArgs[0]; + RestOfArgs.erase(RestOfArgs.begin()); +} + // getArchive - Get the archive file name from the command line static void getArchive() { if(RestOfArgs.size() == 0) @@ -175,6 +175,7 @@ static void getMembers() { // operation specified. Process all modifiers and check to make sure that // constraints on modifier/operation pairs have not been violated. static ArchiveOperation parseCommandLine() { + getOptions(); // Keep track of number of operations. We can only specify one // per execution. @@ -781,6 +782,13 @@ static void performWriteOperation(ArchiveOperation Operation, sys::fs::file_status Status; failIfError(sys::fs::status(FD, Status), FileName); + // Opening a directory doesn't make sense. Let it failed. + // Linux cannot open directories with open(2), although + // cygwin and *bsd can. + if (Status.type() == sys::fs::file_type::directory_file) + failIfError(error_code(errc::is_a_directory, posix_category()), + FileName); + OwningPtr<MemoryBuffer> File; failIfError(MemoryBuffer::getOpenFile(FD, FileName, File, Status.getSize(), false), @@ -857,6 +865,9 @@ static void performOperation(ArchiveOperation Operation, llvm_unreachable("Unknown operation."); } +static int ar_main(char **argv); +static int ranlib_main(); + // main - main program for llvm-ar .. see comments in the code int main(int argc, char **argv) { ToolName = argv[0]; @@ -872,15 +883,36 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); + StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("ar") != StringRef::npos) + return ar_main(argv); + if (Stem.find("ranlib") != StringRef::npos) + return ranlib_main(); + fail("Not ranlib or ar!"); +} + +static int performOperation(ArchiveOperation Operation); + +int ranlib_main() { + if (RestOfArgs.size() != 1) + fail(ToolName + "takes just one archive as argument"); + ArchiveName = RestOfArgs[0]; + return performOperation(CreateSymTab); +} + +int ar_main(char **argv) { // Do our own parsing of the command line because the CommandLine utility // can't handle the grouped positional parameters without a dash. ArchiveOperation Operation = parseCommandLine(); + return performOperation(Operation); +} +static int performOperation(ArchiveOperation Operation) { // Create or open the archive object. OwningPtr<MemoryBuffer> Buf; error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); if (EC && EC != llvm::errc::no_such_file_or_directory) { - errs() << argv[0] << ": error opening '" << ArchiveName + errs() << ToolName << ": error opening '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } @@ -889,7 +921,7 @@ int main(int argc, char **argv) { object::Archive Archive(Buf.take(), EC); if (EC) { - errs() << argv[0] << ": error loading '" << ArchiveName + errs() << ToolName << ": error loading '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } @@ -904,7 +936,7 @@ int main(int argc, char **argv) { } else { if (!Create) { // Produce a warning if we should and we're creating the archive - errs() << argv[0] << ": creating " << ArchiveName << "\n"; + errs() << ToolName << ": creating " << ArchiveName << "\n"; } } diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index 186eea9..da40da2 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" #include <algorithm> +#include <cctype> #include <map> using namespace llvm; diff --git a/tools/llvm-c-test/CMakeLists.txt b/tools/llvm-c-test/CMakeLists.txt new file mode 100644 index 0000000..2926d9d --- /dev/null +++ b/tools/llvm-c-test/CMakeLists.txt @@ -0,0 +1,16 @@ +set(LLVM_LINK_COMPONENTS all) + +if (LLVM_COMPILER_IS_GCC_COMPATIBLE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wstrict-prototypes") +endif () + +add_llvm_tool(llvm-c-test + calc.c + disassemble.c + helpers.c + include-all.c + main.c + module.c + object.c + targets.c + ) diff --git a/tools/llvm-c-test/Makefile b/tools/llvm-c-test/Makefile new file mode 100644 index 0000000..08be7c3 --- /dev/null +++ b/tools/llvm-c-test/Makefile @@ -0,0 +1,29 @@ +##===- tools/llvm-c-test -----------------------------------*- 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-c-test + +TOOL_NO_EXPORTS = 1 +NO_INSTALL = 1 + + +# If there is no shared lib, link all components... +ifneq ($(ENABLE_SHARED),1) +LINK_COMPONENTS = all +endif + +include $(LEVEL)/Makefile.common + +CFLAGS += -std=c99 -Wall -Wstrict-prototypes + +# ...but if it is built - use it +ifeq ($(ENABLE_SHARED),1) +LIBS = -lLLVM-$(LLVMVersion) +endif diff --git a/tools/llvm-c-test/calc.c b/tools/llvm-c-test/calc.c new file mode 100644 index 0000000..3119ccf --- /dev/null +++ b/tools/llvm-c-test/calc.c @@ -0,0 +1,148 @@ +/*===-- calc.c - tool for testing libLLVM and llvm-c API ------------------===*\ +|* *| +|* 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 --calc command in llvm-c-test. --calc reads lines *| +|* from stdin, parses them as a name and an expression in reverse polish *| +|* notation and prints a module with a function with the expression. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +typedef LLVMValueRef (*binop_func_t)(LLVMBuilderRef, LLVMValueRef LHS, + LLVMValueRef RHS, const char *Name); + +static LLVMOpcode op_to_opcode(char op) { + switch (op) { + case '+': return LLVMAdd; + case '-': return LLVMSub; + case '*': return LLVMMul; + case '/': return LLVMSDiv; + case '&': return LLVMAnd; + case '|': return LLVMOr; + case '^': return LLVMXor; + } + assert(0 && "unknown operation"); + return 0; +} + +#define MAX_DEPTH 32 + +static LLVMValueRef build_from_tokens(char **tokens, int ntokens, + LLVMBuilderRef builder, + LLVMValueRef param) { + LLVMValueRef stack[MAX_DEPTH]; + int depth = 0; + int i; + + for (i = 0; i < ntokens; i++) { + char tok = tokens[i][0]; + switch (tok) { + case '+': + case '-': + case '*': + case '/': + case '&': + case '|': + case '^': + if (depth < 2) { + printf("stack underflow\n"); + return NULL; + } + + stack[depth - 2] = LLVMBuildBinOp(builder, op_to_opcode(tok), + stack[depth - 1], stack[depth - 2], ""); + depth--; + + break; + + case '@': { + LLVMValueRef off; + + if (depth < 1) { + printf("stack underflow\n"); + return NULL; + } + + off = LLVMBuildGEP(builder, param, &stack[depth - 1], 1, ""); + stack[depth - 1] = LLVMBuildLoad(builder, off, ""); + + break; + } + + default: { + char *end; + long val = strtol(tokens[i], &end, 0); + if (end[0] != '\0') { + printf("error parsing number\n"); + return NULL; + } + + if (depth >= MAX_DEPTH) { + printf("stack overflow\n"); + return NULL; + } + + stack[depth++] = LLVMConstInt(LLVMInt64Type(), val, 1); + break; + } + } + } + + if (depth < 1) { + printf("stack underflow at return\n"); + return NULL; + } + + LLVMBuildRet(builder, stack[depth - 1]); + + return stack[depth - 1]; +} + +static void handle_line(char **tokens, int ntokens) { + char *name = tokens[0]; + LLVMValueRef param; + LLVMValueRef res; + + LLVMModuleRef M = LLVMModuleCreateWithName(name); + + LLVMTypeRef I64ty = LLVMInt64Type(); + LLVMTypeRef I64Ptrty = LLVMPointerType(I64ty, 0); + LLVMTypeRef Fty = LLVMFunctionType(I64ty, &I64Ptrty, 1, 0); + + LLVMValueRef F = LLVMAddFunction(M, name, Fty); + LLVMBuilderRef builder = LLVMCreateBuilder(); + LLVMPositionBuilderAtEnd(builder, LLVMAppendBasicBlock(F, "entry")); + + LLVMGetParams(F, ¶m); + LLVMSetValueName(param, "in"); + + res = build_from_tokens(tokens + 1, ntokens - 1, builder, param); + if (res) { + char *irstr = LLVMPrintModuleToString(M); + puts(irstr); + LLVMDisposeMessage(irstr); + } + + LLVMDisposeBuilder(builder); + + LLVMDisposeModule(M); +} + +int calc(void) { + + tokenize_stdin(handle_line); + + return 0; +} diff --git a/tools/llvm-c-test/disassemble.c b/tools/llvm-c-test/disassemble.c new file mode 100644 index 0000000..eb40bf3 --- /dev/null +++ b/tools/llvm-c-test/disassemble.c @@ -0,0 +1,88 @@ +/*===-- disassemble.c - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* 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 --disassemble command in llvm-c-test. *| +|* --disassemble reads lines from stdin, parses them as a triple and hex *| +|* machine code, and prints disassembly of the machine code. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Disassembler.h" +#include "llvm-c/Target.h" +#include <stdio.h> +#include <stdlib.h> + +static void pprint(int pos, unsigned char *buf, int len, const char *disasm) { + int i; + printf("%04x: ", pos); + for (i = 0; i < 8; i++) { + if (i < len) { + printf("%02x ", buf[i]); + } else { + printf(" "); + } + } + + printf(" %s\n", disasm); +} + +static void do_disassemble(const char *triple, unsigned char *buf, int siz) { + LLVMDisasmContextRef D = LLVMCreateDisasm(triple, NULL, 0, NULL, NULL); + char outline[1024]; + int pos; + + if (!D) { + printf("ERROR: Couldn't create disassebler for triple %s\n", triple); + return; + } + + pos = 0; + while (pos < siz) { + size_t l = LLVMDisasmInstruction(D, buf + pos, siz - pos, 0, outline, + sizeof(outline)); + if (!l) { + pprint(pos, buf + pos, 1, "\t???"); + pos++; + } else { + pprint(pos, buf + pos, l, outline); + pos += l; + } + } + + LLVMDisasmDispose(D); +} + +static void handle_line(char **tokens, int ntokens) { + unsigned char disbuf[128]; + size_t disbuflen = 0; + char *triple = tokens[0]; + int i; + + printf("triple: %s\n", triple); + + for (i = 1; i < ntokens; i++) { + disbuf[disbuflen++] = strtol(tokens[i], NULL, 16); + if (disbuflen >= sizeof(disbuf)) { + fprintf(stderr, "Warning: Too long line, truncating\n"); + break; + } + } + do_disassemble(triple, disbuf, disbuflen); +} + +int disassemble(void) { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllDisassemblers(); + + tokenize_stdin(handle_line); + + return 0; +} diff --git a/tools/llvm-c-test/helpers.c b/tools/llvm-c-test/helpers.c new file mode 100644 index 0000000..1ea8a4f --- /dev/null +++ b/tools/llvm-c-test/helpers.c @@ -0,0 +1,40 @@ +/*===-- helpers.c - tool for testing libLLVM and llvm-c API ---------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Helper functions *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include <stdio.h> +#include <string.h> + +#define MAX_TOKENS 512 +#define MAX_LINE_LEN 1024 + +void tokenize_stdin(void (*cb)(char **tokens, int ntokens)) { + char line[MAX_LINE_LEN]; + char *tokbuf[MAX_TOKENS]; + + while (fgets(line, sizeof(line), stdin)) { + int c = 0; + + if (line[0] == ';' || line[0] == '\n') + continue; + + while (c < MAX_TOKENS) { + tokbuf[c] = strtok(c ? NULL : line, " \n"); + if (!tokbuf[c]) + break; + c++; + } + if (c) + cb(tokbuf, c); + } +} diff --git a/tools/llvm-c-test/include-all.c b/tools/llvm-c-test/include-all.c new file mode 100644 index 0000000..17b9917 --- /dev/null +++ b/tools/llvm-c-test/include-all.c @@ -0,0 +1,33 @@ +/*===-- include-all.c - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* This file doesn't have any actual code. It just make sure that all *| +|* the llvm-c include files are good and doesn't generate any warnings *| +|* *| +\*===----------------------------------------------------------------------===*/ + +// FIXME: Autogenerate this list + +#include "llvm-c/Analysis.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/BitWriter.h" +#include "llvm-c/Core.h" +#include "llvm-c/Disassembler.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Initialization.h" +#include "llvm-c/LinkTimeOptimizer.h" +#include "llvm-c/Linker.h" +#include "llvm-c/Object.h" +#include "llvm-c/Target.h" +#include "llvm-c/TargetMachine.h" +#include "llvm-c/Transforms/IPO.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Transforms/Scalar.h" +#include "llvm-c/Transforms/Vectorize.h" +#include "llvm-c/lto.h" diff --git a/tools/llvm-c-test/llvm-c-test.h b/tools/llvm-c-test/llvm-c-test.h new file mode 100644 index 0000000..0a25aa6 --- /dev/null +++ b/tools/llvm-c-test/llvm-c-test.h @@ -0,0 +1,37 @@ +/*===-- llvm-c-test.h - tool for testing libLLVM and llvm-c API -----------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Header file for llvm-c-test *| +|* *| +\*===----------------------------------------------------------------------===*/ +#ifndef LLVM_C_TEST_H +#define LLVM_C_TEST_H + +// helpers.c +void tokenize_stdin(void (*cb)(char **tokens, int ntokens)); + +// module.c +int module_dump(void); +int module_list_functions(void); +int module_list_globals(void); + +// calc.c +int calc(void); + +// disassemble.c +int disassemble(void); + +// object.c +int object_list_sections(void); +int object_list_symbols(void); + +// targets.c +int targets_list(void); + +#endif diff --git a/tools/llvm-c-test/main.c b/tools/llvm-c-test/main.c new file mode 100644 index 0000000..72f8b04 --- /dev/null +++ b/tools/llvm-c-test/main.c @@ -0,0 +1,73 @@ +/*===-- main.c - tool for testing libLLVM and llvm-c API ------------------===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Main file for llvm-c-tests. "Parses" arguments and dispatches. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void print_usage(void) { + fprintf(stderr, "llvm-c-test command\n\n"); + fprintf(stderr, " Commands:\n"); + fprintf(stderr, " * --module-dump\n"); + fprintf(stderr, " Read bytecode from stdin - print disassembly\n\n"); + fprintf(stderr, " * --module-list-functions\n"); + fprintf(stderr, + " Read bytecode from stdin - list summary of functions\n\n"); + fprintf(stderr, " * --module-list-globals\n"); + fprintf(stderr, " Read bytecode from stdin - list summary of globals\n\n"); + fprintf(stderr, " * --targets-list\n"); + fprintf(stderr, " List available targets\n\n"); + fprintf(stderr, " * --object-list-sections\n"); + fprintf(stderr, " Read object file form stdin - list sections\n\n"); + fprintf(stderr, " * --object-list-symbols\n"); + fprintf(stderr, + " Read object file form stdin - list symbols (like nm)\n\n"); + fprintf(stderr, " * --disassemble\n"); + fprintf(stderr, " Read lines of triple, hex ascii machine code from stdin " + "- print disassembly\n\n"); + fprintf(stderr, " * --calc\n"); + fprintf( + stderr, + " Read lines of name, rpn from stdin - print generated module\n\n"); +} + +int main(int argc, char **argv) { + LLVMPassRegistryRef pr = LLVMGetGlobalPassRegistry(); + + LLVMInitializeCore(pr); + + if (argc == 2 && !strcmp(argv[1], "--module-dump")) { + return module_dump(); + } else if (argc == 2 && !strcmp(argv[1], "--module-list-functions")) { + return module_list_functions(); + } else if (argc == 2 && !strcmp(argv[1], "--module-list-globals")) { + return module_list_globals(); + } else if (argc == 2 && !strcmp(argv[1], "--targets-list")) { + return targets_list(); + } else if (argc == 2 && !strcmp(argv[1], "--object-list-sections")) { + return object_list_sections(); + } else if (argc == 2 && !strcmp(argv[1], "--object-list-symbols")) { + return object_list_symbols(); + } else if (argc == 2 && !strcmp(argv[1], "--disassemble")) { + return disassemble(); + } else if (argc == 2 && !strcmp(argv[1], "--calc")) { + return calc(); + } else { + print_usage(); + } + + return 1; +} diff --git a/tools/llvm-c-test/module.c b/tools/llvm-c-test/module.c new file mode 100644 index 0000000..2661fc8 --- /dev/null +++ b/tools/llvm-c-test/module.c @@ -0,0 +1,116 @@ +/*===-- module.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* 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 --module-dump, --module-list-functions and *| +|* --module-list-globals commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/BitReader.h" +#include "llvm-c/Core.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static LLVMModuleRef load_module(void) { + LLVMMemoryBufferRef MB; + LLVMModuleRef M; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + if (LLVMParseBitcode(MB, &M, &msg)) { + fprintf(stderr, "Error parsing bitcode: %s\n", msg); + LLVMDisposeMemoryBuffer(MB); + exit(1); + } + + LLVMDisposeMemoryBuffer(MB); + return M; +} + +int module_dump(void) { + LLVMModuleRef M = load_module(); + + char *irstr = LLVMPrintModuleToString(M); + puts(irstr); + LLVMDisposeMessage(irstr); + + LLVMDisposeModule(M); + + return 0; +} + +int module_list_functions(void) { + LLVMModuleRef M = load_module(); + LLVMValueRef f; + + f = LLVMGetFirstFunction(M); + while (f) { + if (LLVMIsDeclaration(f)) { + printf("FunctionDeclaration: %s\n", LLVMGetValueName(f)); + } else { + LLVMBasicBlockRef bb; + LLVMValueRef isn; + unsigned nisn = 0; + unsigned nbb = 0; + + printf("FunctionDefinition: %s [#bb=%u]\n", LLVMGetValueName(f), + LLVMCountBasicBlocks(f)); + + for (bb = LLVMGetFirstBasicBlock(f); bb; + bb = LLVMGetNextBasicBlock(bb)) { + nbb++; + for (isn = LLVMGetFirstInstruction(bb); isn; + isn = LLVMGetNextInstruction(isn)) { + nisn++; + if (LLVMIsACallInst(isn)) { + LLVMValueRef callee = + LLVMGetOperand(isn, LLVMGetNumOperands(isn) - 1); + printf(" calls: %s\n", LLVMGetValueName(callee)); + } + } + } + printf(" #isn: %u\n", nisn); + printf(" #bb: %u\n\n", nbb); + } + f = LLVMGetNextFunction(f); + } + + LLVMDisposeModule(M); + + return 0; +} + +int module_list_globals(void) { + LLVMModuleRef M = load_module(); + LLVMValueRef g; + + g = LLVMGetFirstGlobal(M); + while (g) { + LLVMTypeRef T = LLVMTypeOf(g); + char *s = LLVMPrintTypeToString(T); + + printf("Global%s: %s %s\n", + LLVMIsDeclaration(g) ? "Declaration" : "Definition", + LLVMGetValueName(g), s); + + LLVMDisposeMessage(s); + + g = LLVMGetNextGlobal(g); + } + + LLVMDisposeModule(M); + + return 0; +} diff --git a/tools/llvm-c-test/object.c b/tools/llvm-c-test/object.c new file mode 100644 index 0000000..2792928 --- /dev/null +++ b/tools/llvm-c-test/object.c @@ -0,0 +1,88 @@ +/*===-- object.c - tool for testing libLLVM and llvm-c API ----------------===*\ +|* *| +|* 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 --object-list-sections and --object-list-symbols *| +|* commands in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c-test.h" +#include "llvm-c/Object.h" +#include <stdio.h> +#include <stdlib.h> + +int object_list_sections(void) { + LLVMMemoryBufferRef MB; + LLVMObjectFileRef O; + LLVMSectionIteratorRef sect; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + O = LLVMCreateObjectFile(MB); + if (!O) { + fprintf(stderr, "Error reading object\n"); + exit(1); + } + + sect = LLVMGetSections(O); + while (!LLVMIsSectionIteratorAtEnd(O, sect)) { + printf("'%s': @0x%08" PRIx64 " +%" PRIu64 "\n", LLVMGetSectionName(sect), + LLVMGetSectionAddress(sect), LLVMGetSectionSize(sect)); + + LLVMMoveToNextSection(sect); + } + + LLVMDisposeSectionIterator(sect); + + LLVMDisposeObjectFile(O); + + return 0; +} + +int object_list_symbols(void) { + LLVMMemoryBufferRef MB; + LLVMObjectFileRef O; + LLVMSectionIteratorRef sect; + LLVMSymbolIteratorRef sym; + char *msg = NULL; + + if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) { + fprintf(stderr, "Error reading file: %s\n", msg); + exit(1); + } + + O = LLVMCreateObjectFile(MB); + if (!O) { + fprintf(stderr, "Error reading object\n"); + exit(1); + } + + sect = LLVMGetSections(O); + sym = LLVMGetSymbols(O); + while (!LLVMIsSymbolIteratorAtEnd(O, sym)) { + + LLVMMoveToContainingSection(sect, sym); + printf("%s @0x%08" PRIx64 "/0x%08" PRIx64 " +%" PRIu64 " (%s)\n", + LLVMGetSymbolName(sym), LLVMGetSymbolAddress(sym), + LLVMGetSymbolFileOffset(sym), LLVMGetSymbolSize(sym), + LLVMGetSectionName(sect)); + + LLVMMoveToNextSymbol(sym); + } + + LLVMDisposeSymbolIterator(sym); + + LLVMDisposeObjectFile(O); + + return 0; +} diff --git a/tools/llvm-c-test/targets.c b/tools/llvm-c-test/targets.c new file mode 100644 index 0000000..252c2e0 --- /dev/null +++ b/tools/llvm-c-test/targets.c @@ -0,0 +1,30 @@ +/*===-- targets.c - tool for testing libLLVM and llvm-c API ---------------===*\ +|* *| +|* 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 --targets command in llvm-c-test. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#include "llvm-c/TargetMachine.h" +#include <stdio.h> + +int targets_list(void) { + LLVMTargetRef t; + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + + for (t = LLVMGetFirstTarget(); t; t = LLVMGetNextTarget(t)) { + printf("%s", LLVMGetTargetName(t)); + if (LLVMTargetHasJIT(t)) + printf(" (+jit)"); + printf("\n - %s\n", LLVMGetTargetDescription(t)); + } + + return 0; +} diff --git a/tools/llvm-config/CMakeLists.txt b/tools/llvm-config/CMakeLists.txt index 5ad58bf..c651833 100644 --- a/tools/llvm-config/CMakeLists.txt +++ b/tools/llvm-config/CMakeLists.txt @@ -1,37 +1,26 @@ set(LLVM_LINK_COMPONENTS support) -# We need to generate the BuildVariables.inc file containing values which are -# only defined when under certain build modes. Unfortunately, that precludes -# doing this inside CMake so we have to shell out to sed. For now, that means we -# can't expect to build llvm-config on Window.s set(BUILDVARIABLES_SRCPATH ${CMAKE_CURRENT_SOURCE_DIR}/BuildVariables.inc.in) set(BUILDVARIABLES_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.inc) -set(SEDSCRIPT_OBJPATH ${CMAKE_CURRENT_BINARY_DIR}/BuildVariables.configure.sed) # Compute the substitution values for various items. get_system_libs(LLVM_SYSTEM_LIBS_LIST) foreach(l ${LLVM_SYSTEM_LIBS_LIST}) set(SYSTEM_LIBS ${SYSTEM_LIBS} "-l${l}") endforeach() -set(C_FLGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CXX_FLGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") -set(CPP_FLGS "${CMAKE_CPP_FLAGS} ${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +string(REPLACE ";" " " SYSTEM_LIBS "${SYSTEM_LIBS}") -add_custom_command(OUTPUT ${BUILDVARIABLES_OBJPATH} - COMMAND echo s!@LLVM_SRC_ROOT@!${LLVM_MAIN_SRC_DIR}! > ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_OBJ_ROOT@!${LLVM_BINARY_DIR}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CPPFLAGS@!${CPP_FLGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CFLAGS@!${C_FLGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_CXXFLAGS@!${CXX_FLGS}! >> ${SEDSCRIPT_OBJPATH} - # TODO: Use general flags for linking! not just for shared libs: - COMMAND echo s!@LLVM_LDFLAGS@!${CMAKE_SHARED_LINKER_FLAGS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_BUILDMODE@!${CMAKE_BUILD_TYPE}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_SYSTEM_LIBS@!${SYSTEM_LIBS}! >> ${SEDSCRIPT_OBJPATH} - COMMAND echo s!@LLVM_TARGETS_BUILT@!${LLVM_TARGETS_TO_BUILD}! >> ${SEDSCRIPT_OBJPATH} - COMMAND sed -f ${SEDSCRIPT_OBJPATH} < ${BUILDVARIABLES_SRCPATH} > ${BUILDVARIABLES_OBJPATH} - VERBATIM - COMMENT "Building BuildVariables.inc include." - ) +# Use configure_file to create BuildVariables.inc. +set(LLVM_SRC_ROOT ${LLVM_MAIN_SRC_DIR}) +set(LLVM_OBJ_ROOT ${LLVM_BINARY_DIR}) +set(LLVM_CPPFLAGS "${CMAKE_CPP_FLAGS} ${CMAKE_CPP_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_CFLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_CXXFLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${uppercase_CMAKE_BUILD_TYPE}} ${LLVM_DEFINITIONS}") +set(LLVM_LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}) +set(LLVM_BUILDMODE ${CMAKE_BUILD_TYPE}) +set(LLVM_SYSTEM_LIBS ${SYSTEM_LIBS}) +string(REPLACE ";" " " LLVM_TARGETS_BUILT "${LLVM_TARGETS_TO_BUILD}") +configure_file(${BUILDVARIABLES_SRCPATH} ${BUILDVARIABLES_OBJPATH} @ONLY) # Add the llvm-config tool. add_llvm_tool(llvm-config diff --git a/tools/llvm-cov/CMakeLists.txt b/tools/llvm-cov/CMakeLists.txt index 7184b9e..67cea71 100644 --- a/tools/llvm-cov/CMakeLists.txt +++ b/tools/llvm-cov/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LLVM_LINK_COMPONENTS instrumentation ) +set(LLVM_LINK_COMPONENTS core support ) add_llvm_tool(llvm-cov llvm-cov.cpp diff --git a/tools/llvm-cov/Makefile b/tools/llvm-cov/Makefile index 2d47ce4..efed6cc 100644 --- a/tools/llvm-cov/Makefile +++ b/tools/llvm-cov/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-cov -LINK_COMPONENTS := instrumentation +LINK_COMPONENTS := core support # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 7b21c5b..5f6999e 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -17,6 +17,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryObject.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/Signals.h" #include "llvm/Support/system_error.h" using namespace llvm; @@ -30,6 +31,9 @@ InputGCNO("gcno", cl::desc("<input gcno file>"), cl::init("")); static cl::opt<std::string> InputGCDA("gcda", cl::desc("<input gcda file>"), cl::init("")); +static cl::opt<std::string> +OutputFile("o", cl::desc("<output llvm-cov file>"), cl::init("-")); + //===----------------------------------------------------------------------===// int main(int argc, char **argv) { @@ -38,7 +42,12 @@ int main(int argc, char **argv) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - cl::ParseCommandLineOptions(argc, argv, "llvm cov\n"); + cl::ParseCommandLineOptions(argc, argv, "llvm coverage tool\n"); + + std::string ErrorInfo; + raw_fd_ostream OS(OutputFile.c_str(), ErrorInfo); + if (!ErrorInfo.empty()) + errs() << ErrorInfo << "\n"; GCOVFile GF; if (InputGCNO.empty()) @@ -49,7 +58,7 @@ int main(int argc, char **argv) { errs() << InputGCNO << ": " << ec.message() << "\n"; return 1; } - GCOVBuffer GCNO_GB(GCNO_Buff.take()); + GCOVBuffer GCNO_GB(GCNO_Buff.get()); if (!GF.read(GCNO_GB)) { errs() << "Invalid .gcno File!\n"; return 1; @@ -61,7 +70,7 @@ int main(int argc, char **argv) { errs() << InputGCDA << ": " << ec.message() << "\n"; return 1; } - GCOVBuffer GCDA_GB(GCDA_Buff.take()); + GCOVBuffer GCDA_GB(GCDA_Buff.get()); if (!GF.read(GCDA_GB)) { errs() << "Invalid .gcda File!\n"; return 1; @@ -74,5 +83,6 @@ int main(int argc, char **argv) { FileInfo FI; GF.collectLineCounts(FI); + FI.print(OS, InputGCNO, InputGCDA); return 0; } diff --git a/tools/llvm-diff/DifferenceEngine.cpp b/tools/llvm-diff/DifferenceEngine.cpp index 4b11315..768b94b 100644 --- a/tools/llvm-diff/DifferenceEngine.cpp +++ b/tools/llvm-diff/DifferenceEngine.cpp @@ -195,8 +195,6 @@ class FunctionDifferenceEngine { BasicBlock::iterator LI = L->begin(), LE = L->end(); BasicBlock::iterator RI = R->begin(); - llvm::SmallVector<std::pair<Instruction*,Instruction*>, 20> TentativePairs; - do { assert(LI != LE && RI != R->end()); Instruction *LeftI = &*LI, *RightI = &*RI; @@ -316,15 +314,15 @@ class FunctionDifferenceEngine { bool Difference = false; - DenseMap<Constant*, BasicBlock*> LCases; + DenseMap<ConstantInt*,BasicBlock*> LCases; for (SwitchInst::CaseIt I = LI->case_begin(), E = LI->case_end(); I != E; ++I) - LCases[I.getCaseValueEx()] = I.getCaseSuccessor(); + LCases[I.getCaseValue()] = I.getCaseSuccessor(); for (SwitchInst::CaseIt I = RI->case_begin(), E = RI->case_end(); I != E; ++I) { - IntegersSubset CaseValue = I.getCaseValueEx(); + ConstantInt *CaseValue = I.getCaseValue(); BasicBlock *LCase = LCases[CaseValue]; if (LCase) { if (TryUnify) tryUnify(LCase, I.getCaseSuccessor()); @@ -336,7 +334,7 @@ class FunctionDifferenceEngine { } } if (!Difference) - for (DenseMap<Constant*, BasicBlock*>::iterator + for (DenseMap<ConstantInt*,BasicBlock*>::iterator I = LCases.begin(), E = LCases.end(); I != E; ++I) { if (Complain) Engine.logf("left switch has extra case %l") << I->first; diff --git a/tools/llvm-diff/llvm-diff.cpp b/tools/llvm-diff/llvm-diff.cpp index 6eca1e2..f70219e 100644 --- a/tools/llvm-diff/llvm-diff.cpp +++ b/tools/llvm-diff/llvm-diff.cpp @@ -70,7 +70,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); LLVMContext Context; - + // Load both modules. Die if that fails. Module *LModule = ReadModule(Context, LeftFilename); Module *RModule = ReadModule(Context, RightFilename); diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index eef6f79..413a50b 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -62,11 +62,15 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValN(DIDT_Aranges, "aranges", ".debug_aranges"), clEnumValN(DIDT_Info, "info", ".debug_info"), clEnumValN(DIDT_InfoDwo, "info.dwo", ".debug_info.dwo"), + clEnumValN(DIDT_Types, "types", ".debug_types"), clEnumValN(DIDT_Line, "line", ".debug_line"), clEnumValN(DIDT_Loc, "loc", ".debug_loc"), clEnumValN(DIDT_Frames, "frames", ".debug_frame"), clEnumValN(DIDT_Ranges, "ranges", ".debug_ranges"), clEnumValN(DIDT_Pubnames, "pubnames", ".debug_pubnames"), + clEnumValN(DIDT_Pubtypes, "pubtypes", ".debug_pubtypes"), + clEnumValN(DIDT_GnuPubnames, "gnu_pubnames", ".debug_gnu_pubnames"), + clEnumValN(DIDT_GnuPubtypes, "gnu_pubtypes", ".debug_gnu_pubtypes"), clEnumValN(DIDT_Str, "str", ".debug_str"), clEnumValN(DIDT_StrDwo, "str.dwo", ".debug_str.dwo"), clEnumValN(DIDT_StrOffsetsDwo, "str_offsets.dwo", ".debug_str_offsets.dwo"), diff --git a/tools/llvm-extract/llvm-extract.cpp b/tools/llvm-extract/llvm-extract.cpp index 9ba68b4..dc1a410 100644 --- a/tools/llvm-extract/llvm-extract.cpp +++ b/tools/llvm-extract/llvm-extract.cpp @@ -53,7 +53,7 @@ static cl::list<std::string> ExtractFuncs("func", cl::desc("Specify function to extract"), cl::ZeroOrMore, cl::value_desc("function")); -// ExtractRegExpFuncs - The functions, matched via regular expression, to +// ExtractRegExpFuncs - The functions, matched via regular expression, to // extract from the module. static cl::list<std::string> ExtractRegExpFuncs("rfunc", cl::desc("Specify function(s) to extract using a " diff --git a/tools/llvm-link/llvm-link.cpp b/tools/llvm-link/llvm-link.cpp index 652c414..99cca23 100644 --- a/tools/llvm-link/llvm-link.cpp +++ b/tools/llvm-link/llvm-link.cpp @@ -70,7 +70,7 @@ int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - + LLVMContext &Context = getGlobalContext(); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm linker\n"); diff --git a/tools/llvm-lto/CMakeLists.txt b/tools/llvm-lto/CMakeLists.txt new file mode 100644 index 0000000..348976c --- /dev/null +++ b/tools/llvm-lto/CMakeLists.txt @@ -0,0 +1,6 @@ +set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} lto support) + +add_llvm_tool(llvm-lto + llvm-lto.cpp + ) + diff --git a/tools/llvm-lto/LLVMBuild.txt b/tools/llvm-lto/LLVMBuild.txt new file mode 100644 index 0000000..c1613a3 --- /dev/null +++ b/tools/llvm-lto/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-lto/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-lto +parent = Tools +required_libraries = LTO Support all-targets diff --git a/tools/llvm-prof/Makefile b/tools/llvm-lto/Makefile index f829786..f1801b4 100644 --- a/tools/llvm-prof/Makefile +++ b/tools/llvm-lto/Makefile @@ -1,17 +1,19 @@ -##===- tools/llvm-prof/Makefile ----------------------------*- Makefile -*-===## -# +##===- tools/llvm-lto/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-prof -LINK_COMPONENTS := bitreader analysis +TOOLNAME := llvm-lto +LINK_COMPONENTS := lto ipo scalaropts linker bitreader bitwriter mcdisassembler support target vectorize all-targets # This tool has no plugins, optimize startup time. -TOOL_NO_EXPORTS = 1 +TOOL_NO_EXPORTS := 1 + +NO_INSTALL := 1 include $(LEVEL)/Makefile.common diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp new file mode 100644 index 0000000..0fc68ae --- /dev/null +++ b/tools/llvm-lto/llvm-lto.cpp @@ -0,0 +1,187 @@ +//===-- llvm-lto: a simple command-line program to link modules with LTO --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program takes in a list of bitcode files, links them, performs link-time +// optimization, and outputs an object file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringSet.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/TargetSelect.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")); + +static cl::opt<bool> +DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); + +static cl::list<std::string> +InputFilenames(cl::Positional, cl::OneOrMore, + cl::desc("<input bitcode files>")); + +static cl::opt<std::string> +OutputFilename("o", cl::init(""), + cl::desc("Override output filename"), + cl::value_desc("filename")); + +static cl::list<std::string> +ExportedSymbols("exported-symbol", + cl::desc("Symbol to export from the resulting object file"), + cl::ZeroOrMore); + +static cl::list<std::string> +DSOSymbols("dso-symbol", + cl::desc("Symbol to put in the symtab in the resulting dso"), + cl::ZeroOrMore); + +namespace { +struct ModuleInfo { + std::vector<bool> CanBeHidden; +}; +} + +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 LTO linker\n"); + + // Initialize the configured targets. + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + + // set up the TargetOptions for the machine + TargetOptions Options; + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; + + unsigned BaseArg = 0; + + LTOCodeGenerator CodeGen; + + CodeGen.setCodePICModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC); + CodeGen.setDebugInfo(LTO_DEBUG_MODEL_DWARF); + CodeGen.setTargetOptions(Options); + + llvm::StringSet<llvm::MallocAllocator> DSOSymbolsSet; + for (unsigned i = 0; i < DSOSymbols.size(); ++i) + DSOSymbolsSet.insert(DSOSymbols[i]); + + std::vector<std::string> KeptDSOSyms; + + for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { + std::string error; + OwningPtr<LTOModule> Module(LTOModule::makeLTOModule(InputFilenames[i].c_str(), + Options, error)); + if (!error.empty()) { + errs() << argv[0] << ": error loading file '" << InputFilenames[i] + << "': " << error << "\n"; + return 1; + } + + + if (!CodeGen.addModule(Module.get(), error)) { + errs() << argv[0] << ": error adding file '" << InputFilenames[i] + << "': " << error << "\n"; + return 1; + } + + unsigned NumSyms = Module->getSymbolCount(); + for (unsigned I = 0; I < NumSyms; ++I) { + StringRef Name = Module->getSymbolName(I); + if (!DSOSymbolsSet.count(Name)) + continue; + lto_symbol_attributes Attrs = Module->getSymbolAttributes(I); + unsigned Scope = Attrs & LTO_SYMBOL_SCOPE_MASK; + if (Scope != LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN) + KeptDSOSyms.push_back(Name); + } + } + + // Add all the exported symbols to the table of symbols to preserve. + for (unsigned i = 0; i < ExportedSymbols.size(); ++i) + CodeGen.addMustPreserveSymbol(ExportedSymbols[i].c_str()); + + // Add all the dso symbols to the table of symbols to expose. + for (unsigned i = 0; i < KeptDSOSyms.size(); ++i) + CodeGen.addMustPreserveSymbol(KeptDSOSyms[i].c_str()); + + if (!OutputFilename.empty()) { + size_t len = 0; + std::string ErrorInfo; + const void *Code = CodeGen.compile(&len, DisableOpt, DisableInline, + DisableGVNLoadPRE, ErrorInfo); + if (Code == NULL) { + errs() << argv[0] + << ": error compiling the code: " << ErrorInfo << "\n"; + return 1; + } + + raw_fd_ostream FileStream(OutputFilename.c_str(), ErrorInfo, + sys::fs::F_Binary); + if (!ErrorInfo.empty()) { + errs() << argv[0] << ": error opening the file '" << OutputFilename + << "': " << ErrorInfo << "\n"; + return 1; + } + + FileStream.write(reinterpret_cast<const char *>(Code), len); + } else { + std::string ErrorInfo; + const char *OutputName = NULL; + if (!CodeGen.compile_to_file(&OutputName, DisableOpt, DisableInline, + DisableGVNLoadPRE, ErrorInfo)) { + errs() << argv[0] + << ": error compiling the code: " << ErrorInfo + << "\n"; + return 1; + } + + outs() << "Wrote native object file '" << OutputName << "'\n"; + } + + return 0; +} diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index f10a614..7ec2bba 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -319,10 +319,10 @@ static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) static int AssembleInput(const char *ProgName, const Target *TheTarget, SourceMgr &SrcMgr, MCContext &Ctx, MCStreamer &Str, - MCAsmInfo &MAI, MCSubtargetInfo &STI) { + MCAsmInfo &MAI, MCSubtargetInfo &STI, MCInstrInfo &MCII) { OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, Ctx, Str, MAI)); - OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(STI, *Parser)); + OwningPtr<MCTargetAsmParser> TAP(TheTarget->createMCAsmParser(STI, *Parser, MCII)); if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; @@ -432,7 +432,7 @@ int main(int argc, char **argv) { MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); - MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); + MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); } bool UseCFI = !DisableCFI; Str.reset(TheTarget->createAsmStreamer(Ctx, FOS, /*asmverbose*/true, @@ -446,7 +446,7 @@ int main(int argc, char **argv) { } else { assert(FileType == OFT_ObjectFile && "Invalid file type!"); MCCodeEmitter *CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, *STI, Ctx); - MCAsmBackend *MAB = TheTarget->createMCAsmBackend(TripleName, MCPU); + MCAsmBackend *MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, MCPU); Str.reset(TheTarget->createMCObjectStreamer(TripleName, Ctx, *MAB, FOS, CE, RelaxAll, NoExecStack)); @@ -459,7 +459,7 @@ int main(int argc, char **argv) { Res = AsLexInput(SrcMgr, *MAI, Out.get()); break; case AC_Assemble: - Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI); + Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI, *MCII); break; case AC_MDisassemble: assert(IP && "Expected assembly output"); diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 01dd1c3..8449c29 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -20,6 +20,9 @@ #include "llvm/Bitcode/ReaderWriter.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" @@ -303,6 +306,226 @@ static void DumpSymbolNamesFromModule(Module *M) { SortAndPrintSymbolList(); } +template <class ELFT> +error_code getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, symbol_iterator I, + char &Result) { + typedef typename ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + + DataRefImpl Symb = I->getRawDataRefImpl(); + const Elf_Sym *ESym = Obj.getSymbol(Symb); + const ELFFile<ELFT> &EF = *Obj.getELFFile(); + const Elf_Shdr *ESec = EF.getSection(ESym); + + char ret = '?'; + + if (ESec) { + switch (ESec->sh_type) { + case ELF::SHT_PROGBITS: + case ELF::SHT_DYNAMIC: + switch (ESec->sh_flags) { + case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) : + ret = 't'; + break; + case(ELF::SHF_ALLOC | ELF::SHF_WRITE) : + ret = 'd'; + break; + case ELF::SHF_ALLOC: + case(ELF::SHF_ALLOC | ELF::SHF_MERGE) : + case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) : + ret = 'r'; + break; + } + break; + case ELF::SHT_NOBITS: + ret = 'b'; + } + } + + switch (EF.getSymbolTableIndex(ESym)) { + case ELF::SHN_UNDEF: + if (ret == '?') + ret = 'U'; + break; + case ELF::SHN_ABS: + ret = 'a'; + break; + case ELF::SHN_COMMON: + ret = 'c'; + break; + } + + switch (ESym->getBinding()) { + case ELF::STB_GLOBAL: + ret = ::toupper(ret); + break; + case ELF::STB_WEAK: + if (EF.getSymbolTableIndex(ESym) == ELF::SHN_UNDEF) + ret = 'w'; + else if (ESym->getType() == ELF::STT_OBJECT) + ret = 'V'; + else + ret = 'W'; + } + + if (ret == '?' && ESym->getType() == ELF::STT_SECTION) { + StringRef Name; + error_code EC = I->getName(Name); + if (EC) + return EC; + Result = StringSwitch<char>(Name) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n') + .Default('?'); + return object_error::success; + } + + Result = ret; + return object_error::success; +} + +static error_code getSymbolNMTypeChar(COFFObjectFile &Obj, symbol_iterator I, + char &Result) { + const coff_symbol *symb = Obj.getCOFFSymbol(I); + StringRef name; + if (error_code ec = I->getName(name)) + return ec; + char ret = StringSwitch<char>(name) + .StartsWith(".debug", 'N') + .StartsWith(".sxdata", 'N') + .Default('?'); + + if (ret != '?') { + Result = ret; + return object_error::success; + } + + uint32_t Characteristics = 0; + if (symb->SectionNumber > 0) { + section_iterator SecI = Obj.end_sections(); + if (error_code ec = I->getSection(SecI)) + return ec; + const coff_section *Section = Obj.getCOFFSection(SecI); + Characteristics = Section->Characteristics; + } + + switch (symb->SectionNumber) { + case COFF::IMAGE_SYM_UNDEFINED: + // Check storage classes. + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) { + Result = 'w'; + return object_error::success; // Don't do ::toupper. + } else if (symb->Value != 0) // Check for common symbols. + ret = 'c'; + else + ret = 'u'; + break; + case COFF::IMAGE_SYM_ABSOLUTE: + ret = 'a'; + break; + case COFF::IMAGE_SYM_DEBUG: + ret = 'n'; + break; + default: + // Check section type. + if (Characteristics & COFF::IMAGE_SCN_CNT_CODE) + ret = 't'; + else if (Characteristics & COFF::IMAGE_SCN_MEM_READ && + ~Characteristics & COFF::IMAGE_SCN_MEM_WRITE) // Read only. + ret = 'r'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA) + ret = 'd'; + else if (Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) + ret = 'b'; + else if (Characteristics & COFF::IMAGE_SCN_LNK_INFO) + ret = 'i'; + + // Check for section symbol. + else if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC && + symb->Value == 0) + ret = 's'; + } + + if (symb->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL) + ret = ::toupper(static_cast<unsigned char>(ret)); + + Result = ret; + return object_error::success; +} + +static uint8_t getNType(MachOObjectFile &Obj, DataRefImpl Symb) { + if (Obj.is64Bit()) { + MachO::nlist_64 STE = Obj.getSymbol64TableEntry(Symb); + return STE.n_type; + } + MachO::nlist STE = Obj.getSymbolTableEntry(Symb); + return STE.n_type; +} + +static error_code getSymbolNMTypeChar(MachOObjectFile &Obj, symbol_iterator I, + char &Res) { + DataRefImpl Symb = I->getRawDataRefImpl(); + uint8_t NType = getNType(Obj, Symb); + + char Char; + switch (NType & MachO::N_TYPE) { + case MachO::N_UNDF: + Char = 'u'; + break; + case MachO::N_ABS: + Char = 's'; + break; + case MachO::N_SECT: { + section_iterator Sec = Obj.end_sections(); + Obj.getSymbolSection(Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + Obj.getSectionName(Ref, SectionName); + StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); + if (SegmentName == "__TEXT" && SectionName == "__text") + Char = 't'; + else + Char = 's'; + } break; + default: + Char = '?'; + break; + } + + if (NType & (MachO::N_EXT | MachO::N_PEXT)) + Char = toupper(static_cast<unsigned char>(Char)); + Res = Char; + return object_error::success; +} + +static char getNMTypeChar(ObjectFile *Obj, symbol_iterator I) { + char Res = '?'; + if (COFFObjectFile *COFF = dyn_cast<COFFObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*COFF, I, Res)); + return Res; + } + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*MachO, I, Res)); + return Res; + } + + if (ELF32LEObjectFile *ELF = dyn_cast<ELF32LEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + if (ELF64LEObjectFile *ELF = dyn_cast<ELF64LEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + if (ELF32BEObjectFile *ELF = dyn_cast<ELF32BEObjectFile>(Obj)) { + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; + } + ELF64BEObjectFile *ELF = cast<ELF64BEObjectFile>(Obj); + error(getSymbolNMTypeChar(*ELF, I, Res)); + return Res; +} + static void DumpSymbolNamesFromObject(ObjectFile *obj) { error_code ec; symbol_iterator ibegin = obj->begin_symbols(); @@ -325,7 +548,7 @@ static void DumpSymbolNamesFromObject(ObjectFile *obj) { } if (PrintAddress) if (error(i->getAddress(s.Address))) break; - if (error(i->getNMTypeChar(s.TypeChar))) break; + s.TypeChar = getNMTypeChar(obj, i); if (error(i->getName(s.Name))) break; SymbolList.push_back(s); } diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index bca6fc9..5f0bcbb 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -227,6 +227,48 @@ static void printCOFFSymbolAddress(llvm::raw_ostream &Out, Out << format(" + 0x%04x", Disp); } +// Prints import tables. The import table is a table containing the list of +// DLL name and symbol names which will be linked by the loader. +static void printImportTables(const COFFObjectFile *Obj) { + outs() << "The Import Tables:\n"; + error_code ec; + for (import_directory_iterator i = Obj->import_directory_begin(), + e = Obj->import_directory_end(); + i != e; i = i.increment(ec)) { + if (ec) + return; + + const import_directory_table_entry *Dir; + StringRef Name; + if (i->getImportTableEntry(Dir)) return; + if (i->getName(Name)) return; + + outs() << format(" lookup %08x time %08x fwd %08x name %08x addr %08x\n\n", + static_cast<uint32_t>(Dir->ImportLookupTableRVA), + static_cast<uint32_t>(Dir->TimeDateStamp), + static_cast<uint32_t>(Dir->ForwarderChain), + static_cast<uint32_t>(Dir->NameRVA), + static_cast<uint32_t>(Dir->ImportAddressTableRVA)); + outs() << " DLL Name: " << Name << "\n"; + outs() << " Hint/Ord Name\n"; + const import_lookup_table_entry32 *entry; + if (i->getImportLookupEntry(entry)) + return; + for (; entry->data; ++entry) { + if (entry->isOrdinal()) { + outs() << format(" % 6d\n", entry->getOrdinal()); + continue; + } + uint16_t Hint; + StringRef Name; + if (Obj->getHintName(entry->getHintNameRVA(), Hint, Name)) + return; + outs() << format(" % 6d ", Hint) << Name << "\n"; + } + outs() << "\n"; + } +} + void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { const coff_file_header *Header; if (error(Obj->getCOFFHeader(Header))) return; @@ -353,3 +395,7 @@ void llvm::printCOFFUnwindInfo(const COFFObjectFile *Obj) { } } } + +void llvm::printCOFFFileHeader(const object::ObjectFile *Obj) { + printImportTables(dyn_cast<const COFFObjectFile>(Obj)); +} diff --git a/tools/llvm-objdump/ELFDump.cpp b/tools/llvm-objdump/ELFDump.cpp index ef1f0e9..9c091a41 100644 --- a/tools/llvm-objdump/ELFDump.cpp +++ b/tools/llvm-objdump/ELFDump.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm-objdump.h" -#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -21,10 +21,8 @@ using namespace llvm; using namespace llvm::object; -template<class ELFT> -void printProgramHeaders( - const ELFObjectFile<ELFT> *o) { - typedef ELFObjectFile<ELFT> ELFO; +template <class ELFT> void printProgramHeaders(const ELFFile<ELFT> *o) { + typedef ELFFile<ELFT> ELFO; outs() << "Program Header:\n"; for (typename ELFO::Elf_Phdr_Iter pi = o->begin_program_headers(), pe = o->end_program_headers(); @@ -80,17 +78,17 @@ void printProgramHeaders( void llvm::printELFFileHeader(const object::ObjectFile *Obj) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - printProgramHeaders(ELFObj); + printProgramHeaders(ELFObj->getELFFile()); // Big-endian 32-bit if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - printProgramHeaders(ELFObj); + printProgramHeaders(ELFObj->getELFFile()); // Little-endian 64-bit if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - printProgramHeaders(ELFObj); + printProgramHeaders(ELFObj->getELFFile()); // Big-endian 64-bit if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - printProgramHeaders(ELFObj); + printProgramHeaders(ELFObj->getELFFile()); } diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index e0ec9cc..86923fd 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -104,7 +104,7 @@ static void DumpDataInCode(const char *bytes, uint64_t Size, uint64_t Value; switch (Kind) { - case macho::Data: + case MachO::DICE_KIND_DATA: switch (Size) { case 4: Value = bytes[3] << 24 | @@ -125,16 +125,16 @@ static void DumpDataInCode(const char *bytes, uint64_t Size, } outs() << "\t@ KIND_DATA\n"; break; - case macho::JumpTable8: + case MachO::DICE_KIND_JUMP_TABLE8: Value = bytes[0]; outs() << "\t.byte " << Value << "\t@ KIND_JUMP_TABLE8"; break; - case macho::JumpTable16: + case MachO::DICE_KIND_JUMP_TABLE16: Value = bytes[1] << 8 | bytes[0]; outs() << "\t.short " << Value << "\t@ KIND_JUMP_TABLE16"; break; - case macho::JumpTable32: + case MachO::DICE_KIND_JUMP_TABLE32: Value = bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | @@ -148,7 +148,7 @@ static void DumpDataInCode(const char *bytes, uint64_t Size, } static void -getSectionsAndSymbols(const macho::Header Header, +getSectionsAndSymbols(const MachO::mach_header Header, MachOObjectFile *MachOObj, std::vector<SectionRef> &Sections, std::vector<SymbolRef> &Symbols, @@ -171,25 +171,25 @@ getSectionsAndSymbols(const macho::Header Header, MachOObj->getFirstLoadCommandInfo(); bool BaseSegmentAddressSet = false; for (unsigned i = 0; ; ++i) { - if (Command.C.Type == macho::LCT_FunctionStarts) { + if (Command.C.cmd == MachO::LC_FUNCTION_STARTS) { // We found a function starts segment, parse the addresses for later // consumption. - macho::LinkeditDataLoadCommand LLC = + MachO::linkedit_data_command LLC = MachOObj->getLinkeditDataLoadCommand(Command); - MachOObj->ReadULEB128s(LLC.DataOffset, FoundFns); + MachOObj->ReadULEB128s(LLC.dataoff, FoundFns); } - else if (Command.C.Type == macho::LCT_Segment) { - macho::SegmentLoadCommand SLC = + else if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command SLC = MachOObj->getSegmentLoadCommand(Command); - StringRef SegName = SLC.Name; + StringRef SegName = SLC.segname; if(!BaseSegmentAddressSet && SegName != "__PAGEZERO") { BaseSegmentAddressSet = true; - BaseSegmentAddress = SLC.VMAddress; + BaseSegmentAddress = SLC.vmaddr; } } - if (i == Header.NumLoadCommands - 1) + if (i == Header.ncmds - 1) break; else Command = MachOObj->getNextLoadCommandInfo(Command); @@ -244,7 +244,7 @@ static void DisassembleInputMachO2(StringRef Filename, outs() << '\n' << Filename << ":\n\n"; - macho::Header Header = MachOOF->getHeader(); + MachO::mach_header Header = MachOOF->getHeader(); // FIXME: FoundFns isn't used anymore. Using symbols/LC_FUNCTION_STARTS to // determine function locations will eventually go in MCObjectDisassembler. @@ -260,14 +260,12 @@ static void DisassembleInputMachO2(StringRef Filename, getSectionsAndSymbols(Header, MachOOF, Sections, Symbols, FoundFns, BaseSegmentAddress); - // Make a copy of the unsorted symbol list. FIXME: duplication - std::vector<SymbolRef> UnsortedSymbols(Symbols); // Sort the symbols by address, just in case they didn't come in that way. std::sort(Symbols.begin(), Symbols.end(), SymbolSorter()); // Build a data in code table that is sorted on by the address of each entry. uint64_t BaseAddress = 0; - if (Header.FileType == macho::HFT_Object) + if (Header.filetype == MachO::MH_OBJECT) Sections[0].getAddress(BaseAddress); else BaseAddress = BaseSegmentAddress; diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 122ac83..9bc092e 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -31,6 +31,7 @@ #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCModule.h" +#include "llvm/MC/MCModuleYAML.h" #include "llvm/MC/MCObjectDisassembler.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCObjectSymbolizer.h" @@ -61,6 +62,7 @@ #include <algorithm> #include <cctype> #include <cstring> + using namespace llvm; using namespace object; @@ -139,6 +141,12 @@ static cl::opt<bool> CFG("cfg", cl::desc("Create a CFG for every function found in the object" " and write it to a graphviz file")); +// FIXME: Does it make sense to have a dedicated tool for yaml cfg output? +static cl::opt<std::string> +YAMLCFG("yaml-cfg", + cl::desc("Create a CFG and write it as a YAML MCModule."), + cl::value_desc("yaml output file")); + static StringRef ToolName; bool llvm::error(error_code ec) { @@ -178,6 +186,7 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) { } // Write a graphviz file for the CFG inside an MCFunction. +// FIXME: Use GraphWriter static void emitDOTFile(const char *FileName, const MCFunction &f, MCInstPrinter *IP) { // Start a new dot file. @@ -333,7 +342,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { return; } - if (CFG) { + if (CFG || !YAMLCFG.empty()) { OwningPtr<MCObjectDisassembler> OD( new MCObjectDisassembler(*Obj, *DisAsm, *MIA)); OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true)); @@ -350,14 +359,25 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } } } - for (MCModule::const_func_iterator FI = Mod->func_begin(), - FE = Mod->func_end(); - FI != FE; ++FI) { - static int filenum = 0; - emitDOTFile((Twine((*FI)->getName()) + "_" + - utostr(filenum) + ".dot").str().c_str(), - **FI, IP.get()); - ++filenum; + if (CFG) { + for (MCModule::const_func_iterator FI = Mod->func_begin(), + FE = Mod->func_end(); + FI != FE; ++FI) { + static int filenum = 0; + emitDOTFile((Twine((*FI)->getName()) + "_" + + utostr(filenum) + ".dot").str().c_str(), + **FI, IP.get()); + ++filenum; + } + } + if (!YAMLCFG.empty()) { + std::string Error; + raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error); + if (!Error.empty()) { + errs() << ToolName << ": warning: " << Error << '\n'; + return; + } + mcmodule2yaml(YAMLOut, *Mod, *MII, *MRI); } } @@ -750,6 +770,14 @@ static void PrintUnwindInfo(const ObjectFile *o) { } } +static void printPrivateFileHeader(const ObjectFile *o) { + if (o->isELF()) { + printELFFileHeader(o); + } else if (o->isCOFF()) { + printCOFFFileHeader(o); + } +} + static void DumpObject(const ObjectFile *o) { outs() << '\n'; outs() << o->getFileName() @@ -767,8 +795,8 @@ static void DumpObject(const ObjectFile *o) { PrintSymbolTable(o); if (UnwindInfo) PrintUnwindInfo(o); - if (PrivateHeaders && o->isELF()) - printELFFileHeader(o); + if (PrivateHeaders) + printPrivateFileHeader(o); } /// @brief Dump each object file in \a a; diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index 87f19ba..b716a26 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -34,7 +34,8 @@ void DumpBytes(StringRef bytes); void DisassembleInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); +void printCOFFFileHeader(const object::ObjectFile *o); -} +} // end namespace llvm #endif diff --git a/tools/llvm-prof/CMakeLists.txt b/tools/llvm-prof/CMakeLists.txt deleted file mode 100644 index 442112b..0000000 --- a/tools/llvm-prof/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -set(LLVM_LINK_COMPONENTS bitreader analysis) - -add_llvm_tool(llvm-prof - llvm-prof.cpp - ) diff --git a/tools/llvm-prof/llvm-prof.cpp b/tools/llvm-prof/llvm-prof.cpp deleted file mode 100644 index b2c3f06..0000000 --- a/tools/llvm-prof/llvm-prof.cpp +++ /dev/null @@ -1,293 +0,0 @@ -//===- llvm-prof.cpp - Read in and process llvmprof.out data files --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This tools is meant for use with the various LLVM profiling instrumentation -// passes. It reads in the data file produced by executing an instrumented -// program, and outputs a nice report. -// -//===----------------------------------------------------------------------===// - -#include "llvm/IR/LLVMContext.h" -#include "llvm/Analysis/Passes.h" -#include "llvm/Analysis/ProfileInfo.h" -#include "llvm/Analysis/ProfileInfoLoader.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/Signals.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" -#include <algorithm> -#include <iomanip> -#include <map> -#include <set> - -using namespace llvm; - -namespace { - cl::opt<std::string> - BitcodeFile(cl::Positional, cl::desc("<program bitcode file>"), - cl::Required); - - cl::opt<std::string> - ProfileDataFile(cl::Positional, cl::desc("<llvmprof.out file>"), - cl::Optional, cl::init("llvmprof.out")); - - cl::opt<bool> - PrintAnnotatedLLVM("annotated-llvm", - cl::desc("Print LLVM code with frequency annotations")); - cl::alias PrintAnnotated2("A", cl::desc("Alias for --annotated-llvm"), - cl::aliasopt(PrintAnnotatedLLVM)); - cl::opt<bool> - PrintAllCode("print-all-code", - cl::desc("Print annotated code for the entire program")); -} - -// PairSecondSort - A sorting predicate to sort by the second element of a pair. -template<class T> -struct PairSecondSortReverse - : public std::binary_function<std::pair<T, double>, - std::pair<T, double>, bool> { - bool operator()(const std::pair<T, double> &LHS, - const std::pair<T, double> &RHS) const { - return LHS.second > RHS.second; - } -}; - -static double ignoreMissing(double w) { - if (w == ProfileInfo::MissingValue) return 0; - return w; -} - -namespace { - class ProfileAnnotator : public AssemblyAnnotationWriter { - ProfileInfo &PI; - public: - ProfileAnnotator(ProfileInfo &pi) : PI(pi) {} - - virtual void emitFunctionAnnot(const Function *F, - formatted_raw_ostream &OS) { - double w = PI.getExecutionCount(F); - if (w != ProfileInfo::MissingValue) { - OS << ";;; %" << F->getName() << " called "<<(unsigned)w - <<" times.\n;;;\n"; - } - } - virtual void emitBasicBlockStartAnnot(const BasicBlock *BB, - formatted_raw_ostream &OS) { - double w = PI.getExecutionCount(BB); - if (w != ProfileInfo::MissingValue) { - if (w != 0) { - OS << "\t;;; Basic block executed " << (unsigned)w << " times.\n"; - } else { - OS << "\t;;; Never executed!\n"; - } - } - } - - virtual void emitBasicBlockEndAnnot(const BasicBlock *BB, - formatted_raw_ostream &OS) { - // Figure out how many times each successor executed. - std::vector<std::pair<ProfileInfo::Edge, double> > SuccCounts; - - const TerminatorInst *TI = BB->getTerminator(); - for (unsigned s = 0, e = TI->getNumSuccessors(); s != e; ++s) { - BasicBlock* Succ = TI->getSuccessor(s); - double w = ignoreMissing(PI.getEdgeWeight(std::make_pair(BB, Succ))); - if (w != 0) - SuccCounts.push_back(std::make_pair(std::make_pair(BB, Succ), w)); - } - if (!SuccCounts.empty()) { - OS << "\t;;; Out-edge counts:"; - for (unsigned i = 0, e = SuccCounts.size(); i != e; ++i) - OS << " [" << (SuccCounts[i]).second << " -> " - << (SuccCounts[i]).first.second->getName() << "]"; - OS << "\n"; - } - } - }; -} - -namespace { - /// ProfileInfoPrinterPass - Helper pass to dump the profile information for - /// a module. - // - // FIXME: This should move elsewhere. - class ProfileInfoPrinterPass : public ModulePass { - ProfileInfoLoader &PIL; - public: - static char ID; // Class identification, replacement for typeinfo. - explicit ProfileInfoPrinterPass(ProfileInfoLoader &_PIL) - : ModulePass(ID), PIL(_PIL) {} - - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesAll(); - AU.addRequired<ProfileInfo>(); - } - - bool runOnModule(Module &M); - }; -} - -char ProfileInfoPrinterPass::ID = 0; - -bool ProfileInfoPrinterPass::runOnModule(Module &M) { - ProfileInfo &PI = getAnalysis<ProfileInfo>(); - std::map<const Function *, unsigned> FuncFreqs; - std::map<const BasicBlock*, unsigned> BlockFreqs; - std::map<ProfileInfo::Edge, unsigned> EdgeFreqs; - - // Output a report. Eventually, there will be multiple reports selectable on - // the command line, for now, just keep things simple. - - // Emit the most frequent function table... - std::vector<std::pair<Function*, double> > FunctionCounts; - std::vector<std::pair<BasicBlock*, double> > Counts; - for (Module::iterator FI = M.begin(), FE = M.end(); FI != FE; ++FI) { - if (FI->isDeclaration()) continue; - double w = ignoreMissing(PI.getExecutionCount(FI)); - FunctionCounts.push_back(std::make_pair(FI, w)); - for (Function::iterator BB = FI->begin(), BBE = FI->end(); - BB != BBE; ++BB) { - double w = ignoreMissing(PI.getExecutionCount(BB)); - Counts.push_back(std::make_pair(BB, w)); - } - } - - // Sort by the frequency, backwards. - sort(FunctionCounts.begin(), FunctionCounts.end(), - PairSecondSortReverse<Function*>()); - - double TotalExecutions = 0; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) - TotalExecutions += FunctionCounts[i].second; - - outs() << "===" << std::string(73, '-') << "===\n" - << "LLVM profiling output for execution"; - if (PIL.getNumExecutions() != 1) outs() << "s"; - outs() << ":\n"; - - for (unsigned i = 0, e = PIL.getNumExecutions(); i != e; ++i) { - outs() << " "; - if (e != 1) outs() << i+1 << ". "; - outs() << PIL.getExecution(i) << "\n"; - } - - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Function execution frequencies:\n\n"; - - // Print out the function frequencies... - outs() << " ## Frequency\n"; - for (unsigned i = 0, e = FunctionCounts.size(); i != e; ++i) { - if (FunctionCounts[i].second == 0) { - outs() << "\n NOTE: " << e-i << " function" - << (e-i-1 ? "s were" : " was") << " never executed!\n"; - break; - } - - outs() << format("%3d", i+1) << ". " - << format("%5.2g", FunctionCounts[i].second) << "/" - << format("%g", TotalExecutions) << " " - << FunctionCounts[i].first->getName() << "\n"; - } - - std::set<Function*> FunctionsToPrint; - - TotalExecutions = 0; - for (unsigned i = 0, e = Counts.size(); i != e; ++i) - TotalExecutions += Counts[i].second; - - // Sort by the frequency, backwards. - sort(Counts.begin(), Counts.end(), - PairSecondSortReverse<BasicBlock*>()); - - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Top 20 most frequently executed basic blocks:\n\n"; - - // Print out the function frequencies... - outs() <<" ## %% \tFrequency\n"; - unsigned BlocksToPrint = Counts.size(); - if (BlocksToPrint > 20) BlocksToPrint = 20; - for (unsigned i = 0; i != BlocksToPrint; ++i) { - if (Counts[i].second == 0) break; - Function *F = Counts[i].first->getParent(); - outs() << format("%3d", i+1) << ". " - << format("%5g", Counts[i].second/(double)TotalExecutions*100)<<"% " - << format("%5.0f", Counts[i].second) << "/" - << format("%g", TotalExecutions) << "\t" - << F->getName() << "() - " - << Counts[i].first->getName() << "\n"; - FunctionsToPrint.insert(F); - } - - if (PrintAnnotatedLLVM || PrintAllCode) { - outs() << "\n===" << std::string(73, '-') << "===\n"; - outs() << "Annotated LLVM code for the module:\n\n"; - - ProfileAnnotator PA(PI); - - if (FunctionsToPrint.empty() || PrintAllCode) - M.print(outs(), &PA); - else - // Print just a subset of the functions. - for (std::set<Function*>::iterator I = FunctionsToPrint.begin(), - E = FunctionsToPrint.end(); I != E; ++I) - (*I)->print(outs(), &PA); - } - - return false; -} - -int main(int argc, char **argv) { - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - - LLVMContext &Context = getGlobalContext(); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - cl::ParseCommandLineOptions(argc, argv, "llvm profile dump decoder\n"); - - // Read in the bitcode file... - std::string ErrorMessage; - OwningPtr<MemoryBuffer> Buffer; - error_code ec; - Module *M = 0; - if (!(ec = MemoryBuffer::getFileOrSTDIN(BitcodeFile, Buffer))) { - M = ParseBitcodeFile(Buffer.get(), Context, &ErrorMessage); - } else - ErrorMessage = ec.message(); - if (M == 0) { - errs() << argv[0] << ": " << BitcodeFile << ": " - << ErrorMessage << "\n"; - return 1; - } - - // Read the profiling information. This is redundant since we load it again - // using the standard profile info provider pass, but for now this gives us - // access to additional information not exposed via the ProfileInfo - // interface. - ProfileInfoLoader PIL(argv[0], ProfileDataFile); - - // Run the printer pass. - PassManager PassMgr; - PassMgr.add(createProfileLoaderPass(ProfileDataFile)); - PassMgr.add(new ProfileInfoPrinterPass(PIL)); - PassMgr.run(*M); - - return 0; -} diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 3628c3b..07a9083 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -18,7 +18,7 @@ #include "StreamWriter.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" @@ -28,7 +28,6 @@ using namespace llvm; using namespace llvm::object; using namespace ELF; - #define LLVM_READOBJ_ENUM_CASE(ns, enum) \ case ns::enum: return #enum; @@ -37,9 +36,8 @@ namespace { template<typename ELFT> class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFObjectFile<ELFT> *Obj, StreamWriter& Writer) - : ObjDumper(Writer) - , Obj(Obj) { } + ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) {} virtual void printFileHeaders() LLVM_OVERRIDE; virtual void printSections() LLVM_OVERRIDE; @@ -53,24 +51,32 @@ public: virtual void printProgramHeaders() LLVM_OVERRIDE; private: - typedef ELFObjectFile<ELFT> ELFO; + typedef ELFFile<ELFT> ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; - void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + void printSymbol(typename ELFO::Elf_Sym_Iter Symbol); - void printRelocation(section_iterator SecI, relocation_iterator RelI); + void printRelocations(const Elf_Shdr *Sec); + void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); const ELFO *Obj; }; -} // namespace +template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { + if (!Val) { + error(Val); + return Default; + } + return *Val; +} +} // namespace namespace llvm { template <class ELFT> -static error_code createELFDumper(const ELFObjectFile<ELFT> *Obj, +static error_code createELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer, OwningPtr<ObjDumper> &Result) { Result.reset(new ELFDumper<ELFT>(Obj, Writer)); @@ -82,26 +88,25 @@ error_code createELFDumper(const object::ObjectFile *Obj, OwningPtr<ObjDumper> &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 32-bit if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Little-endian 64-bit if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 64-bit if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + return createELFDumper(ELFObj->getELFFile(), Writer, Result); return readobj_error::unsupported_obj_file_format; } } // namespace llvm - static const EnumEntry<unsigned> ElfClass[] = { { "None", ELF::ELFCLASSNONE }, { "32-bit", ELF::ELFCLASS32 }, @@ -322,7 +327,7 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = { static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { - case Triple::arm: + case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); @@ -330,16 +335,12 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { 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: + case ELF::EM_HEXAGON: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); } + case ELF::EM_X86_64: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); @@ -376,6 +377,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { 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_EXCLUDE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), @@ -389,26 +391,41 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) }; -static const EnumEntry<unsigned> ElfSegmentTypes[] = { - LLVM_READOBJ_ENUM_ENT(ELF, PT_NULL ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_LOAD ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_DYNAMIC), - LLVM_READOBJ_ENUM_ENT(ELF, PT_INTERP ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_NOTE ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SHLIB ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_PHDR ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_TLS ), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_EH_FRAME), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_EH_FRAME), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_UNWIND), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_STACK), - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_RELRO), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_EXIDX), - LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_UNWIND) -}; +static const char *getElfSegmentType(unsigned Arch, unsigned Type) { + // Check potentially overlapped processor-specific + // program header type. + switch (Arch) { + case ELF::EM_ARM: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); + } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS); + } + } + + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS ); + + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME); + LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND); + + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK); + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); + default: return ""; + } +} static const EnumEntry<unsigned> ElfSegmentFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, PF_X), @@ -416,12 +433,9 @@ static const EnumEntry<unsigned> ElfSegmentFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, PF_R) }; - template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { - error_code EC; - - const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader(); + const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -461,24 +475,20 @@ 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; - + for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; ++SecI) { ++SectionIndex; - const Elf_Shdr *Section = Obj->getElfSection(SecI); - StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + const Elf_Shdr *Section = &*SecI; + StringRef Name = errorOrDefault(Obj->getSectionName(Section)); 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.printHex("Type", + getElfSectionType(Obj->getHeader()->e_machine, 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); @@ -490,35 +500,23 @@ void ELFDumper<ELFT>::printSections() { 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); - } + printRelocations(Section); } 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); + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; ++SymI) { + if (Obj->getSection(&*SymI) == Section) + printSymbol(SymI); } } if (opts::SectionData) { - StringRef Data; - if (error(SecI->getContents(Data))) break; - - W.printBinaryBlock("SectionData", Data); + ArrayRef<uint8_t> Data = errorOrDefault(Obj->getSectionContents(Section)); + W.printBinaryBlock("SectionData", + StringRef((const char *)Data.data(), Data.size())); } } } @@ -527,72 +525,74 @@ 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; - + for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), + SecE = Obj->end_sections(); + SecI != SecE; ++SecI) { ++SectionNumber; - StringRef Name; - if (error(SecI->getName(Name))) + + if (SecI->sh_type != ELF::SHT_REL && SecI->sh_type != ELF::SHT_RELA) continue; - bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; + StringRef Name = errorOrDefault(Obj->getSectionName(&*SecI)); - if (!PrintedGroup) { - W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; - W.indent(); - PrintedGroup = true; - } + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); - printRelocation(SecI, RelI); - } + printRelocations(&*SecI); - if (PrintedGroup) { - W.unindent(); - W.startLine() << "}\n"; + W.unindent(); + W.startLine() << "}\n"; + } +} + +template <class ELFT> +void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) { + switch (Sec->sh_type) { + case ELF::SHT_REL: + for (typename ELFO::Elf_Rel_Iter RI = Obj->begin_rel(Sec), + RE = Obj->end_rel(Sec); + RI != RE; ++RI) { + typename ELFO::Elf_Rela Rela; + Rela.r_offset = RI->r_offset; + Rela.r_info = RI->r_info; + Rela.r_addend = 0; + printRelocation(Sec, Rela); } + break; + case ELF::SHT_RELA: + for (typename ELFO::Elf_Rela_Iter RI = Obj->begin_rela(Sec), + RE = Obj->end_rela(Sec); + RI != RE; ++RI) { + printRelocation(Sec, *RI); + } + break; } } -template<class ELFT> -void ELFDumper<ELFT>::printRelocation(section_iterator Sec, - relocation_iterator RelI) { - uint64_t Offset; - uint64_t RelocType; +template <class ELFT> +void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, + typename ELFO::Elf_Rela Rel) { SmallString<32> RelocName; - int64_t Addend; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; - if (Obj->getElfHeader()->e_type == ELF::ET_REL){ - if (error(RelI->getOffset(Offset))) return; - } else { - if (error(RelI->getAddress(Offset))) return; - } - if (error(RelI->getType(RelocType))) return; - if (error(RelI->getTypeName(RelocName))) return; - if (error(getELFRelocationAddend(*RelI, Addend))) return; - symbol_iterator Symbol = RelI->getSymbol(); - if (Symbol != Obj->end_symbols() && error(Symbol->getName(SymbolName))) - return; + std::pair<const Elf_Shdr *, const Elf_Sym *> Sym = + Obj->getRelocationSymbol(Sec, &Rel); + if (Sym.first) + SymbolName = errorOrDefault(Obj->getSymbolName(Sym.first, Sym.second)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", Offset); - W.printNumber("Type", RelocName, RelocType); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Addend", Addend); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(Offset) + OS << W.hex(Rel.r_offset) << " " << RelocName << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(Addend) + << " " << W.hex(Rel.r_addend) << "\n"; } } @@ -600,12 +600,9 @@ void ELFDumper<ELFT>::printRelocation(section_iterator Sec, 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; - + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), + SymE = Obj->end_symbols(); + SymI != SymE; ++SymI) { printSymbol(SymI); } } @@ -614,41 +611,27 @@ 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); + for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_dynamic_symbols(), + SymE = Obj->end_dynamic_symbols(); + SymI != SymE; ++SymI) { + printSymbol(SymI); } } -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); - +template <class ELFT> +void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { + StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); + const Elf_Shdr *Sec = Obj->getSection(&*Symbol); + StringRef SectionName = Sec ? errorOrDefault(Obj->getSectionName(Sec)) : ""; std::string FullSymbolName(SymbolName); - if (IsDynamic) { - StringRef Version; + if (Symbol.isDynamic()) { bool IsDefault; - if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) - return; - if (!Version.empty()) { + ErrorOr<StringRef> Version = Obj->getSymbolVersion(0, &*Symbol, IsDefault); + if (Version) { FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += Version; - } + FullSymbolName += *Version; + } else + error(Version); } DictScope D(W, "Symbol"); @@ -700,15 +683,25 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(SYMENT); LLVM_READOBJ_TYPE_CASE(SYMTAB); LLVM_READOBJ_TYPE_CASE(TEXTREL); + LLVM_READOBJ_TYPE_CASE(VERNEED); + LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); + LLVM_READOBJ_TYPE_CASE(VERSYM); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); + LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); + LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO); + LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM); 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) { +template <class ELFT> +static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, + bool Is64, raw_ostream &OS) { switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -732,9 +725,21 @@ static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERNEED: + case DT_VERSYM: case DT_NULL: + case DT_MIPS_FLAGS: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_GOTSYM: OS << format("0x%" PRIX64, Value); break; + case DT_VERNEEDNUM: + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + OS << Value; + break; case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: @@ -748,12 +753,14 @@ static void printValue(const ELFObjectFile<ELFT> *O, uint64_t Type, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "SharedLibrary (" << O->getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "LibrarySoname (" << O->getDynamicString(Value) << ")"; + break; + case DT_RPATH: + case DT_RUNPATH: + OS << O->getDynamicString(Value); break; } } @@ -765,9 +772,8 @@ void ELFDumper<ELFT>::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - typedef typename ELFO::Elf_Dyn_iterator EDI; - EDI Start = Obj->begin_dynamic_table(), - End = Obj->end_dynamic_table(true); + typedef typename ELFO::Elf_Dyn_Iter EDI; + EDI Start = Obj->begin_dynamic_table(), End = Obj->end_dynamic_table(true); if (Start == End) return; @@ -776,7 +782,7 @@ void ELFDumper<ELFT>::printDynamicTable() { raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; - bool Is64 = Obj->getBytesInAddress() == 8; + bool Is64 = ELFT::Is64Bits; W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" @@ -793,38 +799,23 @@ void ELFDumper<ELFT>::printDynamicTable() { 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; + typedef std::vector<StringRef> 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); - } + for (typename ELFO::Elf_Dyn_Iter DynI = Obj->begin_dynamic_table(), + DynE = Obj->end_dynamic_table(); + DynI != DynE; ++DynI) + if (DynI->d_tag == ELF::DT_NEEDED) + Libs.push_back(Obj->getDynamicString(DynI->d_un.d_val)); - std::sort(Libs.begin(), Libs.end(), &compareLibraryName); + std::stable_sort(Libs.begin(), Libs.end()); - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); - I != E; ++I) { - StringRef Path; - I->getPath(Path); - outs() << " " << Path << "\n"; + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { + outs() << " " << *I << "\n"; } } @@ -836,7 +827,9 @@ void ELFDumper<ELFT>::printProgramHeaders() { PE = Obj->end_program_headers(); PI != PE; ++PI) { DictScope P(W, "ProgramHeader"); - W.printEnum ("Type", PI->p_type, makeArrayRef(ElfSegmentTypes)); + W.printHex ("Type", + getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type), + PI->p_type); W.printHex ("Offset", PI->p_offset); W.printHex ("VirtualAddress", PI->p_vaddr); W.printHex ("PhysicalAddress", PI->p_paddr); diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index 8df6fd6..b97166b 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -166,28 +166,28 @@ static void getSection(const MachOObjectFile *Obj, DataRefImpl Sec, MachOSection &Section) { if (!Obj->is64Bit()) { - macho::Section Sect = Obj->getSection(Sec); - 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; + MachO::section Sect = Obj->getSection(Sec); + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; + Section.RelocationTableOffset = Sect.reloff; + Section.NumRelocationTableEntries = Sect.nreloc; + Section.Flags = Sect.flags; + Section.Reserved1 = Sect.reserved1; + Section.Reserved2 = Sect.reserved2; return; } - macho::Section64 Sect = Obj->getSection64(Sec); - 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; + MachO::section_64 Sect = Obj->getSection64(Sec); + Section.Address = Sect.addr; + Section.Size = Sect.size; + Section.Offset = Sect.offset; + Section.Alignment = Sect.align; + Section.RelocationTableOffset = Sect.reloff; + Section.NumRelocationTableEntries = Sect.nreloc; + Section.Flags = Sect.flags; + Section.Reserved1 = Sect.reserved1; + Section.Reserved2 = Sect.reserved2; } @@ -195,20 +195,20 @@ static void getSymbol(const MachOObjectFile *Obj, DataRefImpl DRI, MachOSymbol &Symbol) { if (!Obj->is64Bit()) { - macho::SymbolTableEntry Entry = Obj->getSymbolTableEntry(DRI); - Symbol.StringIndex = Entry.StringIndex; - Symbol.Type = Entry.Type; - Symbol.SectionIndex = Entry.SectionIndex; - Symbol.Flags = Entry.Flags; - Symbol.Value = Entry.Value; + MachO::nlist Entry = Obj->getSymbolTableEntry(DRI); + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; + Symbol.SectionIndex = Entry.n_sect; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_value; return; } - macho::Symbol64TableEntry Entry = Obj->getSymbol64TableEntry(DRI); - Symbol.StringIndex = Entry.StringIndex; - Symbol.Type = Entry.Type; - Symbol.SectionIndex = Entry.SectionIndex; - Symbol.Flags = Entry.Flags; - Symbol.Value = Entry.Value; + MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); + Symbol.StringIndex = Entry.n_strx; + Symbol.Type = Entry.n_type; + Symbol.SectionIndex = Entry.n_sect; + Symbol.Flags = Entry.n_desc; + Symbol.Value = Entry.n_value; } void MachODumper::printFileHeaders() { @@ -349,7 +349,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, return; DataRefImpl DR = RelI->getRawDataRefImpl(); - macho::RelocationEntry RE = Obj->getRelocation(DR); + MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); if (opts::ExpandRelocs) { @@ -398,8 +398,6 @@ void MachODumper::printDynamicSymbols() { } void MachODumper::printSymbol(symbol_iterator SymI) { - error_code EC; - StringRef SymbolName; if (SymI->getName(SymbolName)) SymbolName = ""; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 2e95b6b..f84a72f 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -130,12 +130,15 @@ namespace opts { cl::desc("Expand each shown relocation to multiple lines")); } // namespace opts +static int ReturnValue = EXIT_SUCCESS; + namespace llvm { bool error(error_code EC) { if (!EC) return false; + ReturnValue = EXIT_FAILURE; outs() << "\nError reading file: " << EC.message() << ".\n"; outs().flush(); return true; @@ -157,6 +160,7 @@ static void reportError(StringRef Input, error_code EC) { errs() << Input << ": " << EC.message() << "\n"; errs().flush(); + ReturnValue = EXIT_FAILURE; } static void reportError(StringRef Input, StringRef Message) { @@ -164,6 +168,7 @@ static void reportError(StringRef Input, StringRef Message) { Input = "<stdin>"; errs() << Input << ": " << Message << "\n"; + ReturnValue = EXIT_FAILURE; } /// @brief Creates an format-specific object file dumper. @@ -289,5 +294,5 @@ int main(int argc, const char *argv[]) { std::for_each(opts::InputFilenames.begin(), opts::InputFilenames.end(), dumpInput); - return 0; + return ReturnValue; } diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index 7f042d2..531595e 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -22,6 +22,8 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Memory.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/system_error.h" using namespace llvm; @@ -60,9 +62,10 @@ public: SmallVector<sys::MemoryBlock, 16> DataMemory; uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID); + unsigned SectionID, StringRef SectionName); uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID, bool IsReadOnly); + unsigned SectionID, StringRef SectionName, + bool IsReadOnly); virtual void *getPointerToNamedFunction(const std::string &Name, bool AbortOnFailure = true) { @@ -80,7 +83,8 @@ public: uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, unsigned Alignment, - unsigned SectionID) { + unsigned SectionID, + StringRef SectionName) { sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); FunctionMemory.push_back(MB); return (uint8_t*)MB.base(); @@ -89,6 +93,7 @@ uint8_t *TrivialMemoryManager::allocateCodeSection(uintptr_t Size, uint8_t *TrivialMemoryManager::allocateDataSection(uintptr_t Size, unsigned Alignment, unsigned SectionID, + StringRef SectionName, bool IsReadOnly) { sys::MemoryBlock MB = sys::Memory::AllocateRWX(Size, 0, 0); DataMemory.push_back(MB); @@ -236,6 +241,9 @@ static int executeInput() { } int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. diff --git a/tools/llvm-shlib/Makefile b/tools/llvm-shlib/Makefile index 1d9053b..92f3132 100644 --- a/tools/llvm-shlib/Makefile +++ b/tools/llvm-shlib/Makefile @@ -62,13 +62,13 @@ ifeq ($(HOST_OS),Darwin) endif endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), DragonFly Linux FreeBSD GNU/kFreeBSD OpenBSD GNU Bitrig)) # Include everything from the .a's into the shared library. LLVMLibsOptions := -Wl,--whole-archive $(LLVMLibsOptions) \ -Wl,--no-whole-archive endif -ifeq ($(HOST_OS), $(filter $(HOST_OS), Linux FreeBSD GNU/kFreeBSD GNU)) +ifeq ($(HOST_OS), $(filter $(HOST_OS), DragonFly Linux FreeBSD GNU/kFreeBSD GNU)) # Add soname to the library. LLVMLibsOptions += -Wl,--soname,lib$(LIBRARYNAME)$(SHLIBEXT) endif diff --git a/tools/llvm-stress/llvm-stress.cpp b/tools/llvm-stress/llvm-stress.cpp index 15f7abf..fd10baf 100644 --- a/tools/llvm-stress/llvm-stress.cpp +++ b/tools/llvm-stress/llvm-stress.cpp @@ -52,6 +52,7 @@ static cl::opt<bool> GenPPCFP128("generate-ppc-fp128", static cl::opt<bool> GenX86MMX("generate-x86-mmx", cl::desc("Generate X86 MMX floating-point values"), cl::init(false)); +namespace { /// A utility class to provide a pseudo-random number generator which is /// the same across all platforms. This is somewhat close to the libc /// implementation. Note: This is not a cryptographically secure pseudorandom @@ -607,7 +608,9 @@ struct CmpModifier: public Modifier { } }; -void FillFunction(Function *F, Random &R) { +} // end anonymous namespace + +static void FillFunction(Function *F, Random &R) { // Create a legal entry block. BasicBlock *BB = BasicBlock::Create(F->getContext(), "BB", F); ReturnInst::Create(F->getContext(), BB); @@ -654,7 +657,7 @@ void FillFunction(Function *F, Random &R) { SM->ActN(5); // Throw in a few stores. } -void IntroduceControlFlow(Function *F, Random &R) { +static void IntroduceControlFlow(Function *F, Random &R) { std::vector<Instruction*> BoolInst; for (BasicBlock::iterator it = F->begin()->begin(), e = F->begin()->end(); it != e; ++it) { diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 0346fb2..320ab3f 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -13,12 +13,17 @@ #include "LLVMSymbolize.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/Config/config.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/DataExtractor.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include <sstream> +#include <stdlib.h> namespace llvm { namespace symbolize { @@ -191,7 +196,7 @@ std::string LLVMSymbolizer::symbolizeData(const std::string &ModuleName, if (Opts.UseSymbolTable) { if (ModuleInfo *Info = getOrCreateModuleInfo(ModuleName)) { if (Info->symbolizeData(ModuleOffset, Name, Start, Size) && Opts.Demangle) - Name = DemangleName(Name); + Name = DemangleGlobalName(Name); } } std::stringstream ss; @@ -215,6 +220,81 @@ static std::string getDarwinDWARFResourceForPath(const std::string &Path) { return ResourceName.str(); } +static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { + OwningPtr<MemoryBuffer> MB; + if (MemoryBuffer::getFileOrSTDIN(Path, MB)) + return false; + return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); +} + +static bool findDebugBinary(const std::string &OrigPath, + const std::string &DebuglinkName, uint32_t CRCHash, + std::string &Result) { + std::string OrigRealPath = OrigPath; +#if defined(HAVE_REALPATH) + if (char *RP = realpath(OrigPath.c_str(), NULL)) { + OrigRealPath = RP; + free(RP); + } +#endif + SmallString<16> OrigDir(OrigRealPath); + llvm::sys::path::remove_filename(OrigDir); + SmallString<16> DebugPath = OrigDir; + // Try /path/to/original_binary/debuglink_name + llvm::sys::path::append(DebugPath, DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /path/to/original_binary/.debug/debuglink_name + DebugPath = OrigRealPath; + llvm::sys::path::append(DebugPath, ".debug", DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + // Try /usr/lib/debug/path/to/original_binary/debuglink_name + DebugPath = "/usr/lib/debug"; + llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir), + DebuglinkName); + if (checkFileCRC(DebugPath, CRCHash)) { + Result = DebugPath.str(); + return true; + } + return false; +} + +static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName, + uint32_t &CRCHash) { + const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin); + if (!Obj) + return false; + error_code EC; + for (section_iterator I = Obj->begin_sections(), E = Obj->end_sections(); + I != E; I.increment(EC)) { + StringRef Name; + I->getName(Name); + Name = Name.substr(Name.find_first_not_of("._")); + if (Name == "gnu_debuglink") { + StringRef Data; + I->getContents(Data); + DataExtractor DE(Data, Obj->isLittleEndian(), 0); + uint32_t Offset = 0; + if (const char *DebugNameStr = DE.getCStr(&Offset)) { + // 4-byte align the offset. + Offset = (Offset + 3) & ~0x3; + if (DE.isValidOffsetForDataOfSize(Offset, 4)) { + DebugName = DebugNameStr; + CRCHash = DE.getU32(&Offset); + return true; + } + } + break; + } + } + return false; +} + LLVMSymbolizer::BinaryPair LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { BinaryMapTy::iterator I = BinaryForPath.find(Path); @@ -241,6 +321,18 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { ParsedBinariesAndObjects.push_back(DbgBin); } } + // Try to locate the debug binary using .gnu_debuglink section. + if (DbgBin == 0) { + std::string DebuglinkName; + uint32_t CRCHash; + std::string DebugBinaryPath; + if (getGNUDebuglinkContents(Bin, DebuglinkName, CRCHash) && + findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath) && + !error(createBinary(DebugBinaryPath, ParsedDbgBinary))) { + DbgBin = ParsedDbgBinary.take(); + ParsedBinariesAndObjects.push_back(DbgBin); + } + } } if (DbgBin == 0) DbgBin = Bin; @@ -344,5 +436,11 @@ std::string LLVMSymbolizer::DemangleName(const std::string &Name) { #endif } +std::string LLVMSymbolizer::DemangleGlobalName(const std::string &Name) { + // We can spoil names of globals with C linkage, so use an heuristic + // approach to check if the name should be demangled. + return (Name.substr(0, 2) == "_Z") ? DemangleName(Name) : Name; +} + } // namespace symbolize } // namespace llvm diff --git a/tools/llvm-symbolizer/LLVMSymbolize.h b/tools/llvm-symbolizer/LLVMSymbolize.h index 03c765c..eb2666a 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.h +++ b/tools/llvm-symbolizer/LLVMSymbolize.h @@ -71,6 +71,7 @@ private: ObjectFile *getObjectFileFromBinary(Binary *Bin, const std::string &ArchName); std::string printDILineInfo(DILineInfo LineInfo) const; + static std::string DemangleGlobalName(const std::string &Name); // Owns all the parsed binaries and object files. SmallVector<Binary*, 4> ParsedBinariesAndObjects; diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 5820b14..957a9f0 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -1,22 +1,38 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} - ipo scalaropts linker bitreader bitwriter mcdisassembler vectorize) + ipo scalaropts linker bitreader bitwriter lto mcdisassembler vectorize) 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 CYGWIN AND LLVM_ENABLE_PIC ) + if ( WIN32 ) + # Create .def file containing a list of exports preceeded by + # 'EXPORTS'. The file "lto.exports" already contains the list, so we + # massage it into the correct format here to create "lto.exports.def". + set(LTO_EXPORTS_DEF ${CMAKE_CURRENT_BINARY_DIR}/lto.exports.def) + set(LTO_EXPORTS_DEF_TEMP ${LTO_EXPORTS_DEF}.txt) + file(READ "lto.exports" exports_list) + file(WRITE ${LTO_EXPORTS_DEF_TEMP} "LIBRARY LTO\n") + file(APPEND ${LTO_EXPORTS_DEF_TEMP} "EXPORTS\n") + file(APPEND ${LTO_EXPORTS_DEF_TEMP} ${exports_list}) + + # Copy the file only if it has changed. + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${LTO_EXPORTS_DEF_TEMP} ${LTO_EXPORTS_DEF}) + + set(SHARED_LIB_SOURCES ${SOURCES} ${LTO_EXPORTS_DEF}) + else() + set(SHARED_LIB_SOURCES ${SOURCES}) + endif() -if( NOT WIN32 AND LLVM_ENABLE_PIC ) set(bsl ${BUILD_SHARED_LIBS}) set(BUILD_SHARED_LIBS ON) - add_llvm_library(LTO ${SOURCES}) + add_llvm_library(LTO ${SHARED_LIB_SOURCES}) set_property(TARGET LTO PROPERTY OUTPUT_NAME "LTO") set(BUILD_SHARED_LIBS ${bsl}) set(LTO_STATIC_TARGET_NAME LTO_static) @@ -28,3 +44,8 @@ if( NOT BUILD_SHARED_LIBS ) add_llvm_library(${LTO_STATIC_TARGET_NAME} ${SOURCES}) set_property(TARGET ${LTO_STATIC_TARGET_NAME} PROPERTY OUTPUT_NAME "LTO") endif() + +if( NOT CYGWIN ) + install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h + DESTINATION include/llvm-c) +endif() diff --git a/tools/lto/LTOCodeGenerator.cpp b/tools/lto/LTOCodeGenerator.cpp deleted file mode 100644 index 758227d..0000000 --- a/tools/lto/LTOCodeGenerator.cpp +++ /dev/null @@ -1,459 +0,0 @@ -//===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// -// -// 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 Link Time Optimization library. This library is -// intended to be used by linker to optimize code at link time. -// -//===----------------------------------------------------------------------===// - -#include "LTOCodeGenerator.h" -#include "LTOModule.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/InitializePasses.h" -#include "llvm/Linker.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/SubtargetFeature.h" -#include "llvm/PassManager.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/FormattedStream.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/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")); - -static cl::opt<bool> -DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), - cl::desc("Do not run the GVN load PRE pass")); - -const char* LTOCodeGenerator::getVersionString() { -#ifdef LLVM_VERSION_INFO - return PACKAGE_NAME " version " PACKAGE_VERSION ", " LLVM_VERSION_INFO; -#else - return PACKAGE_NAME " version " PACKAGE_VERSION; -#endif -} - -LTOCodeGenerator::LTOCodeGenerator() - : _context(getGlobalContext()), - _linker(new Module("ld-temp.o", _context)), _target(NULL), - _emitDwarfDebugInfo(false), _scopeRestrictionsDone(false), - _codeModel(LTO_CODEGEN_PIC_MODEL_DYNAMIC), - _nativeObjectFile(NULL) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmPrinters(); - initializeLTOPasses(); -} - -LTOCodeGenerator::~LTOCodeGenerator() { - delete _target; - delete _nativeObjectFile; - delete _linker.getModule(); - - for (std::vector<char*>::iterator I = _codegenOptions.begin(), - E = _codegenOptions.end(); I != E; ++I) - free(*I); -} - -// Initialize LTO passes. Please keep this funciton in sync with -// PassManagerBuilder::populateLTOPassManager(), and make sure all LTO -// passes are initialized. -// -void LTOCodeGenerator::initializeLTOPasses() { - PassRegistry &R = *PassRegistry::getPassRegistry(); - - initializeInternalizePassPass(R); - initializeIPSCCPPass(R); - initializeGlobalOptPass(R); - initializeConstantMergePass(R); - initializeDAHPass(R); - initializeInstCombinerPass(R); - initializeSimpleInlinerPass(R); - initializePruneEHPass(R); - initializeGlobalDCEPass(R); - initializeArgPromotionPass(R); - initializeJumpThreadingPass(R); - initializeSROAPass(R); - initializeSROA_DTPass(R); - initializeSROA_SSAUpPass(R); - initializeFunctionAttrsPass(R); - initializeGlobalsModRefPass(R); - initializeLICMPass(R); - initializeGVNPass(R); - initializeMemCpyOptPass(R); - initializeDCEPass(R); - initializeCFGSimplifyPassPass(R); -} - -bool LTOCodeGenerator::addModule(LTOModule* mod, std::string& errMsg) { - bool ret = _linker.linkInModule(mod->getLLVVMModule(), &errMsg); - - const std::vector<const char*> &undefs = mod->getAsmUndefinedRefs(); - for (int i = 0, e = undefs.size(); i != e; ++i) - _asmUndefinedRefs[undefs[i]] = 1; - - return !ret; -} - -void LTOCodeGenerator::setDebugInfo(lto_debug_model debug) { - switch (debug) { - case LTO_DEBUG_MODEL_NONE: - _emitDwarfDebugInfo = false; - return; - - case LTO_DEBUG_MODEL_DWARF: - _emitDwarfDebugInfo = true; - return; - } - llvm_unreachable("Unknown debug format!"); -} - -void LTOCodeGenerator::setCodePICModel(lto_codegen_model model) { - switch (model) { - case LTO_CODEGEN_PIC_MODEL_STATIC: - case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - _codeModel = model; - return; - } - llvm_unreachable("Unknown PIC model!"); -} - -bool LTOCodeGenerator::writeMergedModules(const char *path, - std::string &errMsg) { - if (!determineTarget(errMsg)) - return false; - - // Run the verifier on the merged modules. - PassManager passes; - passes.add(createVerifierPass()); - passes.run(*_linker.getModule()); - - // create output file - std::string ErrInfo; - tool_output_file Out(path, ErrInfo, sys::fs::F_Binary); - if (!ErrInfo.empty()) { - errMsg = "could not open bitcode file for writing: "; - errMsg += path; - return false; - } - - // write bitcode to it - WriteBitcodeToFile(_linker.getModule(), Out.os()); - Out.os().close(); - - if (Out.os().has_error()) { - errMsg = "could not write bitcode file: "; - errMsg += path; - Out.os().clear_error(); - return false; - } - - Out.keep(); - return true; -} - -bool LTOCodeGenerator::compile_to_file(const char** name, std::string& errMsg) { - // make unique temp .o file to put generated object file - SmallString<128> Filename; - int FD; - error_code EC = sys::fs::createTemporaryFile("lto-llvm", "o", FD, Filename); - if (EC) { - errMsg = EC.message(); - return false; - } - - // generate object file - tool_output_file objFile(Filename.c_str(), FD); - - bool genResult = generateObjectFile(objFile.os(), errMsg); - objFile.os().close(); - if (objFile.os().has_error()) { - objFile.os().clear_error(); - sys::fs::remove(Twine(Filename)); - return false; - } - - objFile.keep(); - if (!genResult) { - sys::fs::remove(Twine(Filename)); - return false; - } - - _nativeObjectPath = Filename.c_str(); - *name = _nativeObjectPath.c_str(); - return true; -} - -const void* LTOCodeGenerator::compile(size_t* length, std::string& errMsg) { - const char *name; - if (!compile_to_file(&name, errMsg)) - return NULL; - - // remove old buffer if compile() called twice - delete _nativeObjectFile; - - // read .o file into memory buffer - OwningPtr<MemoryBuffer> BuffPtr; - if (error_code ec = MemoryBuffer::getFile(name, BuffPtr, -1, false)) { - errMsg = ec.message(); - sys::fs::remove(_nativeObjectPath); - return NULL; - } - _nativeObjectFile = BuffPtr.take(); - - // remove temp files - sys::fs::remove(_nativeObjectPath); - - // return buffer, unless error - if (_nativeObjectFile == NULL) - return NULL; - *length = _nativeObjectFile->getBufferSize(); - return _nativeObjectFile->getBufferStart(); -} - -bool LTOCodeGenerator::determineTarget(std::string &errMsg) { - if (_target != NULL) - return true; - - // if options were requested, set them - if (!_codegenOptions.empty()) - cl::ParseCommandLineOptions(_codegenOptions.size(), - const_cast<char **>(&_codegenOptions[0])); - - std::string TripleStr = _linker.getModule()->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // create target machine from info for merged modules - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (march == NULL) - return false; - - // The relocation model is actually a static member of TargetMachine and - // needs to be set before the TargetMachine is instantiated. - Reloc::Model RelocModel = Reloc::Default; - switch (_codeModel) { - case LTO_CODEGEN_PIC_MODEL_STATIC: - RelocModel = Reloc::Static; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC: - RelocModel = Reloc::PIC_; - break; - case LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC: - RelocModel = Reloc::DynamicNoPIC; - break; - } - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - if (_mCpu.empty() && Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - _mCpu = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - _mCpu = "yonah"; - } - TargetOptions Options; - LTOModule::getTargetOptions(Options); - _target = march->createTargetMachine(TripleStr, _mCpu, FeatureStr, Options, - RelocModel, CodeModel::Default, - CodeGenOpt::Aggressive); - return true; -} - -void LTOCodeGenerator:: -applyRestriction(GlobalValue &GV, - std::vector<const char*> &mustPreserveList, - SmallPtrSet<GlobalValue*, 8> &asmUsed, - Mangler &mangler) { - SmallString<64> Buffer; - mangler.getNameWithPrefix(Buffer, &GV, false); - - if (GV.isDeclaration()) - return; - if (_mustPreserveSymbols.count(Buffer)) - mustPreserveList.push_back(GV.getName().data()); - if (_asmUndefinedRefs.count(Buffer)) - asmUsed.insert(&GV); -} - -static void findUsedValues(GlobalVariable *LLVMUsed, - SmallPtrSet<GlobalValue*, 8> &UsedValues) { - if (LLVMUsed == 0) return; - - ConstantArray *Inits = cast<ConstantArray>(LLVMUsed->getInitializer()); - for (unsigned i = 0, e = Inits->getNumOperands(); i != e; ++i) - if (GlobalValue *GV = - dyn_cast<GlobalValue>(Inits->getOperand(i)->stripPointerCasts())) - UsedValues.insert(GV); -} - -void LTOCodeGenerator::applyScopeRestrictions() { - if (_scopeRestrictionsDone) return; - Module *mergedModule = _linker.getModule(); - - // Start off with a verification pass. - PassManager passes; - passes.add(createVerifierPass()); - - // mark which symbols can not be internalized - MCContext Context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL); - Mangler mangler(Context, _target); - std::vector<const char*> mustPreserveList; - SmallPtrSet<GlobalValue*, 8> asmUsed; - - for (Module::iterator f = mergedModule->begin(), - e = mergedModule->end(); f != e; ++f) - applyRestriction(*f, mustPreserveList, asmUsed, mangler); - for (Module::global_iterator v = mergedModule->global_begin(), - e = mergedModule->global_end(); v != e; ++v) - applyRestriction(*v, mustPreserveList, asmUsed, mangler); - for (Module::alias_iterator a = mergedModule->alias_begin(), - e = mergedModule->alias_end(); a != e; ++a) - applyRestriction(*a, mustPreserveList, asmUsed, mangler); - - GlobalVariable *LLVMCompilerUsed = - mergedModule->getGlobalVariable("llvm.compiler.used"); - findUsedValues(LLVMCompilerUsed, asmUsed); - if (LLVMCompilerUsed) - LLVMCompilerUsed->eraseFromParent(); - - if (!asmUsed.empty()) { - llvm::Type *i8PTy = llvm::Type::getInt8PtrTy(_context); - std::vector<Constant*> asmUsed2; - for (SmallPtrSet<GlobalValue*, 16>::const_iterator i = asmUsed.begin(), - e = asmUsed.end(); i !=e; ++i) { - GlobalValue *GV = *i; - Constant *c = ConstantExpr::getBitCast(GV, i8PTy); - asmUsed2.push_back(c); - } - - llvm::ArrayType *ATy = llvm::ArrayType::get(i8PTy, asmUsed2.size()); - LLVMCompilerUsed = - new llvm::GlobalVariable(*mergedModule, ATy, false, - llvm::GlobalValue::AppendingLinkage, - llvm::ConstantArray::get(ATy, asmUsed2), - "llvm.compiler.used"); - - LLVMCompilerUsed->setSection("llvm.metadata"); - } - - passes.add(createInternalizePass(mustPreserveList)); - - // apply scope restrictions - passes.run(*mergedModule); - - _scopeRestrictionsDone = true; -} - -/// Optimize merged modules using various IPO passes -bool LTOCodeGenerator::generateObjectFile(raw_ostream &out, - std::string &errMsg) { - if (!this->determineTarget(errMsg)) - return false; - - Module* mergedModule = _linker.getModule(); - - // Mark which symbols can not be internalized - this->applyScopeRestrictions(); - - // Instantiate the pass manager to organize the passes. - PassManager passes; - - // Start off with a verification pass. - passes.add(createVerifierPass()); - - // Add an appropriate DataLayout instance for this module... - passes.add(new DataLayout(*_target->getDataLayout())); - _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. - if (!DisableOpt) - PassManagerBuilder().populateLTOPassManager(passes, - /*Internalize=*/false, - !DisableInline, - DisableGVNLoadPRE); - - // Make sure everything is still good. - passes.add(createVerifierPass()); - - PassManager codeGenPasses; - - codeGenPasses.add(new DataLayout(*_target->getDataLayout())); - _target->addAnalysisPasses(codeGenPasses); - - formatted_raw_ostream Out(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 false; - } - - // Run our queue of passes all at once now, efficiently. - passes.run(*mergedModule); - - // Run the code generator, and write assembly file - codeGenPasses.run(*mergedModule); - - return true; -} - -/// setCodeGenDebugOptions - Set codegen debugging options to aid in debugging -/// LTO problems. -void LTOCodeGenerator::setCodeGenDebugOptions(const char *options) { - for (std::pair<StringRef, StringRef> o = getToken(options); - !o.first.empty(); o = getToken(o.second)) { - // ParseCommandLineOptions() expects argv[0] to be program name. Lazily add - // that. - if (_codegenOptions.empty()) - _codegenOptions.push_back(strdup("libLTO")); - _codegenOptions.push_back(strdup(o.first.str().c_str())); - } -} diff --git a/tools/lto/LTOCodeGenerator.h b/tools/lto/LTOCodeGenerator.h deleted file mode 100644 index 8f37cf0..0000000 --- a/tools/lto/LTOCodeGenerator.h +++ /dev/null @@ -1,132 +0,0 @@ -//===-LTOCodeGenerator.h - LLVM Link Time Optimizer -----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the LTOCodeGenerator class. -// -// LTO compilation consists of three phases: Pre-IPO, IPO and Post-IPO. -// -// The Pre-IPO phase compiles source code into bitcode file. The resulting -// bitcode files, along with object files and libraries, will be fed to the -// linker to through the IPO and Post-IPO phases. By using obj-file extension, -// the resulting bitcode file disguises itself as an object file, and therefore -// obviates the need of writing a special set of the make-rules only for LTO -// compilation. -// -// The IPO phase perform inter-procedural analyses and optimizations, and -// the Post-IPO consists two sub-phases: intra-procedural scalar optimizations -// (SOPT), and intra-procedural target-dependent code generator (CG). -// -// As of this writing, we don't separate IPO and the Post-IPO SOPT. They -// are intermingled together, and are driven by a single pass manager (see -// PassManagerBuilder::populateLTOPassManager()). -// -// The "LTOCodeGenerator" is the driver for the IPO and Post-IPO stages. -// The "CodeGenerator" here is bit confusing. Don't confuse the "CodeGenerator" -// with the machine specific code generator. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_CODE_GENERATOR_H -#define LTO_CODE_GENERATOR_H - -#include "llvm-c/lto.h" -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Linker.h" -#include <string> -#include <vector> - -namespace llvm { - class LLVMContext; - class GlobalValue; - class Mangler; - class MemoryBuffer; - class TargetMachine; - class raw_ostream; -} - -//===----------------------------------------------------------------------===// -/// LTOCodeGenerator - C++ class which implements the opaque lto_code_gen_t -/// type. -/// -struct LTOCodeGenerator { - static const char *getVersionString(); - - LTOCodeGenerator(); - ~LTOCodeGenerator(); - - // Merge given module, return true on success. - bool addModule(struct LTOModule*, std::string &errMsg); - - void setDebugInfo(lto_debug_model); - void setCodePICModel(lto_codegen_model); - - void setCpu(const char* mCpu) { _mCpu = mCpu; } - - void addMustPreserveSymbol(const char* sym) { - _mustPreserveSymbols[sym] = 1; - } - - // To pass options to the driver and optimization passes. These options are - // not necessarily for debugging purpose (The function name is misleading). - // This function should be called before LTOCodeGenerator::compilexxx(), - // and LTOCodeGenerator::writeMergedModules(). - // - void setCodeGenDebugOptions(const char *opts); - - // Write the merged module to the file specified by the given path. - // Return true on success. - bool writeMergedModules(const char *path, std::string &errMsg); - - // Compile the merged module into a *single* object file; the path to object - // file is returned to the caller via argument "name". Return true on - // success. - // - // NOTE that it is up to the linker to remove the intermediate object file. - // Do not try to remove the object file in LTOCodeGenerator's destructor - // as we don't who (LTOCodeGenerator or the obj file) will last longer. - // - bool compile_to_file(const char **name, std::string &errMsg); - - // As with compile_to_file(), this function compiles the merged module into - // single object file. Instead of returning the object-file-path to the caller - // (linker), it brings the object to a buffer, and return the buffer to the - // caller. This function should delete intermediate object file once its content - // is brought to memory. Return NULL is the compilation was not successful. - // - const void *compile(size_t *length, std::string &errMsg); - -private: - void initializeLTOPasses(); - - bool generateObjectFile(llvm::raw_ostream &out, std::string &errMsg); - void applyScopeRestrictions(); - void applyRestriction(llvm::GlobalValue &GV, - std::vector<const char*> &mustPreserveList, - llvm::SmallPtrSet<llvm::GlobalValue*, 8> &asmUsed, - llvm::Mangler &mangler); - bool determineTarget(std::string &errMsg); - - typedef llvm::StringMap<uint8_t> StringSet; - - llvm::LLVMContext& _context; - llvm::Linker _linker; - llvm::TargetMachine* _target; - bool _emitDwarfDebugInfo; - bool _scopeRestrictionsDone; - lto_codegen_model _codeModel; - StringSet _mustPreserveSymbols; - StringSet _asmUndefinedRefs; - llvm::MemoryBuffer* _nativeObjectFile; - std::vector<char*> _codegenOptions; - std::string _mCpu; - std::string _nativeObjectPath; -}; - -#endif // LTO_CODE_GENERATOR_H diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp deleted file mode 100644 index e89733f..0000000 --- a/tools/lto/LTOModule.cpp +++ /dev/null @@ -1,902 +0,0 @@ -//===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===// -// -// 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 Link Time Optimization library. This library is -// intended to be used by linker to optimize code at link time. -// -//===----------------------------------------------------------------------===// - -#include "LTOModule.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/Support/CommandLine.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/system_error.h" -#include "llvm/Target/TargetRegisterInfo.h" -using namespace llvm; - -static cl::opt<bool> -EnableFPMAD("enable-fp-mad", - cl::desc("Enable less precise MAD instructions to be generated"), - cl::init(false)); - -static cl::opt<bool> -DisableFPElim("disable-fp-elim", - cl::desc("Disable frame pointer elimination optimization"), - cl::init(false)); - -static cl::opt<bool> -EnableUnsafeFPMath("enable-unsafe-fp-math", - cl::desc("Enable optimizations that may decrease FP precision"), - cl::init(false)); - -static cl::opt<bool> -EnableNoInfsFPMath("enable-no-infs-fp-math", - cl::desc("Enable FP math optimizations that assume no +-Infs"), - cl::init(false)); - -static cl::opt<bool> -EnableNoNaNsFPMath("enable-no-nans-fp-math", - cl::desc("Enable FP math optimizations that assume no NaNs"), - cl::init(false)); - -static cl::opt<bool> -EnableHonorSignDependentRoundingFPMath("enable-sign-dependent-rounding-fp-math", - cl::Hidden, - cl::desc("Force codegen to assume rounding mode can change dynamically"), - cl::init(false)); - -static cl::opt<bool> -GenerateSoftFloatCalls("soft-float", - cl::desc("Generate software floating point library calls"), - cl::init(false)); - -static cl::opt<llvm::FloatABI::ABIType> -FloatABIForCalls("float-abi", - cl::desc("Choose float ABI type"), - cl::init(FloatABI::Default), - cl::values( - clEnumValN(FloatABI::Default, "default", - "Target default float ABI type"), - clEnumValN(FloatABI::Soft, "soft", - "Soft float ABI (implied by -soft-float)"), - clEnumValN(FloatABI::Hard, "hard", - "Hard float ABI (uses FP registers)"), - clEnumValEnd)); - -static cl::opt<llvm::FPOpFusion::FPOpFusionMode> -FuseFPOps("fp-contract", - cl::desc("Enable aggresive formation of fused FP ops"), - cl::init(FPOpFusion::Standard), - cl::values( - clEnumValN(FPOpFusion::Fast, "fast", - "Fuse FP ops whenever profitable"), - clEnumValN(FPOpFusion::Standard, "on", - "Only fuse 'blessed' FP ops."), - clEnumValN(FPOpFusion::Strict, "off", - "Only fuse FP ops when the result won't be effected."), - clEnumValEnd)); - -static cl::opt<bool> -DontPlaceZerosInBSS("nozero-initialized-in-bss", - cl::desc("Don't place zero-initialized symbols into bss section"), - cl::init(false)); - -static cl::opt<bool> -EnableGuaranteedTailCallOpt("tailcallopt", - cl::desc("Turn fastcc calls into tail calls by (potentially) changing ABI."), - cl::init(false)); - -static cl::opt<bool> -DisableTailCalls("disable-tail-calls", - cl::desc("Never emit tail calls"), - cl::init(false)); - -static cl::opt<unsigned> -OverrideStackAlignment("stack-alignment", - cl::desc("Override default stack alignment"), - cl::init(0)); - -static cl::opt<std::string> -TrapFuncName("trap-func", cl::Hidden, - cl::desc("Emit a call to trap function rather than a trap instruction"), - cl::init("")); - -static cl::opt<bool> -EnablePIE("enable-pie", - cl::desc("Assume the creation of a position independent executable."), - cl::init(false)); - -static cl::opt<bool> -SegmentedStacks("segmented-stacks", - cl::desc("Use segmented stacks if possible."), - cl::init(false)); - -static cl::opt<bool> -UseInitArray("use-init-array", - cl::desc("Use .init_array instead of .ctors."), - cl::init(false)); - -LTOModule::LTOModule(llvm::Module *m, llvm::TargetMachine *t) - : _module(m), _target(t), - _context(_target->getMCAsmInfo(), _target->getRegisterInfo(), NULL), - _mangler(_context, t) {} - -/// isBitcodeFile - Returns 'true' if the file (or memory contents) is LLVM -/// bitcode. -bool LTOModule::isBitcodeFile(const void *mem, size_t length) { - return sys::fs::identify_magic(StringRef((const char *)mem, length)) == - sys::fs::file_magic::bitcode; -} - -bool LTOModule::isBitcodeFile(const char *path) { - sys::fs::file_magic type; - if (sys::fs::identify_magic(path, type)) - return false; - return type == sys::fs::file_magic::bitcode; -} - -/// isBitcodeFileForTarget - Returns 'true' if the file (or memory contents) is -/// LLVM bitcode for the specified triple. -bool LTOModule::isBitcodeFileForTarget(const void *mem, size_t length, - const char *triplePrefix) { - MemoryBuffer *buffer = makeBuffer(mem, length); - if (!buffer) - return false; - return isTargetMatch(buffer, triplePrefix); -} - -bool LTOModule::isBitcodeFileForTarget(const char *path, - const char *triplePrefix) { - OwningPtr<MemoryBuffer> buffer; - if (MemoryBuffer::getFile(path, buffer)) - return false; - return isTargetMatch(buffer.take(), triplePrefix); -} - -/// isTargetMatch - Returns 'true' if the memory buffer is for the specified -/// target triple. -bool LTOModule::isTargetMatch(MemoryBuffer *buffer, const char *triplePrefix) { - std::string Triple = getBitcodeTargetTriple(buffer, getGlobalContext()); - delete buffer; - return strncmp(Triple.c_str(), triplePrefix, strlen(triplePrefix)) == 0; -} - -/// makeLTOModule - Create an LTOModule. N.B. These methods take ownership of -/// the buffer. -LTOModule *LTOModule::makeLTOModule(const char *path, std::string &errMsg) { - OwningPtr<MemoryBuffer> buffer; - if (error_code ec = MemoryBuffer::getFile(path, buffer)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t size, std::string &errMsg) { - return makeLTOModule(fd, path, size, 0, errMsg); -} - -LTOModule *LTOModule::makeLTOModule(int fd, const char *path, - size_t map_size, - off_t offset, - std::string &errMsg) { - OwningPtr<MemoryBuffer> buffer; - if (error_code ec = - MemoryBuffer::getOpenFileSlice(fd, path, buffer, map_size, offset)) { - errMsg = ec.message(); - return NULL; - } - return makeLTOModule(buffer.take(), errMsg); -} - -LTOModule *LTOModule::makeLTOModule(const void *mem, size_t length, - std::string &errMsg) { - OwningPtr<MemoryBuffer> buffer(makeBuffer(mem, length)); - if (!buffer) - return NULL; - return makeLTOModule(buffer.take(), errMsg); -} - -void LTOModule::getTargetOptions(TargetOptions &Options) { - Options.LessPreciseFPMADOption = EnableFPMAD; - Options.NoFramePointerElim = DisableFPElim; - Options.AllowFPOpFusion = FuseFPOps; - Options.UnsafeFPMath = EnableUnsafeFPMath; - Options.NoInfsFPMath = EnableNoInfsFPMath; - Options.NoNaNsFPMath = EnableNoNaNsFPMath; - Options.HonorSignDependentRoundingFPMathOption = - EnableHonorSignDependentRoundingFPMath; - Options.UseSoftFloat = GenerateSoftFloatCalls; - if (FloatABIForCalls != FloatABI::Default) - Options.FloatABIType = FloatABIForCalls; - Options.NoZerosInBSS = DontPlaceZerosInBSS; - Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; - Options.DisableTailCalls = DisableTailCalls; - Options.StackAlignmentOverride = OverrideStackAlignment; - Options.TrapFuncName = TrapFuncName; - Options.PositionIndependentExecutable = EnablePIE; - Options.EnableSegmentedStacks = SegmentedStacks; - Options.UseInitArray = UseInitArray; -} - -LTOModule *LTOModule::makeLTOModule(MemoryBuffer *buffer, - std::string &errMsg) { - static bool Initialized = false; - if (!Initialized) { - InitializeAllTargets(); - InitializeAllTargetMCs(); - InitializeAllAsmParsers(); - Initialized = true; - } - - // parse bitcode buffer - OwningPtr<Module> m(getLazyBitcodeModule(buffer, getGlobalContext(), - &errMsg)); - if (!m) { - delete buffer; - return NULL; - } - - std::string TripleStr = m->getTargetTriple(); - if (TripleStr.empty()) - TripleStr = sys::getDefaultTargetTriple(); - llvm::Triple Triple(TripleStr); - - // find machine architecture for this module - const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); - if (!march) - return NULL; - - // construct LTOModule, hand over ownership of module and target - SubtargetFeatures Features; - Features.getDefaultSubtargetFeatures(Triple); - std::string FeatureStr = Features.getString(); - // Set a default CPU for Darwin triples. - std::string CPU; - if (Triple.isOSDarwin()) { - if (Triple.getArch() == llvm::Triple::x86_64) - CPU = "core2"; - else if (Triple.getArch() == llvm::Triple::x86) - CPU = "yonah"; - } - TargetOptions Options; - getTargetOptions(Options); - TargetMachine *target = march->createTargetMachine(TripleStr, CPU, FeatureStr, - Options); - LTOModule *Ret = new LTOModule(m.take(), target); - if (Ret->parseSymbols(errMsg)) { - delete Ret; - return NULL; - } - - return Ret; -} - -/// makeBuffer - Create a MemoryBuffer from a memory range. -MemoryBuffer *LTOModule::makeBuffer(const void *mem, size_t length) { - const char *startPtr = (const char*)mem; - return MemoryBuffer::getMemBuffer(StringRef(startPtr, length), "", false); -} - -/// objcClassNameFromExpression - Get string that the data pointer points to. -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(); - if (ConstantDataArray *ca = dyn_cast<ConstantDataArray>(cn)) { - if (ca->isCString()) { - name = ".objc_class_name_" + ca->getAsCString().str(); - return true; - } - } - } - } - return false; -} - -/// addObjCClass - Parse i386/ppc ObjC class data structure. -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 - std::string superclassName; - if (objcClassNameFromExpression(c->getOperand(1), superclassName)) { - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(superclassName); - if (!entry.getValue().name) { - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); - } - } - - // third slot in __OBJC,__class is pointer to class name - std::string className; - if (objcClassNameFromExpression(c->getOperand(2), className)) { - StringSet::value_type &entry = _defines.GetOrCreateValue(className); - entry.setValue(1); - - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = LTO_SYMBOL_PERMISSIONS_DATA | - LTO_SYMBOL_DEFINITION_REGULAR | LTO_SYMBOL_SCOPE_DEFAULT; - info.isFunction = false; - info.symbol = clgv; - _symbols.push_back(info); - } -} - -/// addObjCCategory - Parse i386/ppc ObjC category data structure. -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 - std::string targetclassName; - if (!objcClassNameFromExpression(c->getOperand(1), targetclassName)) - return; - - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addObjCClassRef - Parse i386/ppc ObjC class list data structure. -void LTOModule::addObjCClassRef(const GlobalVariable *clgv) { - std::string targetclassName; - if (!objcClassNameFromExpression(clgv->getInitializer(), targetclassName)) - return; - - NameAndAttributes info; - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(targetclassName); - if (entry.getValue().name) - return; - - const char *symbolName = entry.getKey().data(); - info.name = symbolName; - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - info.isFunction = false; - info.symbol = clgv; - entry.setValue(info); -} - -/// addDefinedDataSymbol - Add a data symbol as defined to the list. -void LTOModule::addDefinedDataSymbol(const GlobalValue *v) { - // Add to list of defined symbols. - addDefinedSymbol(v, false); - - if (!v->hasSection() /* || !isTargetDarwin */) - return; - - // Special case i386/ppc ObjC data structures in magic sections: - // The issue is that the old ObjC object format did some strange - // contortions to avoid real linker symbols. For instance, the - // ObjC class data structure is allocated statically in the executable - // that defines that class. That data structures contains a pointer to - // its superclass. But instead of just initializing that part of the - // struct to the address of its superclass, and letting the static and - // dynamic linkers do the rest, the runtime works by having that field - // instead point to a C-string that is the name of the superclass. - // At runtime the objc initialization updates that pointer and sets - // it to point to the actual super class. As far as the linker - // knows it is just a pointer to a string. But then someone wanted the - // linker to issue errors at build time if the superclass was not found. - // So they figured out a way in mach-o object format to use an absolute - // symbols (.objc_class_name_Foo = 0) and a floating reference - // (.reference .objc_class_name_Bar) to cause the linker into erroring when - // a class was missing. - // The following synthesizes the implicit .objc_* symbols for the linker - // from the ObjC data structures generated by the front end. - - // special case if this data blob is an ObjC class definition - if (v->getSection().compare(0, 15, "__OBJC,__class,") == 0) { - 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 (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 (const GlobalVariable *gv = dyn_cast<GlobalVariable>(v)) { - addObjCClassRef(gv); - } - } -} - -/// addDefinedFunctionSymbol - Add a function symbol as defined to the list. -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(const GlobalValue *def, bool isFunction) { - // ignore all llvm.* symbols - if (def->getName().startswith("llvm.")) - return; - - // string is owned by _defines - SmallString<64> Buffer; - _mangler.getNameWithPrefix(Buffer, def, false); - - // set alignment part log2() can have rounding errors - uint32_t align = def->getAlignment(); - uint32_t attr = align ? countTrailingZeros(def->getAlignment()) : 0; - - // set permissions part - if (isFunction) { - attr |= LTO_SYMBOL_PERMISSIONS_CODE; - } else { - const GlobalVariable *gv = dyn_cast<GlobalVariable>(def); - if (gv && gv->isConstant()) - attr |= LTO_SYMBOL_PERMISSIONS_RODATA; - else - attr |= LTO_SYMBOL_PERMISSIONS_DATA; - } - - // set definition part - if (def->hasWeakLinkage() || def->hasLinkOnceLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_DEFINITION_WEAK; - else if (def->hasCommonLinkage()) - attr |= LTO_SYMBOL_DEFINITION_TENTATIVE; - else - attr |= LTO_SYMBOL_DEFINITION_REGULAR; - - // set scope part - if (def->hasHiddenVisibility()) - attr |= LTO_SYMBOL_SCOPE_HIDDEN; - else if (def->hasProtectedVisibility()) - attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (def->hasExternalLinkage() || def->hasWeakLinkage() || - def->hasLinkOnceLinkage() || def->hasCommonLinkage() || - def->hasLinkerPrivateWeakLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - else if (def->hasLinkOnceODRAutoHideLinkage()) - attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; - else - attr |= LTO_SYMBOL_SCOPE_INTERNAL; - - StringSet::value_type &entry = _defines.GetOrCreateValue(Buffer); - entry.setValue(1); - - // fill information structure - NameAndAttributes info; - StringRef Name = entry.getKey(); - info.name = Name.data(); - assert(info.name[Name.size()] == '\0'); - info.attributes = attr; - info.isFunction = isFunction; - info.symbol = def; - - // add to table of symbols - _symbols.push_back(info); -} - -/// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the -/// defined list. -void LTOModule::addAsmGlobalSymbol(const char *name, - lto_symbol_attributes scope) { - StringSet::value_type &entry = _defines.GetOrCreateValue(name); - - // only add new define if not already defined - if (entry.getValue()) - return; - - entry.setValue(1); - - NameAndAttributes &info = _undefines[entry.getKey().data()]; - - if (info.symbol == 0) { - // FIXME: This is trying to take care of module ASM like this: - // - // module asm ".zerofill __FOO, __foo, _bar_baz_qux, 0" - // - // but is gross and its mother dresses it funny. Have the ASM parser give us - // more details for this type of situation so that we're not guessing so - // much. - - // fill information structure - info.name = entry.getKey().data(); - info.attributes = - LTO_SYMBOL_PERMISSIONS_DATA | LTO_SYMBOL_DEFINITION_REGULAR | scope; - info.isFunction = false; - info.symbol = 0; - - // add to table of symbols - _symbols.push_back(info); - return; - } - - if (info.isFunction) - addDefinedFunctionSymbol(cast<Function>(info.symbol)); - else - addDefinedDataSymbol(info.symbol); - - _symbols.back().attributes &= ~LTO_SYMBOL_SCOPE_MASK; - _symbols.back().attributes |= scope; -} - -/// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to the -/// undefined list. -void LTOModule::addAsmGlobalSymbolUndef(const char *name) { - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(name); - - _asm_undefines.push_back(entry.getKey().data()); - - // we already have the symbol - if (entry.getValue().name) - return; - - uint32_t attr = LTO_SYMBOL_DEFINITION_UNDEFINED;; - attr |= LTO_SYMBOL_SCOPE_DEFAULT; - NameAndAttributes info; - info.name = entry.getKey().data(); - info.attributes = attr; - info.isFunction = false; - info.symbol = 0; - - entry.setValue(info); -} - -/// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet to a -/// list to be resolved later. -void -LTOModule::addPotentialUndefinedSymbol(const GlobalValue *decl, bool isFunc) { - // ignore all llvm.* symbols - if (decl->getName().startswith("llvm.")) - return; - - // ignore all aliases - if (isa<GlobalAlias>(decl)) - return; - - SmallString<64> name; - _mangler.getNameWithPrefix(name, decl, false); - - StringMap<NameAndAttributes>::value_type &entry = - _undefines.GetOrCreateValue(name); - - // we already have the symbol - if (entry.getValue().name) - return; - - NameAndAttributes info; - - info.name = entry.getKey().data(); - - if (decl->hasExternalWeakLinkage()) - info.attributes = LTO_SYMBOL_DEFINITION_WEAKUNDEF; - else - info.attributes = LTO_SYMBOL_DEFINITION_UNDEFINED; - - info.isFunction = isFunc; - info.symbol = decl; - - entry.setValue(info); -} - -namespace { - class RecordStreamer : public MCStreamer { - public: - enum State { NeverSeen, Global, Defined, DefinedGlobal, Used }; - - private: - StringMap<State> Symbols; - - void markDefined(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Global: - S = DefinedGlobal; - break; - case NeverSeen: - case Defined: - case Used: - S = Defined; - break; - } - } - void markGlobal(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - S = DefinedGlobal; - break; - - case NeverSeen: - case Global: - case Used: - S = Global; - break; - } - } - void markUsed(const MCSymbol &Symbol) { - State &S = Symbols[Symbol.getName()]; - switch (S) { - case DefinedGlobal: - case Defined: - case Global: - break; - - case NeverSeen: - case Used: - S = Used; - break; - } - } - - // FIXME: mostly copied for the obj streamer. - void AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: - // FIXME: What should we do in here? - break; - - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - markUsed(cast<MCSymbolRefExpr>(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); - break; - } - } - - public: - typedef StringMap<State>::const_iterator const_iterator; - - const_iterator begin() { - return Symbols.begin(); - } - - const_iterator end() { - return Symbols.end(); - } - - RecordStreamer(MCContext &Context) - : MCStreamer(SK_RecordStreamer, Context) {} - - virtual void EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - } - virtual void EmitLabel(MCSymbol *Symbol) { - Symbol->setSection(*getCurrentSection().first); - markDefined(*Symbol); - } - virtual void EmitDebugLabel(MCSymbol *Symbol) { - EmitLabel(Symbol); - } - virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { - // FIXME: should we handle aliases? - markDefined(*Symbol); - } - virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { - if (Attribute == MCSA_Global) - markGlobal(*Symbol); - } - virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size , unsigned ByteAlignment) { - markDefined(*Symbol); - } - virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { - markDefined(*Symbol); - } - - virtual void EmitBundleAlignMode(unsigned AlignPow2) {} - virtual void EmitBundleLock(bool AlignToEnd) {} - virtual void EmitBundleUnlock() {} - - // Noop calls. - virtual void ChangeSection(const MCSection *Section, - const MCExpr *Subsection) {} - virtual void InitToTextSection() {} - virtual void InitSections() {} - virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} - virtual void EmitThumbFunc(MCSymbol *Func) {} - virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} - virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {} - virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} - virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} - virtual void EmitCOFFSymbolType(int Type) {} - virtual void EndCOFFSymbolDef() {} - virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) {} - virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment) {} - virtual void EmitBytes(StringRef Data) {} - virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} - virtual void EmitULEB128Value(const MCExpr *Value) {} - virtual void EmitSLEB128Value(const MCExpr *Value) {} - virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, - unsigned ValueSize, - unsigned MaxBytesToEmit) {} - virtual void EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit) {} - virtual bool EmitValueToOffset(const MCExpr *Offset, - unsigned char Value ) { return false; } - virtual void EmitFileDirective(StringRef Filename) {} - virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, - const MCSymbol *LastLabel, - const MCSymbol *Label, - unsigned PointerSize) {} - virtual void FinishImpl() {} - - static bool classof(const MCStreamer *S) { - return S->getKind() == SK_RecordStreamer; - } - }; -} // end anonymous namespace - -/// addAsmGlobalSymbols - Add global symbols from module-level ASM to the -/// defined or undefined lists. -bool LTOModule::addAsmGlobalSymbols(std::string &errMsg) { - const std::string &inlineAsm = _module->getModuleInlineAsm(); - if (inlineAsm.empty()) - return false; - - OwningPtr<RecordStreamer> Streamer(new RecordStreamer(_context)); - MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(inlineAsm); - SourceMgr SrcMgr; - SrcMgr.AddNewSourceBuffer(Buffer, SMLoc()); - OwningPtr<MCAsmParser> Parser(createMCAsmParser(SrcMgr, - _context, *Streamer, - *_target->getMCAsmInfo())); - const Target &T = _target->getTarget(); - OwningPtr<MCSubtargetInfo> - STI(T.createMCSubtargetInfo(_target->getTargetTriple(), - _target->getTargetCPU(), - _target->getTargetFeatureString())); - OwningPtr<MCTargetAsmParser> TAP(T.createMCAsmParser(*STI, *Parser.get())); - if (!TAP) { - errMsg = "target " + std::string(T.getName()) + - " does not define AsmParser."; - return true; - } - - Parser->setTargetParser(*TAP); - if (Parser->Run(false)) - return true; - - for (RecordStreamer::const_iterator i = Streamer->begin(), - e = Streamer->end(); i != e; ++i) { - StringRef Key = i->first(); - RecordStreamer::State Value = i->second; - if (Value == RecordStreamer::DefinedGlobal) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_DEFAULT); - else if (Value == RecordStreamer::Defined) - addAsmGlobalSymbol(Key.data(), LTO_SYMBOL_SCOPE_INTERNAL); - else if (Value == RecordStreamer::Global || - Value == RecordStreamer::Used) - addAsmGlobalSymbolUndef(Key.data()); - } - - return false; -} - -/// isDeclaration - Return 'true' if the global value is a declaration. -static bool isDeclaration(const GlobalValue &V) { - if (V.hasAvailableExternallyLinkage()) - return true; - - if (V.isMaterializable()) - return false; - - return V.isDeclaration(); -} - -/// parseSymbols - Parse the symbols from the module and model-level ASM and add -/// them to either the defined or undefined lists. -bool LTOModule::parseSymbols(std::string &errMsg) { - // add functions - for (Module::iterator f = _module->begin(), e = _module->end(); f != e; ++f) { - if (isDeclaration(*f)) - addPotentialUndefinedSymbol(f, true); - else - addDefinedFunctionSymbol(f); - } - - // add data - for (Module::global_iterator v = _module->global_begin(), - e = _module->global_end(); v != e; ++v) { - if (isDeclaration(*v)) - addPotentialUndefinedSymbol(v, false); - else - addDefinedDataSymbol(v); - } - - // add asm globals - if (addAsmGlobalSymbols(errMsg)) - return true; - - // add aliases - for (Module::alias_iterator a = _module->alias_begin(), - e = _module->alias_end(); a != e; ++a) { - if (isDeclaration(*a->getAliasedGlobal())) - // Is an alias to a declaration. - addPotentialUndefinedSymbol(a, false); - else - addDefinedDataSymbol(a); - } - - // make symbols for all undefines - for (StringMap<NameAndAttributes>::iterator u =_undefines.begin(), - e = _undefines.end(); u != e; ++u) { - // If this symbol also has a definition, then don't make an undefine because - // it is a tentative definition. - if (_defines.count(u->getKey())) continue; - NameAndAttributes info = u->getValue(); - _symbols.push_back(info); - } - - return false; -} diff --git a/tools/lto/LTOModule.h b/tools/lto/LTOModule.h deleted file mode 100644 index 902e9c5..0000000 --- a/tools/lto/LTOModule.h +++ /dev/null @@ -1,190 +0,0 @@ -//===-LTOModule.h - LLVM Link Time Optimizer ------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file declares the LTOModule class. -// -//===----------------------------------------------------------------------===// - -#ifndef LTO_MODULE_H -#define LTO_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 <string> -#include <vector> - -// Forward references to llvm classes. -namespace llvm { - class Function; - class GlobalValue; - class MemoryBuffer; - class TargetOptions; - class Value; -} - -//===----------------------------------------------------------------------===// -/// LTOModule - C++ class which implements the opaque lto_module_t type. -/// -struct LTOModule { -private: - typedef llvm::StringMap<uint8_t> StringSet; - - struct NameAndAttributes { - const char *name; - uint32_t attributes; - bool isFunction; - const llvm::GlobalValue *symbol; - }; - - llvm::OwningPtr<llvm::Module> _module; - llvm::OwningPtr<llvm::TargetMachine> _target; - std::vector<NameAndAttributes> _symbols; - - // _defines and _undefines only needed to disambiguate tentative definitions - StringSet _defines; - llvm::StringMap<NameAndAttributes> _undefines; - std::vector<const char*> _asm_undefines; - llvm::MCContext _context; - - // Use mangler to add GlobalPrefix to names to match linker names. - llvm::Mangler _mangler; - - LTOModule(llvm::Module *m, llvm::TargetMachine *t); -public: - /// isBitcodeFile - Returns 'true' if the file or memory contents is LLVM - /// bitcode. - static bool isBitcodeFile(const void *mem, size_t length); - static bool isBitcodeFile(const char *path); - - /// isBitcodeFileForTarget - Returns 'true' if the file or memory contents - /// is LLVM bitcode for the specified triple. - static bool isBitcodeFileForTarget(const void *mem, - size_t length, - const char *triplePrefix); - static bool isBitcodeFileForTarget(const char *path, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule. N.B. These methods take ownership - /// of the buffer. - static LTOModule *makeLTOModule(const char* path, - std::string &errMsg); - static LTOModule *makeLTOModule(int fd, const char *path, - size_t size, std::string &errMsg); - static LTOModule *makeLTOModule(int fd, const char *path, - size_t map_size, - off_t offset, - std::string& errMsg); - static LTOModule *makeLTOModule(const void *mem, size_t length, - std::string &errMsg); - - /// getTargetTriple - Return the Module's target triple. - const char *getTargetTriple() { - return _module->getTargetTriple().c_str(); - } - - /// setTargetTriple - Set the Module's target triple. - void setTargetTriple(const char *triple) { - _module->setTargetTriple(triple); - } - - /// getSymbolCount - Get the number of symbols - uint32_t getSymbolCount() { - return _symbols.size(); - } - - /// getSymbolAttributes - Get the attributes for a symbol at the specified - /// index. - lto_symbol_attributes getSymbolAttributes(uint32_t index) { - if (index < _symbols.size()) - return lto_symbol_attributes(_symbols[index].attributes); - return lto_symbol_attributes(0); - } - - /// getSymbolName - Get the name of the symbol at the specified index. - const char *getSymbolName(uint32_t index) { - if (index < _symbols.size()) - return _symbols[index].name; - return NULL; - } - - /// getLLVVMModule - Return the Module. - llvm::Module *getLLVVMModule() { return _module.get(); } - - /// getAsmUndefinedRefs - - const std::vector<const char*> &getAsmUndefinedRefs() { - return _asm_undefines; - } - - /// getTargetOptions - Fill the TargetOptions object with the options - /// specified on the command line. - static void getTargetOptions(llvm::TargetOptions &Options); - -private: - /// parseSymbols - Parse the symbols from the module and model-level ASM and - /// add them to either the defined or undefined lists. - bool parseSymbols(std::string &errMsg); - - /// addPotentialUndefinedSymbol - Add a symbol which isn't defined just yet - /// to a list to be resolved later. - void addPotentialUndefinedSymbol(const llvm::GlobalValue *dcl, bool isFunc); - - /// addDefinedSymbol - Add a defined symbol to the list. - void addDefinedSymbol(const llvm::GlobalValue *def, bool isFunction); - - /// addDefinedFunctionSymbol - Add a function symbol as defined to the list. - void addDefinedFunctionSymbol(const llvm::Function *f); - - /// addDefinedDataSymbol - Add a data symbol as defined to the list. - void addDefinedDataSymbol(const llvm::GlobalValue *v); - - /// addAsmGlobalSymbols - Add global symbols from module-level ASM to the - /// defined or undefined lists. - bool addAsmGlobalSymbols(std::string &errMsg); - - /// addAsmGlobalSymbol - Add a global symbol from module-level ASM to the - /// defined list. - void addAsmGlobalSymbol(const char *, lto_symbol_attributes scope); - - /// addAsmGlobalSymbolUndef - Add a global symbol from module-level ASM to - /// the undefined list. - void addAsmGlobalSymbolUndef(const char *); - - /// addObjCClass - Parse i386/ppc ObjC class data structure. - void addObjCClass(const llvm::GlobalVariable *clgv); - - /// addObjCCategory - Parse i386/ppc ObjC category data structure. - void addObjCCategory(const llvm::GlobalVariable *clgv); - - /// addObjCClassRef - Parse i386/ppc ObjC class list data structure. - void addObjCClassRef(const llvm::GlobalVariable *clgv); - - /// objcClassNameFromExpression - Get string that the data pointer points - /// to. - bool objcClassNameFromExpression(const llvm::Constant* c, std::string &name); - - /// isTargetMatch - Returns 'true' if the memory buffer is for the specified - /// target triple. - static bool isTargetMatch(llvm::MemoryBuffer *memBuffer, - const char *triplePrefix); - - /// makeLTOModule - Create an LTOModule (private version). N.B. This - /// method takes ownership of the buffer. - static LTOModule *makeLTOModule(llvm::MemoryBuffer *buffer, - std::string &errMsg); - - /// makeBuffer - Create a MemoryBuffer from a memory range. - static llvm::MemoryBuffer *makeBuffer(const void *mem, size_t length); -}; - -#endif // LTO_MODULE_H diff --git a/tools/lto/Makefile b/tools/lto/Makefile index 56c67df..cedbee1 100644 --- a/tools/lto/Makefile +++ b/tools/lto/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. LIBRARYNAME := LTO LINK_COMPONENTS := all-targets ipo scalaropts linker bitreader bitwriter \ - mcdisassembler vectorize + lto mcdisassembler vectorize LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 @@ -46,7 +46,7 @@ ifeq ($(HOST_OS),Darwin) ifneq ($(DARWIN_VERS),8) LLVMLibsOptions := $(LLVMLibsOptions) \ -Wl,-install_name \ - -Wl,"@rpath/lib$(LIBRARYNAME)$(SHLIBEXT)" + -Wl,"@executable_path/../lib/lib$(LIBRARYNAME)$(SHLIBEXT)" endif # If we're doing an Apple-style build, add the LTO object path. diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index db7147c..7bfddcd 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,15 +13,71 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" -#include "LTOCodeGenerator.h" -#include "LTOModule.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" #include "llvm-c/Core.h" +#include "llvm-c/Target.h" +// extra command-line flags needed for LTOCodeGenerator +static cl::opt<bool> +DisableOpt("disable-opt", cl::init(false), + cl::desc("Do not run any optimization passes")); + +static cl::opt<bool> +DisableInline("disable-inlining", cl::init(false), + cl::desc("Do not run the inliner pass")); + +static cl::opt<bool> +DisableGVNLoadPRE("disable-gvn-loadpre", cl::init(false), + cl::desc("Do not run the GVN load PRE pass")); // Holds most recent error string. // *** Not thread safe *** static std::string sLastErrorString; +// Holds the initialization state of the LTO module. +// *** Not thread safe *** +static bool initialized = false; + +// Holds the command-line option parsing state of the LTO module. +static bool parsedOptions = false; + +// Initialize the configured targets if they have not been initialized. +static void lto_initialize() { + if (!initialized) { + LLVMInitializeAllTargetInfos(); + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllDisassemblers(); + initialized = true; + } +} + +static void lto_set_target_options(llvm::TargetOptions &Options) { + Options.LessPreciseFPMADOption = EnableFPMAD; + Options.NoFramePointerElim = DisableFPElim; + Options.AllowFPOpFusion = FuseFPOps; + Options.UnsafeFPMath = EnableUnsafeFPMath; + Options.NoInfsFPMath = EnableNoInfsFPMath; + Options.NoNaNsFPMath = EnableNoNaNsFPMath; + Options.HonorSignDependentRoundingFPMathOption = + EnableHonorSignDependentRoundingFPMath; + Options.UseSoftFloat = GenerateSoftFloatCalls; + if (FloatABIForCalls != llvm::FloatABI::Default) + Options.FloatABIType = FloatABIForCalls; + Options.NoZerosInBSS = DontPlaceZerosInBSS; + Options.GuaranteedTailCallOpt = EnableGuaranteedTailCallOpt; + Options.DisableTailCalls = DisableTailCalls; + Options.StackAlignmentOverride = OverrideStackAlignment; + Options.TrapFuncName = TrapFuncName; + Options.PositionIndependentExecutable = EnablePIE; + Options.EnableSegmentedStacks = SegmentedStacks; + Options.UseInitArray = UseInitArray; +} + /// lto_get_version - Returns a printable string. extern const char* lto_get_version() { return LTOCodeGenerator::getVersionString(); @@ -63,13 +119,19 @@ lto_module_is_object_file_in_memory_for_target(const void* mem, /// lto_module_create - Loads an object file from disk. Returns NULL on error /// (check lto_get_error_message() for details). lto_module_t lto_module_create(const char* path) { - return LTOModule::makeLTOModule(path, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(path, Options, sLastErrorString); } /// lto_module_create_from_fd - Loads an object file from disk. Returns NULL on /// error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { - return LTOModule::makeLTOModule(fd, path, size, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(fd, path, size, Options, sLastErrorString); } /// lto_module_create_from_fd_at_offset - Loads an object file from disk. @@ -78,13 +140,20 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, size_t file_size, size_t map_size, off_t offset) { - return LTOModule::makeLTOModule(fd, path, map_size, offset, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(fd, path, map_size, offset, Options, + sLastErrorString); } /// lto_module_create_from_memory - Loads an object file from memory. Returns /// NULL on error (check lto_get_error_message() for details). lto_module_t lto_module_create_from_memory(const void* mem, size_t length) { - return LTOModule::makeLTOModule(mem, length, sLastErrorString); + lto_initialize(); + llvm::TargetOptions Options; + lto_set_target_options(Options); + return LTOModule::makeLTOModule(mem, length, Options, sLastErrorString); } /// lto_module_dispose - Frees all memory for a module. Upon return the @@ -127,7 +196,15 @@ lto_symbol_attributes lto_module_get_symbol_attribute(lto_module_t mod, /// lto_codegen_create - Instantiates a code generator. Returns NULL if there /// is an error. lto_code_gen_t lto_codegen_create(void) { - return new LTOCodeGenerator(); + lto_initialize(); + + TargetOptions Options; + lto_set_target_options(Options); + + LTOCodeGenerator *CodeGen = new LTOCodeGenerator(); + if (CodeGen) + CodeGen->setTargetOptions(Options); + return CodeGen; } /// lto_codegen_dispose - Frees all memory for a code generator. Upon return the @@ -187,6 +264,10 @@ void lto_codegen_add_must_preserve_symbol(lto_code_gen_t cg, /// that contains the merged contents of all modules added so far. Returns true /// on error (check lto_get_error_message() for details). bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } return !cg->writeMergedModules(path, sLastErrorString); } @@ -197,14 +278,24 @@ bool lto_codegen_write_merged_modules(lto_code_gen_t cg, const char *path) { /// lto_codegen_compile() is called again. On failure, returns NULL (check /// lto_get_error_message() for details). const void *lto_codegen_compile(lto_code_gen_t cg, size_t *length) { - return cg->compile(length, sLastErrorString); + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } + return cg->compile(length, DisableOpt, DisableInline, DisableGVNLoadPRE, + sLastErrorString); } /// lto_codegen_compile_to_file - Generates code for all added modules into one /// native object file. The name of the file is written to name. Returns true on /// error. bool lto_codegen_compile_to_file(lto_code_gen_t cg, const char **name) { - return !cg->compile_to_file(name, sLastErrorString); + if (!parsedOptions) { + cg->parseCodeGenDebugOptions(); + parsedOptions = true; + } + return !cg->compile_to_file(name, DisableOpt, DisableInline, DisableGVNLoadPRE, + sLastErrorString); } /// lto_codegen_debug_options - Used to pass extra options to the code diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 897a785..0dfbd5f 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -97,12 +97,12 @@ static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, outs() << " ('_relocations', [\n"; unsigned RelNum = 0; error_code EC; - for (relocation_iterator I = Obj.getSectionRelBegin(Index), - E = Obj.getSectionRelEnd(Index); I != E; I.increment(EC), ++RelNum) { - macho::RelocationEntry RE = Obj.getRelocation(I->getRawDataRefImpl()); + for (relocation_iterator I = Obj.section_rel_begin(Index), + E = Obj.section_rel_end(Index); I != E; I.increment(EC), ++RelNum) { + MachO::any_relocation_info RE = Obj.getRelocation(I->getRawDataRefImpl()); outs() << " # Relocation " << RelNum << "\n"; - outs() << " (('word-0', " << format("0x%x", RE.Word0) << "),\n"; - outs() << " ('word-1', " << format("0x%x", RE.Word1) << ")),\n"; + outs() << " (('word-0', " << format("0x%x", RE.r_word0) << "),\n"; + outs() << " ('word-1', " << format("0x%x", RE.r_word1) << ")),\n"; } outs() << " ])\n"; @@ -124,23 +124,21 @@ static int DumpSectionData(const MachOObjectFile &Obj, unsigned Index, static int DumpSegmentCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::SegmentLoadCommand SLC = Obj.getSegmentLoadCommand(LCI); + MachO::segment_command SLC = Obj.getSegmentLoadCommand(LCI); - DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, - SLC.VMSize, SLC.FileOffset, SLC.FileSize, - SLC.MaxVMProtection, SLC.InitialVMProtection, - SLC.NumSections, SLC.Flags); + DumpSegmentCommandData(StringRef(SLC.segname, 16), SLC.vmaddr, + SLC.vmsize, SLC.fileoff, SLC.filesize, + SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); // Dump the sections. outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.NumSections; ++i) { - macho::Section Sect = Obj.getSection(LCI, i); - DumpSectionData(Obj, i, StringRef(Sect.Name, 16), - StringRef(Sect.SegmentName, 16), Sect.Address, - Sect.Size, Sect.Offset, Sect.Align, - Sect.RelocationTableOffset, - Sect.NumRelocationTableEntries, Sect.Flags, - Sect.Reserved1, Sect.Reserved2); + for (unsigned i = 0; i != SLC.nsects; ++i) { + MachO::section Sect = Obj.getSection(LCI, i); + DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), + StringRef(Sect.segname, 16), Sect.addr, + Sect.size, Sect.offset, Sect.align, + Sect.reloff, Sect.nreloc, Sect.flags, + Sect.reserved1, Sect.reserved2); } outs() << " ])\n"; @@ -149,24 +147,22 @@ static int DumpSegmentCommand(const MachOObjectFile &Obj, static int DumpSegment64Command(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::Segment64LoadCommand SLC = Obj.getSegment64LoadCommand(LCI); - DumpSegmentCommandData(StringRef(SLC.Name, 16), SLC.VMAddress, - SLC.VMSize, SLC.FileOffset, SLC.FileSize, - SLC.MaxVMProtection, SLC.InitialVMProtection, - SLC.NumSections, SLC.Flags); + MachO::segment_command_64 SLC = Obj.getSegment64LoadCommand(LCI); + DumpSegmentCommandData(StringRef(SLC.segname, 16), SLC.vmaddr, + SLC.vmsize, SLC.fileoff, SLC.filesize, + SLC.maxprot, SLC.initprot, SLC.nsects, SLC.flags); // Dump the sections. outs() << " ('sections', [\n"; - for (unsigned i = 0; i != SLC.NumSections; ++i) { - macho::Section64 Sect = Obj.getSection64(LCI, i); - - DumpSectionData(Obj, i, StringRef(Sect.Name, 16), - StringRef(Sect.SegmentName, 16), Sect.Address, - Sect.Size, Sect.Offset, Sect.Align, - Sect.RelocationTableOffset, - Sect.NumRelocationTableEntries, Sect.Flags, - Sect.Reserved1, Sect.Reserved2, - Sect.Reserved3); + for (unsigned i = 0; i != SLC.nsects; ++i) { + MachO::section_64 Sect = Obj.getSection64(LCI, i); + + DumpSectionData(Obj, i, StringRef(Sect.sectname, 16), + StringRef(Sect.segname, 16), Sect.addr, + Sect.size, Sect.offset, Sect.align, + Sect.reloff, Sect.nreloc, Sect.flags, + Sect.reserved1, Sect.reserved2, + Sect.reserved3); } outs() << " ])\n"; @@ -190,12 +186,12 @@ static void DumpSymbolTableEntryData(const MachOObjectFile &Obj, } static int DumpSymtabCommand(const MachOObjectFile &Obj) { - macho::SymtabLoadCommand SLC = Obj.getSymtabLoadCommand(); + MachO::symtab_command SLC = Obj.getSymtabLoadCommand(); - outs() << " ('symoff', " << SLC.SymbolTableOffset << ")\n"; - outs() << " ('nsyms', " << SLC.NumSymbolTableEntries << ")\n"; - outs() << " ('stroff', " << SLC.StringTableOffset << ")\n"; - outs() << " ('strsize', " << SLC.StringTableSize << ")\n"; + outs() << " ('symoff', " << SLC.symoff << ")\n"; + outs() << " ('nsyms', " << SLC.nsyms << ")\n"; + outs() << " ('stroff', " << SLC.stroff << ")\n"; + outs() << " ('strsize', " << SLC.strsize << ")\n"; // Dump the string data. outs() << " ('_string_data', '"; @@ -211,14 +207,14 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { I.increment(EC), ++SymNum) { DataRefImpl DRI = I->getRawDataRefImpl(); if (Obj.is64Bit()) { - macho::Symbol64TableEntry STE = Obj.getSymbol64TableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, - STE.SectionIndex, STE.Flags, STE.Value, + MachO::nlist_64 STE = Obj.getSymbol64TableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, + STE.n_sect, STE.n_desc, STE.n_value, StringTable); } else { - macho::SymbolTableEntry STE = Obj.getSymbolTableEntry(DRI); - DumpSymbolTableEntryData(Obj, SymNum, STE.StringIndex, STE.Type, - STE.SectionIndex, STE.Flags, STE.Value, + MachO::nlist STE = Obj.getSymbolTableEntry(DRI); + DumpSymbolTableEntryData(Obj, SymNum, STE.n_strx, STE.n_type, + STE.n_sect, STE.n_desc, STE.n_value, StringTable); } } @@ -228,37 +224,33 @@ static int DumpSymtabCommand(const MachOObjectFile &Obj) { } static int DumpDysymtabCommand(const MachOObjectFile &Obj) { - macho::DysymtabLoadCommand DLC = Obj.getDysymtabLoadCommand(); - - outs() << " ('ilocalsym', " << DLC.LocalSymbolsIndex << ")\n"; - outs() << " ('nlocalsym', " << DLC.NumLocalSymbols << ")\n"; - outs() << " ('iextdefsym', " << DLC.ExternalSymbolsIndex << ")\n"; - outs() << " ('nextdefsym', " << DLC.NumExternalSymbols << ")\n"; - outs() << " ('iundefsym', " << DLC.UndefinedSymbolsIndex << ")\n"; - outs() << " ('nundefsym', " << DLC.NumUndefinedSymbols << ")\n"; - outs() << " ('tocoff', " << DLC.TOCOffset << ")\n"; - outs() << " ('ntoc', " << DLC.NumTOCEntries << ")\n"; - outs() << " ('modtaboff', " << DLC.ModuleTableOffset << ")\n"; - outs() << " ('nmodtab', " << DLC.NumModuleTableEntries << ")\n"; - outs() << " ('extrefsymoff', " << DLC.ReferenceSymbolTableOffset << ")\n"; - outs() << " ('nextrefsyms', " - << DLC.NumReferencedSymbolTableEntries << ")\n"; - outs() << " ('indirectsymoff', " << DLC.IndirectSymbolTableOffset << ")\n"; - outs() << " ('nindirectsyms', " - << DLC.NumIndirectSymbolTableEntries << ")\n"; - outs() << " ('extreloff', " << DLC.ExternalRelocationTableOffset << ")\n"; - outs() << " ('nextrel', " << DLC.NumExternalRelocationTableEntries << ")\n"; - outs() << " ('locreloff', " << DLC.LocalRelocationTableOffset << ")\n"; - outs() << " ('nlocrel', " << DLC.NumLocalRelocationTableEntries << ")\n"; + MachO::dysymtab_command DLC = Obj.getDysymtabLoadCommand(); + + outs() << " ('ilocalsym', " << DLC.ilocalsym << ")\n"; + outs() << " ('nlocalsym', " << DLC.nlocalsym << ")\n"; + outs() << " ('iextdefsym', " << DLC.iextdefsym << ")\n"; + outs() << " ('nextdefsym', " << DLC.nextdefsym << ")\n"; + outs() << " ('iundefsym', " << DLC.iundefsym << ")\n"; + outs() << " ('nundefsym', " << DLC.nundefsym << ")\n"; + outs() << " ('tocoff', " << DLC.tocoff << ")\n"; + outs() << " ('ntoc', " << DLC.ntoc << ")\n"; + outs() << " ('modtaboff', " << DLC.modtaboff << ")\n"; + outs() << " ('nmodtab', " << DLC.nmodtab << ")\n"; + outs() << " ('extrefsymoff', " << DLC.extrefsymoff << ")\n"; + outs() << " ('nextrefsyms', " << DLC.nextrefsyms << ")\n"; + outs() << " ('indirectsymoff', " << DLC.indirectsymoff << ")\n"; + outs() << " ('nindirectsyms', " << DLC.nindirectsyms << ")\n"; + outs() << " ('extreloff', " << DLC.extreloff << ")\n"; + outs() << " ('nextrel', " << DLC.nextrel << ")\n"; + outs() << " ('locreloff', " << DLC.locreloff << ")\n"; + outs() << " ('nlocrel', " << DLC.nlocrel << ")\n"; // Dump the indirect symbol table. outs() << " ('_indirect_symbols', [\n"; - for (unsigned i = 0; i != DLC.NumIndirectSymbolTableEntries; ++i) { - macho::IndirectSymbolTableEntry ISTE = - Obj.getIndirectSymbolTableEntry(DLC, i); + for (unsigned i = 0; i != DLC.nindirectsyms; ++i) { + uint32_t ISTE = Obj.getIndirectSymbolTableEntry(DLC, i); outs() << " # Indirect Symbol " << i << "\n"; - outs() << " (('symbol_index', " - << format("0x%x", ISTE.Index) << "),),\n"; + outs() << " (('symbol_index', " << format("0x%x", ISTE) << "),),\n"; } outs() << " ])\n"; @@ -268,13 +260,13 @@ static int DumpDysymtabCommand(const MachOObjectFile &Obj) { static int DumpLinkeditDataCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); - outs() << " ('dataoff', " << LLC.DataOffset << ")\n" - << " ('datasize', " << LLC.DataSize << ")\n" + MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.dataoff << ")\n" + << " ('datasize', " << LLC.datasize << ")\n" << " ('_addresses', [\n"; SmallVector<uint64_t, 8> Addresses; - Obj.ReadULEB128s(LLC.DataOffset, Addresses); + Obj.ReadULEB128s(LLC.dataoff, Addresses); for (unsigned i = 0, e = Addresses.size(); i != e; ++i) outs() << " # Address " << i << '\n' << " ('address', " << format("0x%x", Addresses[i]) << "),\n"; @@ -287,19 +279,18 @@ DumpLinkeditDataCommand(const MachOObjectFile &Obj, static int DumpDataInCodeDataCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::LinkeditDataLoadCommand LLC = Obj.getLinkeditDataLoadCommand(LCI); - outs() << " ('dataoff', " << LLC.DataOffset << ")\n" - << " ('datasize', " << LLC.DataSize << ")\n" + MachO::linkedit_data_command LLC = Obj.getLinkeditDataLoadCommand(LCI); + outs() << " ('dataoff', " << LLC.dataoff << ")\n" + << " ('datasize', " << LLC.datasize << ")\n" << " ('_data_regions', [\n"; - unsigned NumRegions = LLC.DataSize / sizeof(macho::DataInCodeTableEntry); + unsigned NumRegions = LLC.datasize / sizeof(MachO::data_in_code_entry); for (unsigned i = 0; i < NumRegions; ++i) { - macho::DataInCodeTableEntry DICE = - Obj.getDataInCodeTableEntry(LLC.DataOffset, i); + MachO::data_in_code_entry DICE= Obj.getDataInCodeTableEntry(LLC.dataoff, i); outs() << " # DICE " << i << "\n" - << " ('offset', " << DICE.Offset << ")\n" - << " ('length', " << DICE.Length << ")\n" - << " ('kind', " << DICE.Kind << ")\n"; + << " ('offset', " << DICE.offset << ")\n" + << " ('length', " << DICE.length << ")\n" + << " ('kind', " << DICE.kind << ")\n"; } outs() <<" ])\n"; @@ -310,46 +301,46 @@ DumpDataInCodeDataCommand(const MachOObjectFile &Obj, static int DumpLinkerOptionsCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &LCI) { - macho::LinkerOptionsLoadCommand LOLC = Obj.getLinkerOptionsLoadCommand(LCI); - outs() << " ('count', " << LOLC.Count << ")\n" - << " ('_strings', [\n"; - - uint64_t DataSize = LOLC.Size - sizeof(macho::LinkerOptionsLoadCommand); - const char *P = LCI.Ptr + sizeof(macho::LinkerOptionsLoadCommand); - StringRef Data(P, 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"; + MachO::linker_options_command LOLC = Obj.getLinkerOptionsLoadCommand(LCI); + outs() << " ('count', " << LOLC.count << ")\n" + << " ('_strings', [\n"; + + uint64_t DataSize = LOLC.cmdsize - sizeof(MachO::linker_options_command); + const char *P = LCI.Ptr + sizeof(MachO::linker_options_command); + StringRef Data(P, 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(const MachOObjectFile &Obj, MachOObjectFile::LoadCommandInfo &LCI) { - switch (LCI.C.Type) { - case macho::LCT_Segment: + switch (LCI.C.cmd) { + case MachO::LC_SEGMENT: return DumpSegmentCommand(Obj, LCI); - case macho::LCT_Segment64: + case MachO::LC_SEGMENT_64: return DumpSegment64Command(Obj, LCI); - case macho::LCT_Symtab: + case MachO::LC_SYMTAB: return DumpSymtabCommand(Obj); - case macho::LCT_Dysymtab: + case MachO::LC_DYSYMTAB: return DumpDysymtabCommand(Obj); - case macho::LCT_CodeSignature: - case macho::LCT_SegmentSplitInfo: - case macho::LCT_FunctionStarts: + case MachO::LC_CODE_SIGNATURE: + case MachO::LC_SEGMENT_SPLIT_INFO: + case MachO::LC_FUNCTION_STARTS: return DumpLinkeditDataCommand(Obj, LCI); - case macho::LCT_DataInCode: + case MachO::LC_DATA_IN_CODE: return DumpDataInCodeDataCommand(Obj, LCI); - case macho::LCT_LinkerOptions: + case MachO::LC_LINKER_OPTIONS: return DumpLinkerOptionsCommand(Obj, LCI); default: - Warning("unknown load command: " + Twine(LCI.C.Type)); + Warning("unknown load command: " + Twine(LCI.C.cmd)); return 0; } } @@ -358,26 +349,27 @@ static int DumpLoadCommand(const MachOObjectFile &Obj, static int DumpLoadCommand(const MachOObjectFile &Obj, unsigned Index, MachOObjectFile::LoadCommandInfo &LCI) { outs() << " # Load Command " << Index << "\n" - << " (('command', " << LCI.C.Type << ")\n" - << " ('size', " << LCI.C.Size << ")\n"; + << " (('command', " << LCI.C.cmd << ")\n" + << " ('size', " << LCI.C.cmdsize << ")\n"; int Res = DumpLoadCommand(Obj, LCI); outs() << " ),\n"; return Res; } static void printHeader(const MachOObjectFile *Obj, - const macho::Header &Header) { - outs() << "('cputype', " << Header.CPUType << ")\n"; - outs() << "('cpusubtype', " << Header.CPUSubtype << ")\n"; - outs() << "('filetype', " << Header.FileType << ")\n"; - outs() << "('num_load_commands', " << Header.NumLoadCommands << ")\n"; - outs() << "('load_commands_size', " << Header.SizeOfLoadCommands << ")\n"; - outs() << "('flag', " << Header.Flags << ")\n"; + const MachO::mach_header &Header) { + outs() << "('cputype', " << Header.cputype << ")\n"; + outs() << "('cpusubtype', " << Header.cpusubtype << ")\n"; + outs() << "('filetype', " << Header.filetype << ")\n"; + outs() << "('num_load_commands', " << Header.ncmds << ")\n"; + outs() << "('load_commands_size', " << Header.sizeofcmds << ")\n"; + outs() << "('flag', " << Header.flags << ")\n"; // Print extended header if 64-bit. if (Obj->is64Bit()) { - macho::Header64Ext Header64Ext = Obj->getHeader64Ext(); - outs() << "('reserved', " << Header64Ext.Reserved << ")\n"; + const MachO::mach_header_64 *Header64 = + reinterpret_cast<const MachO::mach_header_64 *>(&Header); + outs() << "('reserved', " << Header64->reserved << ")\n"; } } @@ -396,8 +388,13 @@ int main(int argc, char **argv) { return Error("Not a MachO object"); // Print the header - macho::Header Header = InputObject->getHeader(); - printHeader(InputObject, Header); + MachO::mach_header_64 Header64; + MachO::mach_header *Header = reinterpret_cast<MachO::mach_header*>(&Header64); + if (InputObject->is64Bit()) + Header64 = InputObject->getHeader64(); + else + *Header = InputObject->getHeader(); + printHeader(InputObject, *Header); // Print the load commands. int Res = 0; @@ -408,7 +405,7 @@ int main(int argc, char **argv) { if (DumpLoadCommand(*InputObject, i, Command)) break; - if (i == Header.NumLoadCommands - 1) + if (i == Header->ncmds - 1) break; Command = InputObject->getNextLoadCommandInfo(Command); } diff --git a/tools/msbuild/CMakeLists.txt b/tools/msbuild/CMakeLists.txt new file mode 100644 index 0000000..08b8aee --- /dev/null +++ b/tools/msbuild/CMakeLists.txt @@ -0,0 +1,42 @@ +if (WIN32) + set(prop_file_in "Microsoft.Cpp.Win32.llvm.props.in") + set(prop_file_v100 "Microsoft.Cpp.Win32.LLVM-vs2010.props") + set(prop_file_v110 "Microsoft.Cpp.Win32.LLVM-vs2012.props") + set(prop_file_v110_xp "Microsoft.Cpp.Win32.LLVM-vs2012_xp.props") + set(prop_file_v120 "toolset-vs2013.props") + set(prop_file_v120_xp "toolset-vs2013_xp.props") + + # CPack will install a registry key in this format that we wish to reference. + set(REG_KEY "${CPACK_PACKAGE_INSTALL_REGISTRY_KEY}") + + set(VS_VERSION "v100") + set(MSC_VERSION "1600") + configure_file(${prop_file_in} ${prop_file_v100}) + set(VS_VERSION "v110") + set(MSC_VERSION "1700") + configure_file(${prop_file_in} ${prop_file_v110}) + set(VS_VERSION "v110_xp") + configure_file(${prop_file_in} ${prop_file_v110_xp}) + set(VS_VERSION "v120") + set(MSC_VERSION "1800") + configure_file(${prop_file_in} ${prop_file_v120}) + set(VS_VERSION "v120_xp") + configure_file(${prop_file_in} ${prop_file_v120_xp}) + + set(REG_KEY) + set(VS_VERSION) + set(MSC_VERSION) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v100}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v110_xp}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120}" DESTINATION tools/msbuild) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${prop_file_v120_xp}" DESTINATION tools/msbuild) + + install(DIRECTORY . + DESTINATION tools/msbuild + FILES_MATCHING + PATTERN "*.targets" + PATTERN "*.bat" + PATTERN ".svn" EXCLUDE + ) +endif() diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets new file mode 100644 index 0000000..df41a84 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2010.targets @@ -0,0 +1,2 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+</Project>
diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets new file mode 100644 index 0000000..f7432f2 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012.targets @@ -0,0 +1,3 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+</Project>
diff --git a/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets new file mode 100644 index 0000000..e8250d8 --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets @@ -0,0 +1,21 @@ +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!-- Force TargetFrameworkVersion to v4.0 to support XP--> + <PropertyGroup> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <BeforeClCompileTargets>NoSupportCodeAnalysisXP;$(BeforeClCompileTargets)</BeforeClCompileTargets> + </PropertyGroup> + + <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" /> + + <Target Name="NoSupportCodeAnalysisXP" Condition="'$(ErrorNoSupportCodeAnalysisXP)' != 'false'"> + <VCMessage Condition="'$(DesignTimeBuild)' != 'true' and '@(ClCompile->AnyHaveMetadataValue('EnablePREfast', 'true'))'=='true'" Code="MSB8026" Type="Error"/> + </Target> + + <PropertyGroup> + <PrepareForBuildDependsOn>CheckWindowsSDK71A;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn> + </PropertyGroup> + + <Target Name="CheckWindowsSDK71A"> + <VCMessage Code="MSB8003" Type="Warning" Arguments="WindowsSdkDir_71A" Condition="'$(WindowsSdkDir_71A)'=='' and '$(UseEnv)' != 'true'" /> + </Target> +</Project> diff --git a/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in new file mode 100644 index 0000000..a6ef4ea --- /dev/null +++ b/tools/msbuild/Microsoft.Cpp.Win32.llvm.props.in @@ -0,0 +1,18 @@ +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Microsoft.Cpp.$(Platform).@VS_VERSION@.props" Condition="Exists('$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Microsoft.Cpp.$(Platform).@VS_VERSION@.props')"/>
+ <Import Project="$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Toolset.props" Condition="Exists('$(VCTargetsPath)\Platforms\$(Platform)\PlatformToolsets\@VS_VERSION@\Toolset.props')"/>
+
+ <PropertyGroup>
+ <LLVMInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\LLVM\@REG_KEY@)</LLVMInstallDir>
+ <LLVMInstallDir Condition="'$(LLVMInstallDir)' == ''">$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\LLVM\@REG_KEY@)</LLVMInstallDir>
+ <ExecutablePath>$(LLVMInstallDir)\msbuild-bin;$(ExecutablePath)</ExecutablePath>
+ <LibraryPath>$(LLVMInstallDir)\lib\clang\3.4\lib\windows;$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <!-- Set the value of _MSC_VER to claim for compatibility -->
+ <AdditionalOptions>-fmsc-version=@MSC_VERSION@ %(AdditionalOptions)</AdditionalOptions>
+ </ClCompile>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/tools/msbuild/install.bat b/tools/msbuild/install.bat new file mode 100644 index 0000000..c4c61ac --- /dev/null +++ b/tools/msbuild/install.bat @@ -0,0 +1,81 @@ +@echo off
+
+echo Installing MSVC integration...
+set SUCCESS=0
+
+REM Change to the directory of this batch file.
+cd /d %~dp0
+
+REM Search for the MSBuild toolsets directory.
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V100
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V100
+
+:TRY_V110
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V110
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V110
+
+:TRY_V120
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V120
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D% GOTO FOUND_V120
+
+IF %SUCCESS% == 1 goto DONE
+echo Failed to find MSBuild toolsets directory.
+goto FAILED
+
+
+:FOUND_V100
+IF NOT EXIST %D%\LLVM-vs2010 mkdir %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2010.props %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2010.targets %D%\LLVM-vs2010
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO TRY_V110
+
+:FOUND_V110
+IF NOT EXIST %D%\LLVM-vs2012 mkdir %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012.props %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012.targets %D%\LLVM-vs2012
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+IF NOT EXIST %D%\LLVM-vs2012_xp mkdir %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.props %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets %D%\LLVM-vs2012_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+set SUCCESS=1
+GOTO TRY_V120
+
+:FOUND_V120
+IF NOT EXIST %D%\LLVM-vs2013 mkdir %D%\LLVM-vs2013
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013.props %D%\LLVM-vs2013\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013.targets %D%\LLVM-vs2013\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+IF NOT EXIST %D%\LLVM-vs2013_xp mkdir %D%\LLVM-vs2013_xp
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013_xp.props %D%\LLVM-vs2013_xp\toolset.props
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+copy toolset-vs2013_xp.targets %D%\LLVM-vs2013_xp\toolset.targets
+IF NOT %ERRORLEVEL% == 0 GOTO FAILED
+
+:DONE
+echo Done!
+goto END
+
+:FAILED
+echo MSVC integration install failed.
+pause
+goto END
+
+:END
diff --git a/tools/msbuild/toolset-vs2013.targets b/tools/msbuild/toolset-vs2013.targets new file mode 100644 index 0000000..a6efac4 --- /dev/null +++ b/tools/msbuild/toolset-vs2013.targets @@ -0,0 +1,3 @@ +<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" />
+</Project>
diff --git a/tools/msbuild/toolset-vs2013_xp.targets b/tools/msbuild/toolset-vs2013_xp.targets new file mode 100644 index 0000000..e719681 --- /dev/null +++ b/tools/msbuild/toolset-vs2013_xp.targets @@ -0,0 +1,21 @@ +<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <!-- Force TargetFrameworkVersion to v4.0 to support XP--> + <PropertyGroup> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <BeforeClCompileTargets>NoSupportCodeAnalysisXP;$(BeforeClCompileTargets)</BeforeClCompileTargets> + </PropertyGroup> + + <Import Project="$(VCTargetsPath)\Microsoft.CppCommon.targets" /> + + <Target Name="NoSupportCodeAnalysisXP" Condition="'$(ErrorNoSupportCodeAnalysisXP)' != 'false'"> + <VCMessage Condition="'$(DesignTimeBuild)' != 'true' and '@(ClCompile->AnyHaveMetadataValue('EnablePREfast', 'true'))'=='true'" Code="MSB8026" Type="Error"/> + </Target> + + <PropertyGroup> + <PrepareForBuildDependsOn>CheckWindowsSDK71A;$(PrepareForBuildDependsOn)</PrepareForBuildDependsOn> + </PropertyGroup> + + <Target Name="CheckWindowsSDK71A"> + <VCMessage Code="MSB8003" Type="Warning" Arguments="WindowsSdkDir_71A" Condition="'$(WindowsSdkDir_71A)'=='' and '$(UseEnv)' != 'true'" /> + </Target> +</Project> diff --git a/tools/msbuild/uninstall.bat b/tools/msbuild/uninstall.bat new file mode 100644 index 0000000..7e94f87 --- /dev/null +++ b/tools/msbuild/uninstall.bat @@ -0,0 +1,50 @@ +@echo off
+
+echo Uninstalling MSVC integration...
+
+REM CD to the directory of this batch file.
+cd /d %~dp0
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
+IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.props
+IF EXIST %D%\LLVM-vs2010 del %D%\LLVM-vs2010\Microsoft.Cpp.Win32.LLVM-vs2010.targets
+IF EXIST %D%\LLVM-vs2010 rmdir %D%\LLVM-vs2010
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V110\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.props
+IF EXIST %D%\LLVM-vs2012 del %D%\LLVM-vs2012\Microsoft.Cpp.Win32.LLVM-vs2012.targets
+IF EXIST %D%\LLVM-vs2012 rmdir %D%\LLVM-vs2012
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.props
+IF EXIST %D%\LLVM-vs2012_xp del %D%\LLVM-vs2012_xp\Microsoft.Cpp.Win32.LLVM-vs2012_xp.targets
+IF EXIST %D%\LLVM-vs2012_xp rmdir %D%\LLVM-vs2012_xp
+
+SET D="%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
+IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+
+SET D="%ProgramFiles(x86)%\MSBuild\Microsoft.Cpp\v4.0\V120\Platforms\Win32\PlatformToolsets"
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.props
+IF EXIST %D%\LLVM-vs2013 del %D%\LLVM-vs2013\toolset.targets
+IF EXIST %D%\LLVM-vs2013 rmdir %D%\LLVM-vs2013
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.props
+IF EXIST %D%\LLVM-vs2013_xp del %D%\LLVM-vs2013_xp\toolset.targets
+IF EXIST %D%\LLVM-vs2013_xp rmdir %D%\LLVM-vs2013_xp
+
+echo Done!
diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp index 1e28c4e..02d7ebf 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -72,7 +72,6 @@ void COFFDumper::dumpSections(unsigned NumSections) { const object::coff_relocation *reloc = Obj.getCOFFRelocation(rIter); COFFYAML::Relocation Rel; object::symbol_iterator Sym = rIter->getSymbol(); - StringRef Name; Sym->getName(Rel.SymbolName); Rel.VirtualAddress = reloc->VirtualAddress; Rel.Type = reloc->Type; diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 37637ca..dba16f7 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -136,6 +136,21 @@ UnitAtATime("funit-at-a-time", cl::init(true)); static cl::opt<bool> +DisableLoopUnrolling("disable-loop-unrolling", + cl::desc("Disable loop unrolling in all relevant passes"), + cl::init(false)); +static cl::opt<bool> +DisableLoopVectorization("disable-loop-vectorization", + cl::desc("Disable the loop vectorization pass"), + cl::init(false)); + +static cl::opt<bool> +DisableSLPVectorization("disable-slp-vectorization", + cl::desc("Disable the slp vectorization pass"), + cl::init(false)); + + +static cl::opt<bool> DisableSimplifyLibCalls("disable-simplify-libcalls", cl::desc("Disable simplify-libcalls")); @@ -362,6 +377,7 @@ char BasicBlockPassPrinter::ID = 0; struct BreakpointPrinter : public ModulePass { raw_ostream &Out; static char ID; + DITypeIdentifierMap TypeIdentifierMap; BreakpointPrinter(raw_ostream &out) : ModulePass(ID), Out(out) { @@ -377,13 +393,18 @@ struct BreakpointPrinter : public ModulePass { } else if (Context.isType()) { DIType TY(Context); if (!TY.getName().empty()) { - getContextName(TY.getContext(), N); + getContextName(TY.getContext().resolve(TypeIdentifierMap), N); N = N + TY.getName().str() + "::"; } } } virtual bool runOnModule(Module &M) { + TypeIdentifierMap.clear(); + NamedMDNode *CU_Nodes = M.getNamedMetadata("llvm.dbg.cu"); + if (CU_Nodes) + TypeIdentifierMap = generateDITypeIdentifierMap(CU_Nodes); + StringSet<> Processed; if (NamedMDNode *NMD = M.getNamedMetadata("llvm.dbg.sp")) for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { @@ -393,7 +414,7 @@ struct BreakpointPrinter : public ModulePass { "A MDNode in llvm.dbg.sp should be null or a DISubprogram."); if (!SP) continue; - getContextName(SP.getContext(), Name); + getContextName(SP.getContext().resolve(TypeIdentifierMap), Name); Name = Name + SP.getDisplayName().str(); if (!Name.empty() && Processed.insert(Name)) { Out << Name << "\n"; @@ -406,7 +427,7 @@ struct BreakpointPrinter : public ModulePass { AU.setPreservesAll(); } }; - + } // anonymous namespace char BreakpointPrinter::ID = 0; @@ -447,8 +468,14 @@ static void AddOptimizationPasses(PassManagerBase &MPM,FunctionPassManager &FPM, Builder.Inliner = createAlwaysInlinerPass(); } Builder.DisableUnitAtATime = !UnitAtATime; - Builder.DisableUnrollLoops = OptLevel == 0; - + Builder.DisableUnrollLoops = (DisableLoopUnrolling.getNumOccurrences() > 0) ? + DisableLoopUnrolling : OptLevel == 0; + + Builder.LoopVectorize = + DisableLoopVectorization ? false : OptLevel > 1 && SizeLevel < 2; + Builder.SLPVectorize = + DisableSLPVectorization ? false : OptLevel > 1 && SizeLevel < 2; + Builder.populateFunctionPassManager(FPM); Builder.populateModulePassManager(MPM); } diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index 11aae0e..c757eb6 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -32,7 +32,7 @@ struct COFFParser { COFFParser(COFFYAML::Object &Obj) : Obj(Obj) { // A COFF string table always starts with a 4 byte size field. Offsets into // it include this size, so allocate it now. - StringTable.append(4, 0); + StringTable.append(4, char(0)); } bool parseSections() { diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index 61252a4..d46e154 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -13,7 +13,8 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" -#include "llvm/Object/ELF.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFYAML.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MemoryBuffer.h" @@ -119,13 +120,13 @@ public: } // end anonymous namespace template <class T> -static size_t vectorDataSize(const std::vector<T> &Vec) { - return Vec.size() * sizeof(T); +static size_t arrayDataSize(ArrayRef<T> A) { + return A.size() * sizeof(T); } template <class T> -static void writeVectorData(raw_ostream &OS, const std::vector<T> &Vec) { - OS.write((const char *)Vec.data(), vectorDataSize(Vec)); +static void writeArrayData(raw_ostream &OS, ArrayRef<T> A) { + OS.write((const char *)A.data(), arrayDataSize(A)); } template <class T> @@ -157,7 +158,7 @@ class ELFState { unsigned DotStrtabSecNo; /// \brief The accumulated contents of all sections so far. ContiguousBlobAccumulator &SectionContentAccum; - typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; /// \brief The ELF file header. Elf_Ehdr &Header; @@ -185,9 +186,9 @@ public: template <class ELFT> static void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State, - std::vector<typename object::ELFObjectFile<ELFT>::Elf_Sym> &Syms, + std::vector<typename object::ELFFile<ELFT>::Elf_Sym> &Syms, unsigned SymbolBinding) { - typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; for (unsigned i = 0, e = Symbols.size(); i != e; ++i) { const ELFYAML::Symbol &Sym = Symbols[i]; Elf_Sym Symbol; @@ -211,11 +212,12 @@ addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, ELFState<ELFT> &State, } template <class ELFT> -static void handleSymtabSectionHeader( - const ELFYAML::LocalGlobalWeakSymbols &Symbols, ELFState<ELFT> &State, - typename object::ELFObjectFile<ELFT>::Elf_Shdr &SHeader) { +static void +handleSymtabSectionHeader(const ELFYAML::LocalGlobalWeakSymbols &Symbols, + ELFState<ELFT> &State, + typename object::ELFFile<ELFT>::Elf_Shdr &SHeader) { - typedef typename object::ELFObjectFile<ELFT>::Elf_Sym Elf_Sym; + typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym; SHeader.sh_type = ELF::SHT_SYMTAB; SHeader.sh_link = State.getDotStrTabSecNo(); // One greater than symbol table index of the last local symbol. @@ -234,15 +236,16 @@ static void handleSymtabSectionHeader( addSymbols(Symbols.Weak, State, Syms, ELF::STB_WEAK); ContiguousBlobAccumulator &CBA = State.getSectionContentAccum(); - writeVectorData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), Syms); - SHeader.sh_size = vectorDataSize(Syms); + writeArrayData(CBA.getOSAndAlignedOffset(SHeader.sh_offset), + makeArrayRef(Syms)); + SHeader.sh_size = arrayDataSize(makeArrayRef(Syms)); } template <class ELFT> static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { using namespace llvm::ELF; - typedef typename object::ELFObjectFile<ELFT>::Elf_Ehdr Elf_Ehdr; - typedef typename object::ELFObjectFile<ELFT>::Elf_Shdr Elf_Shdr; + typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr; + typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; const ELFYAML::FileHeader &Hdr = Doc.Header; @@ -358,7 +361,7 @@ static int writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) { SHeaders.push_back(SHStrTabSHeader); OS.write((const char *)&Header, sizeof(Header)); - writeVectorData(OS, SHeaders); + writeArrayData(OS, makeArrayRef(SHeaders)); CBA.writeBlobToStream(OS); return 0; } |