diff --git a/tools/llvm-strings/CMakeLists.txt b/tools/llvm-strings/CMakeLists.txt new file mode 100644 index 00000000000..6d217aa717f --- /dev/null +++ b/tools/llvm-strings/CMakeLists.txt @@ -0,0 +1,8 @@ +set(LLVM_LINK_COMPONENTS + Object + ) + +add_llvm_tool(llvm-strings + llvm-strings.cpp + ) + diff --git a/tools/llvm-strings/LLVMBuild.txt b/tools/llvm-strings/LLVMBuild.txt new file mode 100644 index 00000000000..9cd41d0eebf --- /dev/null +++ b/tools/llvm-strings/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-strings/LLVMBuild.txt -----------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-strings +parent = Tools +required_libraries = Archive Object diff --git a/tools/llvm-strings/llvm-strings.cpp b/tools/llvm-strings/llvm-strings.cpp new file mode 100644 index 00000000000..daabcd6e6d9 --- /dev/null +++ b/tools/llvm-strings/llvm-strings.cpp @@ -0,0 +1,120 @@ +//===-- llvm-strings.cpp - Printable String dumping utility ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This program is a utility that works like binutils "strings", that is, it +// prints out printable strings in a binary, objdump, or archive file. +// +//===----------------------------------------------------------------------===// + +#include "llvm/IR/LLVMContext.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include + +using namespace llvm; +using namespace llvm::object; + +static cl::list InputFileNames(cl::Positional, + cl::desc(""), + cl::ZeroOrMore); + +static void dump(raw_ostream &OS, StringRef Contents) { + const char *S = nullptr; + for (const char *P = Contents.begin(), *E = Contents.end(); P < E; ++P) { + if (std::isgraph(*P) || std::isblank(*P)) { + if (S == nullptr) + S = P; + } else if (S) { + if (P - S > 3) + OS << StringRef(S, P - S) << '\n'; + S = nullptr; + } + } +} + +namespace { +class Strings { + LLVMContext Context; + raw_ostream &OS; + + void dump(const ObjectFile *O) { + for (const auto &S : O->sections()) { + StringRef Contents; + if (!S.getContents(Contents)) + ::dump(OS, Contents); + } + } + + void dump(const Archive *A) { + Error E; + for (auto &Element : A->children(E)) { + if (Expected> Child = + Element.getAsBinary(&Context)) { + dump(dyn_cast(&**Child)); + } else { + if (auto E = isNotObjectErrorInvalidFileType(Child.takeError())) { + errs() << A->getFileName(); + if (Expected Name = Element.getName()) + errs() << '(' << *Name << ')'; + logAllUnhandledErrors(std::move(E), errs(), ""); + errs() << '\n'; + } + } + } + static_cast(E); + } + +public: + Strings(raw_ostream &S) : OS(S) {} + + void scan(StringRef File) { + ErrorOr> Buffer = + MemoryBuffer::getFileOrSTDIN(File); + if (std::error_code EC = Buffer.getError()) { + errs() << File << ": " << EC.message() << '\n'; + return; + } + + if (Expected> B = + createBinary(Buffer.get()->getMemBufferRef(), &Context)) { + if (auto *A = dyn_cast(&**B)) + return dump(A); + if (auto *O = dyn_cast(&**B)) + return dump(O); + ::dump(OS, Buffer.get()->getMemBufferRef().getBuffer()); + } else { + consumeError(B.takeError()); + ::dump(OS, Buffer.get()->getMemBufferRef().getBuffer()); + } + } +}; +} + +int main(int argc, char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + PrettyStackTraceProgram X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, "llvm string dumper\n"); + + if (InputFileNames.empty()) + InputFileNames.push_back("-"); + + Strings S(llvm::outs()); + std::for_each(InputFileNames.begin(), InputFileNames.end(), + [&S](StringRef F) { S.scan(F); }); + return EXIT_SUCCESS; +} +