diff --git a/llvm/test/tools/llvm-gsymutil/cmdline.test b/llvm/test/tools/llvm-gsymutil/cmdline.test --- a/llvm/test/tools/llvm-gsymutil/cmdline.test +++ b/llvm/test/tools/llvm-gsymutil/cmdline.test @@ -3,21 +3,17 @@ HELP: OVERVIEW: A tool for dumping, searching and creating GSYM files. HELP: USAGE: llvm-gsymutil{{[^ ]*}} [options] HELP: OPTIONS: -HELP: Conversion Options: -HELP: --arch= -HELP: --convert= -HELP: --num-threads= -HELP: --out-file= +HELP: --address= +HELP: --addresses-from-stdin +HELP: --arch= +HELP: --convert= +HELP: --help +HELP: --num-threads= +HELP: --out-file= HELP: --quiet +HELP: --verbose HELP: --verify -HELP: Generic Options: -HELP: --help HELP: --version -HELP: Lookup Options: -HELP: --address= -HELP: --addresses-from-stdin -HELP: Options: -HELP: --verbose RUN: llvm-gsymutil --version 2>&1 | FileCheck --check-prefix=VERSION %s VERSION: {{ version }} diff --git a/llvm/tools/llvm-gsymutil/CMakeLists.txt b/llvm/tools/llvm-gsymutil/CMakeLists.txt --- a/llvm/tools/llvm-gsymutil/CMakeLists.txt +++ b/llvm/tools/llvm-gsymutil/CMakeLists.txt @@ -4,10 +4,18 @@ DebugInfoGSYM MC Object + Option Support TargetParser ) +set(LLVM_TARGET_DEFINITIONS Opts.td) +tablegen(LLVM Opts.inc -gen-opt-parser-defs) +add_public_tablegen_target(GSYMUtilOptsTableGen) + add_llvm_tool(llvm-gsymutil llvm-gsymutil.cpp + + DEPENDS + GSYMUtilOptsTableGen ) diff --git a/llvm/tools/llvm-gsymutil/Opts.td b/llvm/tools/llvm-gsymutil/Opts.td new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-gsymutil/Opts.td @@ -0,0 +1,37 @@ +include "llvm/Option/OptParser.td" + +class F : Flag<["-"], letter>, HelpText; +class FF : Flag<["--"], name>, HelpText; + +multiclass Eq { + def NAME #_EQ : Joined<["--"], name #"=">, HelpText; + def : Separate<["--"], name>, Alias(NAME #_EQ)>; +} + +def help : FF<"help", "Display this help">; +def : F<"h", "Alias for --help">, Alias; +def version : FF<"version", "Display the version">; +def : F<"v", "Alias for --version">, Alias; +def verbose : FF<"verbose", "Enable verbose logging and encoding details">; +defm convert : + Eq<"convert", + "Convert the specified file to the GSYM format.\nSupported files include ELF and mach-o files that will have their debug info (DWARF) and symbol table converted">; +defm arch : + Eq<"arch", + "Process debug information for the specified CPU architecture only.\nArchitectures may be specified by name or by number.\nThis option can be specified multiple times, once for each desired architecture">; +defm out_file : + Eq<"out-file", + "Specify the path where the converted GSYM file will be saved.\nWhen not specified, a '.gsym' extension will be appended to the file name specified in the --convert option">; +def : Separate<["-"], "o">, HelpText<"Alias for --out-file">, Alias; +def verify : FF<"verify", "Verify the generated GSYM file against the information in the file that was converted">; +defm num_threads : + Eq<"num-threads", + "Specify the maximum number (n) of simultaneous threads to use when converting files to GSYM.\nDefaults to the number of cores on the current machine">; +defm segment_size : + Eq<"segment-size", + "Specify the size in bytes of the size the final GSYM file should be segmented into. This allows GSYM files to be split across multiple files">; +def quiet : FF<"quiet", "Do not output warnings about the debug information">; +defm address : Eq<"address", "Lookup an address in a GSYM file">; +def addresses_from_stdin : + FF<"addresses-from-stdin", + "Emit a section containing remark diagnostics metadata. By default, this is enabled for the following formats: yaml-strtab, bitstream">; diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp @@ -14,6 +14,8 @@ #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Format.h" @@ -52,85 +54,132 @@ /// Command line options. /// @{ -namespace { -using namespace cl; - -OptionCategory GeneralOptions("Options"); -OptionCategory ConversionOptions("Conversion Options"); -OptionCategory LookupOptions("Lookup Options"); - -static opt Help("h", desc("Alias for -help"), Hidden, - cat(GeneralOptions)); - -static opt Verbose("verbose", - desc("Enable verbose logging and encoding details."), - cat(GeneralOptions)); - -static list InputFilenames(Positional, desc(""), - cat(GeneralOptions)); - -static opt - ConvertFilename("convert", cl::init(""), - cl::desc("Convert the specified file to the GSYM format.\n" - "Supported files include ELF and mach-o files " - "that will have their debug info (DWARF) and " - "symbol table converted."), - cl::value_desc("path"), cat(ConversionOptions)); - -static list - ArchFilters("arch", - desc("Process debug information for the specified CPU " - "architecture only.\nArchitectures may be specified by " - "name or by number.\nThis option can be specified " - "multiple times, once for each desired architecture."), - cl::value_desc("arch"), cat(ConversionOptions)); - -static opt - OutputFilename("out-file", cl::init(""), - cl::desc("Specify the path where the converted GSYM file " - "will be saved.\nWhen not specified, a '.gsym' " - "extension will be appended to the file name " - "specified in the --convert option."), - cl::value_desc("path"), cat(ConversionOptions)); -static alias OutputFilenameAlias("o", desc("Alias for -out-file."), - aliasopt(OutputFilename), - cat(ConversionOptions)); - -static opt Verify("verify", - desc("Verify the generated GSYM file against the " - "information in the file that was converted."), - cat(ConversionOptions)); - -static opt - NumThreads("num-threads", - desc("Specify the maximum number (n) of simultaneous threads " - "to use when converting files to GSYM.\nDefaults to the " - "number of cores on the current machine."), - cl::value_desc("n"), cat(ConversionOptions)); - -static opt - SegmentSize("segment-size", - desc("Specify the size in bytes of the size the final GSYM file " - "should be segmented into. This allows GSYM files to be " - "split across multiple files."), - cl::value_desc("s"), cat(ConversionOptions)); - -static opt - Quiet("quiet", desc("Do not output warnings about the debug information"), - cat(ConversionOptions)); - -static list LookupAddresses("address", - desc("Lookup an address in a GSYM file"), - cl::value_desc("addr"), - cat(LookupOptions)); - -static opt LookupAddressesFromStdin( - "addresses-from-stdin", - desc("Lookup addresses in a GSYM file that are read from stdin\nEach input " - "line is expected to be of the following format: "), - cat(LookupOptions)); - -} // 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 +}; + +#define PREFIX(NAME, VALUE) \ + constexpr llvm::StringLiteral NAME##_init[] = VALUE; \ + constexpr llvm::ArrayRef NAME( \ + NAME##_init, std::size(NAME##_init) - 1); +#include "Opts.inc" +#undef PREFIX + +const 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 GSYMUtilOptTable : public llvm::opt::GenericOptTable { +public: + GSYMUtilOptTable() : GenericOptTable(InfoTable) { + setGroupedShortOptions(true); + } +}; + +static bool Verbose; +static std::vector InputFilenames; +static std::string ConvertFilename; +static std::vector ArchFilters; +static std::string OutputFilename; +static bool Verify; +static unsigned NumThreads; +static uint64_t SegmentSize; +static bool Quiet; +static std::vector LookupAddresses; +static bool LookupAddressesFromStdin; + +static void parseArgs(int argc, char **argv) { + GSYMUtilOptTable Tbl; + llvm::StringRef ToolName = argv[0]; + llvm::BumpPtrAllocator A; + llvm::StringSaver Saver{A}; + llvm::opt::InputArgList Args = + Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) { + llvm::errs() << Msg << '\n'; + std::exit(1); + }); + if (Args.hasArg(OPT_help)) { + const char *Overview = + "A tool for dumping, searching and creating GSYM files.\n\n" + "Specify one or more GSYM paths as arguments to dump all of the " + "information in each GSYM file.\n" + "Specify a single GSYM file along with one or more --lookup options to " + "lookup addresses within that GSYM file.\n" + "Use the --convert option to specify a file with option --out-file " + "option to convert to GSYM format.\n"; + + Tbl.printHelp(llvm::outs(), "llvm-gsymutil [options] ", + Overview); + std::exit(0); + } + if (Args.hasArg(OPT_version)) { + llvm::outs() << ToolName << '\n'; + cl::PrintVersionMessage(); + std::exit(0); + } + + Verbose = Args.hasArg(OPT_verbose); + + for (const llvm::opt::Arg *A : Args.filtered(OPT_INPUT)) + InputFilenames.emplace_back(A->getValue()); + + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_convert_EQ)) + ConvertFilename = A->getValue(); + + for (const llvm::opt::Arg *A : Args.filtered(OPT_arch_EQ)) + ArchFilters.emplace_back(A->getValue()); + + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_out_file_EQ)) + OutputFilename = A->getValue(); + + Verify = Args.hasArg(OPT_verify); + + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_num_threads_EQ)) { + StringRef S{A->getValue()}; + if (!llvm::to_integer(S, NumThreads, 0)) { + llvm::errs() << ToolName << ": for the --num-threads option: '" << S + << "' value invalid for uint argument!\n"; + std::exit(1); + } + } + + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_segment_size_EQ)) { + StringRef S{A->getValue()}; + if (!llvm::to_integer(S, SegmentSize, 0)) { + llvm::errs() << ToolName << ": for the --segment-size option: '" << S + << "' value invalid for uint argument!\n"; + std::exit(1); + } + } + + Quiet = Args.hasArg(OPT_quiet); + + for (const llvm::opt::Arg *A : Args.filtered(OPT_address_EQ)) { + StringRef S{A->getValue()}; + if (!llvm::to_integer(S, LookupAddresses.emplace_back(), 0)) { + llvm::errs() << ToolName << ": for the --segment-size option: '" << S + << "' value invalid for uint argument!\n"; + std::exit(1); + } + } + + LookupAddressesFromStdin = Args.hasArg(OPT_addresses_from_stdin); +} + /// @} //===----------------------------------------------------------------------===// @@ -443,7 +492,7 @@ OS << "\n"; } -int main(int argc, char const *argv[]) { +int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0]); PrettyStackTraceProgram X(argc, argv); @@ -451,21 +500,7 @@ llvm::InitializeAllTargets(); - const char *Overview = - "A tool for dumping, searching and creating GSYM files.\n\n" - "Specify one or more GSYM paths as arguments to dump all of the " - "information in each GSYM file.\n" - "Specify a single GSYM file along with one or more --lookup options to " - "lookup addresses within that GSYM file.\n" - "Use the --convert option to specify a file with option --out-file " - "option to convert to GSYM format.\n"; - HideUnrelatedOptions({&GeneralOptions, &ConversionOptions, &LookupOptions}); - cl::ParseCommandLineOptions(argc, argv, Overview); - - if (Help) { - PrintHelpMessage(/*Hidden =*/false, /*Categorized =*/true); - return 0; - } + parseArgs(argc, argv); raw_ostream &OS = outs(); diff --git a/llvm/utils/gn/secondary/llvm/tools/llvm-gsymutil/BUILD.gn b/llvm/utils/gn/secondary/llvm/tools/llvm-gsymutil/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/tools/llvm-gsymutil/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/tools/llvm-gsymutil/BUILD.gn @@ -1,8 +1,17 @@ +import("//llvm/utils/TableGen/tablegen.gni") + +tablegen("Opts") { + visibility = [ ":llvm-gsymutil" ] + args = [ "-gen-opt-parser-defs" ] +} + executable("llvm-gsymutil") { deps = [ + ":Opts", "//llvm/lib/DebugInfo/DWARF", "//llvm/lib/DebugInfo/GSYM", "//llvm/lib/Object", + "//llvm/lib/Option", "//llvm/lib/Support", "//llvm/lib/Target", "//llvm/lib/Target:TargetsToBuild", diff --git a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel --- a/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel +++ b/utils/bazel/llvm-project-overlay/llvm/BUILD.bazel @@ -3449,6 +3449,18 @@ ], ) +gentbl( + name = "GSYMUtilOptionsTableGen", + strip_include_prefix = "tools/llvm-gsymutil", + tbl_outs = [( + "-gen-opt-parser-defs", + "tools/llvm-gsymutil/Opts.inc", + )], + tblgen = ":llvm-tblgen", + td_file = "tools/llvm-gsymutil/Opts.td", + td_srcs = ["include/llvm/Option/OptParser.td"], +) + cc_binary( name = "llvm-gsymutil", srcs = glob([ @@ -3462,8 +3474,10 @@ ":DebugInfo", ":DebugInfoDWARF", ":DebugInfoGSYM", + ":GSYMUtilOptionsTableGen", ":MC", ":Object", + ":Option", ":Support", ":Target", ":TargetParser",