diff options
author | Lai Wei-Chih <Robert.Lai@mediatek.com> | 2013-03-07 11:52:02 +0800 |
---|---|---|
committer | Lai Wei-Chih <Robert.Lai@mediatek.com> | 2013-03-07 14:32:10 +0800 |
commit | ae75ca96930ef6cf698a3e9aaff80b7be1467066 (patch) | |
tree | 74c1b14be0ea1d8d085503252bb42ac501b126c9 | |
parent | 850c213c2d72ae753738ab8596ba38ee9c210459 (diff) | |
download | llvm-ae75ca96930ef6cf698a3e9aaff80b7be1467066.tar.gz |
Bitcode strip tool for le32-none-ndk triple.
Change-Id: I0c33fa7d5da4c86c458d18e13d366470d7aa0798
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/le32-none-ndk-strip/Makefile | 14 | ||||
-rw-r--r-- | tools/le32-none-ndk-strip/le32-none-ndk-strip.cpp | 213 |
3 files changed, 228 insertions, 1 deletions
diff --git a/tools/Makefile b/tools/Makefile index a31b52d8ab4..901db1dc9b5 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -35,7 +35,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \ llvm-diff macho-dump llvm-objdump llvm-readobj \ llvm-rtdyld llvm-dwarfdump llvm-cov \ llvm-size llvm-stress \ - le32-none-ndk-link + le32-none-ndk-link le32-none-ndk-strip # Let users override the set of tools to build from the command line. ifdef ONLY_TOOLS diff --git a/tools/le32-none-ndk-strip/Makefile b/tools/le32-none-ndk-strip/Makefile new file mode 100644 index 00000000000..c71e2f6977a --- /dev/null +++ b/tools/le32-none-ndk-strip/Makefile @@ -0,0 +1,14 @@ +LEVEL := ../.. + +TOOLNAME = le32-none-ndk-strip + +LINK_COMPONENTS := asmparser bitreader bitwriter codegen \ + instrumentation ipo linker selectiondag + +USEDLIBS := LLVMWrap.a + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common + diff --git a/tools/le32-none-ndk-strip/le32-none-ndk-strip.cpp b/tools/le32-none-ndk-strip/le32-none-ndk-strip.cpp new file mode 100644 index 00000000000..22c2941d0ca --- /dev/null +++ b/tools/le32-none-ndk-strip/le32-none-ndk-strip.cpp @@ -0,0 +1,213 @@ +/* + * Copyright 2013, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <fcntl.h> +#include <unistd.h> +#include <cstdlib> +#include <vector> +#include <utility> + +#include "llvm/LLVMContext.h" +#include "llvm/Module.h" +#include "llvm/PassManager.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Bitcode/ReaderWriter.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/FileUtilities.h" +#include "llvm/Support/IRReader.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/ToolOutputFile.h" +#include "llvm/Target/TargetData.h" +#include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/PassManagerBuilder.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Wrap/BitcodeWrapper.h" + +using namespace llvm; + +static cl::opt<std::string> +InputFilename(cl::Positional, cl::desc("<input bitcode file>"), + cl::value_desc("filename")); + +static cl::opt<std::string> +OutputFilename("o", cl::desc("Override output filename"), + cl::value_desc("filename")); + +static cl::opt<bool> +Strip("strip-all", cl::desc("Strip all symbol info")); + +static cl::opt<bool> +StripDebug("strip-debug", cl::desc("Strip debugger symbol info")); + +static cl::alias A0("s", cl::desc("Alias for --strip-all"), + cl::aliasopt(Strip)); + +static cl::alias A1("S", cl::desc("Alias for --strip-debug"), + cl::aliasopt(StripDebug)); + +static cl::alias A2("strip-unneeded", cl::desc("Alias for -strip-all"), + cl::aliasopt(Strip)); + + +static uint32_t ReadInt32(unsigned char *wrapper, size_t offset) { + uint32_t value = wrapper[offset] | + wrapper[offset+1] << 8 | + wrapper[offset+2] << 16 | + wrapper[offset+3] << 24; + return value; +} + +static void WriteInt32(unsigned char *wrapper, unsigned offset, uint32_t value) +{ + wrapper[offset ] = value & 0x000000ff; + wrapper[offset+1] = (value & 0x0000ff00) >> 8; + wrapper[offset+2] = (value & 0x00ff0000) >> 16; + wrapper[offset+3] = (value & 0xff000000) >> 24; +} + +static size_t ReadBitcodeWrapper(int input_fd, unsigned char **wrapper, size_t& bitcode_size) { + size_t buffer_size = 1024; + size_t fixed_field_size = 7*4; + + *wrapper = (unsigned char*) calloc(1, buffer_size); + size_t nread = read(input_fd, (void*) *wrapper, fixed_field_size); + + if (nread != fixed_field_size) { + errs() << "Could not read bitcode header\n"; + exit(1); + } + + if (!isBitcodeWrapper((const unsigned char *) *wrapper, + (const unsigned char *) *wrapper+fixed_field_size)) { + errs() << "Input file is not bitcode wrapper\n"; + exit(0); + } + + size_t offset_field = 2*4; + size_t size_field = 3*4; + size_t header_size = ReadInt32(*wrapper, offset_field); + bitcode_size = ReadInt32(*wrapper, size_field); + + if (header_size > buffer_size) { + *wrapper = (unsigned char*) realloc((void *) *wrapper, header_size); + } + + size_t variable_field_size = header_size-fixed_field_size; + if (variable_field_size > 0) { + nread = read(input_fd, (void*) ((*wrapper)+fixed_field_size), variable_field_size); + if (nread != (variable_field_size)) { + errs() << "Could not read bitcode header\n"; + exit(1); + } + } + + return header_size; +} + + +static void StripBitcode(const char *Bitcode, size_t BitcodeSize, std::string &BCString, LLVMContext &Context) { + StringRef input_data(Bitcode, BitcodeSize); + MemoryBuffer *buffer = MemoryBuffer::getMemBuffer(input_data, "", false); + + std::string ParseErrorMessage; + Module *Result = ParseBitcodeFile(buffer, Context, &ParseErrorMessage); + + if (!ParseErrorMessage.empty()) { + errs() << ParseErrorMessage << '\n'; + } + + std::auto_ptr<Module> M(Result); + raw_string_ostream BCStream(BCString); + + PassManager PM; + + PM.add(createVerifierPass()); + PM.add(new TargetData(M.get())); + + // Strip debug info and symbols. + if (Strip || StripDebug) + PM.add(createStripSymbolsPass(StripDebug && !Strip)); + + PM.add(createBitcodeWriterPass(BCStream)); + PM.run(*M.get()); + BCStream.flush(); +} + +int main(int argc, char **argv) { + + sys::PrintStackTraceOnErrorSignal(); + llvm::PrettyStackTraceProgram X(argc, argv); + + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + LLVMContext &Context = getGlobalContext(); + + cl::ParseCommandLineOptions(argc, argv, "Bitcode strip tool\n"); + + int input_fd = open(InputFilename.c_str(), O_RDONLY); + + unsigned char *wrapper = NULL; + const char *bitcode = NULL; + + // Read bitcode wrapper + size_t bitcode_size = 0; + size_t wrapper_size = ReadBitcodeWrapper(input_fd, &wrapper, bitcode_size); + + // Read bitcode + bitcode = (const char*) calloc(1, bitcode_size); + size_t nread = read(input_fd, (void*) bitcode, bitcode_size); + if (nread != bitcode_size) { + errs() << "Could not read bitcode\n"; + return 1; + } + + // Strip bitcode + std::string BCString; + StripBitcode(bitcode, bitcode_size, BCString, Context); + + // Update bitcode size + WriteInt32(wrapper, 12, BCString.length()); + + // Output stripped bitcode + OwningPtr<tool_output_file> Out; + + // Default to input filename + if (OutputFilename.empty()) + OutputFilename = InputFilename; + + std::string ErrorInfo; + Out.reset(new tool_output_file(OutputFilename.c_str(), ErrorInfo, + raw_fd_ostream::F_Binary)); + if (!ErrorInfo.empty()) { + errs() << ErrorInfo << '\n'; + return 1; + } + + Out->os().write((const char *) wrapper, wrapper_size); + Out->os().write(BCString.c_str(), BCString.length()); + Out->keep(); + + // Clean up + free((void *) wrapper); + free((void *) bitcode); + close(input_fd); + + return 0; +} |