Path: blob/main/contrib/llvm-project/llvm/tools/llvm-strings/llvm-strings.cpp
35260 views
//===-- llvm-strings.cpp - Printable String dumping utility ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This program is a utility that works like binutils "strings", that is, it9// prints out printable strings in a binary, objdump, or archive file.10//11//===----------------------------------------------------------------------===//1213#include "Opts.inc"14#include "llvm/ADT/StringExtras.h"15#include "llvm/Object/Binary.h"16#include "llvm/Option/Arg.h"17#include "llvm/Option/ArgList.h"18#include "llvm/Option/Option.h"19#include "llvm/Support/CommandLine.h"20#include "llvm/Support/Error.h"21#include "llvm/Support/Format.h"22#include "llvm/Support/InitLLVM.h"23#include "llvm/Support/MemoryBuffer.h"24#include "llvm/Support/Program.h"25#include "llvm/Support/WithColor.h"26#include <cctype>27#include <string>2829using namespace llvm;30using namespace llvm::object;3132namespace {33enum ID {34OPT_INVALID = 0, // This is not an option ID.35#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),36#include "Opts.inc"37#undef OPTION38};3940#define PREFIX(NAME, VALUE) \41static constexpr StringLiteral NAME##_init[] = VALUE; \42static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \43std::size(NAME##_init) - 1);44#include "Opts.inc"45#undef PREFIX4647using namespace llvm::opt;48static constexpr opt::OptTable::Info InfoTable[] = {49#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),50#include "Opts.inc"51#undef OPTION52};5354class StringsOptTable : public opt::GenericOptTable {55public:56StringsOptTable() : GenericOptTable(InfoTable) {57setGroupedShortOptions(true);58setDashDashParsing(true);59}60};61} // namespace6263static StringRef ToolName;6465static cl::list<std::string> InputFileNames(cl::Positional,66cl::desc("<input object files>"));6768static int MinLength = 4;69static bool PrintFileName;7071enum radix { none, octal, hexadecimal, decimal };72static radix Radix;7374[[noreturn]] static void reportCmdLineError(const Twine &Message) {75WithColor::error(errs(), ToolName) << Message << "\n";76exit(1);77}7879template <typename T>80static void parseIntArg(const opt::InputArgList &Args, int ID, T &Value) {81if (const opt::Arg *A = Args.getLastArg(ID)) {82StringRef V(A->getValue());83if (!llvm::to_integer(V, Value, 0) || Value <= 0)84reportCmdLineError("expected a positive integer, but got '" + V + "'");85}86}8788static void strings(raw_ostream &OS, StringRef FileName, StringRef Contents) {89auto print = [&OS, FileName](unsigned Offset, StringRef L) {90if (L.size() < static_cast<size_t>(MinLength))91return;92if (PrintFileName)93OS << FileName << ": ";94switch (Radix) {95case none:96break;97case octal:98OS << format("%7o ", Offset);99break;100case hexadecimal:101OS << format("%7x ", Offset);102break;103case decimal:104OS << format("%7u ", Offset);105break;106}107OS << L << '\n';108};109110const char *B = Contents.begin();111const char *P = nullptr, *E = nullptr, *S = nullptr;112for (P = Contents.begin(), E = Contents.end(); P < E; ++P) {113if (isPrint(*P) || *P == '\t') {114if (S == nullptr)115S = P;116} else if (S) {117print(S - B, StringRef(S, P - S));118S = nullptr;119}120}121if (S)122print(S - B, StringRef(S, E - S));123}124125int main(int argc, char **argv) {126InitLLVM X(argc, argv);127BumpPtrAllocator A;128StringSaver Saver(A);129StringsOptTable Tbl;130ToolName = argv[0];131opt::InputArgList Args =132Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver,133[&](StringRef Msg) { reportCmdLineError(Msg); });134if (Args.hasArg(OPT_help)) {135Tbl.printHelp(136outs(),137(Twine(ToolName) + " [options] <input object files>").str().c_str(),138"llvm string dumper");139// TODO Replace this with OptTable API once it adds extrahelp support.140outs() << "\nPass @FILE as argument to read options from FILE.\n";141return 0;142}143if (Args.hasArg(OPT_version)) {144outs() << ToolName << '\n';145cl::PrintVersionMessage();146return 0;147}148149parseIntArg(Args, OPT_bytes_EQ, MinLength);150PrintFileName = Args.hasArg(OPT_print_file_name);151StringRef R = Args.getLastArgValue(OPT_radix_EQ);152if (R.empty())153Radix = none;154else if (R == "o")155Radix = octal;156else if (R == "d")157Radix = decimal;158else if (R == "x")159Radix = hexadecimal;160else161reportCmdLineError("--radix value should be one of: '' (no offset), 'o' "162"(octal), 'd' (decimal), 'x' (hexadecimal)");163164if (MinLength == 0) {165errs() << "invalid minimum string length 0\n";166return EXIT_FAILURE;167}168169std::vector<std::string> InputFileNames = Args.getAllArgValues(OPT_INPUT);170if (InputFileNames.empty())171InputFileNames.push_back("-");172173for (const auto &File : InputFileNames) {174ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =175MemoryBuffer::getFileOrSTDIN(File);176if (std::error_code EC = Buffer.getError())177errs() << File << ": " << EC.message() << '\n';178else179strings(llvm::outs(), File == "-" ? "{standard input}" : File,180Buffer.get()->getMemBufferRef().getBuffer());181}182183return EXIT_SUCCESS;184}185186187