| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/zxdb/console/command_line_options.h" |
| |
| #include <lib/cmdline/args_parser.h> |
| |
| #include <filesystem> |
| #include <iostream> |
| #include <system_error> |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| // Appears at the top of the --help output above the switch list. |
| const char kHelpIntro[] = R"(zxdb [ <options> ] |
| |
| For information on using the debugger, type "help" at the interactive prompt. |
| |
| Options |
| |
| )"; |
| |
| const char kUnixConnectHelp[] = R"( --unix-connect=<filepath> |
| -u <filepath> |
| Attempts to connect to a debug_agent through a unix socket.)"; |
| |
| const char kLocalHelp[] = R"( --local |
| -l |
| Runs the built-in local debug_agent for debugging the local system. Only |
| supported on x64 Linux. |
| |
| In this mode, any non-switch parameters (or anything after '--') will be |
| treated as the program to debug and its parameters.)"; |
| |
| const char kConnectHelp[] = R"( --connect=<host>:<port> |
| -c <host>:<port> |
| Attempts to connect to a debug_agent running on the given host/port.)"; |
| |
| const char kCoreHelp[] = R"( --core=<filename> |
| Attempts to open a core file for analysis.)"; |
| |
| const char kDebugModeHelp[] = R"( --debug-mode |
| -d |
| Output debug information about zxdb. |
| Should only be useful for people developing zxdb.)"; |
| |
| const char kConsoleModeHelp[] = R"( --console-mode |
| The style in which zxdb interacts with the console. Valid values are |
| "shell" (default), "embedded", and "embedded-interactive".)"; |
| |
| const char kEmbeddedModeContextHelp[] = R"( --embedded-mode-context |
| A short contextual string shown to the user when zxdb breaks out of |
| Embedded mode. This is typically something that the user would expect |
| to need to debug e.g. "test failure" or "crash". If unspecified, the |
| exception that caused the debugger to appear will be shown.)"; |
| |
| const char kHelpHelp[] = R"( --help |
| -h |
| Prints all command-line switches.)"; |
| |
| const char kAttachHelp[] = R"( --attach=<koid|filter> |
| -a <koid|filter> |
| Attaches to the given process or creates a filter that matches current |
| and future processes. The argument will be parsed in the same way as the |
| "attach" command in the console. Multiple attaches can be specified to |
| match more than one process.)"; |
| |
| const char kScriptFileHelp[] = R"( --script-file=<file> |
| -S <file> |
| Reads a script file from a file. The file must contains valid zxdb |
| commands as they would be input from the command line. They will be |
| executed sequentially.)"; |
| |
| const char kExecuteCommandHelp[] = R"( --execute=<command> |
| -e <command> |
| Execute one zxdb command. Multiple commands will be executed sequentially.)"; |
| |
| const char kSymbolIndexHelp[] = R"( --symbol-index=<path> |
| Populates --ids-txt and --build-id-dir using the given symbol-index file, |
| which defaults to ~/.fuchsia/debug/symbol-index.json. The file should be |
| created and maintained by the "symbol-index" host tool.)"; |
| |
| const char kSymbolPathHelp[] = R"( --symbol-path=<path> |
| -s <path> |
| Adds the given directory or file to the symbol search path. Multiple |
| -s switches can be passed to add multiple locations. When a directory |
| path is passed, the directory will be enumerated non-recursively to |
| index all ELF files. When a file is passed, it will be loaded as an ELF |
| file (if possible).)"; |
| |
| const char kBuildIdDirHelp[] = R"( --build-id-dir=<path> |
| Adds the given directory to the symbol search path. Multiple |
| --build-id-dir switches can be passed to add multiple directories. |
| The directory must have the same structure as a .build-id directory, |
| that is, each symbol file lives at xx/yyyyyyyy.debug where xx is |
| the first two characters of the build ID and yyyyyyyy is the rest. |
| However, the name of the directory doesn't need to be .build-id.)"; |
| |
| const char kIdsTxtHelp[] = R"( --ids-txt=<path> |
| Adds the given file to the symbol search path. Multiple --ids-txt |
| switches can be passed to add multiple files. The file, typically named |
| "ids.txt", serves as a mapping from build ID to symbol file path and |
| should contain multiple lines in the format of "<build ID> <file path>".)"; |
| |
| const char kSymbolCacheHelp[] = R"( --symbol-cache=<path> |
| Directory where we can keep a symbol cache, which defaults to |
| ~/.fuchsia/debug/symbol-cache. If a symbol server has been specified, |
| downloaded symbols will be stored in this directory. The directory |
| structure will be the same as a .build-id directory, and symbols will |
| be read from this location as though you had specified |
| "--build-id-dir=<path>".)"; |
| |
| const char kPrivateSymbolServerHelp[] = R"( --symbol-server=<url> |
| Adds the given URL to symbol servers. Symbol servers host the debug |
| symbols for prebuilt binaries and dynamic libraries. Servers specified |
| with this option will be required to authenticate against the given url.)"; |
| |
| const char kPublicSymbolServerHelp[] = R"( --public-symbol-server=<url> |
| Adds the given URL to symbol servers. Symbol servers host the debug |
| symbols for prebuilt binaries and dynamic libraries.)"; |
| |
| using ::analytics::core_dev_tools::kAnalyticsHelp; |
| using ::analytics::core_dev_tools::kAnalyticsShowHelp; |
| |
| const char kVersionHelp[] = R"( --version |
| -v |
| Prints the version.)"; |
| |
| const char kEnableDebugAdapterHelp[] = R"( --enable-debug-adapter |
| Starts the debug adapter that serves debug adapter protocol. |
| This is useful for connecting the debugger with an IDE.)"; |
| |
| const char kDebugAdapterPortHelp[] = R"( --debug-adapter-port=<port> |
| Uses this port number to serve debug adapter protocol. |
| By default 15678 is used.)"; |
| |
| const char kAutoAttachLimboHelp[] = R"( --auto-attach-limbo |
| Enables automatically attaching to all processes found in Process Limbo |
| upon successful connection.)"; |
| |
| const char kSignalWhenReadyHelp[] = R"( --signal-when-ready=<pid> |
| Send SIGUSR1 to pid when ready for interactive commands.)"; |
| |
| const char kStreamFileHelp[] = R"( --stream-file=<path> |
| Stream the contents of the given file, usually a pipe, to the console.)"; |
| |
| } // namespace |
| |
| cmdline::Status ParseCommandLine(int argc, const char* argv[], CommandLineOptions* options, |
| std::vector<std::string>* params) { |
| using analytics::core_dev_tools::AnalyticsOption; |
| using analytics::core_dev_tools::ParseAnalyticsOption; |
| |
| cmdline::ArgsParser<CommandLineOptions> parser; |
| |
| parser.AddSwitch("connect", 'c', kConnectHelp, &CommandLineOptions::connect); |
| parser.AddSwitch("unix-connect", 'u', kUnixConnectHelp, &CommandLineOptions::unix_connect); |
| parser.AddSwitch("local", 'l', kLocalHelp, &CommandLineOptions::local); |
| parser.AddSwitch("core", 0, kCoreHelp, &CommandLineOptions::core); |
| parser.AddSwitch("debug-mode", 'd', kDebugModeHelp, &CommandLineOptions::debug_mode); |
| parser.AddSwitch("console-mode", 0, kConsoleModeHelp, &CommandLineOptions::console_mode); |
| parser.AddSwitch("embedded-mode-context", 0, kEmbeddedModeContextHelp, |
| &CommandLineOptions::embedded_mode_context); |
| parser.AddSwitch("attach", 'a', kAttachHelp, &CommandLineOptions::attach); |
| parser.AddSwitch("script-file", 'S', kScriptFileHelp, &CommandLineOptions::script_files); |
| parser.AddSwitch("execute", 'e', kExecuteCommandHelp, &CommandLineOptions::execute_commands); |
| parser.AddSwitch("symbol-index", 0, kSymbolIndexHelp, &CommandLineOptions::symbol_index_files); |
| parser.AddSwitch("symbol-path", 's', kSymbolPathHelp, &CommandLineOptions::symbol_paths); |
| parser.AddSwitch("build-id-dir", 0, kBuildIdDirHelp, &CommandLineOptions::build_id_dirs); |
| parser.AddSwitch("ids-txt", 0, kIdsTxtHelp, &CommandLineOptions::ids_txts); |
| parser.AddSwitch("symbol-cache", 0, kSymbolCacheHelp, &CommandLineOptions::symbol_cache); |
| parser.AddSwitch("symbol-server", 0, kPrivateSymbolServerHelp, |
| &CommandLineOptions::private_symbol_servers); |
| parser.AddSwitch("public-symbol-server", 0, kPublicSymbolServerHelp, |
| &CommandLineOptions::public_symbol_servers); |
| parser.AddSwitch("version", 'v', kVersionHelp, &CommandLineOptions::requested_version); |
| parser.AddSwitch("analytics", 0, kAnalyticsHelp, &CommandLineOptions::analytics); |
| parser.AddSwitch("analytics-show", 0, kAnalyticsShowHelp, &CommandLineOptions::analytics_show); |
| parser.AddSwitch("enable-debug-adapter", 0, kEnableDebugAdapterHelp, |
| &CommandLineOptions::enable_debug_adapter); |
| parser.AddSwitch("debug-adapter-port", 0, kDebugAdapterPortHelp, |
| &CommandLineOptions::debug_adapter_port); |
| parser.AddSwitch("auto-attach-limbo", 0, kAutoAttachLimboHelp, |
| &CommandLineOptions::auto_attach_limbo); |
| parser.AddSwitch("signal-when-ready", 0, kSignalWhenReadyHelp, |
| &CommandLineOptions::signal_when_ready); |
| parser.AddSwitch("stream-file", 0, kStreamFileHelp, &CommandLineOptions::stream_files); |
| |
| // Special --help switch which doesn't exist in the options structure. |
| bool requested_help = false; |
| parser.AddGeneralSwitch("help", 'h', kHelpHelp, [&requested_help]() { requested_help = true; }); |
| |
| cmdline::Status status = parser.Parse(argc, argv, options, params); |
| if (status.has_error()) |
| return status; |
| |
| // Handle --help switch since we're the one that knows about the switches. |
| if (requested_help) |
| return cmdline::Status::Error(kHelpIntro + parser.GetHelp()); |
| |
| // Default values for vector types. |
| if (const char* home = std::getenv("HOME"); home) { |
| std::string home_str = home; |
| if (!options->symbol_cache) { |
| options->symbol_cache = home_str + "/.fuchsia/debug/symbol-cache"; |
| } |
| if (options->symbol_index_files.empty()) { |
| std::error_code ec; |
| std::string symbol_index = home_str + "/.fuchsia/debug/symbol-index.json"; |
| if (std::filesystem::exists(symbol_index, ec)) { |
| options->symbol_index_files.push_back(symbol_index); |
| } |
| } |
| std::string zxdbrc = home_str + "/.fuchsia/debug/zxdbrc"; |
| std::error_code ec; |
| if (std::filesystem::exists(zxdbrc, ec)) { |
| // zxdbrc is expected to execute first. |
| options->script_files.insert(options->script_files.begin(), zxdbrc); |
| } |
| } |
| |
| return cmdline::Status::Ok(); |
| } |
| |
| } // namespace zxdb |