diff options
author | Stephen Hines <srhines@google.com> | 2014-07-21 00:45:20 -0700 |
---|---|---|
committer | Stephen Hines <srhines@google.com> | 2014-07-21 00:45:20 -0700 |
commit | c6a4f5e819217e1e12c458aed8e7b122e23a3a58 (patch) | |
tree | 81b7dd2bb4370a392f31d332a566c903b5744764 /tools | |
parent | 19c6fbb3e8aaf74093afa08013134b61fa08f245 (diff) | |
download | external_llvm-c6a4f5e819217e1e12c458aed8e7b122e23a3a58.zip external_llvm-c6a4f5e819217e1e12c458aed8e7b122e23a3a58.tar.gz external_llvm-c6a4f5e819217e1e12c458aed8e7b122e23a3a58.tar.bz2 |
Update LLVM for rebase to r212749.
Includes a cherry-pick of:
r212948 - fixes a small issue with atomic calls
Change-Id: Ib97bd980b59f18142a69506400911a6009d9df18
Diffstat (limited to 'tools')
79 files changed, 3065 insertions, 785 deletions
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 13b7f5a..846ad1e 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -49,7 +49,7 @@ add_llvm_tool_subdirectory(llvm-c-test) add_llvm_tool_subdirectory(obj2yaml) add_llvm_tool_subdirectory(yaml2obj) -if( NOT CYGWIN ) +if(NOT CYGWIN AND LLVM_ENABLE_PIC) add_llvm_tool_subdirectory(lto) add_llvm_tool_subdirectory(llvm-lto) else() diff --git a/tools/Makefile b/tools/Makefile index 2b8c32e..97ad99a 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -19,9 +19,9 @@ else OPTIONAL_PARALLEL_DIRS := clang endif -# Build LLDB if present. Note LLDB must be built last as it depends on the -# wider LLVM infrastructure (including Clang). -OPTIONAL_DIRS := lldb +# Build LLD and LLDB if present. Note LLDB must be built last as it depends on +# the wider LLVM infrastructure (including Clang). +OPTIONAL_DIRS := lld lldb # NOTE: The tools are organized into five groups of four consisting of one # large and three small executables. This is done to minimize memory load diff --git a/tools/bugpoint/ExecutionDriver.cpp b/tools/bugpoint/ExecutionDriver.cpp index 5ed7d2c..25813b3 100644 --- a/tools/bugpoint/ExecutionDriver.cpp +++ b/tools/bugpoint/ExecutionDriver.cpp @@ -267,7 +267,7 @@ void BugDriver::compileProgram(Module *M, std::string *Error) const { // Emit the program to a bitcode file... SmallString<128> BitcodeFile; int BitcodeFD; - error_code EC = sys::fs::createUniqueFile( + std::error_code EC = sys::fs::createUniqueFile( OutputPrefix + "-test-program-%%%%%%%.bc", BitcodeFD, BitcodeFile); if (EC) { errs() << ToolName << ": Error making unique filename: " << EC.message() @@ -305,7 +305,7 @@ std::string BugDriver::executeProgram(const Module *Program, // Emit the program to a bitcode file... SmallString<128> UniqueFilename; int UniqueFD; - error_code EC = sys::fs::createUniqueFile( + std::error_code EC = sys::fs::createUniqueFile( OutputPrefix + "-test-program-%%%%%%%.bc", UniqueFD, UniqueFilename); if (EC) { errs() << ToolName << ": Error making unique filename: " @@ -331,7 +331,7 @@ std::string BugDriver::executeProgram(const Module *Program, // Check to see if this is a valid output filename... SmallString<128> UniqueFile; - error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile); + std::error_code EC = sys::fs::createUniqueFile(OutputFile, UniqueFile); if (EC) { errs() << ToolName << ": Error making unique filename: " << EC.message() << "\n"; diff --git a/tools/bugpoint/ExtractFunction.cpp b/tools/bugpoint/ExtractFunction.cpp index 38cdf24..4fb6856 100644 --- a/tools/bugpoint/ExtractFunction.cpp +++ b/tools/bugpoint/ExtractFunction.cpp @@ -366,7 +366,7 @@ Module *BugDriver::ExtractMappedBlocksFromModule(const Module *M) { SmallString<128> Filename; int FD; - error_code EC = sys::fs::createUniqueFile( + std::error_code EC = sys::fs::createUniqueFile( OutputPrefix + "-extractblocks%%%%%%%", FD, Filename); if (EC) { outs() << "*** Basic Block extraction failed!\n"; diff --git a/tools/bugpoint/Miscompilation.cpp b/tools/bugpoint/Miscompilation.cpp index f5936ac..3f1f84e 100644 --- a/tools/bugpoint/Miscompilation.cpp +++ b/tools/bugpoint/Miscompilation.cpp @@ -964,8 +964,8 @@ static bool TestCodeGenerator(BugDriver &BD, Module *Test, Module *Safe, SmallString<128> TestModuleBC; int TestModuleFD; - error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", - TestModuleFD, TestModuleBC); + std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); if (EC) { errs() << BD.getToolName() << "Error making unique filename: " << EC.message() << "\n"; @@ -1058,8 +1058,8 @@ bool BugDriver::debugCodeGenerator(std::string *Error) { SmallString<128> TestModuleBC; int TestModuleFD; - error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", - TestModuleFD, TestModuleBC); + std::error_code EC = sys::fs::createTemporaryFile("bugpoint.test", "bc", + TestModuleFD, TestModuleBC); if (EC) { errs() << getToolName() << "Error making unique filename: " << EC.message() << "\n"; diff --git a/tools/bugpoint/OptimizerDriver.cpp b/tools/bugpoint/OptimizerDriver.cpp index b2722e6..d452fd9 100644 --- a/tools/bugpoint/OptimizerDriver.cpp +++ b/tools/bugpoint/OptimizerDriver.cpp @@ -129,7 +129,7 @@ bool BugDriver::runPasses(Module *Program, // setup the output file name outs().flush(); SmallString<128> UniqueFilename; - error_code EC = sys::fs::createUniqueFile( + std::error_code EC = sys::fs::createUniqueFile( OutputPrefix + "-output-%%%%%%%.bc", UniqueFilename); if (EC) { errs() << getToolName() << ": Error making unique filename: " diff --git a/tools/bugpoint/ToolRunner.cpp b/tools/bugpoint/ToolRunner.cpp index c481b03..4a2401b 100644 --- a/tools/bugpoint/ToolRunner.cpp +++ b/tools/bugpoint/ToolRunner.cpp @@ -142,7 +142,7 @@ static std::string ProcessFailure(StringRef ProgPath, const char** Args, // Rerun the compiler, capturing any error messages to print them. SmallString<128> ErrorFilename; int ErrorFD; - error_code EC = sys::fs::createTemporaryFile( + std::error_code EC = sys::fs::createTemporaryFile( "bugpoint.program_error_messages", "", ErrorFD, ErrorFilename); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; @@ -478,7 +478,7 @@ GCC::FileType LLC::OutputCode(const std::string &Bitcode, const char *Suffix = (UseIntegratedAssembler ? ".llc.o" : ".llc.s"); SmallString<128> UniqueFile; - error_code EC = + std::error_code EC = sys::fs::createUniqueFile(Bitcode + "-%%%%%%%" + Suffix, UniqueFile); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; @@ -715,7 +715,7 @@ int GCC::ExecuteProgram(const std::string &ProgramFile, GCCArgs.push_back("-o"); SmallString<128> OutputBinary; - error_code EC = + std::error_code EC = sys::fs::createUniqueFile(ProgramFile + "-%%%%%%%.gcc.exe", OutputBinary); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; @@ -825,7 +825,7 @@ int GCC::MakeSharedObject(const std::string &InputFile, FileType fileType, const std::vector<std::string> &ArgsForGCC, std::string &Error) { SmallString<128> UniqueFilename; - error_code EC = sys::fs::createUniqueFile( + std::error_code EC = sys::fs::createUniqueFile( InputFile + "-%%%%%%%" + LTDL_SHLIB_EXT, UniqueFilename); if (EC) { errs() << "Error making unique filename: " << EC.message() << "\n"; diff --git a/tools/gold/CMakeLists.txt b/tools/gold/CMakeLists.txt index 07a1e28..3864e15 100644 --- a/tools/gold/CMakeLists.txt +++ b/tools/gold/CMakeLists.txt @@ -14,13 +14,14 @@ else() # ABI compatibility. add_definitions( -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 ) - set(LLVM_LINK_COMPONENTS support) + set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} + LTO + ) add_llvm_loadable_module(LLVMgold gold-plugin.cpp ) - target_link_libraries(LLVMgold ${cmake_2_8_12_PRIVATE} LTO) - endif() diff --git a/tools/gold/Makefile b/tools/gold/Makefile index 496e31c..593d8ea 100644 --- a/tools/gold/Makefile +++ b/tools/gold/Makefile @@ -9,7 +9,6 @@ LEVEL := ../.. LIBRARYNAME := LLVMgold -LINK_COMPONENTS := support LINK_LIBS_IN_SHARED := 1 SHARED_LIBRARY := 1 LOADABLE_MODULE := 1 @@ -21,6 +20,8 @@ EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/gold.exports # early so we can set up LINK_COMPONENTS before including Makefile.rules include $(LEVEL)/Makefile.config +LINK_COMPONENTS := $(TARGETS_TO_BUILD) LTO + # Because off_t is used in the public API, the largefile parts are required for # ABI compatibility. CXXFLAGS += -I$(BINUTILS_INCDIR) -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 @@ -28,4 +29,3 @@ LDFLAGS += -L$(SharedLibDir)/$(SharedPrefix) include $(LEVEL)/Makefile.common -LIBS += -lLTO diff --git a/tools/gold/gold-plugin.cpp b/tools/gold/gold-plugin.cpp index 4726d82..b908510 100644 --- a/tools/gold/gold-plugin.cpp +++ b/tools/gold/gold-plugin.cpp @@ -15,19 +15,22 @@ #include "llvm/Config/config.h" // plugin-api.h requires HAVE_STDINT_H #include "llvm-c/lto.h" #include "llvm/ADT/StringSet.h" +#include "llvm/CodeGen/CommandFlags.h" +#include "llvm/LTO/LTOCodeGenerator.h" +#include "llvm/LTO/LTOModule.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/system_error.h" #include <cerrno> #include <cstdlib> #include <cstring> -#include <fstream> #include <list> #include <plugin-api.h> +#include <system_error> #include <vector> // Support Windows/MinGW crazyness. @@ -46,36 +49,32 @@ using namespace llvm; namespace { - ld_plugin_status discard_message(int level, const char *format, ...) { - // Die loudly. Recent versions of Gold pass ld_plugin_message as the first - // callback in the transfer vector. This should never be called. - abort(); - } +struct claimed_file { + void *handle; + std::vector<ld_plugin_symbol> syms; +}; +} - ld_plugin_add_symbols add_symbols = NULL; - ld_plugin_get_symbols get_symbols = NULL; - ld_plugin_add_input_file add_input_file = NULL; - ld_plugin_add_input_library add_input_library = NULL; - ld_plugin_set_extra_library_path set_extra_library_path = NULL; - ld_plugin_get_view get_view = NULL; - ld_plugin_message message = discard_message; - - int api_version = 0; - int gold_version = 0; - - struct claimed_file { - void *handle; - std::vector<ld_plugin_symbol> syms; - }; - - lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC; - std::string output_name = ""; - std::list<claimed_file> Modules; - std::vector<std::string> Cleanup; - lto_code_gen_t code_gen = NULL; - StringSet<> CannotBeHidden; +static ld_plugin_status discard_message(int level, const char *format, ...) { + // Die loudly. Recent versions of Gold pass ld_plugin_message as the first + // callback in the transfer vector. This should never be called. + abort(); } +static ld_plugin_add_symbols add_symbols = NULL; +static ld_plugin_get_symbols get_symbols = NULL; +static ld_plugin_add_input_file add_input_file = NULL; +static ld_plugin_set_extra_library_path set_extra_library_path = NULL; +static ld_plugin_get_view get_view = NULL; +static ld_plugin_message message = discard_message; +static lto_codegen_model output_type = LTO_CODEGEN_PIC_MODEL_STATIC; +static std::string output_name = ""; +static std::list<claimed_file> Modules; +static std::vector<std::string> Cleanup; +static LTOCodeGenerator *CodeGen = nullptr; +static StringSet<> CannotBeHidden; +static llvm::TargetOptions TargetOpts; + namespace options { enum generate_bc { BC_NO, BC_ALSO, BC_ONLY }; static bool generate_api_file = false; @@ -135,6 +134,12 @@ static ld_plugin_status cleanup_hook(void); extern "C" ld_plugin_status onload(ld_plugin_tv *tv); ld_plugin_status onload(ld_plugin_tv *tv) { + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + // We're given a pointer to the first transfer vector. We read through them // until we find one where tv_tag == LDPT_NULL. The REGISTER_* tagged values // contain pointers to functions that we need to call to register our own @@ -142,15 +147,10 @@ ld_plugin_status onload(ld_plugin_tv *tv) { // for services. bool registeredClaimFile = false; + bool RegisteredAllSymbolsRead = false; for (; tv->tv_tag != LDPT_NULL; ++tv) { switch (tv->tv_tag) { - case LDPT_API_VERSION: - api_version = tv->tv_u.tv_val; - break; - case LDPT_GOLD_VERSION: // major * 100 + minor - gold_version = tv->tv_u.tv_val; - break; case LDPT_OUTPUT_NAME: output_name = tv->tv_u.tv_string; break; @@ -169,8 +169,6 @@ ld_plugin_status onload(ld_plugin_tv *tv) { tv->tv_u.tv_val); return LDPS_ERR; } - // TODO: add an option to disable PIC. - //output_type = LTO_CODEGEN_PIC_MODEL_DYNAMIC_NO_PIC; break; case LDPT_OPTION: options::process_plugin_option(tv->tv_u.tv_string); @@ -191,7 +189,7 @@ ld_plugin_status onload(ld_plugin_tv *tv) { if ((*callback)(all_symbols_read_hook) != LDPS_OK) return LDPS_ERR; - code_gen = lto_codegen_create(); + RegisteredAllSymbolsRead = true; } break; case LDPT_REGISTER_CLEANUP_HOOK: { ld_plugin_register_cleanup callback; @@ -209,9 +207,6 @@ ld_plugin_status onload(ld_plugin_tv *tv) { case LDPT_ADD_INPUT_FILE: add_input_file = tv->tv_u.tv_add_input_file; break; - case LDPT_ADD_INPUT_LIBRARY: - add_input_library = tv->tv_u.tv_add_input_file; - break; case LDPT_SET_EXTRA_LIBRARY_PATH: set_extra_library_path = tv->tv_u.tv_set_extra_library_path; break; @@ -235,15 +230,41 @@ ld_plugin_status onload(ld_plugin_tv *tv) { return LDPS_ERR; } + if (!RegisteredAllSymbolsRead) + return LDPS_OK; + + CodeGen = new LTOCodeGenerator(); + + // Pass through extra options to the code generator. + if (!options::extra.empty()) { + for (std::vector<std::string>::iterator it = options::extra.begin(); + it != options::extra.end(); ++it) { + CodeGen->setCodeGenDebugOptions((*it).c_str()); + } + } + + CodeGen->parseCodeGenDebugOptions(); + if (MAttrs.size()) { + std::string Attrs; + for (unsigned I = 0; I < MAttrs.size(); ++I) { + if (I > 0) + Attrs.append(","); + Attrs.append(MAttrs[I]); + } + CodeGen->setAttr(Attrs.c_str()); + } + + TargetOpts = InitTargetOptionsFromCodeGenFlags(); + CodeGen->setTargetOptions(TargetOpts); + return LDPS_OK; } -/// claim_file_hook - called by gold to see whether this file is one that -/// our plugin can handle. We'll try to open it and register all the symbols -/// with add_symbol if possible. +/// Called by gold to see whether this file is one that our plugin can handle. +/// We'll try to open it and register all the symbols with add_symbol if +/// possible. static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, int *claimed) { - lto_module_t M; const void *view; std::unique_ptr<MemoryBuffer> buffer; if (get_view) { @@ -258,25 +279,27 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, if (file->offset) { offset = file->offset; } - if (error_code ec = MemoryBuffer::getOpenFileSlice( - file->fd, file->name, buffer, file->filesize, offset)) { - (*message)(LDPL_ERROR, ec.message().c_str()); + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = + MemoryBuffer::getOpenFileSlice(file->fd, file->name, file->filesize, + offset); + if (std::error_code EC = BufferOrErr.getError()) { + (*message)(LDPL_ERROR, EC.message().c_str()); return LDPS_ERR; } + buffer = std::move(BufferOrErr.get()); view = buffer->getBufferStart(); } - if (!lto_module_is_object_file_in_memory(view, file->filesize)) + if (!LTOModule::isBitcodeFile(view, file->filesize)) return LDPS_OK; - M = lto_module_create_from_memory(view, file->filesize); + std::string Error; + LTOModule *M = + LTOModule::createFromBuffer(view, file->filesize, TargetOpts, Error); if (!M) { - if (const char* msg = lto_get_error_message()) { - (*message)(LDPL_ERROR, - "LLVM gold plugin has failed to create LTO module: %s", - msg); - return LDPS_ERR; - } + (*message)(LDPL_ERROR, + "LLVM gold plugin has failed to create LTO module: %s", + Error.c_str()); return LDPS_OK; } @@ -285,21 +308,20 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, claimed_file &cf = Modules.back(); if (!options::triple.empty()) - lto_module_set_target_triple(M, options::triple.c_str()); + M->setTargetTriple(options::triple.c_str()); cf.handle = file->handle; - unsigned sym_count = lto_module_get_num_symbols(M); + unsigned sym_count = M->getSymbolCount(); cf.syms.reserve(sym_count); for (unsigned i = 0; i != sym_count; ++i) { - lto_symbol_attributes attrs = lto_module_get_symbol_attribute(M, i); + lto_symbol_attributes attrs = M->getSymbolAttributes(i); if ((attrs & LTO_SYMBOL_SCOPE_MASK) == LTO_SYMBOL_SCOPE_INTERNAL) continue; cf.syms.push_back(ld_plugin_symbol()); ld_plugin_symbol &sym = cf.syms.back(); - sym.name = const_cast<char *>(lto_module_get_symbol_name(M, i)); - sym.name = strdup(sym.name); + sym.name = strdup(M->getSymbolName(i)); sym.version = NULL; int scope = attrs & LTO_SYMBOL_SCOPE_MASK; @@ -361,15 +383,15 @@ static ld_plugin_status claim_file_hook(const ld_plugin_input_file *file, } } - if (code_gen) { - if (lto_codegen_add_module(code_gen, M)) { - (*message)(LDPL_ERROR, "Error linking module: %s", - lto_get_error_message()); + if (CodeGen) { + std::string Error; + if (!CodeGen->addModule(M, Error)) { + (*message)(LDPL_ERROR, "Error linking module: %s", Error.c_str()); return LDPS_ERR; } } - lto_module_dispose(M); + delete M; return LDPS_OK; } @@ -387,15 +409,17 @@ static bool mustPreserve(const claimed_file &F, int i) { /// been overridden by a native object file. Then, perform optimization and /// codegen. static ld_plugin_status all_symbols_read_hook(void) { - std::ofstream api_file; - assert(code_gen); + // FIXME: raw_fd_ostream should be able to represent an unopened file. + std::unique_ptr<raw_fd_ostream> api_file; + + assert(CodeGen); if (options::generate_api_file) { - api_file.open("apifile.txt", std::ofstream::out | std::ofstream::trunc); - if (!api_file.is_open()) { - (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing."); - abort(); - } + std::string Error; + api_file.reset(new raw_fd_ostream("apifile.txt", Error, sys::fs::F_None)); + if (!Error.empty()) + (*message)(LDPL_FATAL, "Unable to open apifile.txt for writing: %s", + Error.c_str()); } for (std::list<claimed_file>::iterator I = Modules.begin(), @@ -405,29 +429,18 @@ static ld_plugin_status all_symbols_read_hook(void) { (*get_symbols)(I->handle, I->syms.size(), &I->syms[0]); for (unsigned i = 0, e = I->syms.size(); i != e; i++) { if (mustPreserve(*I, i)) { - lto_codegen_add_must_preserve_symbol(code_gen, I->syms[i].name); + CodeGen->addMustPreserveSymbol(I->syms[i].name); if (options::generate_api_file) - api_file << I->syms[i].name << "\n"; + (*api_file) << I->syms[i].name << "\n"; } } } - if (options::generate_api_file) - api_file.close(); - - lto_codegen_set_pic_model(code_gen, output_type); - lto_codegen_set_debug_model(code_gen, LTO_DEBUG_MODEL_DWARF); + CodeGen->setCodePICModel(output_type); + CodeGen->setDebugInfo(LTO_DEBUG_MODEL_DWARF); if (!options::mcpu.empty()) - lto_codegen_set_cpu(code_gen, options::mcpu.c_str()); - - // Pass through extra options to the code generator. - if (!options::extra.empty()) { - for (std::vector<std::string>::iterator it = options::extra.begin(); - it != options::extra.end(); ++it) { - lto_codegen_debug_options(code_gen, (*it).c_str()); - } - } + CodeGen->setCpu(options::mcpu.c_str()); if (options::generate_bc_file != options::BC_NO) { std::string path; @@ -437,11 +450,11 @@ static ld_plugin_status all_symbols_read_hook(void) { path = options::bc_path; else path = output_name + ".bc"; - bool err = lto_codegen_write_merged_modules(code_gen, path.c_str()); - if (err) + std::string Error; + if (!CodeGen->writeMergedModules(path.c_str(), Error)) (*message)(LDPL_FATAL, "Failed to write the output file."); if (options::generate_bc_file == options::BC_ONLY) { - lto_codegen_dispose(code_gen); + delete CodeGen; exit(0); } } @@ -449,13 +462,14 @@ static ld_plugin_status all_symbols_read_hook(void) { std::string ObjPath; { const char *Temp; - if (lto_codegen_compile_to_file(code_gen, &Temp)) { + std::string Error; + if (!CodeGen->compile_to_file(&Temp, /*DisableOpt*/ false, /*DisableInline*/ + false, /*DisableGVNLoadPRE*/ false, Error)) (*message)(LDPL_ERROR, "Could not produce a combined object file\n"); - } ObjPath = Temp; } - lto_codegen_dispose(code_gen); + delete CodeGen; for (std::list<claimed_file>::iterator I = Modules.begin(), E = Modules.end(); I != E; ++I) { for (unsigned i = 0; i != I->syms.size(); ++i) { @@ -484,7 +498,7 @@ static ld_plugin_status all_symbols_read_hook(void) { static ld_plugin_status cleanup_hook(void) { for (int i = 0, e = Cleanup.size(); i != e; ++i) { - error_code EC = sys::fs::remove(Cleanup[i]); + std::error_code EC = sys::fs::remove(Cleanup[i]); if (EC) (*message)(LDPL_ERROR, "Failed to delete '%s': %s", Cleanup[i].c_str(), EC.message().c_str()); diff --git a/tools/lli/RemoteMemoryManager.cpp b/tools/lli/RemoteMemoryManager.cpp index 200ab75..4816517 100644 --- a/tools/lli/RemoteMemoryManager.cpp +++ b/tools/lli/RemoteMemoryManager.cpp @@ -61,7 +61,7 @@ allocateDataSection(uintptr_t Size, unsigned Alignment, } sys::MemoryBlock RemoteMemoryManager::allocateSection(uintptr_t Size) { - error_code ec; + std::error_code ec; sys::MemoryBlock MB = sys::Memory::allocateMappedMemory(Size, &Near, sys::Memory::MF_READ | diff --git a/tools/lli/lli.cpp b/tools/lli/lli.cpp index 4cde105..48828c1 100644 --- a/tools/lli/lli.cpp +++ b/tools/lli/lli.cpp @@ -285,8 +285,8 @@ public: if (!getCacheFilename(ModuleID, CacheName)) return nullptr; // Load the object from the cache filename - std::unique_ptr<MemoryBuffer> IRObjectBuffer; - MemoryBuffer::getFile(CacheName.c_str(), IRObjectBuffer, -1, false); + ErrorOr<std::unique_ptr<MemoryBuffer>> IRObjectBuffer = + MemoryBuffer::getFile(CacheName.c_str(), -1, false); // If the file isn't there, that's OK. if (!IRObjectBuffer) return nullptr; @@ -294,7 +294,7 @@ public: // because the file has probably just been mmapped. Instead we make // a copy. The filed-based buffer will be released when it goes // out of scope. - return MemoryBuffer::getMemBufferCopy(IRObjectBuffer->getBuffer()); + return MemoryBuffer::getMemBufferCopy(IRObjectBuffer.get()->getBuffer()); } private: @@ -415,7 +415,7 @@ int main(int argc, char **argv, char * const *envp) { // If not jitting lazily, load the whole bitcode file eagerly too. if (NoLazyCompilation) { - if (error_code EC = Mod->materializeAllPermanently()) { + if (std::error_code EC = Mod->materializeAllPermanently()) { errs() << argv[0] << ": bitcode didn't read correctly.\n"; errs() << "Reason: " << EC.message() << "\n"; exit(1); @@ -538,15 +538,15 @@ int main(int argc, char **argv, char * const *envp) { } for (unsigned i = 0, e = ExtraArchives.size(); i != e; ++i) { - std::unique_ptr<MemoryBuffer> ArBuf; - error_code ec; - ec = MemoryBuffer::getFileOrSTDIN(ExtraArchives[i], ArBuf); - if (ec) { + ErrorOr<std::unique_ptr<MemoryBuffer>> ArBuf = + MemoryBuffer::getFileOrSTDIN(ExtraArchives[i]); + if (!ArBuf) { Err.print(argv[0], errs()); return 1; } - object::Archive *Ar = new object::Archive(ArBuf.release(), ec); - if (ec || !Ar) { + std::error_code EC; + object::Archive *Ar = new object::Archive(std::move(ArBuf.get()), EC); + if (EC || !Ar) { Err.print(argv[0], errs()); return 1; } diff --git a/tools/llvm-ar/Android.mk b/tools/llvm-ar/Android.mk index 24bad69..23cd857 100644 --- a/tools/llvm-ar/Android.mk +++ b/tools/llvm-ar/Android.mk @@ -16,6 +16,53 @@ llvm_ar_STATIC_LIBRARIES := \ libLLVMCore \ libLLVMSupport \ +# libLLVMAArch64CodeGen \ + libLLVMAArch64Info \ + libLLVMAArch64Desc \ + libLLVMAArch64AsmParser \ + libLLVMAArch64AsmPrinter \ + libLLVMAArch64Disassembler \ + libLLVMARMCodeGen \ + libLLVMARMInfo \ + libLLVMARMDesc \ + libLLVMARMAsmParser \ + libLLVMARMAsmPrinter \ + libLLVMARMDisassembler \ + libLLVMMipsCodeGen \ + libLLVMMipsInfo \ + libLLVMMipsDesc \ + libLLVMMipsAsmParser \ + libLLVMMipsAsmPrinter \ + libLLVMMipsDisassembler \ + libLLVMX86CodeGen \ + libLLVMX86Info \ + libLLVMX86Desc \ + libLLVMX86AsmParser \ + libLLVMX86AsmPrinter \ + libLLVMX86Disassembler \ + libLLVMAsmPrinter \ + libLLVMSelectionDAG \ + libLLVMCodeGen \ + libLLVMObject \ + libLLVMScalarOpts \ + libLLVMInstCombine \ + libLLVMInstrumentation \ + libLLVMTransformObjCARC \ + libLLVMTransformUtils \ + libLLVMipa \ + libLLVMAnalysis \ + libLLVMTarget \ + libLLVMMC \ + libLLVMMCParser \ + libLLVMCore \ + libLLVMAsmParser \ + libLLVMOption \ + libLLVMSupport \ + libLLVMVectorize \ + + + + include $(CLEAR_VARS) LOCAL_MODULE := llvm-ar @@ -26,6 +73,7 @@ LOCAL_IS_HOST_MODULE := true LOCAL_SRC_FILES := $(llvm_ar_SRC_FILES) LOCAL_STATIC_LIBRARIES := $(llvm_ar_STATIC_LIBRARIES) +LOCAL_SHARED_LIBRARIES := libLLVM LOCAL_LDLIBS += -lpthread -lm -ldl diff --git a/tools/llvm-ar/CMakeLists.txt b/tools/llvm-ar/CMakeLists.txt index 9295efe..0e809a7 100644 --- a/tools/llvm-ar/CMakeLists.txt +++ b/tools/llvm-ar/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Object Support ) diff --git a/tools/llvm-ar/Makefile b/tools/llvm-ar/Makefile index 16a8283..e10d6ac 100644 --- a/tools/llvm-ar/Makefile +++ b/tools/llvm-ar/Makefile @@ -10,7 +10,7 @@ LEVEL := ../.. TOOLNAME := llvm-ar TOOLALIAS = llvm-ranlib -LINK_COMPONENTS := bitreader support object +LINK_COMPONENTS := all-targets bitreader support object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index ed7291e..f638e55 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -17,12 +17,14 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -53,7 +55,7 @@ LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { exit(1); } -static void failIfError(error_code EC, Twine Context = "") { +static void failIfError(std::error_code EC, Twine Context = "") { if (!EC) return; @@ -368,8 +370,9 @@ static void performReadOperation(ArchiveOperation Operation, for (object::Archive::child_iterator I = OldArchive->child_begin(), E = OldArchive->child_end(); I != E; ++I) { - StringRef Name; - failIfError(I->getName(Name)); + ErrorOr<StringRef> NameOrErr = I->getName(); + failIfError(NameOrErr.getError()); + StringRef Name = NameOrErr.get(); if (!Members.empty() && std::find(Members.begin(), Members.end(), Name) == Members.end()) @@ -453,8 +456,7 @@ int NewArchiveIterator::getFD() const { // Linux cannot open directories with open(2), although // cygwin and *bsd can. if (NewStatus.type() == sys::fs::file_type::directory_file) - failIfError(error_code(errc::is_a_directory, posix_category()), - NewFilename); + failIfError(make_error_code(errc::is_a_directory), NewFilename); return NewFD; } @@ -544,8 +546,9 @@ computeNewArchiveMembers(ArchiveOperation Operation, E = OldArchive->child_end(); I != E; ++I) { int Pos = Ret.size(); - StringRef Name; - failIfError(I->getName(Name)); + ErrorOr<StringRef> NameOrErr = I->getName(); + failIfError(NameOrErr.getError()); + StringRef Name = NameOrErr.get(); if (Name == PosName) { assert(AddAfter || AddBefore); if (AddBefore) @@ -681,61 +684,51 @@ static void writeStringTable(raw_fd_ostream &Out, Out.seek(Pos); } -static void writeSymbolTable( - raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, - ArrayRef<MemoryBuffer *> Buffers, - std::vector<std::pair<unsigned, unsigned> > &MemberOffsetRefs) { +static void +writeSymbolTable(raw_fd_ostream &Out, ArrayRef<NewArchiveIterator> Members, + MutableArrayRef<std::unique_ptr<MemoryBuffer>> Buffers, + std::vector<std::pair<unsigned, unsigned>> &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; - std::vector<object::SymbolicFile *> DeleteIt; LLVMContext &Context = getGlobalContext(); for (ArrayRef<NewArchiveIterator>::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { - MemoryBuffer *MemberBuffer = Buffers[MemberNum]; + std::unique_ptr<MemoryBuffer> &MemberBuffer = Buffers[MemberNum]; ErrorOr<object::SymbolicFile *> ObjOrErr = object::SymbolicFile::createSymbolicFile( - MemberBuffer, false, sys::fs::file_magic::unknown, &Context); + MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. - object::SymbolicFile *Obj = ObjOrErr.get(); + std::unique_ptr<object::SymbolicFile> Obj(ObjOrErr.get()); - DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } - for (object::basic_symbol_iterator I = Obj->symbol_begin(), - E = Obj->symbol_end(); - I != E; ++I) { - uint32_t Symflags = I->getFlags(); + for (const object::BasicSymbolRef &S : Obj->symbols()) { + uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; - failIfError(I->printName(NameOS)); + failIfError(S.printName(NameOS)); NameOS << '\0'; ++NumSyms; MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); print32BE(Out, 0); } + MemberBuffer.reset(Obj->releaseBuffer()); } Out << NameOS.str(); - for (std::vector<object::SymbolicFile *>::iterator I = DeleteIt.begin(), - E = DeleteIt.end(); - I != E; ++I) { - object::SymbolicFile *O = *I; - delete O; - } - if (StartOffset == 0) return; @@ -766,7 +759,7 @@ static void performWriteOperation(ArchiveOperation Operation, std::vector<std::pair<unsigned, unsigned> > MemberOffsetRefs; - std::vector<MemoryBuffer *> MemberBuffers; + std::vector<std::unique_ptr<MemoryBuffer>> MemberBuffers; MemberBuffers.resize(NewMembers.size()); for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { @@ -777,15 +770,18 @@ static void performWriteOperation(ArchiveOperation Operation, const char *Filename = Member.getNew(); int FD = Member.getFD(); const sys::fs::file_status &Status = Member.getStatus(); - failIfError(MemoryBuffer::getOpenFile(FD, Filename, MemberBuffer, - Status.getSize(), false), - Filename); - + ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = + MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); + failIfError(MemberBufferOrErr.getError(), Filename); + MemberBuffer = std::move(MemberBufferOrErr.get()); } else { object::Archive::child_iterator OldMember = Member.getOld(); - failIfError(OldMember->getMemoryBuffer(MemberBuffer)); + ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr = + OldMember->getMemoryBuffer(); + failIfError(MemberBufferOrErr.getError()); + MemberBuffer = std::move(MemberBufferOrErr.get()); } - MemberBuffers[I] = MemberBuffer.release(); + MemberBuffers[I].reset(MemberBuffer.release()); } if (Symtab) { @@ -813,7 +809,7 @@ static void performWriteOperation(ArchiveOperation Operation, } Out.seek(Pos); - const MemoryBuffer *File = MemberBuffers[MemberNum]; + const MemoryBuffer *File = MemberBuffers[MemberNum].get(); if (I->isNewMember()) { const char *FileName = I->getNew(); const sys::fs::file_status &Status = I->getStatus(); @@ -849,10 +845,6 @@ static void performWriteOperation(ArchiveOperation Operation, Out << '\n'; } - for (unsigned I = 0, N = MemberBuffers.size(); I < N; ++I) { - delete MemberBuffers[I]; - } - Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); @@ -912,6 +904,10 @@ int main(int argc, char **argv) { " This program archives bitcode files into single libraries\n" ); + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + StringRef Stem = sys::path::stem(ToolName); if (Stem.find("ar") != StringRef::npos) return ar_main(argv); @@ -938,16 +934,17 @@ int ar_main(char **argv) { static int performOperation(ArchiveOperation Operation) { // Create or open the archive object. - std::unique_ptr<MemoryBuffer> Buf; - error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); - if (EC && EC != llvm::errc::no_such_file_or_directory) { + ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = + MemoryBuffer::getFile(ArchiveName, -1, false); + std::error_code EC = Buf.getError(); + if (EC && EC != errc::no_such_file_or_directory) { errs() << ToolName << ": error opening '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } if (!EC) { - object::Archive Archive(Buf.release(), EC); + object::Archive Archive(std::move(Buf.get()), EC); if (EC) { errs() << ToolName << ": error loading '" << ArchiveName @@ -958,7 +955,7 @@ static int performOperation(ArchiveOperation Operation) { return 0; } - assert(EC == llvm::errc::no_such_file_or_directory); + assert(EC == errc::no_such_file_or_directory); if (!shouldCreateArchive(Operation)) { failIfError(EC, Twine("error loading '") + ArchiveName + "'"); diff --git a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp index dfdaa03..15567cf 100644 --- a/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp +++ b/tools/llvm-bcanalyzer/llvm-bcanalyzer.cpp @@ -38,10 +38,10 @@ #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 <cctype> #include <map> +#include <system_error> using namespace llvm; static cl::opt<std::string> @@ -478,11 +478,11 @@ static void PrintSize(uint64_t Bits) { /// AnalyzeBitcode - Analyze the bitcode file specified by InputFilename. static int AnalyzeBitcode() { // Read the input file. - std::unique_ptr<MemoryBuffer> MemBuf; - - if (error_code ec = - MemoryBuffer::getFileOrSTDIN(InputFilename, MemBuf)) - return Error("Error reading '" + InputFilename + "': " + ec.message()); + ErrorOr<std::unique_ptr<MemoryBuffer>> MemBufOrErr = + MemoryBuffer::getFileOrSTDIN(InputFilename); + if (std::error_code EC = MemBufOrErr.getError()) + return Error("Error reading '" + InputFilename + "': " + EC.message()); + std::unique_ptr<MemoryBuffer> MemBuf = std::move(MemBufOrErr.get()); if (MemBuf->getBufferSize() & 3) return Error("Bitcode stream should be a multiple of 4 bytes in length"); diff --git a/tools/llvm-c-test/Android.mk b/tools/llvm-c-test/Android.mk index f26c989..3ab8830 100644 --- a/tools/llvm-c-test/Android.mk +++ b/tools/llvm-c-test/Android.mk @@ -50,6 +50,7 @@ llvm_c_test_STATIC_LIBRARIES := \ libLLVMTarget \ libLLVMMC \ libLLVMObject \ + libLLVMMCParser \ libLLVMCore \ libLLVMAsmParser \ libLLVMOption \ diff --git a/tools/llvm-config/Android.mk b/tools/llvm-config/Android.mk index 628a62c..bdc409d 100644 --- a/tools/llvm-config/Android.mk +++ b/tools/llvm-config/Android.mk @@ -19,7 +19,7 @@ llvm_config_LOCAL_INCLUDES := \ LibraryDependencies.inc llvm_config_DEPENDENCIES := \ - BuildVariables.inc + $(LOCAL_PATH)/BuildVariables.inc.in include $(CLEAR_VARS) diff --git a/tools/llvm-cov/llvm-cov.cpp b/tools/llvm-cov/llvm-cov.cpp index 9463609..18cc1b1 100644 --- a/tools/llvm-cov/llvm-cov.cpp +++ b/tools/llvm-cov/llvm-cov.cpp @@ -13,6 +13,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/GCOV.h" #include "llvm/Support/ManagedStatic.h" @@ -20,11 +21,11 @@ #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include "llvm/Support/system_error.h" +#include <system_error> using namespace llvm; -static cl::opt<std::string> SourceFile(cl::Positional, cl::Required, - cl::desc("SOURCEFILE")); +static cl::list<std::string> SourceFiles(cl::Positional, cl::OneOrMore, + cl::desc("SOURCEFILE")); static cl::opt<bool> AllBlocks("a", cl::Grouping, cl::init(false), cl::desc("Display all basic blocks")); @@ -75,15 +76,7 @@ static cl::opt<std::string> InputGCNO("gcno", cl::cat(DebugCat), cl::init(""), static cl::opt<std::string> InputGCDA("gcda", cl::cat(DebugCat), cl::init(""), cl::desc("Override inferred gcda file")); -//===----------------------------------------------------------------------===// -int main(int argc, char **argv) { - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - - cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); - +void reportCoverage(StringRef SourceFile) { SmallString<128> CoverageFileStem(ObjectDir); if (CoverageFileStem.empty()) { // If no directory was specified with -o, look next to the source file. @@ -96,37 +89,40 @@ int main(int argc, char **argv) { // A file was given. Ignore the source file and look next to this file. sys::path::replace_extension(CoverageFileStem, ""); - if (InputGCNO.empty()) - InputGCNO = (CoverageFileStem.str() + ".gcno").str(); - if (InputGCDA.empty()) - InputGCDA = (CoverageFileStem.str() + ".gcda").str(); - + std::string GCNO = InputGCNO.empty() + ? std::string(CoverageFileStem.str()) + ".gcno" + : InputGCNO; + std::string GCDA = InputGCDA.empty() + ? std::string(CoverageFileStem.str()) + ".gcda" + : InputGCDA; GCOVFile GF; - std::unique_ptr<MemoryBuffer> GCNO_Buff; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCNO, GCNO_Buff)) { - errs() << InputGCNO << ": " << ec.message() << "\n"; - return 1; + ErrorOr<std::unique_ptr<MemoryBuffer>> GCNO_Buff = + MemoryBuffer::getFileOrSTDIN(GCNO); + if (std::error_code EC = GCNO_Buff.getError()) { + errs() << GCNO << ": " << EC.message() << "\n"; + return; } - GCOVBuffer GCNO_GB(GCNO_Buff.get()); + GCOVBuffer GCNO_GB(GCNO_Buff.get().get()); if (!GF.readGCNO(GCNO_GB)) { errs() << "Invalid .gcno File!\n"; - return 1; + return; } - std::unique_ptr<MemoryBuffer> GCDA_Buff; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputGCDA, GCDA_Buff)) { - if (ec != errc::no_such_file_or_directory) { - errs() << InputGCDA << ": " << ec.message() << "\n"; - return 1; + ErrorOr<std::unique_ptr<MemoryBuffer>> GCDA_Buff = + MemoryBuffer::getFileOrSTDIN(GCDA); + if (std::error_code EC = GCDA_Buff.getError()) { + if (EC != errc::no_such_file_or_directory) { + errs() << GCDA << ": " << EC.message() << "\n"; + return; } // Clear the filename to make it clear we didn't read anything. - InputGCDA = "-"; + GCDA = "-"; } else { - GCOVBuffer GCDA_GB(GCDA_Buff.get()); + GCOVBuffer GCDA_GB(GCDA_Buff.get().get()); if (!GF.readGCDA(GCDA_GB)) { errs() << "Invalid .gcda File!\n"; - return 1; + return; } } @@ -137,6 +133,18 @@ int main(int argc, char **argv) { PreservePaths, UncondBranch, LongNames, NoOutput); FileInfo FI(Options); GF.collectLineCounts(FI); - FI.print(SourceFile, InputGCNO, InputGCDA); + FI.print(SourceFile, GCNO, GCDA); +} + +int main(int argc, char **argv) { + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + cl::ParseCommandLineOptions(argc, argv, "LLVM code coverage tool\n"); + + for (const auto &SourceFile : SourceFiles) + reportCoverage(SourceFile); return 0; } diff --git a/tools/llvm-dis/llvm-dis.cpp b/tools/llvm-dis/llvm-dis.cpp index 0df7328..3b0f838 100644 --- a/tools/llvm-dis/llvm-dis.cpp +++ b/tools/llvm-dis/llvm-dis.cpp @@ -32,7 +32,7 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ToolOutputFile.h" -#include "llvm/Support/system_error.h" +#include <system_error> using namespace llvm; static cl::opt<std::string> @@ -137,7 +137,7 @@ int main(int argc, char **argv) { M.reset(getStreamedBitcodeModule(DisplayFilename, streamer, Context, &ErrorMessage)); if(M.get()) { - if (error_code EC = M->materializeAllPermanently()) { + if (std::error_code EC = M->materializeAllPermanently()) { ErrorMessage = EC.message(); M.reset(); } diff --git a/tools/llvm-dwarfdump/Android.mk b/tools/llvm-dwarfdump/Android.mk index 7908201..61049e8 100644 --- a/tools/llvm-dwarfdump/Android.mk +++ b/tools/llvm-dwarfdump/Android.mk @@ -14,6 +14,8 @@ llvm_dwarfdump_STATIC_LIBRARIES := \ libLLVMDebugInfo \ libLLVMObject \ libLLVMBitReader \ + libLLVMMC \ + libLLVMMCParser \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp index 46ac36e..f44b0e3 100644 --- a/tools/llvm-dwarfdump/llvm-dwarfdump.cpp +++ b/tools/llvm-dwarfdump/llvm-dwarfdump.cpp @@ -25,11 +25,11 @@ #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 <cstring> #include <list> #include <string> +#include <system_error> using namespace llvm; using namespace object; @@ -66,15 +66,16 @@ DumpType("debug-dump", cl::init(DIDT_All), clEnumValEnd)); static void DumpInput(const StringRef &Filename) { - std::unique_ptr<MemoryBuffer> Buff; + ErrorOr<std::unique_ptr<MemoryBuffer>> Buff = + MemoryBuffer::getFileOrSTDIN(Filename); - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { - errs() << Filename << ": " << ec.message() << "\n"; + if (std::error_code EC = Buff.getError()) { + errs() << Filename << ": " << EC.message() << "\n"; return; } - ErrorOr<ObjectFile*> ObjOrErr(ObjectFile::createObjectFile(Buff.release())); - if (error_code EC = ObjOrErr.getError()) { + ErrorOr<ObjectFile *> ObjOrErr(ObjectFile::createObjectFile(Buff.get())); + if (std::error_code EC = ObjOrErr.getError()) { errs() << Filename << ": " << EC.message() << '\n'; return; } diff --git a/tools/llvm-lto/Android.mk b/tools/llvm-lto/Android.mk index a5782d9..1a9979e 100644 --- a/tools/llvm-lto/Android.mk +++ b/tools/llvm-lto/Android.mk @@ -19,9 +19,9 @@ llvm_lto_STATIC_LIBRARIES := \ libLLVMARMDisassembler \ libLLVMAArch64CodeGen \ libLLVMAArch64Info \ - libLLVMAArch64Desc \ - libLLVMAArch64AsmPrinter \ libLLVMAArch64AsmParser \ + libLLVMAArch64AsmPrinter \ + libLLVMAArch64Desc \ libLLVMAArch64Utils \ libLLVMAArch64Disassembler \ libLLVMMipsCodeGen \ diff --git a/tools/llvm-lto/llvm-lto.cpp b/tools/llvm-lto/llvm-lto.cpp index 8c2d1cd..8b39f12 100644 --- a/tools/llvm-lto/llvm-lto.cpp +++ b/tools/llvm-lto/llvm-lto.cpp @@ -110,7 +110,7 @@ int main(int argc, char **argv) { for (unsigned i = BaseArg; i < InputFilenames.size(); ++i) { std::string error; std::unique_ptr<LTOModule> Module( - LTOModule::makeLTOModule(InputFilenames[i].c_str(), Options, error)); + LTOModule::createFromFile(InputFilenames[i].c_str(), Options, error)); if (!error.empty()) { errs() << argv[0] << ": error loading file '" << InputFilenames[i] << "': " << error << "\n"; diff --git a/tools/llvm-mc/llvm-mc.cpp b/tools/llvm-mc/llvm-mc.cpp index 84d578b..4c5b230 100644 --- a/tools/llvm-mc/llvm-mc.cpp +++ b/tools/llvm-mc/llvm-mc.cpp @@ -52,7 +52,8 @@ static cl::opt<bool> ShowEncoding("show-encoding", cl::desc("Show instruction encodings")); static cl::opt<bool> -CompressDebugSections("compress-debug-sections", cl::desc("Compress DWARF debug sections")); +CompressDebugSections("compress-debug-sections", + cl::desc("Compress DWARF debug sections")); static cl::opt<bool> ShowInst("show-inst", cl::desc("Show internal instruction representation")); @@ -65,6 +66,10 @@ static cl::opt<unsigned> OutputAsmVariant("output-asm-variant", cl::desc("Syntax variant to use for output printing")); +static cl::opt<bool> +PrintImmHex("print-imm-hex", cl::init(false), + cl::desc("Prefer hex format for immediate values")); + enum OutputFileType { OFT_Null, OFT_AssemblyFile, @@ -145,9 +150,6 @@ static cl::opt<bool> GenDwarfForAssembly("g", cl::desc("Generate dwarf debugging info for assembly " "source files")); -static cl::opt<int> -DwarfVersion("dwarf-version", cl::desc("Dwarf version"), cl::init(4)); - static cl::opt<std::string> DebugCompilationDir("fdebug-compilation-dir", cl::desc("Specifies the debug info's compilation dir")); @@ -167,7 +169,6 @@ enum ActionType { AC_Assemble, AC_Disassemble, AC_MDisassemble, - AC_HDisassemble }; static cl::opt<ActionType> @@ -181,9 +182,6 @@ Action(cl::desc("Action to perform:"), "Disassemble strings of hex bytes"), clEnumValN(AC_MDisassemble, "mdis", "Marked up disassembly of strings of hex bytes"), - clEnumValN(AC_HDisassemble, "hdis", - "Disassemble strings of hex bytes printing " - "immediates as hex"), clEnumValEnd)); static const Target *GetTarget(const char *ProgName) { @@ -240,10 +238,11 @@ static void setDwarfDebugProducer(void) { DwarfDebugProducer += getenv("DEBUG_PRODUCER"); } -static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, tool_output_file *Out) { +static int AsLexInput(SourceMgr &SrcMgr, MCAsmInfo &MAI, + tool_output_file *Out) { AsmLexer Lexer(MAI); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(0)); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer()); bool Error = false; while (Lexer.Lex().isNot(AsmToken::Eof)) { @@ -320,12 +319,13 @@ 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, MCInstrInfo &MCII) { + MCAsmInfo &MAI, MCSubtargetInfo &STI, + MCInstrInfo &MCII, MCTargetOptions &MCOptions) { std::unique_ptr<MCAsmParser> Parser( createMCAsmParser(SrcMgr, Ctx, Str, MAI)); std::unique_ptr<MCTargetAsmParser> TAP( - TheTarget->createMCAsmParser(STI, *Parser, MCII, - InitMCTargetOptionsFromFlags())); + TheTarget->createMCAsmParser(STI, *Parser, MCII, MCOptions)); + if (!TAP) { errs() << ProgName << ": error: this target does not support assembly parsing.\n"; @@ -356,6 +356,7 @@ int main(int argc, char **argv) { cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); cl::ParseCommandLineOptions(argc, argv, "llvm machine code playground\n"); + MCTargetOptions MCOptions = InitMCTargetOptionsFromFlags(); TripleName = Triple::normalize(TripleName); setDwarfDebugFlags(argc, argv); @@ -366,12 +367,13 @@ int main(int argc, char **argv) { if (!TheTarget) return 1; - std::unique_ptr<MemoryBuffer> BufferPtr; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFilename, BufferPtr)) { - errs() << ProgName << ": " << ec.message() << '\n'; + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = + MemoryBuffer::getFileOrSTDIN(InputFilename); + if (std::error_code EC = BufferPtr.getError()) { + errs() << ProgName << ": " << EC.message() << '\n'; return 1; } - MemoryBuffer *Buffer = BufferPtr.release(); + MemoryBuffer *Buffer = BufferPtr->release(); SourceMgr SrcMgr; @@ -390,7 +392,8 @@ int main(int argc, char **argv) { if (CompressDebugSections) { if (!zlib::isAvailable()) { - errs() << ProgName << ": build tools with zlib to enable -compress-debug-sections"; + errs() << ProgName + << ": build tools with zlib to enable -compress-debug-sections"; return 1; } MAI->setCompressDebugSections(true); @@ -398,14 +401,16 @@ int main(int argc, char **argv) { // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and // MCObjectFileInfo needs a MCContext reference in order to initialize itself. - std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo()); - MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); - MOFI->InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); + MCObjectFileInfo MOFI; + MCContext Ctx(MAI.get(), MRI.get(), &MOFI, &SrcMgr); + MOFI.InitMCObjectFileInfo(TripleName, RelocModel, CMModel, Ctx); if (SaveTempLabels) Ctx.setAllowTemporaryLabels(false); Ctx.setGenDwarfForAssembly(GenDwarfForAssembly); + // Default to 4 for dwarf version. + unsigned DwarfVersion = MCOptions.DwarfVersion ? MCOptions.DwarfVersion : 4; if (DwarfVersion < 2 || DwarfVersion > 4) { errs() << ProgName << ": Dwarf version " << DwarfVersion << " is not supported." << '\n'; @@ -445,6 +450,11 @@ int main(int argc, char **argv) { if (FileType == OFT_AssemblyFile) { IP = TheTarget->createMCInstPrinter(OutputAsmVariant, *MAI, *MCII, *MRI, *STI); + + // Set the display preference for hex vs. decimal immediates. + IP->setPrintImmHex(PrintImmHex); + + // Set up the AsmStreamer. MCCodeEmitter *CE = nullptr; MCAsmBackend *MAB = nullptr; if (ShowEncoding) { @@ -473,18 +483,14 @@ 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, *MCII); + Res = AssembleInput(ProgName, TheTarget, SrcMgr, Ctx, *Str, *MAI, *STI, + *MCII, MCOptions); break; case AC_MDisassemble: assert(IP && "Expected assembly output"); IP->setUseMarkup(1); disassemble = true; break; - case AC_HDisassemble: - assert(IP && "Expected assembly output"); - IP->setPrintImmHex(1); - disassemble = true; - break; case AC_Disassemble: disassemble = true; break; diff --git a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp index f3a3e45..a878f11 100644 --- a/tools/llvm-mcmarkup/llvm-mcmarkup.cpp +++ b/tools/llvm-mcmarkup/llvm-mcmarkup.cpp @@ -19,7 +19,7 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" +#include <system_error> using namespace llvm; static cl::list<std::string> @@ -135,12 +135,13 @@ MarkupTag MarkupParser::parseTag() { } static void parseMCMarkup(StringRef Filename) { - std::unique_ptr<MemoryBuffer> BufferPtr; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, BufferPtr)) { - errs() << ToolName << ": " << ec.message() << '\n'; + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferPtr = + MemoryBuffer::getFileOrSTDIN(Filename); + if (std::error_code EC = BufferPtr.getError()) { + errs() << ToolName << ": " << EC.message() << '\n'; return; } - MemoryBuffer *Buffer = BufferPtr.release(); + MemoryBuffer *Buffer = BufferPtr->release(); SourceMgr SrcMgr; diff --git a/tools/llvm-nm/Android.mk b/tools/llvm-nm/Android.mk index 93bd9a3..98e7ba9 100644 --- a/tools/llvm-nm/Android.mk +++ b/tools/llvm-nm/Android.mk @@ -11,8 +11,36 @@ llvm_nm_SRC_FILES := \ llvm-nm.cpp llvm_nm_STATIC_LIBRARIES := \ + libLLVMARMCodeGen \ + libLLVMARMInfo \ + libLLVMARMDesc \ + libLLVMARMAsmPrinter \ + libLLVMARMAsmParser \ + libLLVMARMDisassembler \ + libLLVMAArch64CodeGen \ + libLLVMAArch64Info \ + libLLVMAArch64AsmParser \ + libLLVMAArch64Desc \ + libLLVMAArch64AsmPrinter \ + libLLVMAArch64Utils \ + libLLVMAArch64Disassembler \ + libLLVMMipsCodeGen \ + libLLVMMipsInfo \ + libLLVMMipsAsmParser \ + libLLVMMipsDesc \ + libLLVMMipsAsmPrinter \ + libLLVMMipsDisassembler \ + libLLVMX86CodeGen \ + libLLVMX86Info \ + libLLVMX86Desc \ + libLLVMX86AsmPrinter \ + libLLVMX86AsmParser \ + libLLVMX86Utils \ + libLLVMX86Disassembler \ libLLVMObject \ libLLVMBitReader \ + libLLVMMC \ + libLLVMMCParser \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/llvm-nm/CMakeLists.txt b/tools/llvm-nm/CMakeLists.txt index 6128bf9..1fe4a2d 100644 --- a/tools/llvm-nm/CMakeLists.txt +++ b/tools/llvm-nm/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Object Support ) diff --git a/tools/llvm-nm/Makefile b/tools/llvm-nm/Makefile index b95e920..ec20cef 100644 --- a/tools/llvm-nm/Makefile +++ b/tools/llvm-nm/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-nm -LINK_COMPONENTS := bitreader object +LINK_COMPONENTS := all-targets bitreader object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-nm/llvm-nm.cpp b/tools/llvm-nm/llvm-nm.cpp index 3be9247..3bd9ef9 100644 --- a/tools/llvm-nm/llvm-nm.cpp +++ b/tools/llvm-nm/llvm-nm.cpp @@ -37,21 +37,23 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" +#include "llvm/Support/TargetSelect.h" #include <algorithm> #include <cctype> #include <cerrno> #include <cstring> +#include <system_error> #include <vector> using namespace llvm; using namespace object; namespace { -enum OutputFormatTy { bsd, sysv, posix }; +enum OutputFormatTy { bsd, sysv, posix, darwin }; cl::opt<OutputFormatTy> OutputFormat( "format", cl::desc("Specify output format"), cl::values(clEnumVal(bsd, "BSD format"), clEnumVal(sysv, "System V format"), - clEnumVal(posix, "POSIX.2 format"), clEnumValEnd), + clEnumVal(posix, "POSIX.2 format"), + clEnumVal(darwin, "Darwin -m format"), clEnumValEnd), cl::init(bsd)); cl::alias OutputFormat2("f", cl::desc("Alias for --format"), cl::aliasopt(OutputFormat)); @@ -72,6 +74,8 @@ cl::alias DynamicSyms2("D", cl::desc("Alias for --dynamic"), cl::opt<bool> DefinedOnly("defined-only", cl::desc("Show only defined symbols")); +cl::alias DefinedOnly2("U", cl::desc("Alias for --defined-only"), + cl::aliasopt(DefinedOnly)); cl::opt<bool> ExternalOnly("extern-only", cl::desc("Show only external symbols")); @@ -80,6 +84,12 @@ cl::alias ExternalOnly2("g", cl::desc("Alias for --extern-only"), cl::opt<bool> BSDFormat("B", cl::desc("Alias for --format=bsd")); cl::opt<bool> POSIXFormat("P", cl::desc("Alias for --format=posix")); +cl::opt<bool> DarwinFormat("m", cl::desc("Alias for --format=darwin")); + +static cl::list<std::string> +ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; cl::opt<bool> PrintFileName( "print-file-name", @@ -104,6 +114,10 @@ cl::alias NumericSortv("v", cl::desc("Alias for --numeric-sort"), cl::opt<bool> NoSort("no-sort", cl::desc("Show symbols in order encountered")); cl::alias NoSortp("p", cl::desc("Alias for --no-sort"), cl::aliasopt(NoSort)); +cl::opt<bool> ReverseSort("reverse-sort", cl::desc("Sort in reverse order")); +cl::alias ReverseSortr("r", cl::desc("Alias for --reverse-sort"), + cl::aliasopt(ReverseSort)); + cl::opt<bool> PrintSize("print-size", cl::desc("Show symbol size instead of address")); cl::alias PrintSizeS("S", cl::desc("Alias for --print-size"), @@ -115,8 +129,13 @@ cl::opt<bool> WithoutAliases("without-aliases", cl::Hidden, cl::desc("Exclude aliases from output")); cl::opt<bool> ArchiveMap("print-armap", cl::desc("Print the archive map")); -cl::alias ArchiveMaps("s", cl::desc("Alias for --print-armap"), +cl::alias ArchiveMaps("M", cl::desc("Alias for --print-armap"), cl::aliasopt(ArchiveMap)); + +cl::opt<bool> JustSymbolName("just-symbol-name", + cl::desc("Print just the symbol's name")); +cl::alias JustSymbolNames("j", cl::desc("Alias for --just-symbol-name"), + cl::aliasopt(JustSymbolName)); bool PrintAddress = true; bool MultipleFiles = false; @@ -131,7 +150,7 @@ static void error(Twine Message, Twine Path = Twine()) { errs() << ToolName << ": " << Path << ": " << Message << ".\n"; } -static bool error(error_code EC, Twine Path = Twine()) { +static bool error(std::error_code EC, Twine Path = Twine()) { if (EC) { error(EC.message(), Path); return true; @@ -145,40 +164,74 @@ struct NMSymbol { uint64_t Size; char TypeChar; StringRef Name; + DataRefImpl Symb; }; } static bool compareSymbolAddress(const NMSymbol &A, const NMSymbol &B) { - if (A.Address < B.Address) - return true; - else if (A.Address == B.Address && A.Name < B.Name) - return true; - else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) - return true; - else - return false; + if (!ReverseSort) { + if (A.Address < B.Address) + return true; + else if (A.Address == B.Address && A.Name < B.Name) + return true; + else if (A.Address == B.Address && A.Name == B.Name && A.Size < B.Size) + return true; + else + return false; + } else { + if (A.Address > B.Address) + return true; + else if (A.Address == B.Address && A.Name > B.Name) + return true; + else if (A.Address == B.Address && A.Name == B.Name && A.Size > B.Size) + return true; + else + return false; + } } static bool compareSymbolSize(const NMSymbol &A, const NMSymbol &B) { - if (A.Size < B.Size) - return true; - else if (A.Size == B.Size && A.Name < B.Name) - return true; - else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) - return true; - else - return false; + if (!ReverseSort) { + if (A.Size < B.Size) + return true; + else if (A.Size == B.Size && A.Name < B.Name) + return true; + else if (A.Size == B.Size && A.Name == B.Name && A.Address < B.Address) + return true; + else + return false; + } else { + if (A.Size > B.Size) + return true; + else if (A.Size == B.Size && A.Name > B.Name) + return true; + else if (A.Size == B.Size && A.Name == B.Name && A.Address > B.Address) + return true; + else + return false; + } } static bool compareSymbolName(const NMSymbol &A, const NMSymbol &B) { - if (A.Name < B.Name) - return true; - else if (A.Name == B.Name && A.Size < B.Size) - return true; - else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) - return true; - else - return false; + if (!ReverseSort) { + if (A.Name < B.Name) + return true; + else if (A.Name == B.Name && A.Size < B.Size) + return true; + else if (A.Name == B.Name && A.Size == B.Size && A.Address < B.Address) + return true; + else + return false; + } else { + if (A.Name > B.Name) + return true; + else if (A.Name == B.Name && A.Size > B.Size) + return true; + else if (A.Name == B.Name && A.Size == B.Size && A.Address > B.Address) + return true; + else + return false; + } } static char isSymbolList64Bit(SymbolicFile *Obj) { @@ -194,7 +247,7 @@ static char isSymbolList64Bit(SymbolicFile *Obj) { return true; else if (isa<ELF32BEObjectFile>(Obj)) return false; - else if(isa<ELF64BEObjectFile>(Obj)) + else if (isa<ELF64BEObjectFile>(Obj)) return true; else return false; @@ -204,7 +257,164 @@ static StringRef CurrentFilename; typedef std::vector<NMSymbol> SymbolListT; static SymbolListT SymbolList; -static void sortAndPrintSymbolList(SymbolicFile *Obj) { +// darwinPrintSymbol() is used to print a symbol from a Mach-O file when the +// the OutputFormat is darwin. It produces the same output as darwin's nm(1) -m +// output. +static void darwinPrintSymbol(MachOObjectFile *MachO, SymbolListT::iterator I, + char *SymbolAddrStr, const char *printBlanks) { + MachO::mach_header H; + MachO::mach_header_64 H_64; + uint32_t Filetype, Flags; + MachO::nlist_64 STE_64; + MachO::nlist STE; + uint8_t NType; + uint16_t NDesc; + uint64_t NValue; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + Filetype = H_64.filetype; + Flags = H_64.flags; + STE_64 = MachO->getSymbol64TableEntry(I->Symb); + NType = STE_64.n_type; + NDesc = STE_64.n_desc; + NValue = STE_64.n_value; + } else { + H = MachO->MachOObjectFile::getHeader(); + Filetype = H.filetype; + Flags = H.flags; + STE = MachO->getSymbolTableEntry(I->Symb); + NType = STE.n_type; + NDesc = STE.n_desc; + NValue = STE.n_value; + } + + if (PrintAddress) { + if ((NType & MachO::N_TYPE) == MachO::N_INDR) + strcpy(SymbolAddrStr, printBlanks); + outs() << SymbolAddrStr << ' '; + } + + switch (NType & MachO::N_TYPE) { + case MachO::N_UNDF: + if (NValue != 0) { + outs() << "(common) "; + if (MachO::GET_COMM_ALIGN(NDesc) != 0) + outs() << "(alignment 2^" << (int)MachO::GET_COMM_ALIGN(NDesc) << ") "; + } else { + if ((NType & MachO::N_TYPE) == MachO::N_PBUD) + outs() << "(prebound "; + else + outs() << "("; + if ((NDesc & MachO::REFERENCE_TYPE) == + MachO::REFERENCE_FLAG_UNDEFINED_LAZY) + outs() << "undefined [lazy bound]) "; + else if ((NDesc & MachO::REFERENCE_TYPE) == + MachO::REFERENCE_FLAG_UNDEFINED_LAZY) + outs() << "undefined [private lazy bound]) "; + else if ((NDesc & MachO::REFERENCE_TYPE) == + MachO::REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY) + outs() << "undefined [private]) "; + else + outs() << "undefined) "; + } + break; + case MachO::N_ABS: + outs() << "(absolute) "; + break; + case MachO::N_INDR: + outs() << "(indirect) "; + break; + case MachO::N_SECT: { + section_iterator Sec = MachO->section_end(); + MachO->getSymbolSection(I->Symb, Sec); + DataRefImpl Ref = Sec->getRawDataRefImpl(); + StringRef SectionName; + MachO->getSectionName(Ref, SectionName); + StringRef SegmentName = MachO->getSectionFinalSegmentName(Ref); + outs() << "(" << SegmentName << "," << SectionName << ") "; + break; + } + default: + outs() << "(?) "; + break; + } + + if (NType & MachO::N_EXT) { + if (NDesc & MachO::REFERENCED_DYNAMICALLY) + outs() << "[referenced dynamically] "; + if (NType & MachO::N_PEXT) { + if ((NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) + outs() << "weak private external "; + else + outs() << "private external "; + } else { + if ((NDesc & MachO::N_WEAK_REF) == MachO::N_WEAK_REF || + (NDesc & MachO::N_WEAK_DEF) == MachO::N_WEAK_DEF) { + if ((NDesc & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) == + (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) + outs() << "weak external automatically hidden "; + else + outs() << "weak external "; + } else + outs() << "external "; + } + } else { + if (NType & MachO::N_PEXT) + outs() << "non-external (was a private external) "; + else + outs() << "non-external "; + } + + if (Filetype == MachO::MH_OBJECT && + (NDesc & MachO::N_NO_DEAD_STRIP) == MachO::N_NO_DEAD_STRIP) + outs() << "[no dead strip] "; + + if (Filetype == MachO::MH_OBJECT && + ((NType & MachO::N_TYPE) != MachO::N_UNDF) && + (NDesc & MachO::N_SYMBOL_RESOLVER) == MachO::N_SYMBOL_RESOLVER) + outs() << "[symbol resolver] "; + + if (Filetype == MachO::MH_OBJECT && + ((NType & MachO::N_TYPE) != MachO::N_UNDF) && + (NDesc & MachO::N_ALT_ENTRY) == MachO::N_ALT_ENTRY) + outs() << "[alt entry] "; + + if ((NDesc & MachO::N_ARM_THUMB_DEF) == MachO::N_ARM_THUMB_DEF) + outs() << "[Thumb] "; + + if ((NType & MachO::N_TYPE) == MachO::N_INDR) { + outs() << I->Name << " (for "; + StringRef IndirectName; + if (MachO->getIndirectName(I->Symb, IndirectName)) + outs() << "?)"; + else + outs() << IndirectName << ")"; + } else + outs() << I->Name; + + if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && + (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || + (NType & MachO::N_TYPE) == MachO::N_PBUD)) { + uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); + if (LibraryOrdinal != 0) { + if (LibraryOrdinal == MachO::EXECUTABLE_ORDINAL) + outs() << " (from executable)"; + else if (LibraryOrdinal == MachO::DYNAMIC_LOOKUP_ORDINAL) + outs() << " (dynamically looked up)"; + else { + StringRef LibraryName; + if (MachO->getLibraryShortNameByIndex(LibraryOrdinal - 1, LibraryName)) + outs() << " (from bad library ordinal " << LibraryOrdinal << ")"; + else + outs() << " (from " << LibraryName << ")"; + } + } + } + + outs() << "\n"; +} + +static void sortAndPrintSymbolList(SymbolicFile *Obj, bool printName) { if (!NoSort) { if (NumericSort) std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolAddress); @@ -214,9 +424,9 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj) { std::sort(SymbolList.begin(), SymbolList.end(), compareSymbolName); } - if (OutputFormat == posix && MultipleFiles) { + if (OutputFormat == posix && MultipleFiles && printName) { outs() << '\n' << CurrentFilename << ":\n"; - } else if (OutputFormat == bsd && MultipleFiles) { + } else if (OutputFormat == bsd && MultipleFiles && printName) { outs() << "\n" << CurrentFilename << ":\n"; } else if (OutputFormat == sysv) { outs() << "\n\nSymbols from " << CurrentFilename << ":\n\n" @@ -241,6 +451,10 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj) { continue; if (SizeSort && !PrintAddress && I->Size == UnknownAddressOrSize) continue; + if (JustSymbolName) { + outs() << I->Name << "\n"; + continue; + } char SymbolAddrStr[18] = ""; char SymbolSizeStr[18] = ""; @@ -256,10 +470,16 @@ static void sortAndPrintSymbolList(SymbolicFile *Obj) { if (I->Size != UnknownAddressOrSize) format(printFormat, I->Size).print(SymbolSizeStr, sizeof(SymbolSizeStr)); - if (OutputFormat == posix) { + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // nm(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // fall back to OutputFormat bsd (see below). + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); + if (OutputFormat == darwin && MachO) { + darwinPrintSymbol(MachO, I, SymbolAddrStr, printBlanks); + } else if (OutputFormat == posix) { outs() << I->Name << " " << I->TypeChar << " " << SymbolAddrStr << SymbolSizeStr << "\n"; - } else if (OutputFormat == bsd) { + } else if (OutputFormat == bsd || (OutputFormat == darwin && !MachO)) { if (PrintAddress) outs() << SymbolAddrStr << ' '; if (PrintSize) { @@ -299,14 +519,14 @@ static char getSymbolNMTypeChar(ELFObjectFile<ELFT> &Obj, case ELF::SHT_PROGBITS: case ELF::SHT_DYNAMIC: switch (ESec->sh_flags) { - case(ELF::SHF_ALLOC | ELF::SHF_EXECINSTR) : + case (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR): return 't'; - case(ELF::SHF_TLS | ELF::SHF_ALLOC | ELF::SHF_WRITE) : - case(ELF::SHF_ALLOC | ELF::SHF_WRITE) : + case (ELF::SHF_TLS | ELF::SHF_ALLOC | ELF::SHF_WRITE): + case (ELF::SHF_ALLOC | ELF::SHF_WRITE): return 'd'; case ELF::SHF_ALLOC: - case(ELF::SHF_ALLOC | ELF::SHF_MERGE) : - case(ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS) : + case (ELF::SHF_ALLOC | ELF::SHF_MERGE): + case (ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS): return 'r'; } break; @@ -395,6 +615,8 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { switch (NType & MachO::N_TYPE) { case MachO::N_ABS: return 's'; + case MachO::N_INDR: + return 'i'; case MachO::N_SECT: { section_iterator Sec = Obj.section_end(); Obj.getSymbolSection(Symb, Sec); @@ -404,6 +626,10 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { StringRef SegmentName = Obj.getSectionFinalSegmentName(Ref); if (SegmentName == "__TEXT" && SectionName == "__text") return 't'; + else if (SegmentName == "__DATA" && SectionName == "__data") + return 'd'; + else if (SegmentName == "__DATA" && SectionName == "__bss") + return 'b'; else return 's'; } @@ -413,20 +639,18 @@ static char getSymbolNMTypeChar(MachOObjectFile &Obj, basic_symbol_iterator I) { } static char getSymbolNMTypeChar(const GlobalValue &GV) { - if (isa<Function>(GV)) + if (GV.getType()->getElementType()->isFunctionTy()) return 't'; // FIXME: should we print 'b'? At the IR level we cannot be sure if this // will be in bss or not, but we could approximate. - if (isa<GlobalVariable>(GV)) - return 'd'; - const GlobalAlias *GA = cast<GlobalAlias>(&GV); - const GlobalValue *AliasedGV = GA->getAliasee(); - return getSymbolNMTypeChar(*AliasedGV); + return 'd'; } static char getSymbolNMTypeChar(IRObjectFile &Obj, basic_symbol_iterator I) { - const GlobalValue &GV = Obj.getSymbolGV(I->getRawDataRefImpl()); - return getSymbolNMTypeChar(GV); + const GlobalValue *GV = Obj.getSymbolGV(I->getRawDataRefImpl()); + if (!GV) + return 't'; + return getSymbolNMTypeChar(*GV); } template <class ELFT> @@ -490,7 +714,7 @@ static char getNMTypeChar(SymbolicFile *Obj, basic_symbol_iterator I) { return Ret; } -static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { +static void dumpSymbolNamesFromObject(SymbolicFile *Obj, bool printName) { basic_symbol_iterator IBegin = Obj->symbol_begin(); basic_symbol_iterator IEnd = Obj->symbol_end(); if (DynamicSyms) { @@ -511,8 +735,8 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { continue; if (WithoutAliases) { if (IRObjectFile *IR = dyn_cast<IRObjectFile>(Obj)) { - const GlobalValue &GV = IR->getSymbolGV(I->getRawDataRefImpl()); - if(isa<GlobalAlias>(GV)) + const GlobalValue *GV = IR->getSymbolGV(I->getRawDataRefImpl()); + if (GV && isa<GlobalAlias>(GV)) continue; } } @@ -531,6 +755,7 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { if (error(I->printName(OS))) break; OS << '\0'; + S.Symb = I->getRawDataRefImpl(); SymbolList.push_back(S); } @@ -542,18 +767,55 @@ static void dumpSymbolNamesFromObject(SymbolicFile *Obj) { } CurrentFilename = Obj->getFileName(); - sortAndPrintSymbolList(Obj); + sortAndPrintSymbolList(Obj, printName); +} + +// checkMachOAndArchFlags() checks to see if the SymbolicFile is a Mach-O file +// and if it is and there is a list of architecture flags is specified then +// check to make sure this Mach-O file is one of those architectures or all +// architectures was specificed. If not then an error is generated and this +// routine returns false. Else it returns true. +static bool checkMachOAndArchFlags(SymbolicFile *O, std::string &Filename) { + if (isa<MachOObjectFile>(O) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(O); + bool ArchFound = false; + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + } + unsigned i; + for (i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == T.getArchName()) + ArchFound = true; + break; + } + if (!ArchFound) { + error(ArchFlags[i], + "file: " + Filename + " does not contain architecture"); + return false; + } + } + return true; } static void dumpSymbolNamesFromFile(std::string &Filename) { - std::unique_ptr<MemoryBuffer> Buffer; - if (error(MemoryBuffer::getFileOrSTDIN(Filename, Buffer), Filename)) + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = + MemoryBuffer::getFileOrSTDIN(Filename); + if (error(BufferOrErr.getError(), Filename)) return; + std::unique_ptr<MemoryBuffer> Buffer = std::move(BufferOrErr.get()); LLVMContext &Context = getGlobalContext(); - ErrorOr<Binary *> BinaryOrErr = createBinary(Buffer.release(), &Context); + ErrorOr<Binary *> BinaryOrErr = createBinary(Buffer, &Context); if (error(BinaryOrErr.getError(), Filename)) return; + Buffer.release(); std::unique_ptr<Binary> Bin(BinaryOrErr.get()); if (Archive *A = dyn_cast<Archive>(Bin.get())) { @@ -563,16 +825,14 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { if (I != E) { outs() << "Archive map\n"; for (; I != E; ++I) { - Archive::child_iterator C; - StringRef SymName; - StringRef FileName; - if (error(I->getMember(C))) + ErrorOr<Archive::child_iterator> C = I->getMember(); + if (error(C.getError())) return; - if (error(I->getName(SymName))) + ErrorOr<StringRef> FileNameOrErr = C.get()->getName(); + if (error(FileNameOrErr.getError())) return; - if (error(C->getName(FileName))) - return; - outs() << SymName << " in " << FileName << "\n"; + StringRef SymName = I->getName(); + outs() << SymName << " in " << FileNameOrErr.get() << "\n"; } outs() << "\n"; } @@ -580,36 +840,145 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E; ++I) { - std::unique_ptr<Binary> Child; - if (I->getAsBinary(Child, &Context)) + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary(&Context); + if (ChildOrErr.getError()) continue; - if (SymbolicFile *O = dyn_cast<SymbolicFile>(Child.get())) { - outs() << O->getFileName() << ":\n"; - dumpSymbolNamesFromObject(O); + if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + outs() << "\n"; + if (isa<MachOObjectFile>(O)) { + outs() << Filename << "(" << O->getFileName() << ")"; + } else + outs() << O->getFileName(); + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); } } return; } if (MachOUniversalBinary *UB = dyn_cast<MachOUniversalBinary>(Bin.get())) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchTypeName()) { + ArchFound = true; + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = + I->getAsObjectFile(); + std::unique_ptr<Archive> A; + if (ObjOrErr) { + std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); + if (ArchFlags.size() > 1) { + outs() << "\n" << Obj->getFileName() << " (for architecture " + << I->getArchTypeName() << ")" + << ":\n"; + } + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = + dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName(); + outs() << "(" << O->getFileName() << ")"; + if (ArchFlags.size() > 1) { + outs() << " (for architecture " << I->getArchTypeName() + << ")"; + } + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + } + } + } + if (!ArchFound) { + error(ArchFlags[i], + "file: " + Filename + " does not contain architecture"); + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchTypeName()) { + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); + std::unique_ptr<Archive> A; + if (ObjOrErr) { + std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) + continue; + if (SymbolicFile *O = + dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName() << "(" << O->getFileName() + << ")" + << ":\n"; + dumpSymbolNamesFromObject(O, false); + } + } + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool moreThanOneArch = UB->getNumberOfObjects() > 1; for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), E = UB->end_objects(); I != E; ++I) { - std::unique_ptr<ObjectFile> Obj; + ErrorOr<std::unique_ptr<ObjectFile>> ObjOrErr = I->getAsObjectFile(); std::unique_ptr<Archive> A; - if (!I->getAsObjectFile(Obj)) { - outs() << Obj->getFileName() << ":\n"; - dumpSymbolNamesFromObject(Obj.get()); - } - else if (!I->getAsArchive(A)) { + if (ObjOrErr) { + std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get()); + if (moreThanOneArch) + outs() << "\n"; + outs() << Obj->getFileName(); + if (isa<MachOObjectFile>(Obj.get()) && moreThanOneArch) + outs() << " (for architecture " << I->getArchTypeName() << ")"; + outs() << ":\n"; + dumpSymbolNamesFromObject(Obj.get(), false); + } else if (!I->getAsArchive(A)) { for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); AI != AE; ++AI) { - std::unique_ptr<Binary> Child; - if (AI->getAsBinary(Child, &Context)) + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = + AI->getAsBinary(&Context); + if (ChildOrErr.getError()) continue; - if (SymbolicFile *O = dyn_cast<SymbolicFile>(Child.get())) { - outs() << A->getFileName() << ":"; - outs() << O->getFileName() << ":\n"; - dumpSymbolNamesFromObject(O); + if (SymbolicFile *O = dyn_cast<SymbolicFile>(&*ChildOrErr.get())) { + outs() << "\n" << A->getFileName(); + if (isa<MachOObjectFile>(O)) { + outs() << "(" << O->getFileName() << ")"; + if (moreThanOneArch) + outs() << " (for architecture " << I->getArchTypeName() << ")"; + } else + outs() << ":" << O->getFileName(); + outs() << ":\n"; + dumpSymbolNamesFromObject(O, false); } } } @@ -617,7 +986,9 @@ static void dumpSymbolNamesFromFile(std::string &Filename) { return; } if (SymbolicFile *O = dyn_cast<SymbolicFile>(Bin.get())) { - dumpSymbolNamesFromObject(O); + if (!checkMachOAndArchFlags(O, Filename)) + return; + dumpSymbolNamesFromObject(O, true); return; } error("unrecognizable file type", Filename); @@ -636,11 +1007,17 @@ int main(int argc, char **argv) { if (error(sys::ChangeStdinToBinary())) return 1; + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + ToolName = argv[0]; if (BSDFormat) OutputFormat = bsd; if (POSIXFormat) OutputFormat = posix; + if (DarwinFormat) + OutputFormat = darwin; // The relative order of these is important. If you pass --size-sort it should // only print out the size. However, if you pass -S --size-sort, it should @@ -652,13 +1029,24 @@ int main(int argc, char **argv) { switch (InputFilenames.size()) { case 0: - InputFilenames.push_back("-"); + InputFilenames.push_back("a.out"); case 1: break; default: MultipleFiles = true; } + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == "all") { + ArchAll = true; + } else { + Triple T = MachOObjectFile::getArch(ArchFlags[i]); + if (T.getArch() == Triple::UnknownArch) + error("Unknown architecture named '" + ArchFlags[i] + "'", + "for the -arch option"); + } + } + std::for_each(InputFilenames.begin(), InputFilenames.end(), dumpSymbolNamesFromFile); diff --git a/tools/llvm-objdump/Android.mk b/tools/llvm-objdump/Android.mk index ea738f4..8105ebf 100644 --- a/tools/llvm-objdump/Android.mk +++ b/tools/llvm-objdump/Android.mk @@ -39,15 +39,15 @@ llvm_objdump_STATIC_LIBRARIES := \ libLLVMX86Disassembler \ libLLVMAsmPrinter \ libLLVMTarget \ + libLLVMObject \ libLLVMMCParser \ + libLLVMMCAnalysis \ libLLVMMC \ libLLVMMCDisassembler \ - libLLVMObject \ libLLVMBitReader \ libLLVMCore \ libLLVMAsmParser \ libLLVMSupport \ - libLLVMMCDisassembler \ include $(CLEAR_VARS) diff --git a/tools/llvm-objdump/CMakeLists.txt b/tools/llvm-objdump/CMakeLists.txt index 413cb9b..d63602b 100644 --- a/tools/llvm-objdump/CMakeLists.txt +++ b/tools/llvm-objdump/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} DebugInfo MC + MCAnalysis Object Support ) diff --git a/tools/llvm-objdump/COFFDump.cpp b/tools/llvm-objdump/COFFDump.cpp index 49f2755..39d8e8e 100644 --- a/tools/llvm-objdump/COFFDump.cpp +++ b/tools/llvm-objdump/COFFDump.cpp @@ -22,9 +22,9 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <algorithm> #include <cstring> +#include <system_error> using namespace llvm; using namespace object; @@ -157,14 +157,14 @@ static void printAllUnwindCodes(ArrayRef<UnwindCode> UCs) { } // Given a symbol sym this functions returns the address and section of it. -static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, - const SymbolRef &Sym, - const coff_section *&ResolvedSection, - uint64_t &ResolvedAddr) { - if (error_code EC = Sym.getAddress(ResolvedAddr)) +static std::error_code +resolveSectionAndAddress(const COFFObjectFile *Obj, const SymbolRef &Sym, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddr) { + if (std::error_code EC = Sym.getAddress(ResolvedAddr)) return EC; section_iterator iter(Obj->section_begin()); - if (error_code EC = Sym.getSection(iter)) + if (std::error_code EC = Sym.getSection(iter)) return EC; ResolvedSection = Obj->getCOFFSection(*iter); return object_error::success; @@ -172,13 +172,13 @@ static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, // Given a vector of relocations for a section and an offset into this section // the function returns the symbol used for the relocation at the offset. -static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, - uint64_t Offset, SymbolRef &Sym) { +static std::error_code resolveSymbol(const std::vector<RelocationRef> &Rels, + uint64_t Offset, SymbolRef &Sym) { for (std::vector<RelocationRef>::const_iterator I = Rels.begin(), E = Rels.end(); I != E; ++I) { uint64_t Ofs; - if (error_code EC = I->getOffset(Ofs)) + if (std::error_code EC = I->getOffset(Ofs)) return EC; if (Ofs == Offset) { Sym = *I->getSymbol(); @@ -192,18 +192,17 @@ static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, // the function resolves the symbol used for the relocation at the offset and // returns the section content and the address inside the content pointed to // by the symbol. -static error_code getSectionContents(const COFFObjectFile *Obj, - const std::vector<RelocationRef> &Rels, - uint64_t Offset, - ArrayRef<uint8_t> &Contents, - uint64_t &Addr) { +static std::error_code +getSectionContents(const COFFObjectFile *Obj, + const std::vector<RelocationRef> &Rels, uint64_t Offset, + ArrayRef<uint8_t> &Contents, uint64_t &Addr) { SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; const coff_section *Section; - if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) + if (std::error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) return EC; - if (error_code EC = Obj->getSectionContents(Section, Contents)) + if (std::error_code EC = Obj->getSectionContents(Section, Contents)) return EC; return object_error::success; } @@ -211,12 +210,12 @@ static error_code getSectionContents(const COFFObjectFile *Obj, // Given a vector of relocations for a section and an offset into this section // the function returns the name of the symbol used for the relocation at the // offset. -static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, - uint64_t Offset, StringRef &Name) { +static std::error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, + uint64_t Offset, StringRef &Name) { SymbolRef Sym; - if (error_code EC = resolveSymbol(Rels, Offset, Sym)) + if (std::error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; - if (error_code EC = Sym.getName(Name)) + if (std::error_code EC = Sym.getName(Name)) return EC; return object_error::success; } diff --git a/tools/llvm-objdump/LLVMBuild.txt b/tools/llvm-objdump/LLVMBuild.txt index d16c501..d9c09b6 100644 --- a/tools/llvm-objdump/LLVMBuild.txt +++ b/tools/llvm-objdump/LLVMBuild.txt @@ -19,4 +19,4 @@ type = Tool name = llvm-objdump parent = Tools -required_libraries = DebugInfo MC MCDisassembler MCParser Object all-targets +required_libraries = DebugInfo MC MCAnalysis MCDisassembler MCParser Object all-targets diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 3ca582f..4b46ac4 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -37,9 +37,9 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <algorithm> #include <cstring> +#include <system_error> using namespace llvm; using namespace object; @@ -195,15 +195,15 @@ static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF); void llvm::DisassembleInputMachO(StringRef Filename) { - std::unique_ptr<MemoryBuffer> Buff; - - if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { - errs() << "llvm-objdump: " << Filename << ": " << ec.message() << "\n"; + ErrorOr<std::unique_ptr<MemoryBuffer>> Buff = + MemoryBuffer::getFileOrSTDIN(Filename); + if (std::error_code EC = Buff.getError()) { + errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n"; return; } std::unique_ptr<MachOObjectFile> MachOOF(static_cast<MachOObjectFile *>( - ObjectFile::createMachOObjectFile(Buff.release()).get())); + ObjectFile::createMachOObjectFile(Buff.get()).get())); DisassembleInputMachO2(Filename, MachOOF.get()); } @@ -288,12 +288,13 @@ static void DisassembleInputMachO2(StringRef Filename, // A separate DSym file path was specified, parse it as a macho file, // get the sections and supply it to the section name parsing machinery. if (!DSYMFile.empty()) { - std::unique_ptr<MemoryBuffer> Buf; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(DSYMFile, Buf)) { - errs() << "llvm-objdump: " << Filename << ": " << ec.message() << '\n'; + ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = + MemoryBuffer::getFileOrSTDIN(DSYMFile); + if (std::error_code EC = Buf.getError()) { + errs() << "llvm-objdump: " << Filename << ": " << EC.message() << '\n'; return; } - DbgObj = ObjectFile::createMachOObjectFile(Buf.release()).get(); + DbgObj = ObjectFile::createMachOObjectFile(Buf.get()).get(); } // Setup the DIContext diff --git a/tools/llvm-objdump/Makefile b/tools/llvm-objdump/Makefile index 4616b78..c3601eb 100644 --- a/tools/llvm-objdump/Makefile +++ b/tools/llvm-objdump/Makefile @@ -9,7 +9,7 @@ LEVEL := ../.. TOOLNAME := llvm-objdump -LINK_COMPONENTS := all-targets DebugInfo MC MCParser MCDisassembler Object +LINK_COMPONENTS := all-targets DebugInfo MC MCAnalysis MCParser MCDisassembler Object # This tool has no plugins, optimize startup time. TOOL_NO_EXPORTS := 1 diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index a4fc6d0..309bf23 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -20,17 +20,17 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Triple.h" +#include "llvm/MC/MCAnalysis/MCAtom.h" +#include "llvm/MC/MCAnalysis/MCFunction.h" +#include "llvm/MC/MCAnalysis/MCModule.h" +#include "llvm/MC/MCAnalysis/MCModuleYAML.h" #include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCAtom.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler.h" -#include "llvm/MC/MCFunction.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #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" @@ -57,10 +57,10 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <algorithm> #include <cctype> #include <cstring> +#include <system_error> using namespace llvm; using namespace object; @@ -148,7 +148,7 @@ YAMLCFG("yaml-cfg", static StringRef ToolName; -bool llvm::error(error_code EC) { +bool llvm::error(std::error_code EC) { if (!EC) return false; @@ -395,7 +395,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Create a mapping, RelocSecs = SectionRelocMap[S], where sections // in RelocSecs contain the relocations for section S. - error_code EC; + std::error_code EC; std::map<SectionRef, SmallVector<SectionRef, 1>> SectionRelocMap; for (const SectionRef &Section : Obj->sections()) { section_iterator Sec2 = Section.getRelocatedSection(); @@ -620,7 +620,7 @@ static void PrintSectionHeaders(const ObjectFile *Obj) { } static void PrintSectionContents(const ObjectFile *Obj) { - error_code EC; + std::error_code EC; for (const SectionRef &Section : Obj->sections()) { StringRef Name; StringRef Contents; @@ -850,15 +850,15 @@ static void DumpObject(const ObjectFile *o) { static void DumpArchive(const Archive *a) { for (Archive::child_iterator i = a->child_begin(), e = a->child_end(); i != e; ++i) { - std::unique_ptr<Binary> child; - if (error_code EC = i->getAsBinary(child)) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. if (EC != object_error::invalid_file_type) errs() << ToolName << ": '" << a->getFileName() << "': " << EC.message() << ".\n"; continue; } - if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) DumpObject(o); else errs() << ToolName << ": '" << a->getFileName() << "': " @@ -881,7 +881,7 @@ static void DumpInput(StringRef file) { // Attempt to open the binary. ErrorOr<Binary *> BinaryOrErr = createBinary(file); - if (error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) { errs() << ToolName << ": '" << file << "': " << EC.message() << ".\n"; return; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index b716a26..80f8f58 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -16,19 +16,17 @@ #include "llvm/Support/StringRefMemoryObject.h" namespace llvm { - namespace object { class COFFObjectFile; class ObjectFile; class RelocationRef; } -class error_code; extern cl::opt<std::string> TripleName; extern cl::opt<std::string> ArchName; // Various helper functions. -bool error(error_code ec); +bool error(std::error_code ec); bool RelocAddressLess(object::RelocationRef a, object::RelocationRef b); void DumpBytes(StringRef bytes); void DisassembleInputMachO(StringRef Filename); diff --git a/tools/llvm-profdata/llvm-profdata.cpp b/tools/llvm-profdata/llvm-profdata.cpp index fdde32a..ba88aad 100644 --- a/tools/llvm-profdata/llvm-profdata.cpp +++ b/tools/llvm-profdata/llvm-profdata.cpp @@ -56,11 +56,12 @@ int merge_main(int argc, const char *argv[]) { InstrProfWriter Writer; for (const auto &Filename : Inputs) { std::unique_ptr<InstrProfReader> Reader; - if (error_code ec = InstrProfReader::create(Filename, Reader)) + if (std::error_code ec = InstrProfReader::create(Filename, Reader)) exitWithError(ec.message(), Filename); for (const auto &I : *Reader) - if (error_code EC = Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) + if (std::error_code EC = + Writer.addFunctionCounts(I.Name, I.Hash, I.Counts)) errs() << Filename << ": " << I.Name << ": " << EC.message() << "\n"; if (Reader->hasError()) exitWithError(Reader->getError().message(), Filename); @@ -90,7 +91,7 @@ int show_main(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n"); std::unique_ptr<InstrProfReader> Reader; - if (error_code EC = InstrProfReader::create(Filename, Reader)) + if (std::error_code EC = InstrProfReader::create(Filename, Reader)) exitWithError(EC.message(), Filename); if (OutputFilename.empty()) diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp new file mode 100644 index 0000000..b486e4a --- /dev/null +++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -0,0 +1,744 @@ +//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// Windows on ARM uses a series of serialised data structures (RuntimeFunction) +// to create a table of information for unwinding. In order to conserve space, +// there are two different ways that this data is represented. +// +// For functions with canonical forms for the prologue and epilogue, the data +// can be stored in a "packed" form. In this case, the data is packed into the +// RuntimeFunction's remaining 30-bits and can fully describe the entire frame. +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Packed Form Data | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpPackedEntry. No unwind bytecode is +// associated with such a frame as they can be derived from the provided data. +// The decoder does not synthesize this data as it is unnecessary for the +// purposes of validation, with the synthesis being required only by a proper +// unwinder. +// +// For functions that are large or do not match canonical forms, the data is +// split up into two portions, with the actual data residing in the "exception +// data" table (.xdata) with a reference to the entry from the "procedure data" +// (.pdata) entry. +// +// The exception data contains information about the frame setup, all of the +// epilouge scopes (for functions for which there are multiple exit points) and +// the associated exception handler. Additionally, the entry contains byte-code +// describing how to unwind the function (c.f. Decoder::decodeOpcodes). +// +// +---------------------------------------+ +// | Function Entry Address | +// +---------------------------------------+ +// | Exception Data Entry Address | +// +---------------------------------------+ +// +// This layout is parsed by Decoder::dumpUnpackedEntry. Such an entry must +// first resolve the exception data entry address. This structure +// (ExceptionDataRecord) has a variable sized header +// (c.f. ARM::WinEH::HeaderWords) and encodes most of the same information as +// the packed form. However, because this information is insufficient to +// synthesize the unwinding, there are associated unwinding bytecode which make +// up the bulk of the Decoder. +// +// The decoder itself is table-driven, using the first byte to determine the +// opcode and dispatching to the associated printing routine. The bytecode +// itself is a variable length instruction encoding that can fully describe the +// state of the stack and the necessary operations for unwinding to the +// beginning of the frame. +// +// The byte-code maintains a 1-1 instruction mapping, indicating both the width +// of the instruction (Thumb2 instructions are variable length, 16 or 32 bits +// wide) allowing the program to unwind from any point in the prologue, body, or +// epilogue of the function. + +#include "ARMWinEHPrinter.h" +#include "Error.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/ARMWinEH.h" +#include "llvm/Support/Format.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support; + +namespace llvm { +raw_ostream &operator<<(raw_ostream &OS, const ARM::WinEH::ReturnType &RT) { + switch (RT) { + case ARM::WinEH::ReturnType::RT_POP: + OS << "pop {pc}"; + break; + case ARM::WinEH::ReturnType::RT_B: + OS << "b target"; + break; + case ARM::WinEH::ReturnType::RT_BW: + OS << "b.w target"; + break; + case ARM::WinEH::ReturnType::RT_NoEpilogue: + OS << "(no epilogue)"; + break; + } + return OS; +} +} + +static std::string formatSymbol(StringRef Name, uint64_t Address, + uint64_t Offset = 0) { + std::string Buffer; + raw_string_ostream OS(Buffer); + + if (!Name.empty()) + OS << Name << " "; + + if (Offset) + OS << format("+0x%X (0x%" PRIX64 ")", Offset, Address); + else if (!Name.empty()) + OS << format("(0x%" PRIX64 ")", Address); + else + OS << format("0x%" PRIX64, Address); + + return OS.str(); +} + +namespace llvm { +namespace ARM { +namespace WinEH { +const size_t Decoder::PDataEntrySize = sizeof(RuntimeFunction); + +// TODO name the uops more appropriately +const Decoder::RingEntry Decoder::Ring[] = { + { 0x80, 0x00, &Decoder::opcode_0xxxxxxx }, // UOP_STACK_FREE (16-bit) + { 0xc0, 0x80, &Decoder::opcode_10Lxxxxx }, // UOP_POP (32-bit) + { 0xf0, 0xc0, &Decoder::opcode_1100xxxx }, // UOP_STACK_SAVE (16-bit) + { 0xf8, 0xd0, &Decoder::opcode_11010Lxx }, // UOP_POP (16-bit) + { 0xf8, 0xd8, &Decoder::opcode_11011Lxx }, // UOP_POP (32-bit) + { 0xf8, 0xe0, &Decoder::opcode_11100xxx }, // UOP_VPOP (32-bit) + { 0xfc, 0xe8, &Decoder::opcode_111010xx }, // UOP_STACK_FREE (32-bit) + { 0xfe, 0xec, &Decoder::opcode_1110110L }, // UOP_POP (16-bit) + { 0xff, 0xee, &Decoder::opcode_11101110 }, // UOP_MICROSOFT_SPECIFIC (16-bit) + // UOP_PUSH_MACHINE_FRAME + // UOP_PUSH_CONTEXT + // UOP_PUSH_TRAP_FRAME + // UOP_REDZONE_RESTORE_LR + { 0xff, 0xef, &Decoder::opcode_11101111 }, // UOP_LDRPC_POSTINC (32-bit) + { 0xff, 0xf5, &Decoder::opcode_11110101 }, // UOP_VPOP (32-bit) + { 0xff, 0xf6, &Decoder::opcode_11110110 }, // UOP_VPOP (32-bit) + { 0xff, 0xf7, &Decoder::opcode_11110111 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf8, &Decoder::opcode_11111000 }, // UOP_STACK_RESTORE (16-bit) + { 0xff, 0xf9, &Decoder::opcode_11111001 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfa, &Decoder::opcode_11111010 }, // UOP_STACK_RESTORE (32-bit) + { 0xff, 0xfb, &Decoder::opcode_11111011 }, // UOP_NOP (16-bit) + { 0xff, 0xfc, &Decoder::opcode_11111100 }, // UOP_NOP (32-bit) + { 0xff, 0xfd, &Decoder::opcode_11111101 }, // UOP_NOP (16-bit) / END + { 0xff, 0xfe, &Decoder::opcode_11111110 }, // UOP_NOP (32-bit) / END + { 0xff, 0xff, &Decoder::opcode_11111111 }, // UOP_END +}; + +void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) { + static const char * const GPRRegisterNames[16] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", + "r11", "ip", "sp", "lr", "pc", + }; + + const uint16_t GPRMask = std::get<0>(RegisterMask); + const uint16_t VFPMask = std::get<1>(RegisterMask); + + OS << '{'; + bool Comma = false; + for (unsigned RI = 0, RE = 11; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + for (unsigned RI = 0, RE = 32; RI < RE; ++RI) { + if (VFPMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << "d" << unsigned(RI); + Comma = true; + } + } + for (unsigned RI = 11, RE = 16; RI < RE; ++RI) { + if (GPRMask & (1 << RI)) { + if (Comma) + OS << ", "; + OS << GPRRegisterNames[RI]; + Comma = true; + } + } + OS << '}'; +} + +ErrorOr<object::SectionRef> +Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { + for (const auto &Section : COFF.sections()) { + uint64_t Address; + uint64_t Size; + + if (std::error_code EC = Section.getAddress(Address)) + return EC; + if (std::error_code EC = Section.getSize(Size)) + return EC; + + if (VA >= Address && (VA - Address) <= Size) + return Section; + } + return readobj_error::unknown_symbol; +} + +ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, + uint64_t VA, bool FunctionOnly) { + for (const auto &Symbol : COFF.symbols()) { + if (FunctionOnly) { + SymbolRef::Type Type; + if (std::error_code EC = Symbol.getType(Type)) + return EC; + if (Type != SymbolRef::ST_Function) + continue; + } + + uint64_t Address; + if (std::error_code EC = Symbol.getAddress(Address)) + return EC; + if (Address == VA) + return Symbol; + } + return readobj_error::unknown_symbol; +} + +ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, + const SectionRef &Section, + uint64_t Offset) { + for (const auto &Relocation : Section.relocations()) { + uint64_t RelocationOffset; + if (auto Error = Relocation.getOffset(RelocationOffset)) + return Error; + if (RelocationOffset == Offset) + return *Relocation.getSymbol(); + } + return readobj_error::unknown_symbol; +} + +bool Decoder::opcode_0xxxxxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint8_t Imm = OC[Offset] & 0x7f; + SW.startLine() << format("0x%02x ; %s sp, #(%u * 4)\n", + OC[Offset], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + ++Offset; + return false; +} + +bool Decoder::opcode_10Lxxxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x20) >> 5; + uint16_t RegisterMask = (Link << (Prologue ? 14 : 15)) + | ((OC[Offset + 0] & 0x1f) << 8) + | ((OC[Offset + 1] & 0xff) << 0); + assert((~RegisterMask & (1 << 13)) && "sp must not be set"); + assert((~RegisterMask & (1 << (Prologue ? 15 : 14))) && "pc must not be set"); + + SW.startLine() << format("0x%02x 0x%02x ; %s.w ", + OC[Offset + 0], OC[Offset + 1], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(RegisterMask, 0)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_1100xxxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + if (Prologue) + SW.startLine() << format("0x%02x ; mov r%u, sp\n", + OC[Offset], OC[Offset] & 0xf); + else + SW.startLine() << format("0x%02x ; mov sp, r%u\n", + OC[Offset], OC[Offset] & 0xf); + ++Offset; + return false; +} + +bool Decoder::opcode_11010Lxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x4) >> 3; + unsigned Count = (OC[Offset] & 0x3); + + uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) + | (((1 << (Count + 1)) - 1) << 4); + + SW.startLine() << format("0x%02x ; %s ", OC[Offset], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_11011Lxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Link = (OC[Offset] & 0x4) >> 2; + unsigned Count = (OC[Offset] & 0x3) + 4; + + uint16_t GPRMask = (Link << (Prologue ? 14 : 15)) + | (((1 << (Count + 1)) - 1) << 4); + + SW.startLine() << format("0x%02x ; %s.w ", OC[Offset], + Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_11100xxx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned High = (OC[Offset] & 0x7); + uint32_t VFPMask = (((1 << (High + 1)) - 1) << 8); + + SW.startLine() << format("0x%02x ; %s ", OC[Offset], + Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset; + return false; +} + +bool Decoder::opcode_111010xx(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint16_t Imm = ((OC[Offset + 0] & 0x03) << 8) | ((OC[Offset + 1] & 0xff) << 0); + + SW.startLine() << format("0x%02x 0x%02x ; %s.w sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_1110110L(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint8_t GPRMask = ((OC[Offset + 0] & 0x01) << (Prologue ? 14 : 15)) + | ((OC[Offset + 1] & 0xff) << 0); + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "push" : "pop"); + printRegisters(std::make_pair(GPRMask, 0)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11101110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + assert(!Prologue && "may not be used in prologue"); + + if (OC[Offset + 1] & 0xf0) + SW.startLine() << format("0x%02x 0x%02x ; reserved\n", + OC[Offset + 0], OC[Offset + 1]); + else + SW.startLine() + << format("0x%02x 0x%02x ; microsoft-specific (type: %u)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] & 0x0f); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11101111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + assert(!Prologue && "may not be used in prologue"); + + if (OC[Offset + 1] & 0xf0) + SW.startLine() << format("0x%02x 0x%02x ; reserved\n", + OC[Offset + 0], OC[Offset + 1]); + else + SW.startLine() + << format("0x%02x 0x%02x ; ldr.w lr, [sp], #%u\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 1] << 2); + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110101(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; + unsigned End = (OC[Offset + 1] & 0x0f) >> 0; + uint32_t VFPMask = ((1 << (End - Start)) - 1) << Start; + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + unsigned Start = (OC[Offset + 1] & 0xf0) >> 4; + unsigned End = (OC[Offset + 1] & 0x0f) >> 0; + uint32_t VFPMask = ((1 << (End - Start)) - 1) << 16; + + SW.startLine() << format("0x%02x 0x%02x ; %s ", OC[Offset + 0], + OC[Offset + 1], Prologue ? "vpush" : "vpop"); + printRegisters(std::make_pair(0, VFPMask)); + OS << '\n'; + + ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11110111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); + + SW.startLine() << format("0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], + static_cast<const char *>(Prologue ? "sub" : "add"), + Imm); + + ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111000(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 16) + | (OC[Offset + 2] << 8) + | (OC[Offset + 3] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111001(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 8) | (OC[Offset + 2] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111010(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + uint32_t Imm = (OC[Offset + 1] << 16) + | (OC[Offset + 2] << 8) + | (OC[Offset + 3] << 0); + + SW.startLine() + << format("0x%02x 0x%02x 0x%02x 0x%02x ; %s.w sp, sp, #(%u * 4)\n", + OC[Offset + 0], OC[Offset + 1], OC[Offset + 2], OC[Offset + 3], + static_cast<const char *>(Prologue ? "sub" : "add"), Imm); + + ++Offset, ++Offset, ++Offset, ++Offset; + return false; +} + +bool Decoder::opcode_11111011(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; nop\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_11111100(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; nop.w\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_11111101(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; b\n", OC[Offset]); + ++Offset; + return true; +} + +bool Decoder::opcode_11111110(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; b.w\n", OC[Offset]); + ++Offset; + return true; +} + +bool Decoder::opcode_11111111(const ulittle8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + ++Offset; + return true; +} + +void Decoder::decodeOpcodes(ArrayRef<ulittle8_t> Opcodes, unsigned Offset, + bool Prologue) { + assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); + + bool Terminated = false; + for (unsigned OI = Offset, OE = Opcodes.size(); !Terminated && OI < OE; ) { + for (unsigned DI = 0;; ++DI) { + if ((Opcodes[OI] & Ring[DI].Mask) == Ring[DI].Value) { + Terminated = (this->*Ring[DI].Routine)(Opcodes.data(), OI, 0, Prologue); + break; + } + assert(DI < array_lengthof(Ring) && "unhandled opcode"); + } + } +} + +bool Decoder::dumpXDataRecord(const COFFObjectFile &COFF, + const SectionRef &Section, + uint64_t FunctionAddress, uint64_t VA) { + ArrayRef<uint8_t> Contents; + if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) + return false; + + uint64_t SectionVA; + if (Section.getAddress(SectionVA)) + return false; + + uint64_t Offset = VA - SectionVA; + const ulittle32_t *Data = + reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); + const ExceptionDataRecord XData(Data); + + DictScope XRS(SW, "ExceptionData"); + SW.printNumber("FunctionLength", XData.FunctionLength() << 1); + SW.printNumber("Version", XData.Vers()); + SW.printBoolean("ExceptionData", XData.X()); + SW.printBoolean("EpiloguePacked", XData.E()); + SW.printBoolean("Fragment", XData.F()); + SW.printNumber(XData.E() ? "EpilogueOffset" : "EpilogueScopes", + XData.EpilogueCount()); + SW.printNumber("ByteCodeLength", + static_cast<uint64_t>(XData.CodeWords() * sizeof(uint32_t))); + + if (XData.E()) { + ArrayRef<ulittle8_t> UC = XData.UnwindByteCode(); + if (!XData.F()) { + ListScope PS(SW, "Prologue"); + decodeOpcodes(UC, 0, /*Prologue=*/true); + } + if (XData.EpilogueCount()) { + ListScope ES(SW, "Epilogue"); + decodeOpcodes(UC, XData.EpilogueCount(), /*Prologue=*/false); + } + } else { + ArrayRef<ulittle32_t> EpilogueScopes = XData.EpilogueScopes(); + ListScope ESS(SW, "EpilogueScopes"); + for (const EpilogueScope ES : EpilogueScopes) { + DictScope ESES(SW, "EpilogueScope"); + SW.printNumber("StartOffset", ES.EpilogueStartOffset()); + SW.printNumber("Condition", ES.Condition()); + SW.printNumber("EpilogueStartIndex", ES.EpilogueStartIndex()); + + ListScope Opcodes(SW, "Opcodes"); + decodeOpcodes(XData.UnwindByteCode(), ES.EpilogueStartIndex(), + /*Prologue=*/false); + } + } + + if (XData.X()) { + const uint32_t Address = XData.ExceptionHandlerRVA(); + const uint32_t Parameter = XData.ExceptionHandlerParameter(); + const size_t HandlerOffset = HeaderWords(XData) + + (XData.E() ? 0 : XData.EpilogueCount()) + + XData.CodeWords(); + + ErrorOr<SymbolRef> Symbol = + getRelocatedSymbol(COFF, Section, HandlerOffset * sizeof(uint32_t)); + if (!Symbol) + Symbol = getSymbol(COFF, Address, /*FunctionOnly=*/true); + + StringRef Name; + if (Symbol) + Symbol->getName(Name); + + ListScope EHS(SW, "ExceptionHandler"); + SW.printString("Routine", formatSymbol(Name, Address)); + SW.printHex("Parameter", Parameter); + } + + return true; +} + +bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF, + const SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &RF) { + assert(RF.Flag() == RuntimeFunctionFlag::RFF_Unpacked && + "packed entry cannot be treated as an unpacked entry"); + + ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + ErrorOr<SymbolRef> XDataRecord = getRelocatedSymbol(COFF, Section, Offset + 4); + if (!XDataRecord) + XDataRecord = getSymbol(COFF, RF.ExceptionInformationRVA()); + + if (!RF.BeginAddress && !Function) + return false; + if (!RF.UnwindData && !XDataRecord) + return false; + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Function->getName(FunctionName); + Function->getAddress(FunctionAddress); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; + } + + SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + + if (XDataRecord) { + StringRef Name; + uint64_t Address; + + XDataRecord->getName(Name); + XDataRecord->getAddress(Address); + + SW.printString("ExceptionRecord", formatSymbol(Name, Address)); + + section_iterator SI = COFF.section_end(); + if (XDataRecord->getSection(SI)) + return false; + + return dumpXDataRecord(COFF, *SI, FunctionAddress, Address); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + + uint64_t Address = PEHeader->ImageBase + RF.ExceptionInformationRVA(); + SW.printString("ExceptionRecord", formatSymbol("", Address)); + + ErrorOr<SectionRef> Section = + getSectionContaining(COFF, RF.ExceptionInformationRVA()); + if (!Section) + return false; + + return dumpXDataRecord(COFF, *Section, FunctionAddress, + RF.ExceptionInformationRVA()); + } +} + +bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, + const SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &RF) { + assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && + "unpacked entry cannot be treated as a packed entry"); + + ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Function->getName(FunctionName); + Function->getAddress(FunctionAddress); + } else { + const pe32_header *PEHeader; + if (COFF.getPE32Header(PEHeader)) + return false; + FunctionAddress = PEHeader->ImageBase + RF.BeginAddress; + } + + SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printBoolean("Fragment", + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); + SW.printNumber("FunctionLength", RF.FunctionLength()); + SW.startLine() << "ReturnType: " << RF.Ret() << '\n'; + SW.printBoolean("HomedParameters", RF.H()); + SW.startLine() << "SavedRegisters: "; + printRegisters(SavedRegisterMask(RF)); + OS << '\n'; + SW.printNumber("StackAdjustment", StackAdjustment(RF) << 2); + + return true; +} + +bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, + const SectionRef Section, unsigned Index, + ArrayRef<uint8_t> Contents) { + uint64_t Offset = PDataEntrySize * Index; + const ulittle32_t *Data = + reinterpret_cast<const ulittle32_t *>(Contents.data() + Offset); + + const RuntimeFunction Entry(Data); + DictScope RFS(SW, "RuntimeFunction"); + if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) + return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); + return dumpPackedEntry(COFF, Section, Offset, Index, Entry); +} + +void Decoder::dumpProcedureData(const COFFObjectFile &COFF, + const SectionRef Section) { + ArrayRef<uint8_t> Contents; + if (COFF.getSectionContents(COFF.getCOFFSection(Section), Contents)) + return; + + if (Contents.size() % PDataEntrySize) { + errs() << ".pdata content is not " << PDataEntrySize << "-byte aligned\n"; + return; + } + + for (unsigned EI = 0, EE = Contents.size() / PDataEntrySize; EI < EE; ++EI) + if (!dumpProcedureDataEntry(COFF, Section, EI, Contents)) + break; +} + +std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) { + for (const auto &Section : COFF.sections()) { + StringRef SectionName; + if (std::error_code EC = + COFF.getSectionName(COFF.getCOFFSection(Section), SectionName)) + return EC; + + if (SectionName.startswith(".pdata")) + dumpProcedureData(COFF, Section); + } + return std::error_code(); +} +} +} +} + diff --git a/tools/llvm-readobj/ARMWinEHPrinter.h b/tools/llvm-readobj/ARMWinEHPrinter.h new file mode 100644 index 0000000..740c8b5 --- /dev/null +++ b/tools/llvm-readobj/ARMWinEHPrinter.h @@ -0,0 +1,119 @@ +//===--- ARMWinEHPrinter.h - Windows on ARM Unwind Information Printer ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_READOBJ_ARMWINEHPRINTER_H +#define LLVM_READOBJ_ARMWINEHPRINTER_H + +#include "StreamWriter.h" +#include "llvm/Object/COFF.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +namespace ARM { +namespace WinEH { +class RuntimeFunction; + +class Decoder { + static const size_t PDataEntrySize; + + StreamWriter &SW; + raw_ostream &OS; + + struct RingEntry { + uint8_t Mask; + uint8_t Value; + bool (Decoder::*Routine)(const support::ulittle8_t *, unsigned &, unsigned, + bool); + }; + static const RingEntry Ring[]; + + bool opcode_0xxxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_10Lxxxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_1100xxxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11010Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11011Lxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11100xxx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_111010xx(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_1110110L(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11101110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11101111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110101(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11110111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111000(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111001(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111010(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111011(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111100(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111101(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111110(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_11111111(const support::ulittle8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + + void decodeOpcodes(ArrayRef<support::ulittle8_t> Opcodes, unsigned Offset, + bool Prologue); + + void printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask); + + ErrorOr<object::SectionRef> + getSectionContaining(const object::COFFObjectFile &COFF, uint64_t Address); + + ErrorOr<object::SymbolRef> + getSymbol(const object::COFFObjectFile &COFF, uint64_t Address, + bool FunctionOnly = false); + + ErrorOr<object::SymbolRef> + getRelocatedSymbol(const object::COFFObjectFile &COFF, + const object::SectionRef &Section, uint64_t Offset); + + bool dumpXDataRecord(const object::COFFObjectFile &COFF, + const object::SectionRef &Section, + uint64_t FunctionAddress, uint64_t VA); + bool dumpUnpackedEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &Entry); + bool dumpPackedEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunction &Entry); + bool dumpProcedureDataEntry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, unsigned Entry, + ArrayRef<uint8_t> Contents); + void dumpProcedureData(const object::COFFObjectFile &COFF, + const object::SectionRef Section); + +public: + Decoder(StreamWriter &SW) : SW(SW), OS(SW.getOStream()) {} + std::error_code dumpProcedureData(const object::COFFObjectFile &COFF); +}; +} +} +} + +#endif + diff --git a/tools/llvm-readobj/Android.mk b/tools/llvm-readobj/Android.mk index 10c99db..219e6a9 100644 --- a/tools/llvm-readobj/Android.mk +++ b/tools/llvm-readobj/Android.mk @@ -9,6 +9,7 @@ LLVM_ROOT_PATH := $(LOCAL_PATH)/../.. llvm_readobj_SRC_FILES := \ ARMAttributeParser.cpp \ + ARMWinEHPrinter.cpp \ COFFDumper.cpp \ ELFDumper.cpp \ Error.cpp \ @@ -25,6 +26,8 @@ llvm_readobj_STATIC_LIBRARIES := \ libLLVMX86Info \ libLLVMObject \ libLLVMBitReader \ + libLLVMMC \ + libLLVMMCParser \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt index b057dcd..30f336f 100644 --- a/tools/llvm-readobj/CMakeLists.txt +++ b/tools/llvm-readobj/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_llvm_tool(llvm-readobj ARMAttributeParser.cpp + ARMWinEHPrinter.cpp COFFDumper.cpp ELFDumper.cpp Error.cpp diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp index 91f2a57..7842cd4 100644 --- a/tools/llvm-readobj/COFFDumper.cpp +++ b/tools/llvm-readobj/COFFDumper.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" +#include "ARMWinEHPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" @@ -29,9 +30,9 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/Win64EH.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" #include <algorithm> #include <cstring> +#include <system_error> #include <time.h> using namespace llvm; @@ -68,10 +69,10 @@ private: void cacheRelocations(); - error_code resolveSymbol(const coff_section *Section, uint64_t Offset, - SymbolRef &Sym); - error_code resolveSymbolName(const coff_section *Section, uint64_t Offset, - StringRef &Name); + std::error_code resolveSymbol(const coff_section *Section, uint64_t Offset, + SymbolRef &Sym); + std::error_code resolveSymbolName(const coff_section *Section, + uint64_t Offset, StringRef &Name); typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; @@ -84,8 +85,9 @@ private: namespace llvm { -error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result) { +std::error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); if (!COFFObj) return readobj_error::unsupported_obj_file_format; @@ -98,12 +100,12 @@ error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, // Given a a section and an offset into this section the function returns the // symbol used for the relocation at the offset. -error_code COFFDumper::resolveSymbol(const coff_section *Section, - uint64_t Offset, SymbolRef &Sym) { +std::error_code COFFDumper::resolveSymbol(const coff_section *Section, + uint64_t Offset, SymbolRef &Sym) { const auto &Relocations = RelocMap[Section]; for (const auto &Relocation : Relocations) { uint64_t RelocationOffset; - if (error_code EC = Relocation.getOffset(RelocationOffset)) + if (std::error_code EC = Relocation.getOffset(RelocationOffset)) return EC; if (RelocationOffset == Offset) { @@ -116,12 +118,13 @@ error_code COFFDumper::resolveSymbol(const coff_section *Section, // Given a section and an offset into this section the function returns the name // of the symbol used for the relocation at the offset. -error_code COFFDumper::resolveSymbolName(const coff_section *Section, - uint64_t Offset, StringRef &Name) { +std::error_code COFFDumper::resolveSymbolName(const coff_section *Section, + uint64_t Offset, + StringRef &Name) { SymbolRef Symbol; - if (error_code EC = resolveSymbol(Section, Offset, Symbol)) + if (std::error_code EC = resolveSymbol(Section, Offset, Symbol)) return EC; - if (error_code EC = Symbol.getName(Name)) + if (std::error_code EC = Symbol.getName(Name)) return EC; return object_error::success; } @@ -190,7 +193,9 @@ static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = { LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_SEH ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_NO_BIND ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_APPCONTAINER ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_WDM_DRIVER ), + LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_GUARD_CF ), LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE), }; @@ -306,9 +311,10 @@ WeakExternalCharacteristics[] = { { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } }; -template<typename T> -static error_code getSymbolAuxData(const COFFObjectFile *Obj, - const coff_symbol *Symbol, const T* &Aux) { +template <typename T> +static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, + const coff_symbol *Symbol, + const T *&Aux) { ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); Aux = reinterpret_cast<const T*>(AuxData.data()); return readobj_error::success; @@ -718,7 +724,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_symbol *Symbol = Obj->getCOFFSymbol(Sym); const coff_section *Section; - if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { + if (std::error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { W.startLine() << "Invalid section number: " << EC.message() << "\n"; W.flush(); return; @@ -762,7 +768,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_symbol *Linked; StringRef LinkedName; - error_code EC; + std::error_code EC; if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || (EC = Obj->getSymbolName(Linked, LinkedName))) { LinkedName = ""; @@ -804,7 +810,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { const coff_section *Assoc; StringRef AssocName; - error_code EC; + std::error_code EC; if ((EC = Obj->getSection(Aux->Number, Assoc)) || (EC = Obj->getSectionName(Assoc, AssocName))) { AssocName = ""; @@ -820,7 +826,7 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) { const coff_symbol *ReferredSym; StringRef ReferredName; - error_code EC; + std::error_code EC; if ((EC = Obj->getSymbol(Aux->SymbolTableIndex, ReferredSym)) || (EC = Obj->getSymbolName(ReferredSym, ReferredName))) { ReferredName = ""; @@ -848,16 +854,21 @@ void COFFDumper::printUnwindInfo() { switch (Header->Machine) { case COFF::IMAGE_FILE_MACHINE_AMD64: { Win64EH::Dumper Dumper(W); - Win64EH::Dumper::SymbolResolver Resolver = - [](const object::coff_section *Section, uint64_t Offset, - SymbolRef &Symbol, void *user_data) -> error_code { - COFFDumper *Dumper = reinterpret_cast<COFFDumper*>(user_data); - return Dumper->resolveSymbol(Section, Offset, Symbol); - }; + Win64EH::Dumper::SymbolResolver + Resolver = [](const object::coff_section *Section, uint64_t Offset, + SymbolRef &Symbol, void *user_data) -> std::error_code { + COFFDumper *Dumper = reinterpret_cast<COFFDumper *>(user_data); + return Dumper->resolveSymbol(Section, Offset, Symbol); + }; Win64EH::Dumper::Context Ctx(*Obj, Resolver, this); Dumper.printData(Ctx); break; } + case COFF::IMAGE_FILE_MACHINE_ARMNT: { + ARM::WinEH::Decoder Decoder(W); + Decoder.dumpProcedureData(*Obj); + break; + } default: W.printEnum("unsupported Image Machine", Header->Machine, makeArrayRef(ImageFileMachineType)); diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index de4c207..5df51e2 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -18,6 +18,7 @@ #include "Error.h" #include "ObjDumper.h" #include "StreamWriter.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Object/ELFObjectFile.h" @@ -54,6 +55,7 @@ public: void printProgramHeaders() override; void printAttributes() override; + void printMipsPLTGOT() override; private: typedef ELFFile<ELFT> ELFO; @@ -81,15 +83,16 @@ template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { namespace llvm { template <class ELFT> -static error_code createELFDumper(const ELFFile<ELFT> *Obj, - StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result) { +static std::error_code createELFDumper(const ELFFile<ELFT> *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { Result.reset(new ELFDumper<ELFT>(Obj, Writer)); return readobj_error::success; } -error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result) { +std::error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) return createELFDumper(ELFObj->getELFFile(), Writer, Result); @@ -111,6 +114,62 @@ error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, } // namespace llvm +template <typename ELFO> +static std::string getFullSymbolName(const ELFO &Obj, + typename ELFO::Elf_Sym_Iter Symbol) { + StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol)); + if (!Symbol.isDynamic()) + return SymbolName; + + std::string FullSymbolName(SymbolName); + + bool IsDefault; + ErrorOr<StringRef> Version = + Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault); + if (Version) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += *Version; + } else + error(Version.getError()); + return FullSymbolName; +} + +template <typename ELFO> +static void +getSectionNameIndex(const ELFO &Obj, typename ELFO::Elf_Sym_Iter Symbol, + StringRef &SectionName, unsigned &SectionIndex) { + SectionIndex = Symbol->st_shndx; + if (SectionIndex == SHN_UNDEF) { + SectionName = "Undefined"; + } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) { + SectionName = "Processor Specific"; + } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) { + SectionName = "Operating System Specific"; + } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) { + SectionName = "Reserved"; + } else if (SectionIndex == SHN_ABS) { + SectionName = "Absolute"; + } else if (SectionIndex == SHN_COMMON) { + SectionName = "Common"; + } else { + if (SectionIndex == SHN_XINDEX) + SectionIndex = Obj.getSymbolTableIndex(&*Symbol); + assert(SectionIndex != SHN_XINDEX && + "getSymbolTableIndex should handle this"); + const typename ELFO::Elf_Shdr *Sec = Obj.getSection(SectionIndex); + SectionName = errorOrDefault(Obj.getSectionName(Sec)); + } +} + +template <class ELFT> +static const typename ELFFile<ELFT>::Elf_Shdr * +findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) { + for (const auto &Shdr : Obj->sections()) + if (Shdr.sh_addr == Addr) + return &Shdr; + return nullptr; +} + static const EnumEntry<unsigned> ElfClass[] = { { "None", ELF::ELFCLASSNONE }, { "32-bit", ELF::ELFCLASS32 }, @@ -651,42 +710,10 @@ void ELFDumper<ELFT>::printDynamicSymbols() { template <class ELFT> void ELFDumper<ELFT>::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { - StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); - - unsigned SectionIndex = Symbol->st_shndx; + unsigned SectionIndex = 0; StringRef SectionName; - if (SectionIndex == SHN_UNDEF) { - SectionName = "Undefined"; - } else if (SectionIndex >= SHN_LOPROC && SectionIndex <= SHN_HIPROC) { - SectionName = "Processor Specific"; - } else if (SectionIndex >= SHN_LOOS && SectionIndex <= SHN_HIOS) { - SectionName = "Operating System Specific"; - } else if (SectionIndex > SHN_HIOS && SectionIndex < SHN_ABS) { - SectionName = "Reserved"; - } else if (SectionIndex == SHN_ABS) { - SectionName = "Absolute"; - } else if (SectionIndex == SHN_COMMON) { - SectionName = "Common"; - } else { - if (SectionIndex == SHN_XINDEX) - SectionIndex = Obj->getSymbolTableIndex(&*Symbol); - assert(SectionIndex != SHN_XINDEX && - "getSymbolTableIndex should handle this"); - const Elf_Shdr *Sec = Obj->getSection(SectionIndex); - SectionName = errorOrDefault(Obj->getSectionName(Sec)); - } - - std::string FullSymbolName(SymbolName); - if (Symbol.isDynamic()) { - bool IsDefault; - ErrorOr<StringRef> Version = Obj->getSymbolVersion(nullptr, &*Symbol, - IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version.getError()); - } + getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); + std::string FullSymbolName = getFullSymbolName(*Obj, Symbol); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -902,13 +929,12 @@ void ELFDumper<ELFType<support::little, 2, false> >::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - typedef typename ELFO::Elf_Dyn_Iter EDI; - EDI Start = Obj->begin_dynamic_table(), End = Obj->end_dynamic_table(true); + auto DynTable = Obj->dynamic_table(true); - if (Start == End) + ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.end()); + if (Total == 0) return; - ptrdiff_t Total = std::distance(Start, End); raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; @@ -917,12 +943,12 @@ void ELFDumper<ELFT>::printDynamicTable() { W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (; Start != End; ++Start) { + for (const auto &Entry : DynTable) { W.startLine() << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) - << " " << format("%-21s", getTypeString(Start->getTag())); - printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) + << " " << format("%-21s", getTypeString(Entry.getTag())); + printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS); OS << "\n"; } @@ -936,11 +962,9 @@ void ELFDumper<ELFT>::printNeededLibraries() { typedef std::vector<StringRef> LibsTy; LibsTy Libs; - 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)); + for (const auto &Entry : Obj->dynamic_table()) + if (Entry.d_tag == ELF::DT_NEEDED) + Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); @@ -1008,3 +1032,209 @@ void ELFDumper<ELFType<support::little, 2, false> >::printAttributes() { } } +namespace { +template <class ELFT> class MipsGOTParser { +public: + typedef object::ELFFile<ELFT> ObjectFile; + typedef typename ObjectFile::Elf_Shdr Elf_Shdr; + + MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) : Obj(Obj), W(W) {} + + void parseGOT(const Elf_Shdr &GOTShdr); + +private: + typedef typename ObjectFile::Elf_Sym_Iter Elf_Sym_Iter; + typedef typename ObjectFile::Elf_Addr GOTEntry; + typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry> + GOTIter; + + const ObjectFile *Obj; + StreamWriter &W; + + std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; + GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + + bool getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym); + void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It); + void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It, + Elf_Sym_Iter Sym); +}; +} + +template <class ELFT> +void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) { + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed GOT description. + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + + ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(&GOTShdr); + if (!GOT) { + W.startLine() << "The .got section is empty.\n"; + return; + } + + uint64_t DtLocalGotNum; + uint64_t DtGotSym; + if (!getGOTTags(DtLocalGotNum, DtGotSym)) + return; + + if (DtLocalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n"; + return; + } + + Elf_Sym_Iter DynSymBegin = Obj->begin_dynamic_symbols(); + Elf_Sym_Iter DynSymEnd = Obj->end_dynamic_symbols(); + std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); + + if (DtGotSym > DynSymTotal) { + W.startLine() << "MIPS_GOTSYM exceeds a number of dynamic symbols.\n"; + return; + } + + std::size_t GlobalGotNum = DynSymTotal - DtGotSym; + + if (DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "Number of global GOT entries exceeds the size of GOT.\n"; + return; + } + + GOTIter GotBegin = makeGOTIter(*GOT, 0); + GOTIter GotLocalEnd = makeGOTIter(*GOT, DtLocalGotNum); + GOTIter It = GotBegin; + + DictScope GS(W, "Primary GOT"); + + W.printHex("Canonical gp value", GOTShdr.sh_addr + 0x7ff0); + { + ListScope RS(W, "Reserved entries"); + + { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (; It != GotLocalEnd; ++It) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr.sh_addr, GotBegin, It); + } + } + { + ListScope GS(W, "Global entries"); + + GOTIter GotGlobalEnd = makeGOTIter(*GOT, DtLocalGotNum + GlobalGotNum); + Elf_Sym_Iter GotDynSym = DynSymBegin + DtGotSym; + for (; It != GotGlobalEnd; ++It) { + DictScope D(W, "Entry"); + printGlobalGotEntry(GOTShdr.sh_addr, GotBegin, It, GotDynSym++); + } + } + + std::size_t SpecGotNum = getGOTTotal(*GOT) - DtLocalGotNum - GlobalGotNum; + W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum)); +} + +template <class ELFT> +std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { + return GOT.size() / sizeof(GOTEntry); +} + +template <class ELFT> +typename MipsGOTParser<ELFT>::GOTIter +MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { + const char *Data = reinterpret_cast<const char *>(GOT.data()); + return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); +} + +template <class ELFT> +bool MipsGOTParser<ELFT>::getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym) { + bool FoundLocalGotNum = false; + bool FoundGotSym = false; + for (const auto &Entry : Obj->dynamic_table()) { + switch (Entry.getTag()) { + case ELF::DT_MIPS_LOCAL_GOTNO: + LocalGotNum = Entry.getVal(); + FoundLocalGotNum = true; + break; + case ELF::DT_MIPS_GOTSYM: + GotSym = Entry.getVal(); + FoundGotSym = true; + break; + } + } + + if (!FoundLocalGotNum) { + W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n"; + return false; + } + + if (!FoundGotSym) { + W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n"; + return false; + } + + return true; +} + +template <class ELFT> +void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It) { + int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); + W.printHex("Address", GotAddr + Offset); + W.printNumber("Access", Offset - 0x7ff0); + W.printHex("Initial", *It); +} + +template <class ELFT> +void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It, Elf_Sym_Iter Sym) { + printGotEntry(GotAddr, BeginIt, It); + + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string FullSymbolName = getFullSymbolName(*Obj, Sym); + W.printNumber("Name", FullSymbolName, Sym->st_name); +} + +template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { + if (Obj->getHeader()->e_machine != EM_MIPS) { + W.startLine() << "MIPS PLT GOT is available for MIPS targets only.\n"; + return; + } + + llvm::Optional<uint64_t> DtPltGot; + for (const auto &Entry : Obj->dynamic_table()) { + if (Entry.getTag() == ELF::DT_PLTGOT) { + DtPltGot = Entry.getVal(); + break; + } + } + + if (!DtPltGot) { + W.startLine() << "Cannot find PLTGOT dynamic table tag.\n"; + return; + } + + const Elf_Shdr *GotShdr = findSectionByAddress(Obj, *DtPltGot); + if (!GotShdr) { + W.startLine() << "There is no .got section in the file.\n"; + return; + } + + MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr); +} diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp index 83ed6a7..a078f5c 100644 --- a/tools/llvm-readobj/Error.cpp +++ b/tools/llvm-readobj/Error.cpp @@ -17,11 +17,10 @@ using namespace llvm; namespace { -class _readobj_error_category : public error_category { +class _readobj_error_category : public std::error_category { public: - const char* name() const override; + const char* name() const LLVM_NOEXCEPT override; std::string message(int ev) const override; - error_condition default_error_condition(int ev) const override; }; } // namespace @@ -29,8 +28,8 @@ const char *_readobj_error_category::name() const { return "llvm.readobj"; } -std::string _readobj_error_category::message(int ev) const { - switch (ev) { +std::string _readobj_error_category::message(int EV) const { + switch (static_cast<readobj_error>(EV)) { case readobj_error::success: return "Success"; case readobj_error::file_not_found: return "No such file."; @@ -42,20 +41,13 @@ std::string _readobj_error_category::message(int ev) const { return "Unsupported object file format."; case readobj_error::unknown_symbol: return "Unknown symbol."; - default: - llvm_unreachable("An enumerator of readobj_error does not have a message " - "defined."); } -} - -error_condition _readobj_error_category::default_error_condition(int ev) const { - if (ev == readobj_error::success) - return errc::success; - return errc::invalid_argument; + llvm_unreachable("An enumerator of readobj_error does not have a message " + "defined."); } namespace llvm { -const error_category &readobj_category() { +const std::error_category &readobj_category() { static _readobj_error_category o; return o; } diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h index 5129b4e..81ce408 100644 --- a/tools/llvm-readobj/Error.h +++ b/tools/llvm-readobj/Error.h @@ -14,35 +14,28 @@ #ifndef LLVM_READOBJ_ERROR_H #define LLVM_READOBJ_ERROR_H -#include "llvm/Support/system_error.h" +#include <system_error> namespace llvm { - -const error_category &readobj_category(); - -struct readobj_error { - enum _ { - success = 0, - file_not_found, - unsupported_file_format, - unrecognized_file_format, - unsupported_obj_file_format, - unknown_symbol - }; - _ v_; - - readobj_error(_ v) : v_(v) {} - explicit readobj_error(int v) : v_(_(v)) {} - operator int() const {return v_;} +const std::error_category &readobj_category(); + +enum class readobj_error { + success = 0, + file_not_found, + unsupported_file_format, + unrecognized_file_format, + unsupported_obj_file_format, + unknown_symbol }; -inline error_code make_error_code(readobj_error e) { - return error_code(static_cast<int>(e), readobj_category()); +inline std::error_code make_error_code(readobj_error e) { + return std::error_code(static_cast<int>(e), readobj_category()); } -template <> struct is_error_code_enum<readobj_error> : std::true_type { }; -template <> struct is_error_code_enum<readobj_error::_> : std::true_type { }; - } // namespace llvm +namespace std { +template <> struct is_error_code_enum<llvm::readobj_error> : std::true_type {}; +} + #endif diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp index 2fd5d4a..a5e5cf8 100644 --- a/tools/llvm-readobj/MachODumper.cpp +++ b/tools/llvm-readobj/MachODumper.cpp @@ -16,6 +16,7 @@ #include "ObjDumper.h" #include "StreamWriter.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Object/MachO.h" #include "llvm/Support/Casting.h" @@ -54,9 +55,9 @@ private: namespace llvm { -error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result) { +std::error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); if (!MachOObj) return readobj_error::unsupported_obj_file_format; @@ -277,7 +278,7 @@ void MachODumper::printSections(const MachOObjectFile *Obj) { void MachODumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; + std::error_code EC; for (const SectionRef &Section : Obj->sections()) { StringRef Name; if (error(Section.getName(Name))) @@ -309,18 +310,29 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc) { uint64_t Offset; SmallString<32> RelocName; - StringRef SymbolName; if (error(Reloc.getOffset(Offset))) return; if (error(Reloc.getTypeName(RelocName))) return; - symbol_iterator Symbol = Reloc.getSymbol(); - if (Symbol != Obj->symbol_end() && error(Symbol->getName(SymbolName))) - return; DataRefImpl DR = Reloc.getRawDataRefImpl(); MachO::any_relocation_info RE = Obj->getRelocation(DR); bool IsScattered = Obj->isRelocationScattered(RE); + SmallString<32> SymbolNameOrOffset("0x"); + if (IsScattered) { + // Scattered relocations don't really have an associated symbol + // for some reason, even if one exists in the symtab at the correct address. + SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE)); + } else { + symbol_iterator Symbol = Reloc.getSymbol(); + if (Symbol != Obj->symbol_end()) { + StringRef SymbolName; + if (error(Symbol->getName(SymbolName))) + return; + SymbolNameOrOffset = SymbolName; + } else + SymbolNameOrOffset += utohexstr(Obj->getPlainRelocationSymbolNum(RE)); + } if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -332,7 +344,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, else W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + W.printString("Symbol", SymbolNameOrOffset); W.printNumber("Scattered", IsScattered); } else { raw_ostream& OS = W.startLine(); @@ -345,7 +357,7 @@ void MachODumper::printRelocation(const MachOObjectFile *Obj, OS << " " << Obj->getPlainRelocationExternal(RE); OS << " " << RelocName << " " << IsScattered - << " " << (SymbolName.size() > 0 ? SymbolName : "-") + << " " << SymbolNameOrOffset << "\n"; } } diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 9e0fd2f..f80a28b 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -11,15 +11,13 @@ #define LLVM_READOBJ_OBJDUMPER_H #include <memory> +#include <system_error> namespace llvm { - namespace object { class ObjectFile; } -class error_code; - class StreamWriter; class ObjDumper { @@ -42,19 +40,24 @@ public: // Only implemented for ARM ELF at this time. virtual void printAttributes() { } + // Only implemented for MIPS ELF at this time. + virtual void printMipsPLTGOT() { } + protected: StreamWriter& W; }; -error_code createCOFFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::error_code createCOFFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); -error_code createELFDumper(const object::ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); -error_code createMachODumper(const object::ObjectFile *Obj, - StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::error_code createMachODumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result); } // namespace llvm diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h index 9282dcc..04b38fb 100644 --- a/tools/llvm-readobj/StreamWriter.h +++ b/tools/llvm-readobj/StreamWriter.h @@ -169,6 +169,10 @@ public: startLine() << Label << ": " << int(Value) << "\n"; } + void printBoolean(StringRef Label, bool Value) { + startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; + } + template <typename T_> void printList(StringRef Label, const SmallVectorImpl<T_> &List) { startLine() << Label << ": ["; diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp index c64d362..f058632 100644 --- a/tools/llvm-readobj/Win64EHDumper.cpp +++ b/tools/llvm-readobj/Win64EHDumper.cpp @@ -134,20 +134,21 @@ static std::string formatSymbol(const Dumper::Context &Ctx, return OS.str(); } -static error_code resolveRelocation(const Dumper::Context &Ctx, - const coff_section *Section, - uint64_t Offset, - const coff_section *&ResolvedSection, - uint64_t &ResolvedAddress) { +static std::error_code resolveRelocation(const Dumper::Context &Ctx, + const coff_section *Section, + uint64_t Offset, + const coff_section *&ResolvedSection, + uint64_t &ResolvedAddress) { SymbolRef Symbol; - if (error_code EC = Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) + if (std::error_code EC = + Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData)) return EC; - if (error_code EC = Symbol.getAddress(ResolvedAddress)) + if (std::error_code EC = Symbol.getAddress(ResolvedAddress)) return EC; section_iterator SI = Ctx.COFF.section_begin(); - if (error_code EC = Symbol.getSection(SI)) + if (std::error_code EC = Symbol.getSection(SI)) return EC; ResolvedSection = Ctx.COFF.getCOFFSection(*SI); diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h index 2eac810..9ce4d39 100644 --- a/tools/llvm-readobj/Win64EHDumper.h +++ b/tools/llvm-readobj/Win64EHDumper.h @@ -26,8 +26,9 @@ class Dumper { raw_ostream &OS; public: - typedef error_code (*SymbolResolver)(const object::coff_section *, uint64_t, - object::SymbolRef &, void *); + typedef std::error_code (*SymbolResolver)(const object::coff_section *, + uint64_t, object::SymbolRef &, + void *); struct Context { const object::COFFObjectFile &COFF; diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 5be959f..8d2a997 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -35,8 +35,8 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" -#include "llvm/Support/system_error.h" #include <string> +#include <system_error> using namespace llvm; @@ -135,13 +135,18 @@ namespace opts { cl::desc("Display the ARM attributes section")); cl::alias ARMAttributesShort("-a", cl::desc("Alias for --arm-attributes"), cl::aliasopt(ARMAttributes)); + + // -mips-plt-got + cl::opt<bool> + MipsPLTGOT("mips-plt-got", + cl::desc("Display the MIPS GOT and PLT GOT sections")); } // namespace opts static int ReturnValue = EXIT_SUCCESS; namespace llvm { -bool error(error_code EC) { +bool error(std::error_code EC) { if (!EC) return false; @@ -160,8 +165,7 @@ bool relocAddressLess(RelocationRef a, RelocationRef b) { } // namespace llvm - -static void reportError(StringRef Input, error_code EC) { +static void reportError(StringRef Input, std::error_code EC) { if (Input == "-") Input = "<stdin>"; @@ -178,9 +182,21 @@ static void reportError(StringRef Input, StringRef Message) { ReturnValue = EXIT_FAILURE; } +static bool isMipsArch(unsigned Arch) { + switch (Arch) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return true; + default: + return false; + } +} + /// @brief Creates an format-specific object file dumper. -static error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, - std::unique_ptr<ObjDumper> &Result) { +static std::error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, + std::unique_ptr<ObjDumper> &Result) { if (!Obj) return readobj_error::unsupported_file_format; @@ -199,7 +215,7 @@ static error_code createDumper(const ObjectFile *Obj, StreamWriter &Writer, static void dumpObject(const ObjectFile *Obj) { StreamWriter Writer(outs()); std::unique_ptr<ObjDumper> Dumper; - if (error_code EC = createDumper(Obj, Writer, Dumper)) { + if (std::error_code EC = createDumper(Obj, Writer, Dumper)) { reportError(Obj->getFileName(), EC); return; } @@ -235,6 +251,9 @@ static void dumpObject(const ObjectFile *Obj) { if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) if (opts::ARMAttributes) Dumper->printAttributes(); + if (isMipsArch(Obj->getArch()) && Obj->isELF()) + if (opts::MipsPLTGOT) + Dumper->printMipsPLTGOT(); } @@ -243,15 +262,15 @@ static void dumpArchive(const Archive *Arc) { for (Archive::child_iterator ArcI = Arc->child_begin(), ArcE = Arc->child_end(); ArcI != ArcE; ++ArcI) { - std::unique_ptr<Binary> child; - if (error_code EC = ArcI->getAsBinary(child)) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = ArcI->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { // Ignore non-object files. if (EC != object_error::invalid_file_type) reportError(Arc->getFileName(), EC.message()); continue; } - if (ObjectFile *Obj = dyn_cast<ObjectFile>(child.get())) + if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) dumpObject(Obj); else reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); @@ -269,7 +288,7 @@ static void dumpInput(StringRef File) { // Attempt to open the binary. ErrorOr<Binary *> BinaryOrErr = createBinary(File); - if (error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) { reportError(File, EC); return; } diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h index cc5c85d..0413948 100644 --- a/tools/llvm-readobj/llvm-readobj.h +++ b/tools/llvm-readobj/llvm-readobj.h @@ -18,10 +18,8 @@ namespace llvm { class RelocationRef; } - class error_code; - // Various helper functions. - bool error(error_code ec); + bool error(std::error_code ec); bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm @@ -40,6 +38,7 @@ namespace opts { extern llvm::cl::opt<bool> ExpandRelocs; extern llvm::cl::opt<bool> CodeViewLineTables; extern llvm::cl::opt<bool> ARMAttributes; + extern llvm::cl::opt<bool> MipsPLTGOT; } // namespace opts #define LLVM_READOBJ_ENUM_ENT(ns, enum) \ diff --git a/tools/llvm-rtdyld/Android.mk b/tools/llvm-rtdyld/Android.mk index 54a612a..6f902d3 100644 --- a/tools/llvm-rtdyld/Android.mk +++ b/tools/llvm-rtdyld/Android.mk @@ -11,11 +11,38 @@ llvm_rtdyld_SRC_FILES := \ llvm-rtdyld.cpp llvm_rtdyld_STATIC_LIBRARIES := \ + libLLVMARMCodeGen \ + libLLVMARMInfo \ + libLLVMARMDesc \ + libLLVMARMAsmPrinter \ + libLLVMARMAsmParser \ + libLLVMARMDisassembler \ + libLLVMAArch64CodeGen \ + libLLVMAArch64Info \ + libLLVMAArch64AsmParser \ + libLLVMAArch64Desc \ + libLLVMAArch64AsmPrinter \ + libLLVMAArch64Utils \ + libLLVMAArch64Disassembler \ + libLLVMMipsCodeGen \ + libLLVMMipsInfo \ + libLLVMMipsDesc \ + libLLVMMipsAsmPrinter \ + libLLVMMipsAsmParser \ + libLLVMMipsDisassembler \ + libLLVMX86CodeGen \ + libLLVMX86Info \ + libLLVMX86Desc \ + libLLVMX86AsmPrinter \ + libLLVMX86AsmParser \ + libLLVMX86Utils \ + libLLVMX86Disassembler \ libLLVMDebugInfo \ libLLVMExecutionEngine \ + libLLVMObject \ libLLVMMC \ + libLLVMMCParser \ libLLVMRuntimeDyld \ - libLLVMObject \ libLLVMBitReader \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/llvm-rtdyld/CMakeLists.txt b/tools/llvm-rtdyld/CMakeLists.txt index 3ad127f..feb2134 100644 --- a/tools/llvm-rtdyld/CMakeLists.txt +++ b/tools/llvm-rtdyld/CMakeLists.txt @@ -1,6 +1,8 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} DebugInfo ExecutionEngine + MC RuntimeDyld Support ) diff --git a/tools/llvm-rtdyld/llvm-rtdyld.cpp b/tools/llvm-rtdyld/llvm-rtdyld.cpp index be5c345..45734f4 100644 --- a/tools/llvm-rtdyld/llvm-rtdyld.cpp +++ b/tools/llvm-rtdyld/llvm-rtdyld.cpp @@ -16,6 +16,13 @@ #include "llvm/ExecutionEngine/ObjectBuffer.h" #include "llvm/ExecutionEngine/ObjectImage.h" #include "llvm/ExecutionEngine/RuntimeDyld.h" +#include "llvm/ExecutionEngine/RuntimeDyldChecker.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Object/MachO.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DynamicLibrary.h" @@ -23,9 +30,12 @@ #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" +#include "llvm/Support/Signals.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +#include <system_error> + using namespace llvm; using namespace llvm::object; @@ -35,7 +45,8 @@ InputFileList(cl::Positional, cl::ZeroOrMore, enum ActionType { AC_Execute, - AC_PrintLineInfo + AC_PrintLineInfo, + AC_Verify }; static cl::opt<ActionType> @@ -45,6 +56,8 @@ Action(cl::desc("Action to perform:"), "Load, link, and execute the inputs."), clEnumValN(AC_PrintLineInfo, "printline", "Load, link, and print line information for each function."), + clEnumValN(AC_Verify, "verify", + "Load, link and verify the resulting memory image."), clEnumValEnd)); static cl::opt<std::string> @@ -57,6 +70,14 @@ Dylibs("dylib", cl::desc("Add library."), cl::ZeroOrMore); +static cl::opt<std::string> +TripleName("triple", cl::desc("Target triple for disassembler")); + +static cl::list<std::string> +CheckFiles("check", + cl::desc("File containing RuntimeDyld verifier checks."), + cl::ZeroOrMore); + /* *** */ // A trivial memory manager that doesn't do anything fancy, just uses the @@ -139,7 +160,6 @@ static void loadDylibs() { } } - /* *** */ static int printLineInfoForInput() { @@ -155,14 +175,16 @@ static int printLineInfoForInput() { RuntimeDyld Dyld(&MemMgr); // Load the input memory buffer. - std::unique_ptr<MemoryBuffer> InputBuffer; - std::unique_ptr<ObjectImage> LoadedObject; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], - InputBuffer)) - return Error("unable to read input: '" + ec.message() + "'"); + ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = + MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + if (std::error_code EC = InputBuffer.getError()) + return Error("unable to read input: '" + EC.message() + "'"); + + std::unique_ptr<ObjectImage> LoadedObject; // Load the object file - LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release()))); + LoadedObject.reset( + Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release()))); if (!LoadedObject) { return Error(Dyld.getErrorString()); } @@ -216,14 +238,14 @@ static int executeInput() { InputFileList.push_back("-"); for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { // Load the input memory buffer. - std::unique_ptr<MemoryBuffer> InputBuffer; + ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = + MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + if (std::error_code EC = InputBuffer.getError()) + return Error("unable to read input: '" + EC.message() + "'"); std::unique_ptr<ObjectImage> LoadedObject; - if (error_code ec = MemoryBuffer::getFileOrSTDIN(InputFileList[i], - InputBuffer)) - return Error("unable to read input: '" + ec.message() + "'"); - // Load the object file - LoadedObject.reset(Dyld.loadObject(new ObjectBuffer(InputBuffer.release()))); + LoadedObject.reset( + Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release()))); if (!LoadedObject) { return Error(Dyld.getErrorString()); } @@ -263,6 +285,96 @@ static int executeInput() { return Main(1, Argv); } +static int checkAllExpressions(RuntimeDyldChecker &Checker) { + for (const auto& CheckerFileName : CheckFiles) { + ErrorOr<std::unique_ptr<MemoryBuffer>> CheckerFileBuf = + MemoryBuffer::getFileOrSTDIN(CheckerFileName); + if (std::error_code EC = CheckerFileBuf.getError()) + return Error("unable to read input '" + CheckerFileName + "': " + + EC.message()); + + if (!Checker.checkAllRulesInBuffer("# rtdyld-check:", + CheckerFileBuf.get().get())) + return Error("some checks in '" + CheckerFileName + "' failed"); + } + return 0; +} + +static int linkAndVerify() { + + // Check for missing triple. + if (TripleName == "") { + llvm::errs() << "Error: -triple required when running in -verify mode.\n"; + return 1; + } + + // Look up the target and build the disassembler. + Triple TheTriple(Triple::normalize(TripleName)); + std::string ErrorStr; + const Target *TheTarget = + TargetRegistry::lookupTarget("", TheTriple, ErrorStr); + if (!TheTarget) { + llvm::errs() << "Error accessing target '" << TripleName << "': " + << ErrorStr << "\n"; + return 1; + } + TripleName = TheTriple.getTriple(); + + std::unique_ptr<MCSubtargetInfo> STI( + TheTarget->createMCSubtargetInfo(TripleName, "", "")); + assert(STI && "Unable to create subtarget info!"); + + std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TripleName)); + assert(MRI && "Unable to create target register info!"); + + std::unique_ptr<MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TripleName)); + assert(MAI && "Unable to create target asm info!"); + + MCContext Ctx(MAI.get(), MRI.get(), nullptr); + + std::unique_ptr<MCDisassembler> Disassembler( + TheTarget->createMCDisassembler(*STI, Ctx)); + assert(Disassembler && "Unable to create disassembler!"); + + std::unique_ptr<MCInstrInfo> MII(TheTarget->createMCInstrInfo()); + + std::unique_ptr<MCInstPrinter> InstPrinter( + TheTarget->createMCInstPrinter(0, *MAI, *MII, *MRI, *STI)); + + // Load any dylibs requested on the command line. + loadDylibs(); + + // Instantiate a dynamic linker. + TrivialMemoryManager MemMgr; + RuntimeDyld Dyld(&MemMgr); + + // If we don't have any input files, read from stdin. + if (!InputFileList.size()) + InputFileList.push_back("-"); + for(unsigned i = 0, e = InputFileList.size(); i != e; ++i) { + // Load the input memory buffer. + ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer = + MemoryBuffer::getFileOrSTDIN(InputFileList[i]); + if (std::error_code EC = InputBuffer.getError()) + return Error("unable to read input: '" + EC.message() + "'"); + + std::unique_ptr<ObjectImage> LoadedObject; + // Load the object file + LoadedObject.reset( + Dyld.loadObject(new ObjectBuffer(InputBuffer.get().release()))); + if (!LoadedObject) { + return Error(Dyld.getErrorString()); + } + } + + // Resolve all the relocations we can. + Dyld.resolveRelocations(); + + RuntimeDyldChecker Checker(Dyld, Disassembler.get(), InstPrinter.get(), + llvm::dbgs()); + return checkAllExpressions(Checker); +} + int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); @@ -270,6 +382,10 @@ int main(int argc, char **argv) { ProgramName = argv[0]; llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllDisassemblers(); + cl::ParseCommandLineOptions(argc, argv, "llvm MC-JIT tool\n"); switch (Action) { @@ -277,5 +393,7 @@ int main(int argc, char **argv) { return executeInput(); case AC_PrintLineInfo: return printLineInfoForInput(); + case AC_Verify: + return linkAndVerify(); } } diff --git a/tools/llvm-size/Android.mk b/tools/llvm-size/Android.mk index 0efca96..4c26cce 100644 --- a/tools/llvm-size/Android.mk +++ b/tools/llvm-size/Android.mk @@ -11,10 +11,12 @@ llvm_size_SRC_FILES := \ llvm-size.cpp llvm_size_STATIC_LIBRARIES := \ - libLLVMObject \ - libLLVMBitReader \ - libLLVMCore \ - libLLVMSupport \ + libLLVMObject \ + libLLVMMC \ + libLLVMMCParser \ + libLLVMBitReader \ + libLLVMCore \ + libLLVMSupport include $(CLEAR_VARS) diff --git a/tools/llvm-size/llvm-size.cpp b/tools/llvm-size/llvm-size.cpp index 58eafd4..50b5220 100644 --- a/tools/llvm-size/llvm-size.cpp +++ b/tools/llvm-size/llvm-size.cpp @@ -16,6 +16,8 @@ #include "llvm/ADT/APInt.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" @@ -25,51 +27,61 @@ #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 <string> +#include <system_error> using namespace llvm; using namespace object; -enum OutputFormatTy {berkeley, sysv}; +enum OutputFormatTy { berkeley, sysv, darwin }; static cl::opt<OutputFormatTy> - OutputFormat("format", - cl::desc("Specify output format"), - cl::values(clEnumVal(sysv, "System V format"), - clEnumVal(berkeley, "Berkeley format"), - clEnumValEnd), - cl::init(berkeley)); +OutputFormat("format", cl::desc("Specify output format"), + cl::values(clEnumVal(sysv, "System V format"), + clEnumVal(berkeley, "Berkeley format"), + clEnumVal(darwin, "Darwin -m format"), clEnumValEnd), + cl::init(berkeley)); + +static cl::opt<OutputFormatTy> OutputFormatShort( + cl::desc("Specify output format"), + cl::values(clEnumValN(sysv, "A", "System V format"), + clEnumValN(berkeley, "B", "Berkeley format"), + clEnumValN(darwin, "m", "Darwin -m format"), clEnumValEnd), + cl::init(berkeley)); + +static bool berkeleyHeaderPrinted = false; +static bool moreThanOneFile = false; + +cl::opt<bool> +DarwinLongFormat("l", cl::desc("When format is darwin, use long format " + "to include addresses and offsets.")); -static cl::opt<OutputFormatTy> - OutputFormatShort(cl::desc("Specify output format"), - cl::values(clEnumValN(sysv, "A", "System V format"), - clEnumValN(berkeley, "B", "Berkeley format"), - clEnumValEnd), - cl::init(berkeley)); +static cl::list<std::string> +ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; -enum RadixTy {octal = 8, decimal = 10, hexadecimal = 16}; +enum RadixTy { octal = 8, decimal = 10, hexadecimal = 16 }; static cl::opt<unsigned int> - Radix("-radix", - cl::desc("Print size in radix. Only 8, 10, and 16 are valid"), - cl::init(decimal)); +Radix("-radix", cl::desc("Print size in radix. Only 8, 10, and 16 are valid"), + cl::init(decimal)); static cl::opt<RadixTy> - RadixShort(cl::desc("Print size in radix:"), - cl::values(clEnumValN(octal, "o", "Print size in octal"), - clEnumValN(decimal, "d", "Print size in decimal"), - clEnumValN(hexadecimal, "x", "Print size in hexadecimal"), - clEnumValEnd), - cl::init(decimal)); +RadixShort(cl::desc("Print size in radix:"), + cl::values(clEnumValN(octal, "o", "Print size in octal"), + clEnumValN(decimal, "d", "Print size in decimal"), + clEnumValN(hexadecimal, "x", "Print size in hexadecimal"), + clEnumValEnd), + cl::init(decimal)); static cl::list<std::string> - InputFilenames(cl::Positional, cl::desc("<input files>"), - cl::ZeroOrMore); +InputFilenames(cl::Positional, cl::desc("<input files>"), cl::ZeroOrMore); static std::string ToolName; /// @brief If ec is not success, print the error and return true. -static bool error(error_code ec) { - if (!ec) return false; +static bool error(std::error_code ec) { + if (!ec) + return false; outs() << ToolName << ": error reading file: " << ec.message() << ".\n"; outs().flush(); @@ -85,6 +97,180 @@ static size_t getNumLengthAsString(uint64_t num) { return result.size(); } +/// @brief Return the the printing format for the Radix. +static const char *getRadixFmt(void) { + switch (Radix) { + case octal: + return PRIo64; + case decimal: + return PRIu64; + case hexadecimal: + return PRIx64; + } + return nullptr; +} + +/// @brief Print the size of each Mach-O segment and section in @p MachO. +/// +/// This is when used when @c OutputFormat is darwin and produces the same +/// output as darwin's size(1) -m output. +static void PrintDarwinSectionSizes(MachOObjectFile *MachO) { + std::string fmtbuf; + raw_string_ostream fmt(fmtbuf); + const char *radix_fmt = getRadixFmt(); + if (Radix == hexadecimal) + fmt << "0x"; + fmt << "%" << radix_fmt; + + uint32_t LoadCommandCount = MachO->getHeader().ncmds; + uint32_t Filetype = MachO->getHeader().filetype; + MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo(); + + uint64_t total = 0; + for (unsigned I = 0;; ++I) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg.vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + outs() << format(fmt.str().c_str(), Sec.size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + outs() << "Segment " << Seg.segname << ": " + << format(fmt.str().c_str(), Seg.vmsize); + if (DarwinLongFormat) + outs() << " (vmaddr 0x" << format("%" PRIx64, Seg.vmaddr) << " fileoff " + << Seg.fileoff << ")"; + outs() << "\n"; + total += Seg.vmsize; + uint64_t sec_total = 0; + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + if (Filetype == MachO::MH_OBJECT) + outs() << "\tSection (" << format("%.16s", &Sec.segname) << ", " + << format("%.16s", &Sec.sectname) << "): "; + else + outs() << "\tSection " << format("%.16s", &Sec.sectname) << ": "; + outs() << format(fmt.str().c_str(), Sec.size); + if (DarwinLongFormat) + outs() << " (addr 0x" << format("%" PRIx64, Sec.addr) << " offset " + << Sec.offset << ")"; + outs() << "\n"; + sec_total += Sec.size; + } + if (Seg.nsects != 0) + outs() << "\ttotal " << format(fmt.str().c_str(), sec_total) << "\n"; + } + if (I == LoadCommandCount - 1) + break; + else + Load = MachO->getNextLoadCommandInfo(Load); + } + outs() << "total " << format(fmt.str().c_str(), total) << "\n"; +} + +/// @brief Print the summary sizes of the standard Mach-O segments in @p MachO. +/// +/// This is when used when @c OutputFormat is berkeley with a Mach-O file and +/// produces the same output as darwin's size(1) default output. +static void PrintDarwinSegmentSizes(MachOObjectFile *MachO) { + uint32_t LoadCommandCount = MachO->getHeader().ncmds; + MachOObjectFile::LoadCommandInfo Load = MachO->getFirstLoadCommandInfo(); + + uint64_t total_text = 0; + uint64_t total_data = 0; + uint64_t total_objc = 0; + uint64_t total_others = 0; + for (unsigned I = 0;; ++I) { + if (Load.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 Seg = MachO->getSegment64LoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section_64 Sec = MachO->getSection64(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } else if (Load.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command Seg = MachO->getSegmentLoadCommand(Load); + if (MachO->getHeader().filetype == MachO::MH_OBJECT) { + for (unsigned J = 0; J < Seg.nsects; ++J) { + MachO::section Sec = MachO->getSection(Load, J); + StringRef SegmentName = StringRef(Sec.segname); + if (SegmentName == "__TEXT") + total_text += Sec.size; + else if (SegmentName == "__DATA") + total_data += Sec.size; + else if (SegmentName == "__OBJC") + total_objc += Sec.size; + else + total_others += Sec.size; + } + } else { + StringRef SegmentName = StringRef(Seg.segname); + if (SegmentName == "__TEXT") + total_text += Seg.vmsize; + else if (SegmentName == "__DATA") + total_data += Seg.vmsize; + else if (SegmentName == "__OBJC") + total_objc += Seg.vmsize; + else + total_others += Seg.vmsize; + } + } + if (I == LoadCommandCount - 1) + break; + else + Load = MachO->getNextLoadCommandInfo(Load); + } + uint64_t total = total_text + total_data + total_objc + total_others; + + if (!berkeleyHeaderPrinted) { + outs() << "__TEXT\t__DATA\t__OBJC\tothers\tdec\thex\n"; + berkeleyHeaderPrinted = true; + } + outs() << total_text << "\t" << total_data << "\t" << total_objc << "\t" + << total_others << "\t" << total << "\t" << format("%" PRIx64, total) + << "\t"; +} + /// @brief Print the size of each section in @p Obj. /// /// The format used is determined by @c OutputFormat and @c Radix. @@ -92,20 +278,19 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) { uint64_t total = 0; std::string fmtbuf; raw_string_ostream fmt(fmtbuf); - - const char *radix_fmt = nullptr; - switch (Radix) { - case octal: - radix_fmt = PRIo64; - break; - case decimal: - radix_fmt = PRIu64; - break; - case hexadecimal: - radix_fmt = PRIx64; - break; - } - if (OutputFormat == sysv) { + const char *radix_fmt = getRadixFmt(); + + // If OutputFormat is darwin and we have a MachOObjectFile print as darwin's + // size(1) -m output, else if OutputFormat is darwin and not a Mach-O object + // let it fall through to OutputFormat berkeley. + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(Obj); + if (OutputFormat == darwin && MachO) + PrintDarwinSectionSizes(MachO); + // If we have a MachOObjectFile and the OutputFormat is berkeley print as + // darwin's default berkeley format for Mach-O files. + else if (MachO && OutputFormat == berkeley) + PrintDarwinSegmentSizes(MachO); + else if (OutputFormat == sysv) { // Run two passes over all sections. The first gets the lengths needed for // formatting the output. The second actually does the output. std::size_t max_name_len = strlen("section"); @@ -139,10 +324,9 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) { << "%" << max_addr_len << "s\n"; // Print header - outs() << format(fmt.str().c_str(), - static_cast<const char*>("section"), - static_cast<const char*>("size"), - static_cast<const char*>("addr")); + outs() << format(fmt.str().c_str(), static_cast<const char *>("section"), + static_cast<const char *>("size"), + static_cast<const char *>("addr")); fmtbuf.clear(); // Setup per section format. @@ -170,8 +354,7 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) { fmtbuf.clear(); fmt << "%-" << max_name_len << "s " << "%#" << max_size_len << radix_fmt << "\n"; - outs() << format(fmt.str().c_str(), - static_cast<const char*>("Total"), + outs() << format(fmt.str().c_str(), static_cast<const char *>("Total"), total); } else { // The Berkeley format does not display individual section sizes. It @@ -204,21 +387,56 @@ static void PrintObjectSectionSizes(ObjectFile *Obj) { total = total_text + total_data + total_bss; + if (!berkeleyHeaderPrinted) { + outs() << " text data bss " + << (Radix == octal ? "oct" : "dec") << " hex filename\n"; + berkeleyHeaderPrinted = true; + } + // Print result. fmt << "%#7" << radix_fmt << " " << "%#7" << radix_fmt << " " << "%#7" << radix_fmt << " "; - outs() << format(fmt.str().c_str(), - total_text, - total_data, - total_bss); + outs() << format(fmt.str().c_str(), total_text, total_data, total_bss); fmtbuf.clear(); fmt << "%7" << (Radix == octal ? PRIo64 : PRIu64) << " " << "%7" PRIx64 " "; - outs() << format(fmt.str().c_str(), - total, - total); + outs() << format(fmt.str().c_str(), total, total); + } +} + +/// @brief Checks to see if the @p o ObjectFile is a Mach-O file and if it is +/// and there is a list of architecture flags specified then check to +/// make sure this Mach-O file is one of those architectures or all +/// architectures was specificed. If not then an error is generated and +/// this routine returns false. Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *o, StringRef file) { + if (isa<MachOObjectFile>(o) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + bool ArchFound = false; + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + } + unsigned i; + for (i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == T.getArchName()) + ArchFound = true; + break; + } + if (!ArchFound) { + errs() << ToolName << ": file: " << file + << " does not contain architecture: " << ArchFlags[i] << ".\n"; + return false; + } } + return true; } /// @brief Print the section sizes for @p file. If @p file is an archive, print @@ -228,14 +446,15 @@ static void PrintFileSectionSizes(StringRef file) { if (file != "-") { bool exists; if (sys::fs::exists(file, exists) || !exists) { - errs() << ToolName << ": '" << file << "': " << "No such file\n"; + errs() << ToolName << ": '" << file << "': " + << "No such file\n"; return; } } // Attempt to open the binary. ErrorOr<Binary *> BinaryOrErr = createBinary(file); - if (error_code EC = BinaryOrErr.getError()) { + if (std::error_code EC = BinaryOrErr.getError()) { errs() << ToolName << ": " << file << ": " << EC.message() << ".\n"; return; } @@ -244,29 +463,250 @@ static void PrintFileSectionSizes(StringRef file) { if (Archive *a = dyn_cast<Archive>(binary.get())) { // This is an archive. Iterate over each member and display its sizes. for (object::Archive::child_iterator i = a->child_begin(), - e = a->child_end(); i != e; ++i) { - std::unique_ptr<Binary> child; - if (error_code ec = i->getAsBinary(child)) { - errs() << ToolName << ": " << file << ": " << ec.message() << ".\n"; + e = a->child_end(); + i != e; ++i) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() << ".\n"; continue; } - if (ObjectFile *o = dyn_cast<ObjectFile>(child.get())) { + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (!checkMachOAndArchFlags(o, file)) + return; if (OutputFormat == sysv) - outs() << o->getFileName() << " (ex " << a->getFileName() - << "):\n"; + outs() << o->getFileName() << " (ex " << a->getFileName() << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << a->getFileName() << "(" << o->getFileName() << "):\n"; PrintObjectSectionSizes(o); - if (OutputFormat == berkeley) - outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; + if (OutputFormat == berkeley) { + if (MachO) + outs() << a->getFileName() << "(" << o->getFileName() << ")\n"; + else + outs() << o->getFileName() << " (ex " << a->getFileName() << ")\n"; + } + } + } + } else if (MachOUniversalBinary *UB = + dyn_cast<MachOUniversalBinary>(binary.get())) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchTypeName()) { + ArchFound = true; + ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); + std::unique_ptr<Archive> UA; + if (UO) { + if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (moreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << "): \n"; + } + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || moreThanOneFile || ArchFlags.size() > 1) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + } + } else if (!I->getAsArchive(UA)) { + // This is an archive. Iterate over each member and display its + // sizes. + for (object::Archive::child_iterator i = UA->child_begin(), + e = UA->child_end(); + i != e; ++i) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")" + << " (for architecture " << I->getArchTypeName() + << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) { + outs() << UA->getFileName() << "(" << o->getFileName() + << ")"; + if (ArchFlags.size() > 1) + outs() << " (for architecture " << I->getArchTypeName() + << ")"; + outs() << "\n"; + } else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + } + } + } + if (!ArchFound) { + errs() << ToolName << ": file: " << file + << " does not contain architecture" << ArchFlags[i] << ".\n"; + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchTypeName()) { + ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); + std::unique_ptr<Archive> UA; + if (UO) { + if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (moreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << "):\n"; + } + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || moreThanOneFile) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + } + } else if (!I->getAsArchive(UA)) { + // This is an archive. Iterate over each member and display its + // sizes. + for (object::Archive::child_iterator i = UA->child_begin(), + e = UA->child_end(); + i != e; ++i) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() + << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchTypeName() + << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool moreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + ErrorOr<std::unique_ptr<ObjectFile>> UO = I->getAsObjectFile(); + std::unique_ptr<Archive> UA; + if (UO) { + if (ObjectFile *o = dyn_cast<ObjectFile>(&*UO.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " :\n"; + else if (MachO && OutputFormat == darwin) { + if (moreThanOneFile || moreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << "):"; + outs() << "\n"; + } + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (!MachO || moreThanOneFile || moreThanOneArch) + outs() << o->getFileName() << " (for architecture " + << I->getArchTypeName() << ")"; + outs() << "\n"; + } + } + } else if (!I->getAsArchive(UA)) { + // This is an archive. Iterate over each member and display its sizes. + for (object::Archive::child_iterator i = UA->child_begin(), + e = UA->child_end(); + i != e; ++i) { + ErrorOr<std::unique_ptr<Binary>> ChildOrErr = i->getAsBinary(); + if (std::error_code EC = ChildOrErr.getError()) { + errs() << ToolName << ": " << file << ": " << EC.message() << ".\n"; + continue; + } + if (ObjectFile *o = dyn_cast<ObjectFile>(&*ChildOrErr.get())) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (OutputFormat == sysv) + outs() << o->getFileName() << " (ex " << UA->getFileName() + << "):\n"; + else if (MachO && OutputFormat == darwin) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchTypeName() << "):\n"; + PrintObjectSectionSizes(o); + if (OutputFormat == berkeley) { + if (MachO) + outs() << UA->getFileName() << "(" << o->getFileName() << ")" + << " (for architecture " << I->getArchTypeName() + << ")\n"; + else + outs() << o->getFileName() << " (ex " << UA->getFileName() + << ")\n"; + } + } + } } } } else if (ObjectFile *o = dyn_cast<ObjectFile>(binary.get())) { + if (!checkMachOAndArchFlags(o, file)) + return; if (OutputFormat == sysv) outs() << o->getFileName() << " :\n"; PrintObjectSectionSizes(o); - if (OutputFormat == berkeley) - outs() << o->getFileName() << "\n"; + if (OutputFormat == berkeley) { + MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o); + if (!MachO || moreThanOneFile) + outs() << o->getFileName(); + outs() << "\n"; + } } else { - errs() << ToolName << ": " << file << ": " << "Unrecognized file type.\n"; + errs() << ToolName << ": " << file << ": " + << "Unrecognized file type.\n"; } // System V adds an extra newline at the end of each file. if (OutputFormat == sysv) @@ -278,7 +718,7 @@ int main(int argc, char **argv) { sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. cl::ParseCommandLineOptions(argc, argv, "llvm object size dumper\n"); ToolName = argv[0]; @@ -287,14 +727,23 @@ int main(int argc, char **argv) { if (RadixShort.getNumOccurrences()) Radix = RadixShort; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == "all") { + ArchAll = true; + } else { + Triple T = MachOObjectFile::getArch(ArchFlags[i]); + if (T.getArch() == Triple::UnknownArch) { + outs() << ToolName << ": for the -arch option: Unknown architecture " + << "named '" << ArchFlags[i] << "'"; + return 1; + } + } + } + if (InputFilenames.size() == 0) InputFilenames.push_back("a.out"); - if (OutputFormat == berkeley) - outs() << " text data bss " - << (Radix == octal ? "oct" : "dec") - << " hex filename\n"; - + moreThanOneFile = InputFilenames.size() > 1; std::for_each(InputFilenames.begin(), InputFilenames.end(), PrintFileSectionSizes); diff --git a/tools/llvm-symbolizer/LLVMSymbolize.cpp b/tools/llvm-symbolizer/LLVMSymbolize.cpp index 3e71111..c1d39ef 100644 --- a/tools/llvm-symbolizer/LLVMSymbolize.cpp +++ b/tools/llvm-symbolizer/LLVMSymbolize.cpp @@ -19,6 +19,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -28,7 +29,7 @@ namespace llvm { namespace symbolize { -static bool error(error_code ec) { +static bool error(std::error_code ec) { if (!ec) return false; errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n"; @@ -219,10 +220,11 @@ static std::string getDarwinDWARFResourceForPath(const std::string &Path) { } static bool checkFileCRC(StringRef Path, uint32_t CRCHash) { - std::unique_ptr<MemoryBuffer> MB; - if (MemoryBuffer::getFileOrSTDIN(Path, MB)) + ErrorOr<std::unique_ptr<MemoryBuffer>> MB = + MemoryBuffer::getFileOrSTDIN(Path); + if (!MB) return false; - return !zlib::isAvailable() || CRCHash == zlib::crc32(MB->getBuffer()); + return !zlib::isAvailable() || CRCHash == zlib::crc32(MB.get()->getBuffer()); } static bool findDebugBinary(const std::string &OrigPath, @@ -310,7 +312,7 @@ LLVMSymbolizer::getOrCreateBinary(const std::string &Path) { const std::string &ResourcePath = getDarwinDWARFResourceForPath(Path); BinaryOrErr = createBinary(ResourcePath); - error_code EC = BinaryOrErr.getError(); + std::error_code EC = BinaryOrErr.getError(); if (EC != errc::no_such_file_or_directory && !error(EC)) { DbgBin = BinaryOrErr.get(); ParsedBinariesAndObjects.push_back(std::unique_ptr<Binary>(DbgBin)); @@ -348,10 +350,11 @@ LLVMSymbolizer::getObjectFileFromBinary(Binary *Bin, const std::string &ArchName std::make_pair(UB, ArchName)); if (I != ObjectFileForArch.end()) return I->second; - std::unique_ptr<ObjectFile> ParsedObj; - if (!UB->getObjectForArch(Triple(ArchName).getArch(), ParsedObj)) { - Res = ParsedObj.get(); - ParsedBinariesAndObjects.push_back(std::move(ParsedObj)); + ErrorOr<std::unique_ptr<ObjectFile>> ParsedObj = + UB->getObjectForArch(Triple(ArchName).getArch()); + if (ParsedObj) { + Res = ParsedObj.get().get(); + ParsedBinariesAndObjects.push_back(std::move(ParsedObj.get())); } ObjectFileForArch[std::make_pair(UB, ArchName)] = Res; } else if (Bin->isObject()) { diff --git a/tools/lto/CMakeLists.txt b/tools/lto/CMakeLists.txt index 542053b..71391b7 100644 --- a/tools/lto/CMakeLists.txt +++ b/tools/lto/CMakeLists.txt @@ -16,11 +16,7 @@ set(SOURCES set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/lto.exports) -if(NOT CYGWIN AND LLVM_ENABLE_PIC) - set(ENABLE_SHARED SHARED) -endif() - -add_llvm_library(LTO ${ENABLE_SHARED} STATIC ${SOURCES}) +add_llvm_library(LTO SHARED ${SOURCES}) install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/lto.h DESTINATION include/llvm-c) diff --git a/tools/lto/lto.cpp b/tools/lto/lto.cpp index 64abf5c..b401f9a 100644 --- a/tools/lto/lto.cpp +++ b/tools/lto/lto.cpp @@ -13,11 +13,11 @@ //===----------------------------------------------------------------------===// #include "llvm-c/lto.h" -#include "llvm-c/Core.h" -#include "llvm-c/Target.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/LTO/LTOCodeGenerator.h" #include "llvm/LTO/LTOModule.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TargetSelect.h" // extra command-line flags needed for LTOCodeGenerator static cl::opt<bool> @@ -46,12 +46,12 @@ 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(); + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmParsers(); + InitializeAllAsmPrinters(); + InitializeAllDisassemblers(); initialized = true; } } @@ -88,7 +88,10 @@ bool lto_module_is_object_file(const char* path) { bool lto_module_is_object_file_for_target(const char* path, const char* target_triplet_prefix) { - return LTOModule::isBitcodeFileForTarget(path, target_triplet_prefix); + ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer = MemoryBuffer::getFile(path); + if (!Buffer) + return false; + return LTOModule::isBitcodeForTarget(Buffer->get(), target_triplet_prefix); } bool lto_module_is_object_file_in_memory(const void* mem, size_t length) { @@ -99,20 +102,23 @@ bool lto_module_is_object_file_in_memory_for_target(const void* mem, size_t length, const char* target_triplet_prefix) { - return LTOModule::isBitcodeFileForTarget(mem, length, target_triplet_prefix); + std::unique_ptr<MemoryBuffer> buffer(LTOModule::makeBuffer(mem, length)); + if (!buffer) + return false; + return LTOModule::isBitcodeForTarget(buffer.get(), target_triplet_prefix); } lto_module_t lto_module_create(const char* path) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - return wrap(LTOModule::makeLTOModule(path, Options, sLastErrorString)); + return wrap(LTOModule::createFromFile(path, Options, sLastErrorString)); } lto_module_t lto_module_create_from_fd(int fd, const char *path, size_t size) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return wrap( - LTOModule::makeLTOModule(fd, path, size, Options, sLastErrorString)); + LTOModule::createFromOpenFile(fd, path, size, Options, sLastErrorString)); } lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, @@ -121,14 +127,14 @@ lto_module_t lto_module_create_from_fd_at_offset(int fd, const char *path, off_t offset) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - return wrap(LTOModule::makeLTOModule(fd, path, map_size, offset, Options, - sLastErrorString)); + return wrap(LTOModule::createFromOpenFileSlice(fd, path, map_size, offset, + Options, sLastErrorString)); } lto_module_t lto_module_create_from_memory(const void* mem, size_t length) { lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); - return wrap(LTOModule::makeLTOModule(mem, length, Options, sLastErrorString)); + return wrap(LTOModule::createFromBuffer(mem, length, Options, sLastErrorString)); } lto_module_t lto_module_create_from_memory_with_path(const void* mem, @@ -137,13 +143,13 @@ lto_module_t lto_module_create_from_memory_with_path(const void* mem, lto_initialize(); llvm::TargetOptions Options = InitTargetOptionsFromCodeGenFlags(); return wrap( - LTOModule::makeLTOModule(mem, length, Options, sLastErrorString, path)); + LTOModule::createFromBuffer(mem, length, Options, sLastErrorString, path)); } void lto_module_dispose(lto_module_t mod) { delete unwrap(mod); } const char* lto_module_get_target_triple(lto_module_t mod) { - return unwrap(mod)->getTargetTriple(); + return unwrap(mod)->getTargetTriple().c_str(); } void lto_module_set_target_triple(lto_module_t mod, const char *triple) { diff --git a/tools/macho-dump/Android.mk b/tools/macho-dump/Android.mk index 9699d4a..001f293 100644 --- a/tools/macho-dump/Android.mk +++ b/tools/macho-dump/Android.mk @@ -12,6 +12,8 @@ macho_dump_SRC_FILES := \ macho_dump_STATIC_LIBRARIES := \ libLLVMObject \ + libLLVMMC \ + libLLVMMCParser \ libLLVMBitReader \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/macho-dump/macho-dump.cpp b/tools/macho-dump/macho-dump.cpp index 886487b..7600979 100644 --- a/tools/macho-dump/macho-dump.cpp +++ b/tools/macho-dump/macho-dump.cpp @@ -20,7 +20,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" +#include <system_error> using namespace llvm; using namespace llvm::object; @@ -328,6 +328,17 @@ DumpVersionMin(const MachOObjectFile &Obj, return 0; } +static int +DumpDylibID(const MachOObjectFile &Obj, + const MachOObjectFile::LoadCommandInfo &LCI) { + MachO::dylib_command DLLC = Obj.getDylibIDLoadCommand(LCI); + outs() << " ('install_name', '" << LCI.Ptr + DLLC.dylib.name << "')\n" + << " ('timestamp, " << DLLC.dylib.timestamp << ")\n" + << " ('cur_version, " << DLLC.dylib.current_version << ")\n" + << " ('compat_version, " << DLLC.dylib.compatibility_version << ")\n"; + return 0; +} + static int DumpLoadCommand(const MachOObjectFile &Obj, MachOObjectFile::LoadCommandInfo &LCI) { switch (LCI.C.cmd) { @@ -350,6 +361,8 @@ static int DumpLoadCommand(const MachOObjectFile &Obj, case MachO::LC_VERSION_MIN_IPHONEOS: case MachO::LC_VERSION_MIN_MACOSX: return DumpVersionMin(Obj, LCI); + case MachO::LC_ID_DYLIB: + return DumpDylibID(Obj, LCI); default: Warning("unknown load command: " + Twine(LCI.C.cmd)); return 0; @@ -391,7 +404,7 @@ int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv, "llvm Mach-O dumping tool\n"); ErrorOr<Binary *> BinaryOrErr = createBinary(InputFile); - if (error_code EC = BinaryOrErr.getError()) + if (std::error_code EC = BinaryOrErr.getError()) return Error("unable to read input: '" + EC.message() + "'"); std::unique_ptr<Binary> Binary(BinaryOrErr.get()); diff --git a/tools/obj2yaml/Android.mk b/tools/obj2yaml/Android.mk index 8c8fdab..2994622 100644 --- a/tools/obj2yaml/Android.mk +++ b/tools/obj2yaml/Android.mk @@ -15,6 +15,8 @@ obj2yaml_SRC_FILES := \ obj2yaml_STATIC_LIBRARIES := \ libLLVMObject \ + libLLVMMC \ + libLLVMMCParser \ libLLVMBitReader \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/obj2yaml/Error.cpp b/tools/obj2yaml/Error.cpp index 7be468d..0074128 100644 --- a/tools/obj2yaml/Error.cpp +++ b/tools/obj2yaml/Error.cpp @@ -13,18 +13,17 @@ using namespace llvm; namespace { -class _obj2yaml_error_category : public error_category { +class _obj2yaml_error_category : public std::error_category { public: - const char *name() const override; + const char *name() const LLVM_NOEXCEPT override; std::string message(int ev) const override; - error_condition default_error_condition(int ev) const override; }; } // namespace const char *_obj2yaml_error_category::name() const { return "obj2yaml"; } std::string _obj2yaml_error_category::message(int ev) const { - switch (ev) { + switch (static_cast<obj2yaml_error>(ev)) { case obj2yaml_error::success: return "Success"; case obj2yaml_error::file_not_found: @@ -33,21 +32,13 @@ std::string _obj2yaml_error_category::message(int ev) const { return "Unrecognized file type."; case obj2yaml_error::unsupported_obj_file_format: return "Unsupported object file format."; - default: - llvm_unreachable("An enumerator of obj2yaml_error does not have a message " - "defined."); } -} - -error_condition -_obj2yaml_error_category::default_error_condition(int ev) const { - if (ev == obj2yaml_error::success) - return errc::success; - return errc::invalid_argument; + llvm_unreachable("An enumerator of obj2yaml_error does not have a message " + "defined."); } namespace llvm { -const error_category &obj2yaml_category() { + const std::error_category &obj2yaml_category() { static _obj2yaml_error_category o; return o; } diff --git a/tools/obj2yaml/Error.h b/tools/obj2yaml/Error.h index a326664..4657f0d 100644 --- a/tools/obj2yaml/Error.h +++ b/tools/obj2yaml/Error.h @@ -10,33 +10,26 @@ #ifndef LLVM_TOOLS_ERROR_H #define LLVM_TOOLS_ERROR_H -#include "llvm/Support/system_error.h" +#include <system_error> namespace llvm { +const std::error_category &obj2yaml_category(); -const error_category &obj2yaml_category(); - -struct obj2yaml_error { - enum _ { - success = 0, - file_not_found, - unrecognized_file_format, - unsupported_obj_file_format - }; - _ v_; - - obj2yaml_error(_ v) : v_(v) {} - explicit obj2yaml_error(int v) : v_(_(v)) {} - operator int() const {return v_;} +enum class obj2yaml_error { + success = 0, + file_not_found, + unrecognized_file_format, + unsupported_obj_file_format }; -inline error_code make_error_code(obj2yaml_error e) { - return error_code(static_cast<int>(e), obj2yaml_category()); +inline std::error_code make_error_code(obj2yaml_error e) { + return std::error_code(static_cast<int>(e), obj2yaml_category()); } -template <> struct is_error_code_enum<obj2yaml_error> : std::true_type { }; -template <> struct is_error_code_enum<obj2yaml_error::_> : std::true_type { }; - } // namespace llvm +namespace std { +template <> struct is_error_code_enum<llvm::obj2yaml_error> : std::true_type {}; +} + #endif diff --git a/tools/obj2yaml/coff2yaml.cpp b/tools/obj2yaml/coff2yaml.cpp index 42b09d3..fed4533 100644 --- a/tools/obj2yaml/coff2yaml.cpp +++ b/tools/obj2yaml/coff2yaml.cpp @@ -31,7 +31,7 @@ public: } -static void check(error_code ec) { +static void check(std::error_code ec) { if (ec) report_fatal_error(ec.message()); } @@ -61,7 +61,7 @@ void COFFDumper::dumpSections(unsigned NumSections) { ArrayRef<uint8_t> sectionData; Obj.getSectionContents(Sect, sectionData); - Sec.SectionData = object::yaml::BinaryRef(sectionData); + Sec.SectionData = yaml::BinaryRef(sectionData); std::vector<COFFYAML::Relocation> Relocations; for (const auto &Reloc : Section.relocations()) { @@ -210,7 +210,7 @@ COFFYAML::Object &COFFDumper::getYAMLObj() { return YAMLObj; } -error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) { +std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) { COFFDumper Dumper(Obj); yaml::Output Yout(Out); diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp index 7642921..8b53ee7 100644 --- a/tools/obj2yaml/elf2yaml.cpp +++ b/tools/obj2yaml/elf2yaml.cpp @@ -26,11 +26,13 @@ class ELFDumper { const object::ELFFile<ELFT> &Obj; - error_code dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S); - error_code dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); + std::error_code dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S); + std::error_code dumpCommonSection(const Elf_Shdr *Shdr, ELFYAML::Section &S); + std::error_code dumpCommonRelocationSection(const Elf_Shdr *Shdr, + ELFYAML::RelocationSection &S); template <class RelT> - error_code dumpRelocation(const Elf_Shdr *Shdr, const RelT *Rel, - ELFYAML::Relocation &R); + std::error_code dumpRelocation(const Elf_Shdr *Shdr, const RelT *Rel, + ELFYAML::Relocation &R); ErrorOr<ELFYAML::RelocationSection *> dumpRelSection(const Elf_Shdr *Shdr); ErrorOr<ELFYAML::RelocationSection *> dumpRelaSection(const Elf_Shdr *Shdr); @@ -72,21 +74,22 @@ ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() { break; case ELF::SHT_RELA: { ErrorOr<ELFYAML::RelocationSection *> S = dumpRelaSection(&Sec); - if (error_code EC = S.getError()) + if (std::error_code EC = S.getError()) return EC; Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get())); break; } case ELF::SHT_REL: { ErrorOr<ELFYAML::RelocationSection *> S = dumpRelSection(&Sec); - if (error_code EC = S.getError()) + if (std::error_code EC = S.getError()) return EC; Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get())); break; } + // FIXME: Support SHT_GROUP section format. default: { ErrorOr<ELFYAML::RawContentSection *> S = dumpContentSection(&Sec); - if (error_code EC = S.getError()) + if (std::error_code EC = S.getError()) return EC; Y->Sections.push_back(std::unique_ptr<ELFYAML::Section>(S.get())); } @@ -102,7 +105,7 @@ ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() { } ELFYAML::Symbol S; - if (error_code EC = ELFDumper<ELFT>::dumpSymbol(SI, S)) + if (std::error_code EC = ELFDumper<ELFT>::dumpSymbol(SI, S)) return EC; switch (SI->getBinding()) @@ -125,13 +128,15 @@ ErrorOr<ELFYAML::Object *> ELFDumper<ELFT>::dump() { } template <class ELFT> -error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S) { +std::error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym, + ELFYAML::Symbol &S) { S.Type = Sym->getType(); S.Value = Sym->st_value; S.Size = Sym->st_size; + S.Visibility = Sym->st_other & 0x3; ErrorOr<StringRef> NameOrErr = Obj.getSymbolName(Sym); - if (error_code EC = NameOrErr.getError()) + if (std::error_code EC = NameOrErr.getError()) return EC; S.Name = NameOrErr.get(); @@ -140,7 +145,7 @@ error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S) { return obj2yaml_error::success; NameOrErr = Obj.getSectionName(Shdr); - if (error_code EC = NameOrErr.getError()) + if (std::error_code EC = NameOrErr.getError()) return EC; S.Section = NameOrErr.get(); @@ -149,9 +154,9 @@ error_code ELFDumper<ELFT>::dumpSymbol(Elf_Sym_Iter Sym, ELFYAML::Symbol &S) { template <class ELFT> template <class RelT> -error_code ELFDumper<ELFT>::dumpRelocation(const Elf_Shdr *Shdr, - const RelT *Rel, - ELFYAML::Relocation &R) { +std::error_code ELFDumper<ELFT>::dumpRelocation(const Elf_Shdr *Shdr, + const RelT *Rel, + ELFYAML::Relocation &R) { R.Type = Rel->getType(Obj.isMips64EL()); R.Offset = Rel->r_offset; R.Addend = 0; @@ -162,7 +167,7 @@ error_code ELFDumper<ELFT>::dumpRelocation(const Elf_Shdr *Shdr, ErrorOr<StringRef> NameOrErr = Obj.getSymbolName(NamePair.first, NamePair.second); - if (error_code EC = NameOrErr.getError()) + if (std::error_code EC = NameOrErr.getError()) return EC; R.Symbol = NameOrErr.get(); @@ -170,34 +175,44 @@ error_code ELFDumper<ELFT>::dumpRelocation(const Elf_Shdr *Shdr, } template <class ELFT> -error_code ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr, - ELFYAML::Section &S) { +std::error_code ELFDumper<ELFT>::dumpCommonSection(const Elf_Shdr *Shdr, + ELFYAML::Section &S) { S.Type = Shdr->sh_type; S.Flags = Shdr->sh_flags; S.Address = Shdr->sh_addr; S.AddressAlign = Shdr->sh_addralign; ErrorOr<StringRef> NameOrErr = Obj.getSectionName(Shdr); - if (error_code EC = NameOrErr.getError()) + if (std::error_code EC = NameOrErr.getError()) return EC; S.Name = NameOrErr.get(); if (Shdr->sh_link != ELF::SHN_UNDEF) { if (const Elf_Shdr *LinkSection = Obj.getSection(Shdr->sh_link)) { NameOrErr = Obj.getSectionName(LinkSection); - if (error_code EC = NameOrErr.getError()) + if (std::error_code EC = NameOrErr.getError()) return EC; S.Link = NameOrErr.get(); } } - if (Shdr->sh_info != ELF::SHN_UNDEF) { - if (const Elf_Shdr *InfoSection = Obj.getSection(Shdr->sh_info)) { - NameOrErr = Obj.getSectionName(InfoSection); - if (error_code EC = NameOrErr.getError()) - return EC; - S.Info = NameOrErr.get(); - } + + return obj2yaml_error::success; +} + +template <class ELFT> +std::error_code +ELFDumper<ELFT>::dumpCommonRelocationSection(const Elf_Shdr *Shdr, + ELFYAML::RelocationSection &S) { + if (std::error_code EC = dumpCommonSection(Shdr, S)) + return EC; + + if (const Elf_Shdr *InfoSection = Obj.getSection(Shdr->sh_info)) { + ErrorOr<StringRef> NameOrErr = Obj.getSectionName(InfoSection); + if (std::error_code EC = NameOrErr.getError()) + return EC; + S.Info = NameOrErr.get(); } + return obj2yaml_error::success; } @@ -207,13 +222,13 @@ ELFDumper<ELFT>::dumpRelSection(const Elf_Shdr *Shdr) { assert(Shdr->sh_type == ELF::SHT_REL && "Section type is not SHT_REL"); auto S = make_unique<ELFYAML::RelocationSection>(); - if (error_code EC = dumpCommonSection(Shdr, *S)) + if (std::error_code EC = dumpCommonRelocationSection(Shdr, *S)) return EC; for (auto RI = Obj.begin_rel(Shdr), RE = Obj.end_rel(Shdr); RI != RE; ++RI) { ELFYAML::Relocation R; - if (error_code EC = dumpRelocation(Shdr, &*RI, R)) + if (std::error_code EC = dumpRelocation(Shdr, &*RI, R)) return EC; S->Relocations.push_back(R); } @@ -227,13 +242,13 @@ ELFDumper<ELFT>::dumpRelaSection(const Elf_Shdr *Shdr) { assert(Shdr->sh_type == ELF::SHT_RELA && "Section type is not SHT_RELA"); auto S = make_unique<ELFYAML::RelocationSection>(); - if (error_code EC = dumpCommonSection(Shdr, *S)) + if (std::error_code EC = dumpCommonRelocationSection(Shdr, *S)) return EC; for (auto RI = Obj.begin_rela(Shdr), RE = Obj.end_rela(Shdr); RI != RE; ++RI) { ELFYAML::Relocation R; - if (error_code EC = dumpRelocation(Shdr, &*RI, R)) + if (std::error_code EC = dumpRelocation(Shdr, &*RI, R)) return EC; R.Addend = RI->r_addend; S->Relocations.push_back(R); @@ -247,23 +262,24 @@ ErrorOr<ELFYAML::RawContentSection *> ELFDumper<ELFT>::dumpContentSection(const Elf_Shdr *Shdr) { auto S = make_unique<ELFYAML::RawContentSection>(); - if (error_code EC = dumpCommonSection(Shdr, *S)) + if (std::error_code EC = dumpCommonSection(Shdr, *S)) return EC; ErrorOr<ArrayRef<uint8_t>> ContentOrErr = Obj.getSectionContents(Shdr); - if (error_code EC = ContentOrErr.getError()) + if (std::error_code EC = ContentOrErr.getError()) return EC; - S->Content = object::yaml::BinaryRef(ContentOrErr.get()); + S->Content = yaml::BinaryRef(ContentOrErr.get()); S->Size = S->Content.binary_size(); return S.release(); } template <class ELFT> -static error_code elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj) { +static std::error_code elf2yaml(raw_ostream &Out, + const object::ELFFile<ELFT> &Obj) { ELFDumper<ELFT> Dumper(Obj); ErrorOr<ELFYAML::Object *> YAMLOrErr = Dumper.dump(); - if (error_code EC = YAMLOrErr.getError()) + if (std::error_code EC = YAMLOrErr.getError()) return EC; std::unique_ptr<ELFYAML::Object> YAML(YAMLOrErr.get()); @@ -273,7 +289,7 @@ static error_code elf2yaml(raw_ostream &Out, const object::ELFFile<ELFT> &Obj) { return object::object_error::success; } -error_code elf2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { +std::error_code elf2yaml(raw_ostream &Out, const object::ObjectFile &Obj) { if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(&Obj)) return elf2yaml(Out, *ELFObj->getELFFile()); diff --git a/tools/obj2yaml/obj2yaml.cpp b/tools/obj2yaml/obj2yaml.cpp index 7fe034d..944314a 100644 --- a/tools/obj2yaml/obj2yaml.cpp +++ b/tools/obj2yaml/obj2yaml.cpp @@ -19,7 +19,7 @@ using namespace llvm; using namespace llvm::object; -static error_code dumpObject(const ObjectFile &Obj) { +static std::error_code dumpObject(const ObjectFile &Obj) { if (Obj.isCOFF()) return coff2yaml(outs(), cast<COFFObjectFile>(Obj)); if (Obj.isELF()) @@ -28,12 +28,12 @@ static error_code dumpObject(const ObjectFile &Obj) { return obj2yaml_error::unsupported_obj_file_format; } -static error_code dumpInput(StringRef File) { +static std::error_code dumpInput(StringRef File) { if (File != "-" && !sys::fs::exists(File)) return obj2yaml_error::file_not_found; ErrorOr<Binary *> BinaryOrErr = createBinary(File); - if (error_code EC = BinaryOrErr.getError()) + if (std::error_code EC = BinaryOrErr.getError()) return EC; std::unique_ptr<Binary> Binary(BinaryOrErr.get()); @@ -53,7 +53,7 @@ int main(int argc, char *argv[]) { PrettyStackTraceProgram X(argc, argv); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. - if (error_code EC = dumpInput(InputFilename)) { + if (std::error_code EC = dumpInput(InputFilename)) { errs() << "Error: '" << EC.message() << "'\n"; return 1; } diff --git a/tools/obj2yaml/obj2yaml.h b/tools/obj2yaml/obj2yaml.h index 73c58fa..6d81110 100644 --- a/tools/obj2yaml/obj2yaml.h +++ b/tools/obj2yaml/obj2yaml.h @@ -15,11 +15,11 @@ #include "llvm/Object/COFF.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Support/system_error.h" +#include <system_error> -llvm::error_code coff2yaml(llvm::raw_ostream &Out, - const llvm::object::COFFObjectFile &Obj); -llvm::error_code elf2yaml(llvm::raw_ostream &Out, - const llvm::object::ObjectFile &Obj); +std::error_code coff2yaml(llvm::raw_ostream &Out, + const llvm::object::COFFObjectFile &Obj); +std::error_code elf2yaml(llvm::raw_ostream &Out, + const llvm::object::ObjectFile &Obj); #endif diff --git a/tools/opt/Android.mk b/tools/opt/Android.mk index 3ebb97e..6f3f48d 100644 --- a/tools/opt/Android.mk +++ b/tools/opt/Android.mk @@ -58,6 +58,7 @@ llvm_opt_STATIC_LIBRARIES := \ libLLVMTransformUtils \ libLLVMTarget \ libLLVMMC \ + libLLVMMCParser \ libLLVMObject \ libLLVMCore \ libLLVMAsmParser \ diff --git a/tools/opt/opt.cpp b/tools/opt/opt.cpp index 6f0fbf6..6ba6340 100644 --- a/tools/opt/opt.cpp +++ b/tools/opt/opt.cpp @@ -336,6 +336,7 @@ int main(int argc, char **argv) { InitializeAllTargets(); InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); // Initialize passes PassRegistry &Registry = *PassRegistry::getPassRegistry(); diff --git a/tools/yaml2obj/Android.mk b/tools/yaml2obj/Android.mk index d69075a..3242c31 100644 --- a/tools/yaml2obj/Android.mk +++ b/tools/yaml2obj/Android.mk @@ -14,6 +14,8 @@ yaml2obj_SRC_FILES := \ yaml2obj_STATIC_LIBRARIES := \ libLLVMObject \ + libLLVMMC \ + libLLVMMCParser \ libLLVMBitReader \ libLLVMCore \ libLLVMSupport \ diff --git a/tools/yaml2obj/yaml2coff.cpp b/tools/yaml2obj/yaml2coff.cpp index a0ede24..c772db9 100644 --- a/tools/yaml2obj/yaml2coff.cpp +++ b/tools/yaml2obj/yaml2coff.cpp @@ -327,8 +327,7 @@ bool writeCOFF(COFFParser &CP, raw_ostream &OS) { return true; } -int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { - yaml::Input YIn(Buf->getBuffer()); +int yaml2coff(yaml::Input &YIn, raw_ostream &Out) { COFFYAML::Object Doc; YIn >> Doc; if (YIn.error()) { diff --git a/tools/yaml2obj/yaml2elf.cpp b/tools/yaml2obj/yaml2elf.cpp index bb52cda..6eeecae 100644 --- a/tools/yaml2obj/yaml2elf.cpp +++ b/tools/yaml2obj/yaml2elf.cpp @@ -14,9 +14,9 @@ #include "yaml2obj.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFYAML.h" -#include "llvm/Object/StringTableBuilder.h" #include "llvm/Support/ELF.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLTraits.h" @@ -304,6 +304,7 @@ void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols, Symbol.st_shndx = Index; } // else Symbol.st_shndex == SHN_UNDEF (== 0), since it was zero'd earlier. Symbol.st_value = Sym.Value; + Symbol.st_other = Sym.Visibility; Symbol.st_size = Sym.Size; Syms.push_back(Symbol); } @@ -467,8 +468,7 @@ static bool isLittleEndian(const ELFYAML::Object &Doc) { return Doc.Header.Data == ELFYAML::ELF_ELFDATA(ELF::ELFDATA2LSB); } -int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf) { - yaml::Input YIn(Buf->getBuffer()); +int yaml2elf(yaml::Input &YIn, raw_ostream &Out) { ELFYAML::Object Doc; YIn >> Doc; if (YIn.error()) { diff --git a/tools/yaml2obj/yaml2obj.cpp b/tools/yaml2obj/yaml2obj.cpp index 2493b48..945fad1 100644 --- a/tools/yaml2obj/yaml2obj.cpp +++ b/tools/yaml2obj/yaml2obj.cpp @@ -15,15 +15,17 @@ //===----------------------------------------------------------------------===// #include "yaml2obj.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.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 "llvm/Support/ToolOutputFile.h" +#include "llvm/Support/YAMLTraits.h" +#include "llvm/Support/raw_ostream.h" +#include <system_error> using namespace llvm; @@ -51,9 +53,27 @@ cl::opt<YAMLObjectFormat> Format( clEnumValN(YOF_ELF, "elf", "ELF object file format"), clEnumValEnd)); +cl::opt<unsigned> +DocNum("docnum", cl::init(1), + cl::desc("Read specified document from input (default = 1)")); + static cl::opt<std::string> OutputFilename("o", cl::desc("Output filename"), cl::value_desc("filename")); +typedef int (*ConvertFuncPtr)(yaml::Input & YIn, raw_ostream &Out); + +int convertYAML(yaml::Input & YIn, raw_ostream &Out, ConvertFuncPtr Convert) { + unsigned CurDocNum = 0; + do { + if (++CurDocNum == DocNum) + return Convert(YIn, Out); + } while (YIn.nextDocument()); + + errs() << "yaml2obj: Cannot find the " << DocNum + << llvm::getOrdinalSuffix(DocNum) << " document\n"; + return 1; +} + int main(int argc, char **argv) { cl::ParseCommandLineOptions(argc, argv); sys::PrintStackTraceOnErrorSignal(); @@ -71,18 +91,24 @@ int main(int argc, char **argv) { return 1; } - std::unique_ptr<MemoryBuffer> Buf; - if (MemoryBuffer::getFileOrSTDIN(Input, Buf)) + ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = + MemoryBuffer::getFileOrSTDIN(Input); + if (!Buf) return 1; - int Res = 1; + ConvertFuncPtr Convert = nullptr; if (Format == YOF_COFF) - Res = yaml2coff(Out->os(), Buf.get()); + Convert = yaml2coff; else if (Format == YOF_ELF) - Res = yaml2elf(Out->os(), Buf.get()); - else + Convert = yaml2elf; + else { errs() << "Not yet implemented\n"; + return 1; + } + + yaml::Input YIn(Buf.get()->getBuffer()); + int Res = convertYAML(YIn, Out->os(), Convert); if (Res == 0) Out->keep(); diff --git a/tools/yaml2obj/yaml2obj.h b/tools/yaml2obj/yaml2obj.h index 095435c..086f641 100644 --- a/tools/yaml2obj/yaml2obj.h +++ b/tools/yaml2obj/yaml2obj.h @@ -13,10 +13,12 @@ #define LLVM_TOOLS_YAML2OBJ_H namespace llvm { - class raw_ostream; - class MemoryBuffer; +class raw_ostream; +namespace yaml { +class Input; } -int yaml2coff(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); -int yaml2elf(llvm::raw_ostream &Out, llvm::MemoryBuffer *Buf); +} +int yaml2coff(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); +int yaml2elf(llvm::yaml::Input &YIn, llvm::raw_ostream &Out); #endif |