llvm-strings.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. //===-- llvm-strings.cpp - Printable String dumping utility ---------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This program is a utility that works like binutils "strings", that is, it
  10. // prints out printable strings in a binary, objdump, or archive file.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "Opts.inc"
  14. #include "llvm/Object/Binary.h"
  15. #include "llvm/Option/Arg.h"
  16. #include "llvm/Option/ArgList.h"
  17. #include "llvm/Option/Option.h"
  18. #include "llvm/Support/CommandLine.h"
  19. #include "llvm/Support/Error.h"
  20. #include "llvm/Support/Format.h"
  21. #include "llvm/Support/InitLLVM.h"
  22. #include "llvm/Support/MemoryBuffer.h"
  23. #include "llvm/Support/Program.h"
  24. #include "llvm/Support/WithColor.h"
  25. #include <cctype>
  26. #include <string>
  27. using namespace llvm;
  28. using namespace llvm::object;
  29. namespace {
  30. enum ID {
  31. OPT_INVALID = 0, // This is not an option ID.
  32. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  33. HELPTEXT, METAVAR, VALUES) \
  34. OPT_##ID,
  35. #include "Opts.inc"
  36. #undef OPTION
  37. };
  38. #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
  39. #include "Opts.inc"
  40. #undef PREFIX
  41. const opt::OptTable::Info InfoTable[] = {
  42. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
  43. HELPTEXT, METAVAR, VALUES) \
  44. { \
  45. PREFIX, NAME, HELPTEXT, \
  46. METAVAR, OPT_##ID, opt::Option::KIND##Class, \
  47. PARAM, FLAGS, OPT_##GROUP, \
  48. OPT_##ALIAS, ALIASARGS, VALUES},
  49. #include "Opts.inc"
  50. #undef OPTION
  51. };
  52. class StringsOptTable : public opt::OptTable {
  53. public:
  54. StringsOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
  55. };
  56. } // namespace
  57. static StringRef ToolName;
  58. static cl::list<std::string> InputFileNames(cl::Positional,
  59. cl::desc("<input object files>"),
  60. cl::ZeroOrMore);
  61. static int MinLength = 4;
  62. static bool PrintFileName;
  63. enum radix { none, octal, hexadecimal, decimal };
  64. static radix Radix;
  65. [[noreturn]] static void reportCmdLineError(const Twine &Message) {
  66. WithColor::error(errs(), ToolName) << Message << "\n";
  67. exit(1);
  68. }
  69. template <typename T>
  70. static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {
  71. if (const opt::Arg *A = Args.getLastArg(ID)) {
  72. StringRef V(A->getValue());
  73. if (!llvm::to_integer(V, Value, 0) || Value <= 0)
  74. reportCmdLineError("expected a positive integer, but got '" + V + "'");
  75. }
  76. }
  77. static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) {
  78. auto print = [&OS, FileName](unsigned Offset, StringRef L) {
  79. if (L.size() < static_cast<size_t>(MinLength))
  80. return;
  81. if (PrintFileName)
  82. OS << FileName << ": ";
  83. switch (Radix) {
  84. case none:
  85. break;
  86. case octal:
  87. OS << format("%7o ", Offset);
  88. break;
  89. case hexadecimal:
  90. OS << format("%7x ", Offset);
  91. break;
  92. case decimal:
  93. OS << format("%7u ", Offset);
  94. break;
  95. }
  96. OS << L << '\n';
  97. };
  98. const char *B = Contents.begin();
  99. const char *P = nullptr, *E = nullptr, *S = nullptr;
  100. for (P = Contents.begin(), E = Contents.end(); P < E; ++P) {
  101. if (isPrint(*P) || *P == '\t') {
  102. if (S == nullptr)
  103. S = P;
  104. } else if (S) {
  105. print(S - B, StringRef(S, P - S));
  106. S = nullptr;
  107. }
  108. }
  109. if (S)
  110. print(S - B, StringRef(S, E - S));
  111. }
  112. int main(int argc, char **argv) {
  113. InitLLVM X(argc, argv);
  114. BumpPtrAllocator A;
  115. StringSaver Saver(A);
  116. StringsOptTable Tbl;
  117. ToolName = argv[0];
  118. opt::InputArgList Args =
  119. Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,
  120. [&](StringRef Msg) { reportCmdLineError(Msg); });
  121. if (Args.hasArg(OPT_help)) {
  122. Tbl.printHelp(
  123. outs(),
  124. (Twine(ToolName) + " [options] <input object files>").str().c_str(),
  125. "llvm string dumper");
  126. // TODO Replace this with OptTable API once it adds extrahelp support.
  127. outs() << "\nPass @FILE as argument to read options from FILE.\n";
  128. return 0;
  129. }
  130. if (Args.hasArg(OPT_version)) {
  131. outs() << ToolName << '\n';
  132. cl::PrintVersionMessage();
  133. return 0;
  134. }
  135. parseIntArg(Args, OPT_bytes_EQ, MinLength);
  136. PrintFileName = Args.hasArg(OPT_print_file_name);
  137. StringRef R = Args.getLastArgValue(OPT_radix_EQ);
  138. if (R.empty())
  139. Radix = none;
  140. else if (R == "o")
  141. Radix = octal;
  142. else if (R == "d")
  143. Radix = decimal;
  144. else if (R == "x")
  145. Radix = hexadecimal;
  146. else
  147. reportCmdLineError("--radix value should be one of: '' (no offset), 'o' "
  148. "(octal), 'd' (decimal), 'x' (hexadecimal)");
  149. if (MinLength == 0) {
  150. errs() << "invalid minimum string length 0\n";
  151. return EXIT_FAILURE;
  152. }
  153. std::vector<std::string> InputFileNames = Args.getAllArgValues(OPT_INPUT);
  154. if (InputFileNames.empty())
  155. InputFileNames.push_back("-");
  156. for (const auto &File : InputFileNames) {
  157. ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
  158. MemoryBuffer::getFileOrSTDIN(File);
  159. if (std::error_code EC = Buffer.getError())
  160. errs() << File << ": " << EC.message() << '\n';
  161. else
  162. strings(llvm::outs(), File == "-" ? "{standard input}" : File,
  163. Buffer.get()->getMemBufferRef().getBuffer());
  164. }
  165. return EXIT_SUCCESS;
  166. }