1030ff0f2SSaleem Abdulrasool //===-- llvm-strings.cpp - Printable String dumping utility ---------------===//
2030ff0f2SSaleem Abdulrasool //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6030ff0f2SSaleem Abdulrasool //
7030ff0f2SSaleem Abdulrasool //===----------------------------------------------------------------------===//
8030ff0f2SSaleem Abdulrasool //
9030ff0f2SSaleem Abdulrasool // This program is a utility that works like binutils "strings", that is, it
10030ff0f2SSaleem Abdulrasool // prints out printable strings in a binary, objdump, or archive file.
11030ff0f2SSaleem Abdulrasool //
12030ff0f2SSaleem Abdulrasool //===----------------------------------------------------------------------===//
13030ff0f2SSaleem Abdulrasool
1498f07832SFangrui Song #include "Opts.inc"
15030ff0f2SSaleem Abdulrasool #include "llvm/Object/Binary.h"
1698f07832SFangrui Song #include "llvm/Option/Arg.h"
1798f07832SFangrui Song #include "llvm/Option/ArgList.h"
1898f07832SFangrui Song #include "llvm/Option/Option.h"
19030ff0f2SSaleem Abdulrasool #include "llvm/Support/CommandLine.h"
20030ff0f2SSaleem Abdulrasool #include "llvm/Support/Error.h"
21ba048618SSaleem Abdulrasool #include "llvm/Support/Format.h"
22197194b6SRui Ueyama #include "llvm/Support/InitLLVM.h"
23030ff0f2SSaleem Abdulrasool #include "llvm/Support/MemoryBuffer.h"
24030ff0f2SSaleem Abdulrasool #include "llvm/Support/Program.h"
2598f07832SFangrui Song #include "llvm/Support/WithColor.h"
262dcea63bSSaleem Abdulrasool #include <cctype>
27030ff0f2SSaleem Abdulrasool #include <string>
28030ff0f2SSaleem Abdulrasool
29030ff0f2SSaleem Abdulrasool using namespace llvm;
30030ff0f2SSaleem Abdulrasool using namespace llvm::object;
31030ff0f2SSaleem Abdulrasool
3298f07832SFangrui Song namespace {
3398f07832SFangrui Song enum ID {
3498f07832SFangrui Song OPT_INVALID = 0, // This is not an option ID.
3598f07832SFangrui Song #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
3698f07832SFangrui Song HELPTEXT, METAVAR, VALUES) \
3798f07832SFangrui Song OPT_##ID,
3898f07832SFangrui Song #include "Opts.inc"
3998f07832SFangrui Song #undef OPTION
4098f07832SFangrui Song };
4198f07832SFangrui Song
4298f07832SFangrui Song #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
4398f07832SFangrui Song #include "Opts.inc"
4498f07832SFangrui Song #undef PREFIX
4598f07832SFangrui Song
468189c4eeSFangrui Song const opt::OptTable::Info InfoTable[] = {
4798f07832SFangrui Song #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
4898f07832SFangrui Song HELPTEXT, METAVAR, VALUES) \
4998f07832SFangrui Song { \
5098f07832SFangrui Song PREFIX, NAME, HELPTEXT, \
5198f07832SFangrui Song METAVAR, OPT_##ID, opt::Option::KIND##Class, \
5298f07832SFangrui Song PARAM, FLAGS, OPT_##GROUP, \
5398f07832SFangrui Song OPT_##ALIAS, ALIASARGS, VALUES},
5498f07832SFangrui Song #include "Opts.inc"
5598f07832SFangrui Song #undef OPTION
5698f07832SFangrui Song };
5798f07832SFangrui Song
5898f07832SFangrui Song class StringsOptTable : public opt::OptTable {
5998f07832SFangrui Song public:
StringsOptTable()6098f07832SFangrui Song StringsOptTable() : OptTable(InfoTable) { setGroupedShortOptions(true); }
6198f07832SFangrui Song };
6298f07832SFangrui Song } // namespace
6398f07832SFangrui Song
64b30a18f4Sgbreynoo static StringRef ToolName;
6598f07832SFangrui Song
66030ff0f2SSaleem Abdulrasool static cl::list<std::string> InputFileNames(cl::Positional,
67*95a13425SFangrui Song cl::desc("<input object files>"));
68030ff0f2SSaleem Abdulrasool
6998f07832SFangrui Song static int MinLength = 4;
7098f07832SFangrui Song static bool PrintFileName;
716835cac2SMartin Storsjo
72ba048618SSaleem Abdulrasool enum radix { none, octal, hexadecimal, decimal };
7398f07832SFangrui Song static radix Radix;
74ba048618SSaleem Abdulrasool
reportCmdLineError(const Twine & Message)756da3d8b1SFangrui Song [[noreturn]] static void reportCmdLineError(const Twine &Message) {
7698f07832SFangrui Song WithColor::error(errs(), ToolName) << Message << "\n";
7798f07832SFangrui Song exit(1);
7898f07832SFangrui Song }
7998f07832SFangrui Song
8098f07832SFangrui Song template <typename T>
parseIntArg(const opt::InputArgList & Args,int ID,T & Value)8198f07832SFangrui Song static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {
8298f07832SFangrui Song if (const opt::Arg *A = Args.getLastArg(ID)) {
8398f07832SFangrui Song StringRef V(A->getValue());
8498f07832SFangrui Song if (!llvm::to_integer(V, Value, 0) || Value <= 0)
8598f07832SFangrui Song reportCmdLineError("expected a positive integer, but got '" + V + "'");
8698f07832SFangrui Song }
8798f07832SFangrui Song }
889485b265SJames Henderson
strings(raw_ostream & OS,StringRef FileName,StringRef Contents)89f10a8714SSaleem Abdulrasool static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) {
90ba048618SSaleem Abdulrasool auto print = [&OS, FileName](unsigned Offset, StringRef L) {
91f7009b42SSaleem Abdulrasool if (L.size() < static_cast<size_t>(MinLength))
92f7009b42SSaleem Abdulrasool return;
93f10a8714SSaleem Abdulrasool if (PrintFileName)
94f10a8714SSaleem Abdulrasool OS << FileName << ": ";
95ba048618SSaleem Abdulrasool switch (Radix) {
96ba048618SSaleem Abdulrasool case none:
97ba048618SSaleem Abdulrasool break;
98ba048618SSaleem Abdulrasool case octal:
99dcf1f8e7SJordan Rupprecht OS << format("%7o ", Offset);
100ba048618SSaleem Abdulrasool break;
101ba048618SSaleem Abdulrasool case hexadecimal:
102dcf1f8e7SJordan Rupprecht OS << format("%7x ", Offset);
103ba048618SSaleem Abdulrasool break;
104ba048618SSaleem Abdulrasool case decimal:
105dcf1f8e7SJordan Rupprecht OS << format("%7u ", Offset);
106ba048618SSaleem Abdulrasool break;
107ba048618SSaleem Abdulrasool }
108dcf1f8e7SJordan Rupprecht OS << L << '\n';
109f10a8714SSaleem Abdulrasool };
110f10a8714SSaleem Abdulrasool
111ba048618SSaleem Abdulrasool const char *B = Contents.begin();
1122729786fSSaleem Abdulrasool const char *P = nullptr, *E = nullptr, *S = nullptr;
1132729786fSSaleem Abdulrasool for (P = Contents.begin(), E = Contents.end(); P < E; ++P) {
1145b2e9682SJames Henderson if (isPrint(*P) || *P == '\t') {
115030ff0f2SSaleem Abdulrasool if (S == nullptr)
116030ff0f2SSaleem Abdulrasool S = P;
117030ff0f2SSaleem Abdulrasool } else if (S) {
118ba048618SSaleem Abdulrasool print(S - B, StringRef(S, P - S));
119030ff0f2SSaleem Abdulrasool S = nullptr;
120030ff0f2SSaleem Abdulrasool }
121030ff0f2SSaleem Abdulrasool }
122f7009b42SSaleem Abdulrasool if (S)
123ba048618SSaleem Abdulrasool print(S - B, StringRef(S, E - S));
124030ff0f2SSaleem Abdulrasool }
125030ff0f2SSaleem Abdulrasool
main(int argc,char ** argv)126030ff0f2SSaleem Abdulrasool int main(int argc, char **argv) {
127197194b6SRui Ueyama InitLLVM X(argc, argv);
12898f07832SFangrui Song BumpPtrAllocator A;
12998f07832SFangrui Song StringSaver Saver(A);
13098f07832SFangrui Song StringsOptTable Tbl;
131b30a18f4Sgbreynoo ToolName = argv[0];
13298f07832SFangrui Song opt::InputArgList Args =
13398f07832SFangrui Song Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,
13498f07832SFangrui Song [&](StringRef Msg) { reportCmdLineError(Msg); });
13598f07832SFangrui Song if (Args.hasArg(OPT_help)) {
13698f07832SFangrui Song Tbl.printHelp(
13798f07832SFangrui Song outs(),
13898f07832SFangrui Song (Twine(ToolName) + " [options] <input object files>").str().c_str(),
13998f07832SFangrui Song "llvm string dumper");
14098f07832SFangrui Song // TODO Replace this with OptTable API once it adds extrahelp support.
14198f07832SFangrui Song outs() << "\nPass @FILE as argument to read options from FILE.\n";
14298f07832SFangrui Song return 0;
14398f07832SFangrui Song }
14498f07832SFangrui Song if (Args.hasArg(OPT_version)) {
14598f07832SFangrui Song outs() << ToolName << '\n';
14698f07832SFangrui Song cl::PrintVersionMessage();
14798f07832SFangrui Song return 0;
14898f07832SFangrui Song }
149030ff0f2SSaleem Abdulrasool
15098f07832SFangrui Song parseIntArg(Args, OPT_bytes_EQ, MinLength);
15198f07832SFangrui Song PrintFileName = Args.hasArg(OPT_print_file_name);
15298f07832SFangrui Song StringRef R = Args.getLastArgValue(OPT_radix_EQ);
15398f07832SFangrui Song if (R.empty())
15498f07832SFangrui Song Radix = none;
15598f07832SFangrui Song else if (R == "o")
15698f07832SFangrui Song Radix = octal;
15798f07832SFangrui Song else if (R == "d")
15898f07832SFangrui Song Radix = decimal;
15998f07832SFangrui Song else if (R == "x")
16098f07832SFangrui Song Radix = hexadecimal;
16198f07832SFangrui Song else
16298f07832SFangrui Song reportCmdLineError("--radix value should be one of: '' (no offset), 'o' "
16398f07832SFangrui Song "(octal), 'd' (decimal), 'x' (hexadecimal)");
16498f07832SFangrui Song
165f7009b42SSaleem Abdulrasool if (MinLength == 0) {
166f7009b42SSaleem Abdulrasool errs() << "invalid minimum string length 0\n";
167f7009b42SSaleem Abdulrasool return EXIT_FAILURE;
168f7009b42SSaleem Abdulrasool }
169030ff0f2SSaleem Abdulrasool
17098f07832SFangrui Song std::vector<std::string> InputFileNames = Args.getAllArgValues(OPT_INPUT);
171030ff0f2SSaleem Abdulrasool if (InputFileNames.empty())
172030ff0f2SSaleem Abdulrasool InputFileNames.push_back("-");
173030ff0f2SSaleem Abdulrasool
174be3a2919SSaleem Abdulrasool for (const auto &File : InputFileNames) {
175be3a2919SSaleem Abdulrasool ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
176be3a2919SSaleem Abdulrasool MemoryBuffer::getFileOrSTDIN(File);
177be3a2919SSaleem Abdulrasool if (std::error_code EC = Buffer.getError())
178be3a2919SSaleem Abdulrasool errs() << File << ": " << EC.message() << '\n';
179be3a2919SSaleem Abdulrasool else
180f10a8714SSaleem Abdulrasool strings(llvm::outs(), File == "-" ? "{standard input}" : File,
181f10a8714SSaleem Abdulrasool Buffer.get()->getMemBufferRef().getBuffer());
182030ff0f2SSaleem Abdulrasool }
183030ff0f2SSaleem Abdulrasool
184be3a2919SSaleem Abdulrasool return EXIT_SUCCESS;
185be3a2919SSaleem Abdulrasool }
186