[llvm] a8016e2 - [sancov] Switch to OptTable from llvm::cl
Andrés Villegas via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 25 17:07:04 PDT 2023
Author: Andrés Villegas
Date: 2023-07-26T00:04:36Z
New Revision: a8016e296e6ec161897e7421c5efbc25a6aa3a9f
URL: https://github.com/llvm/llvm-project/commit/a8016e296e6ec161897e7421c5efbc25a6aa3a9f
DIFF: https://github.com/llvm/llvm-project/commit/a8016e296e6ec161897e7421c5efbc25a6aa3a9f.diff
LOG: [sancov] Switch to OptTable from llvm::cl
Switch the parse of command line options from llvm::cl to OptTable.
The motivation for this change is to continue adding llvm based tools
to the llvm driver multicall. For more information about the proposal
and motivation, please see https://discourse.llvm.org/t/rfc-llvm-busybox-proposal/58494
Reviewed By: leonardchan
Differential Revision: https://reviews.llvm.org/D155119
Added:
llvm/tools/sancov/Opts.td
Modified:
llvm/tools/sancov/CMakeLists.txt
llvm/tools/sancov/sancov.cpp
Removed:
################################################################################
diff --git a/llvm/tools/sancov/CMakeLists.txt b/llvm/tools/sancov/CMakeLists.txt
index 3fc1cacba3a6c2..71a1ced689c785 100644
--- a/llvm/tools/sancov/CMakeLists.txt
+++ b/llvm/tools/sancov/CMakeLists.txt
@@ -5,11 +5,19 @@ set(LLVM_LINK_COMPONENTS
MC
MCDisassembler
Object
+ Option
Support
Symbolize
TargetParser
)
+set(LLVM_TARGET_DEFINITIONS Opts.td)
+tablegen(LLVM Opts.inc -gen-opt-parser-defs)
+add_public_tablegen_target(SancovOptsTableGen)
+
add_llvm_tool(sancov
sancov.cpp
+
+ DEPENDS
+ SancovOptsTableGen
)
diff --git a/llvm/tools/sancov/Opts.td b/llvm/tools/sancov/Opts.td
new file mode 100644
index 00000000000000..2e8af81b2a40d3
--- /dev/null
+++ b/llvm/tools/sancov/Opts.td
@@ -0,0 +1,58 @@
+include "llvm/Option/OptParser.td"
+
+class F<string name, string help> : Flag<["-", "--"], name>, HelpText<help>;
+
+multiclass B<string name, string help1, string help2> {
+ def NAME: Flag<["-", "--"], name>, HelpText<help1>;
+ def no_ # NAME: Flag<["-", "--"], "no-" # name>, HelpText<help2>;
+}
+
+multiclass Eq<string name, string help> {
+ def NAME #_EQ : Joined<["-", "--"], name #"=">,
+ HelpText<help>;
+ def : Separate<["-", "--"], name>, Alias<!cast<Joined>(NAME #_EQ)>;
+}
+
+def generic_grp : OptionGroup<"Genric Options">, HelpText<"Generic Options">;
+def help : F<"help", "Display this help">, Group<generic_grp>;
+def : Flag<["-"], "h">, Alias<help>, HelpText<"Alias for --help">, Group<generic_grp>;
+def version : F<"version", "Display the version">, Group<generic_grp>;
+def : Flag<["-"], "v">, Alias<version>, HelpText<"Alias for --version">, Group<generic_grp>;
+
+def action_grp : OptionGroup<"Action">, HelpText<"Action (required)">;
+def print : F<"print", "Print coverage addresses">,
+ Group<action_grp>;
+def printCoveragePcs : F<"print-coverage-pcs", "Print coverage instrumentation points addresses.">,
+ Group<action_grp>;
+def coveredFunctions : F<"covered-functions", "Print all covered funcions.">,
+ Group<action_grp>;
+def notCoveredFunctions : F<"not-covered-functions", "Print all not covered funcions.">,
+ Group<action_grp>;
+def printCoverageStats : F<"print-coverage-stats", "Print coverage statistics.">,
+ Group<action_grp>;
+def htmlReport : F<"html-report", "REMOVED. Use -symbolize & coverage-report-server.py.">,
+ Group<action_grp>;
+def symbolize : F<"symbolize", "Produces a symbolized JSON report from binary report.">,
+ Group<action_grp>;
+def merge : F<"merge", "Merges reports.">,
+ Group<action_grp>;
+
+defm demangle : B<"demangle", "Demangle function names", "Do not demangle function names">;
+defm skipDeadFiles : B<"skip-dead-files", "Do not list dead source files in reports",
+ "List dead source files in reports">;
+defm useDefaultIgnoreList :
+ B<"use_default_ignorelist", "Use the default ignore list", "Don't use the default ignore list">,
+ Flags<[HelpHidden]>;
+
+// Compatibility aliases
+def : Flag<["-"], "demangle=0">, Alias<no_demangle>, HelpText<"Alias for --no-demangle">;
+def : Flag<["-"], "skip-dead-files=0">, Alias<no_skipDeadFiles>, HelpText<"Alias for --no-skip-dead-files">;
+def : Flag<["-"], "use_default_ignorelist=0">, Alias<no_useDefaultIgnoreList>, HelpText<"Alias for --no-use_default_ignore_list">;
+
+defm stripPathPrefix
+ : Eq<"strip_path_prefix", "Strip this prefix from files paths in reports">,
+ MetaVarName<"<string>">;
+
+defm ignorelist
+ : Eq<"ignorelist", "Ignorelist file (sanitizer ignorelist format)">,
+ MetaVarName<"<string>">;
diff --git a/llvm/tools/sancov/sancov.cpp b/llvm/tools/sancov/sancov.cpp
index 9d29e9a13315ce..12eca011c613e9 100644
--- a/llvm/tools/sancov/sancov.cpp
+++ b/llvm/tools/sancov/sancov.cpp
@@ -29,6 +29,8 @@
#include "llvm/Object/COFF.h"
#include "llvm/Object/MachO.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Errc.h"
@@ -55,9 +57,44 @@ using namespace llvm;
namespace {
-// --------- COMMAND LINE FLAGS ---------
+// Command-line option boilerplate.
+namespace {
+using namespace llvm::opt;
+enum ID {
+ OPT_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OPT_##ID,
+#include "Opts.inc"
+#undef OPTION
+};
-cl::OptionCategory Cat("sancov Options");
+#define PREFIX(NAME, VALUE) \
+ static constexpr StringLiteral NAME##_init[] = VALUE; \
+ static constexpr ArrayRef<StringLiteral> NAME(NAME##_init, \
+ std::size(NAME##_init) - 1);
+#include "Opts.inc"
+#undef PREFIX
+
+static constexpr opt::OptTable::Info InfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ { \
+ PREFIX, NAME, HELPTEXT, \
+ METAVAR, OPT_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, \
+ OPT_##ALIAS, ALIASARGS, VALUES},
+#include "Opts.inc"
+#undef OPTION
+};
+
+class SancovOptTable : public opt::GenericOptTable {
+public:
+ SancovOptTable() : GenericOptTable(InfoTable) {}
+};
+} // namespace
+
+// --------- COMMAND LINE FLAGS ---------
enum ActionType {
CoveredFunctionsAction,
@@ -70,53 +107,13 @@ enum ActionType {
SymbolizeAction
};
-cl::opt<ActionType> Action(
- cl::desc("Action (required)"), cl::Required,
- cl::values(
- clEnumValN(PrintAction, "print", "Print coverage addresses"),
- clEnumValN(PrintCovPointsAction, "print-coverage-pcs",
- "Print coverage instrumentation points addresses."),
- clEnumValN(CoveredFunctionsAction, "covered-functions",
- "Print all covered funcions."),
- clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
- "Print all not covered funcions."),
- clEnumValN(StatsAction, "print-coverage-stats",
- "Print coverage statistics."),
- clEnumValN(HtmlReportAction, "html-report",
- "REMOVED. Use -symbolize & coverage-report-server.py."),
- clEnumValN(SymbolizeAction, "symbolize",
- "Produces a symbolized JSON report from binary report."),
- clEnumValN(MergeAction, "merge", "Merges reports.")),
- cl::cat(Cat));
-
-static cl::list<std::string>
- ClInputFiles(cl::Positional, cl::OneOrMore,
- cl::desc("<action> <binary files...> <.sancov files...> "
- "<.symcov files...>"),
- cl::cat(Cat));
-
-static cl::opt<bool> ClDemangle("demangle", cl::init(true),
- cl::desc("Print demangled function name"),
- cl::cat(Cat));
-
-static cl::opt<bool>
- ClSkipDeadFiles("skip-dead-files", cl::init(true),
- cl::desc("Do not list dead source files in reports"),
- cl::cat(Cat));
-
-static cl::opt<std::string>
- ClStripPathPrefix("strip_path_prefix", cl::init(""),
- cl::desc("Strip this prefix from file paths in reports"),
- cl::cat(Cat));
-
-static cl::opt<std::string>
- ClIgnorelist("ignorelist", cl::init(""),
- cl::desc("Ignorelist file (sanitizer ignorelist format)"),
- cl::cat(Cat));
-
-static cl::opt<bool> ClUseDefaultIgnorelist(
- "use_default_ignorelist", cl::init(true), cl::Hidden,
- cl::desc("Controls if default ignorelist should be used"), cl::cat(Cat));
+static ActionType Action;
+static std::vector<std::string> ClInputFiles;
+static bool ClDemangle;
+static bool ClSkipDeadFiles;
+static bool ClUseDefaultIgnorelist;
+static std::string ClStripPathPrefix;
+static std::string ClIgnorelist;
static const char *const DefaultIgnorelistStr = "fun:__sanitizer_.*\n"
"src:/usr/include/.*\n"
@@ -699,8 +696,7 @@ findSanitizerCovFunctions(const object::ObjectFile &O) {
// Ported from
// compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h:GetPreviousInstructionPc
// GetPreviousInstructionPc.
-static uint64_t getPreviousInstructionPc(uint64_t PC,
- Triple TheTriple) {
+static uint64_t getPreviousInstructionPc(uint64_t PC, Triple TheTriple) {
if (TheTriple.isARM())
return (PC - 3) & (~1);
if (TheTriple.isMIPS() || TheTriple.isSPARC())
@@ -1145,31 +1141,101 @@ readSymbolizeAndMergeCmdArguments(std::vector<std::string> FileNames) {
} // namespace
+static void parseArgs(int Argc, char **Argv) {
+ SancovOptTable Tbl;
+ llvm::BumpPtrAllocator A;
+ llvm::StringSaver Saver{A};
+ opt::InputArgList Args =
+ Tbl.parseArgs(Argc, Argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
+ llvm::errs() << Msg << '\n';
+ std::exit(1);
+ });
+
+ if (Args.hasArg(OPT_help)) {
+ Tbl.printHelp(
+ llvm::outs(),
+ "sancov [options] <action> <binary files...> <.sancov files...> "
+ "<.symcov files...>",
+ "Sanitizer Coverage Processing Tool (sancov)\n\n"
+ " This tool can extract various coverage-related information from: \n"
+ " coverage-instrumented binary files, raw .sancov files and their "
+ "symbolized .symcov version.\n"
+ " Depending on chosen action the tool expects
diff erent input files:\n"
+ " -print-coverage-pcs - coverage-instrumented binary files\n"
+ " -print-coverage - .sancov files\n"
+ " <other actions> - .sancov files & corresponding binary "
+ "files, .symcov files\n");
+ std::exit(0);
+ }
+
+ if (Args.hasArg(OPT_version)) {
+ cl::PrintVersionMessage();
+ std::exit(0);
+ }
+
+ if (Args.hasMultipleArgs(OPT_action_grp)) {
+ fail("Only one action option is allowed");
+ }
+
+ for (const opt::Arg *A : Args.filtered(OPT_INPUT)) {
+ ClInputFiles.emplace_back(A->getValue());
+ }
+
+ if (const llvm::opt::Arg *A = Args.getLastArg(OPT_action_grp)) {
+ switch (A->getOption().getID()) {
+ case OPT_print:
+ Action = ActionType::PrintAction;
+ break;
+ case OPT_printCoveragePcs:
+ Action = ActionType::PrintCovPointsAction;
+ break;
+ case OPT_coveredFunctions:
+ Action = ActionType::CoveredFunctionsAction;
+ break;
+ case OPT_notCoveredFunctions:
+ Action = ActionType::NotCoveredFunctionsAction;
+ break;
+ case OPT_printCoverageStats:
+ Action = ActionType::StatsAction;
+ break;
+ case OPT_htmlReport:
+ Action = ActionType::HtmlReportAction;
+ break;
+ case OPT_symbolize:
+ Action = ActionType::SymbolizeAction;
+ break;
+ case OPT_merge:
+ Action = ActionType::MergeAction;
+ break;
+ default:
+ fail("Invalid Action");
+ }
+ }
+
+ ClDemangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true);
+ ClSkipDeadFiles = Args.hasFlag(OPT_skipDeadFiles, OPT_no_skipDeadFiles, true);
+ ClUseDefaultIgnorelist =
+ Args.hasFlag(OPT_useDefaultIgnoreList, OPT_no_useDefaultIgnoreList, true);
+
+ ClStripPathPrefix = Args.getLastArgValue(OPT_stripPathPrefix_EQ);
+ ClIgnorelist = Args.getLastArgValue(OPT_ignorelist_EQ);
+}
+
int main(int Argc, char **Argv) {
llvm::InitLLVM X(Argc, Argv);
- cl::HideUnrelatedOptions(Cat);
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllDisassemblers();
- cl::ParseCommandLineOptions(Argc, Argv,
- "Sanitizer Coverage Processing Tool (sancov)\n\n"
- " This tool can extract various coverage-related information from: \n"
- " coverage-instrumented binary files, raw .sancov files and their "
- "symbolized .symcov version.\n"
- " Depending on chosen action the tool expects
diff erent input files:\n"
- " -print-coverage-pcs - coverage-instrumented binary files\n"
- " -print-coverage - .sancov files\n"
- " <other actions> - .sancov files & corresponding binary "
- "files, .symcov files\n"
- );
+ parseArgs(Argc, Argv);
// -print doesn't need object files.
if (Action == PrintAction) {
readAndPrintRawCoverage(ClInputFiles, outs());
return 0;
- } else if (Action == PrintCovPointsAction) {
+ }
+ if (Action == PrintCovPointsAction) {
// -print-coverage-points doesn't need coverage files.
for (const std::string &ObjFile : ClInputFiles) {
printCovPoints(ObjFile, outs());
More information about the llvm-commits
mailing list