1314564Sdim//===-- CommandObjectCommands.cpp -------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9254721Semaste#include "llvm/ADT/StringRef.h" 10254721Semaste 11309124Sdim#include "CommandObjectCommands.h" 12309124Sdim#include "CommandObjectHelp.h" 13254721Semaste#include "lldb/Core/Debugger.h" 14262528Semaste#include "lldb/Core/IOHandler.h" 15254721Semaste#include "lldb/Interpreter/CommandHistory.h" 16254721Semaste#include "lldb/Interpreter/CommandInterpreter.h" 17254721Semaste#include "lldb/Interpreter/CommandObjectRegexCommand.h" 18254721Semaste#include "lldb/Interpreter/CommandReturnObject.h" 19341825Sdim#include "lldb/Interpreter/OptionArgParser.h" 20254721Semaste#include "lldb/Interpreter/OptionValueBoolean.h" 21309124Sdim#include "lldb/Interpreter/OptionValueString.h" 22254721Semaste#include "lldb/Interpreter/OptionValueUInt64.h" 23254721Semaste#include "lldb/Interpreter/Options.h" 24254721Semaste#include "lldb/Interpreter/ScriptInterpreter.h" 25341825Sdim#include "lldb/Utility/Args.h" 26321369Sdim#include "lldb/Utility/StringList.h" 27254721Semaste 28254721Semasteusing namespace lldb; 29254721Semasteusing namespace lldb_private; 30254721Semaste 31254721Semaste// CommandObjectCommandsSource 32254721Semaste 33360784Sdim#define LLDB_OPTIONS_history 34360784Sdim#include "CommandOptions.inc" 35314564Sdim 36314564Sdimclass CommandObjectCommandsHistory : public CommandObjectParsed { 37254721Semastepublic: 38314564Sdim CommandObjectCommandsHistory(CommandInterpreter &interpreter) 39314564Sdim : CommandObjectParsed(interpreter, "command history", 40321369Sdim "Dump the history of commands in this session.\n" 41321369Sdim "Commands in the history list can be run again " 42321369Sdim "using \"!<INDEX>\". \"!-<OFFSET>\" will re-run " 43321369Sdim "the command that is <OFFSET> commands from the end" 44321369Sdim " of the list (counting the current command).", 45309124Sdim nullptr), 46314564Sdim m_options() {} 47254721Semaste 48314564Sdim ~CommandObjectCommandsHistory() override = default; 49254721Semaste 50314564Sdim Options *GetOptions() override { return &m_options; } 51254721Semaste 52254721Semasteprotected: 53314564Sdim class CommandOptions : public Options { 54314564Sdim public: 55314564Sdim CommandOptions() 56314564Sdim : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { 57314564Sdim } 58254721Semaste 59314564Sdim ~CommandOptions() override = default; 60254721Semaste 61321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 62321369Sdim ExecutionContext *execution_context) override { 63321369Sdim Status error; 64314564Sdim const int short_option = m_getopt_table[option_idx].val; 65254721Semaste 66314564Sdim switch (short_option) { 67314564Sdim case 'c': 68314564Sdim error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); 69314564Sdim break; 70314564Sdim case 's': 71314564Sdim if (option_arg == "end") { 72314564Sdim m_start_idx.SetCurrentValue(UINT64_MAX); 73314564Sdim m_start_idx.SetOptionWasSet(); 74314564Sdim } else 75314564Sdim error = m_start_idx.SetValueFromString(option_arg, 76314564Sdim eVarSetOperationAssign); 77314564Sdim break; 78314564Sdim case 'e': 79314564Sdim error = 80314564Sdim m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); 81314564Sdim break; 82314564Sdim case 'C': 83314564Sdim m_clear.SetCurrentValue(true); 84314564Sdim m_clear.SetOptionWasSet(); 85314564Sdim break; 86314564Sdim default: 87360784Sdim llvm_unreachable("Unimplemented option"); 88314564Sdim } 89254721Semaste 90314564Sdim return error; 91314564Sdim } 92254721Semaste 93314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 94314564Sdim m_start_idx.Clear(); 95314564Sdim m_stop_idx.Clear(); 96314564Sdim m_count.Clear(); 97314564Sdim m_clear.Clear(); 98314564Sdim } 99254721Semaste 100314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 101314564Sdim return llvm::makeArrayRef(g_history_options); 102314564Sdim } 103254721Semaste 104314564Sdim // Instance variables to hold the values for command options. 105254721Semaste 106314564Sdim OptionValueUInt64 m_start_idx; 107314564Sdim OptionValueUInt64 m_stop_idx; 108314564Sdim OptionValueUInt64 m_count; 109314564Sdim OptionValueBoolean m_clear; 110314564Sdim }; 111314564Sdim 112314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 113314564Sdim if (m_options.m_clear.GetCurrentValue() && 114314564Sdim m_options.m_clear.OptionWasSet()) { 115314564Sdim m_interpreter.GetCommandHistory().Clear(); 116314564Sdim result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); 117314564Sdim } else { 118314564Sdim if (m_options.m_start_idx.OptionWasSet() && 119314564Sdim m_options.m_stop_idx.OptionWasSet() && 120314564Sdim m_options.m_count.OptionWasSet()) { 121314564Sdim result.AppendError("--count, --start-index and --end-index cannot be " 122314564Sdim "all specified in the same invocation"); 123314564Sdim result.SetStatus(lldb::eReturnStatusFailed); 124314564Sdim } else { 125314564Sdim std::pair<bool, uint64_t> start_idx( 126314564Sdim m_options.m_start_idx.OptionWasSet(), 127314564Sdim m_options.m_start_idx.GetCurrentValue()); 128314564Sdim std::pair<bool, uint64_t> stop_idx( 129314564Sdim m_options.m_stop_idx.OptionWasSet(), 130314564Sdim m_options.m_stop_idx.GetCurrentValue()); 131314564Sdim std::pair<bool, uint64_t> count(m_options.m_count.OptionWasSet(), 132314564Sdim m_options.m_count.GetCurrentValue()); 133314564Sdim 134314564Sdim const CommandHistory &history(m_interpreter.GetCommandHistory()); 135314564Sdim 136314564Sdim if (start_idx.first && start_idx.second == UINT64_MAX) { 137314564Sdim if (count.first) { 138314564Sdim start_idx.second = history.GetSize() - count.second; 139314564Sdim stop_idx.second = history.GetSize() - 1; 140314564Sdim } else if (stop_idx.first) { 141314564Sdim start_idx.second = stop_idx.second; 142314564Sdim stop_idx.second = history.GetSize() - 1; 143314564Sdim } else { 144314564Sdim start_idx.second = 0; 145314564Sdim stop_idx.second = history.GetSize() - 1; 146314564Sdim } 147314564Sdim } else { 148314564Sdim if (!start_idx.first && !stop_idx.first && !count.first) { 149314564Sdim start_idx.second = 0; 150314564Sdim stop_idx.second = history.GetSize() - 1; 151314564Sdim } else if (start_idx.first) { 152314564Sdim if (count.first) { 153314564Sdim stop_idx.second = start_idx.second + count.second - 1; 154314564Sdim } else if (!stop_idx.first) { 155314564Sdim stop_idx.second = history.GetSize() - 1; 156254721Semaste } 157314564Sdim } else if (stop_idx.first) { 158314564Sdim if (count.first) { 159314564Sdim if (stop_idx.second >= count.second) 160314564Sdim start_idx.second = stop_idx.second - count.second + 1; 161314564Sdim else 162314564Sdim start_idx.second = 0; 163254721Semaste } 164314564Sdim } else /* if (count.first) */ 165314564Sdim { 166314564Sdim start_idx.second = 0; 167314564Sdim stop_idx.second = count.second - 1; 168314564Sdim } 169254721Semaste } 170314564Sdim history.Dump(result.GetOutputStream(), start_idx.second, 171314564Sdim stop_idx.second); 172314564Sdim } 173254721Semaste } 174314564Sdim return result.Succeeded(); 175314564Sdim } 176254721Semaste 177314564Sdim CommandOptions m_options; 178254721Semaste}; 179254721Semaste 180254721Semaste// CommandObjectCommandsSource 181254721Semaste 182360784Sdim#define LLDB_OPTIONS_source 183360784Sdim#include "CommandOptions.inc" 184314564Sdim 185314564Sdimclass CommandObjectCommandsSource : public CommandObjectParsed { 186254721Semastepublic: 187314564Sdim CommandObjectCommandsSource(CommandInterpreter &interpreter) 188314564Sdim : CommandObjectParsed( 189314564Sdim interpreter, "command source", 190314564Sdim "Read and execute LLDB commands from the file <filename>.", 191314564Sdim nullptr), 192314564Sdim m_options() { 193314564Sdim CommandArgumentEntry arg; 194314564Sdim CommandArgumentData file_arg; 195254721Semaste 196314564Sdim // Define the first (and only) variant of this arg. 197314564Sdim file_arg.arg_type = eArgTypeFilename; 198314564Sdim file_arg.arg_repetition = eArgRepeatPlain; 199254721Semaste 200314564Sdim // There is only one variant this argument could be; put it into the 201314564Sdim // argument entry. 202314564Sdim arg.push_back(file_arg); 203254721Semaste 204314564Sdim // Push the data for the first argument into the m_arguments vector. 205314564Sdim m_arguments.push_back(arg); 206314564Sdim } 207254721Semaste 208314564Sdim ~CommandObjectCommandsSource() override = default; 209314564Sdim 210314564Sdim const char *GetRepeatCommand(Args ¤t_command_args, 211314564Sdim uint32_t index) override { 212314564Sdim return ""; 213314564Sdim } 214314564Sdim 215360784Sdim void 216360784Sdim HandleArgumentCompletion(CompletionRequest &request, 217360784Sdim OptionElementVector &opt_element_vector) override { 218314564Sdim CommandCompletions::InvokeCommonCompletionCallbacks( 219314564Sdim GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 220341825Sdim request, nullptr); 221314564Sdim } 222314564Sdim 223314564Sdim Options *GetOptions() override { return &m_options; } 224314564Sdim 225254721Semasteprotected: 226314564Sdim class CommandOptions : public Options { 227314564Sdim public: 228314564Sdim CommandOptions() 229314564Sdim : Options(), m_stop_on_error(true), m_silent_run(false), 230314564Sdim m_stop_on_continue(true) {} 231254721Semaste 232314564Sdim ~CommandOptions() override = default; 233254721Semaste 234321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 235321369Sdim ExecutionContext *execution_context) override { 236321369Sdim Status error; 237314564Sdim const int short_option = m_getopt_table[option_idx].val; 238262528Semaste 239314564Sdim switch (short_option) { 240314564Sdim case 'e': 241314564Sdim error = m_stop_on_error.SetValueFromString(option_arg); 242314564Sdim break; 243262528Semaste 244314564Sdim case 'c': 245314564Sdim error = m_stop_on_continue.SetValueFromString(option_arg); 246314564Sdim break; 247262528Semaste 248314564Sdim case 's': 249314564Sdim error = m_silent_run.SetValueFromString(option_arg); 250314564Sdim break; 251254721Semaste 252314564Sdim default: 253360784Sdim llvm_unreachable("Unimplemented option"); 254314564Sdim } 255254721Semaste 256314564Sdim return error; 257314564Sdim } 258254721Semaste 259314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 260314564Sdim m_stop_on_error.Clear(); 261314564Sdim m_silent_run.Clear(); 262314564Sdim m_stop_on_continue.Clear(); 263314564Sdim } 264254721Semaste 265314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 266314564Sdim return llvm::makeArrayRef(g_source_options); 267314564Sdim } 268254721Semaste 269314564Sdim // Instance variables to hold the values for command options. 270254721Semaste 271314564Sdim OptionValueBoolean m_stop_on_error; 272314564Sdim OptionValueBoolean m_silent_run; 273314564Sdim OptionValueBoolean m_stop_on_continue; 274314564Sdim }; 275254721Semaste 276314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 277314564Sdim if (command.GetArgumentCount() != 1) { 278314564Sdim result.AppendErrorWithFormat( 279314564Sdim "'%s' takes exactly one executable filename argument.\n", 280314564Sdim GetCommandName().str().c_str()); 281314564Sdim result.SetStatus(eReturnStatusFailed); 282314564Sdim return false; 283314564Sdim } 284280031Sdim 285360784Sdim FileSpec cmd_file(command[0].ref()); 286344779Sdim FileSystem::Instance().Resolve(cmd_file); 287314564Sdim ExecutionContext *exe_ctx = nullptr; // Just use the default context. 288314564Sdim 289314564Sdim // If any options were set, then use them 290314564Sdim if (m_options.m_stop_on_error.OptionWasSet() || 291314564Sdim m_options.m_silent_run.OptionWasSet() || 292314564Sdim m_options.m_stop_on_continue.OptionWasSet()) { 293314564Sdim // Use user set settings 294314564Sdim CommandInterpreterRunOptions options; 295314564Sdim 296353358Sdim if (m_options.m_stop_on_continue.OptionWasSet()) 297353358Sdim options.SetStopOnContinue( 298353358Sdim m_options.m_stop_on_continue.GetCurrentValue()); 299353358Sdim 300353358Sdim if (m_options.m_stop_on_error.OptionWasSet()) 301353358Sdim options.SetStopOnError(m_options.m_stop_on_error.GetCurrentValue()); 302353358Sdim 303344779Sdim // Individual silent setting is override for global command echo settings. 304344779Sdim if (m_options.m_silent_run.GetCurrentValue()) { 305344779Sdim options.SetSilent(true); 306344779Sdim } else { 307344779Sdim options.SetPrintResults(true); 308353358Sdim options.SetPrintErrors(true); 309344779Sdim options.SetEchoCommands(m_interpreter.GetEchoCommands()); 310344779Sdim options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); 311344779Sdim } 312344779Sdim 313314564Sdim m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); 314314564Sdim } else { 315341825Sdim // No options were set, inherit any settings from nested "command source" 316341825Sdim // commands, or set to sane default settings... 317314564Sdim CommandInterpreterRunOptions options; 318314564Sdim m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); 319309124Sdim } 320314564Sdim return result.Succeeded(); 321314564Sdim } 322254721Semaste 323314564Sdim CommandOptions m_options; 324254721Semaste}; 325254721Semaste 326254721Semaste#pragma mark CommandObjectCommandsAlias 327254721Semaste// CommandObjectCommandsAlias 328254721Semaste 329360784Sdim#define LLDB_OPTIONS_alias 330360784Sdim#include "CommandOptions.inc" 331254721Semaste 332314564Sdimstatic const char *g_python_command_instructions = 333314564Sdim "Enter your Python command(s). Type 'DONE' to end.\n" 334314564Sdim "You must define a Python function with this signature:\n" 335314564Sdim "def my_command_impl(debugger, args, result, internal_dict):\n"; 336314564Sdim 337314564Sdimclass CommandObjectCommandsAlias : public CommandObjectRaw { 338309124Sdimprotected: 339314564Sdim class CommandOptions : public OptionGroup { 340314564Sdim public: 341314564Sdim CommandOptions() : OptionGroup(), m_help(), m_long_help() {} 342309124Sdim 343314564Sdim ~CommandOptions() override = default; 344314564Sdim 345314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 346314564Sdim return llvm::makeArrayRef(g_alias_options); 347309124Sdim } 348309124Sdim 349321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, 350321369Sdim ExecutionContext *execution_context) override { 351321369Sdim Status error; 352309124Sdim 353314564Sdim const int short_option = GetDefinitions()[option_idx].short_option; 354314564Sdim std::string option_str(option_value); 355314564Sdim 356314564Sdim switch (short_option) { 357314564Sdim case 'h': 358314564Sdim m_help.SetCurrentValue(option_str); 359314564Sdim m_help.SetOptionWasSet(); 360314564Sdim break; 361314564Sdim 362314564Sdim case 'H': 363314564Sdim m_long_help.SetCurrentValue(option_str); 364314564Sdim m_long_help.SetOptionWasSet(); 365314564Sdim break; 366314564Sdim 367314564Sdim default: 368360784Sdim llvm_unreachable("Unimplemented option"); 369314564Sdim } 370314564Sdim 371314564Sdim return error; 372314564Sdim } 373314564Sdim 374314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 375314564Sdim m_help.Clear(); 376314564Sdim m_long_help.Clear(); 377314564Sdim } 378314564Sdim 379314564Sdim OptionValueString m_help; 380314564Sdim OptionValueString m_long_help; 381314564Sdim }; 382314564Sdim 383314564Sdim OptionGroupOptions m_option_group; 384314564Sdim CommandOptions m_command_options; 385314564Sdim 386314564Sdimpublic: 387314564Sdim Options *GetOptions() override { return &m_option_group; } 388314564Sdim 389314564Sdim CommandObjectCommandsAlias(CommandInterpreter &interpreter) 390314564Sdim : CommandObjectRaw( 391314564Sdim interpreter, "command alias", 392314564Sdim "Define a custom command in terms of an existing command."), 393314564Sdim m_option_group(), m_command_options() { 394314564Sdim m_option_group.Append(&m_command_options); 395314564Sdim m_option_group.Finalize(); 396314564Sdim 397314564Sdim SetHelpLong( 398314564Sdim "'alias' allows the user to create a short-cut or abbreviation for long \ 399288943Sdimcommands, multi-word commands, and commands that take particular options. \ 400314564SdimBelow are some simple examples of how one might use the 'alias' command:" 401314564Sdim R"( 402254721Semaste 403288943Sdim(lldb) command alias sc script 404288943Sdim 405288943Sdim Creates the abbreviation 'sc' for the 'script' command. 406288943Sdim 407288943Sdim(lldb) command alias bp breakpoint 408288943Sdim 409314564Sdim)" 410314564Sdim " Creates the abbreviation 'bp' for the 'breakpoint' command. Since \ 411288943Sdimbreakpoint commands are two-word commands, the user would still need to \ 412314564Sdimenter the second word after 'bp', e.g. 'bp enable' or 'bp delete'." 413314564Sdim R"( 414288943Sdim 415288943Sdim(lldb) command alias bpl breakpoint list 416288943Sdim 417288943Sdim Creates the abbreviation 'bpl' for the two-word command 'breakpoint list'. 418288943Sdim 419314564Sdim)" 420314564Sdim "An alias can include some options for the command, with the values either \ 421288943Sdimfilled in at the time the alias is created, or specified as positional \ 422288943Sdimarguments, to be filled in when the alias is invoked. The following example \ 423314564Sdimshows how to create aliases with options:" 424314564Sdim R"( 425288943Sdim 426288943Sdim(lldb) command alias bfl breakpoint set -f %1 -l %2 427288943Sdim 428314564Sdim)" 429314564Sdim " Creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \ 430288943Sdimoptions already part of the alias. So if the user wants to set a breakpoint \ 431288943Sdimby file and line without explicitly having to use the -f and -l options, the \ 432288943Sdimuser can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \ 433288943Sdimfor the actual arguments that will be passed when the alias command is used. \ 434288943SdimThe number in the placeholder refers to the position/order the actual value \ 435288943Sdimoccupies when the alias is used. All the occurrences of '%1' in the alias \ 436288943Sdimwill be replaced with the first argument, all the occurrences of '%2' in the \ 437288943Sdimalias will be replaced with the second argument, and so on. This also allows \ 438288943Sdimactual arguments to be used multiple times within an alias (see 'process \ 439314564Sdimlaunch' example below)." 440314564Sdim R"( 441288943Sdim 442314564Sdim)" 443314564Sdim "Note: the positional arguments must substitute as whole words in the resultant \ 444288943Sdimcommand, so you can't at present do something like this to append the file extension \ 445314564Sdim\".cpp\":" 446314564Sdim R"( 447288943Sdim 448288943Sdim(lldb) command alias bcppfl breakpoint set -f %1.cpp -l %2 449288943Sdim 450314564Sdim)" 451314564Sdim "For more complex aliasing, use the \"command regex\" command instead. In the \ 452288943Sdim'bfl' case above, the actual file value will be filled in with the first argument \ 453288943Sdimfollowing 'bfl' and the actual line number value will be filled in with the second \ 454314564Sdimargument. The user would use this alias as follows:" 455314564Sdim R"( 456288943Sdim 457288943Sdim(lldb) command alias bfl breakpoint set -f %1 -l %2 458288943Sdim(lldb) bfl my-file.c 137 459288943Sdim 460288943SdimThis would be the same as if the user had entered 'breakpoint set -f my-file.c -l 137'. 461288943Sdim 462288943SdimAnother example: 463288943Sdim 464288943Sdim(lldb) command alias pltty process launch -s -o %1 -e %1 465288943Sdim(lldb) pltty /dev/tty0 466288943Sdim 467288943Sdim Interpreted as 'process launch -s -o /dev/tty0 -e /dev/tty0' 468288943Sdim 469314564Sdim)" 470314564Sdim "If the user always wanted to pass the same value to a particular option, the \ 471288943Sdimalias could be defined with that value directly in the alias as a constant, \ 472314564Sdimrather than using a positional placeholder:" 473314564Sdim R"( 474288943Sdim 475288943Sdim(lldb) command alias bl3 breakpoint set -f %1 -l 3 476288943Sdim 477314564Sdim Always sets a breakpoint on line 3 of whatever file is indicated.)"); 478288943Sdim 479314564Sdim CommandArgumentEntry arg1; 480314564Sdim CommandArgumentEntry arg2; 481314564Sdim CommandArgumentEntry arg3; 482314564Sdim CommandArgumentData alias_arg; 483314564Sdim CommandArgumentData cmd_arg; 484314564Sdim CommandArgumentData options_arg; 485314564Sdim 486314564Sdim // Define the first (and only) variant of this arg. 487314564Sdim alias_arg.arg_type = eArgTypeAliasName; 488314564Sdim alias_arg.arg_repetition = eArgRepeatPlain; 489314564Sdim 490314564Sdim // There is only one variant this argument could be; put it into the 491314564Sdim // argument entry. 492314564Sdim arg1.push_back(alias_arg); 493314564Sdim 494314564Sdim // Define the first (and only) variant of this arg. 495314564Sdim cmd_arg.arg_type = eArgTypeCommandName; 496314564Sdim cmd_arg.arg_repetition = eArgRepeatPlain; 497314564Sdim 498314564Sdim // There is only one variant this argument could be; put it into the 499314564Sdim // argument entry. 500314564Sdim arg2.push_back(cmd_arg); 501314564Sdim 502314564Sdim // Define the first (and only) variant of this arg. 503314564Sdim options_arg.arg_type = eArgTypeAliasOptions; 504314564Sdim options_arg.arg_repetition = eArgRepeatOptional; 505314564Sdim 506314564Sdim // There is only one variant this argument could be; put it into the 507314564Sdim // argument entry. 508314564Sdim arg3.push_back(options_arg); 509314564Sdim 510314564Sdim // Push the data for the first argument into the m_arguments vector. 511314564Sdim m_arguments.push_back(arg1); 512314564Sdim m_arguments.push_back(arg2); 513314564Sdim m_arguments.push_back(arg3); 514314564Sdim } 515314564Sdim 516314564Sdim ~CommandObjectCommandsAlias() override = default; 517314564Sdim 518314564Sdimprotected: 519341825Sdim bool DoExecute(llvm::StringRef raw_command_line, 520314564Sdim CommandReturnObject &result) override { 521341825Sdim if (raw_command_line.empty()) { 522314564Sdim result.AppendError("'command alias' requires at least two arguments"); 523314564Sdim return false; 524254721Semaste } 525254721Semaste 526314564Sdim ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext(); 527314564Sdim m_option_group.NotifyOptionParsingStarting(&exe_ctx); 528254721Semaste 529341825Sdim OptionsWithRaw args_with_suffix(raw_command_line); 530341825Sdim const char *remainder = args_with_suffix.GetRawPart().c_str(); 531314564Sdim 532341825Sdim if (args_with_suffix.HasArgs()) 533341825Sdim if (!ParseOptionsAndNotify(args_with_suffix.GetArgs(), result, 534341825Sdim m_option_group, exe_ctx)) 535341825Sdim return false; 536314564Sdim 537314564Sdim llvm::StringRef raw_command_string(remainder); 538314564Sdim Args args(raw_command_string); 539309124Sdim 540314564Sdim if (args.GetArgumentCount() < 2) { 541314564Sdim result.AppendError("'command alias' requires at least two arguments"); 542314564Sdim result.SetStatus(eReturnStatusFailed); 543314564Sdim return false; 544314564Sdim } 545309124Sdim 546314564Sdim // Get the alias command. 547314564Sdim 548360784Sdim auto alias_command = args[0].ref(); 549314564Sdim if (alias_command.startswith("-")) { 550314564Sdim result.AppendError("aliases starting with a dash are not supported"); 551314564Sdim if (alias_command == "--help" || alias_command == "--long-help") { 552314564Sdim result.AppendWarning("if trying to pass options to 'command alias' add " 553314564Sdim "a -- at the end of the options"); 554314564Sdim } 555314564Sdim result.SetStatus(eReturnStatusFailed); 556314564Sdim return false; 557254721Semaste } 558254721Semaste 559314564Sdim // Strip the new alias name off 'raw_command_string' (leave it on args, 560341825Sdim // which gets passed to 'Execute', which does the stripping itself. 561314564Sdim size_t pos = raw_command_string.find(alias_command); 562314564Sdim if (pos == 0) { 563314564Sdim raw_command_string = raw_command_string.substr(alias_command.size()); 564314564Sdim pos = raw_command_string.find_first_not_of(' '); 565314564Sdim if ((pos != std::string::npos) && (pos > 0)) 566314564Sdim raw_command_string = raw_command_string.substr(pos); 567314564Sdim } else { 568314564Sdim result.AppendError("Error parsing command string. No alias created."); 569314564Sdim result.SetStatus(eReturnStatusFailed); 570314564Sdim return false; 571314564Sdim } 572254721Semaste 573314564Sdim // Verify that the command is alias-able. 574314564Sdim if (m_interpreter.CommandExists(alias_command)) { 575314564Sdim result.AppendErrorWithFormat( 576314564Sdim "'%s' is a permanent debugger command and cannot be redefined.\n", 577314564Sdim args[0].c_str()); 578314564Sdim result.SetStatus(eReturnStatusFailed); 579314564Sdim return false; 580314564Sdim } 581254721Semaste 582314564Sdim // Get CommandObject that is being aliased. The command name is read from 583314564Sdim // the front of raw_command_string. raw_command_string is returned with the 584314564Sdim // name of the command object stripped off the front. 585314564Sdim llvm::StringRef original_raw_command_string = raw_command_string; 586314564Sdim CommandObject *cmd_obj = 587314564Sdim m_interpreter.GetCommandObjectForCommand(raw_command_string); 588254721Semaste 589314564Sdim if (!cmd_obj) { 590314564Sdim result.AppendErrorWithFormat("invalid command given to 'command alias'. " 591314564Sdim "'%s' does not begin with a valid command." 592314564Sdim " No alias created.", 593314564Sdim original_raw_command_string.str().c_str()); 594314564Sdim result.SetStatus(eReturnStatusFailed); 595314564Sdim return false; 596314564Sdim } else if (!cmd_obj->WantsRawCommandString()) { 597314564Sdim // Note that args was initialized with the original command, and has not 598341825Sdim // been updated to this point. Therefore can we pass it to the version of 599341825Sdim // Execute that does not need/expect raw input in the alias. 600314564Sdim return HandleAliasingNormalCommand(args, result); 601314564Sdim } else { 602314564Sdim return HandleAliasingRawCommand(alias_command, raw_command_string, 603314564Sdim *cmd_obj, result); 604314564Sdim } 605314564Sdim return result.Succeeded(); 606314564Sdim } 607254721Semaste 608314564Sdim bool HandleAliasingRawCommand(llvm::StringRef alias_command, 609314564Sdim llvm::StringRef raw_command_string, 610314564Sdim CommandObject &cmd_obj, 611314564Sdim CommandReturnObject &result) { 612314564Sdim // Verify & handle any options/arguments passed to the alias command 613254721Semaste 614314564Sdim OptionArgVectorSP option_arg_vector_sp = 615314564Sdim OptionArgVectorSP(new OptionArgVector); 616254721Semaste 617314564Sdim if (CommandObjectSP cmd_obj_sp = 618314564Sdim m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) { 619314564Sdim if (m_interpreter.AliasExists(alias_command) || 620314564Sdim m_interpreter.UserCommandExists(alias_command)) { 621314564Sdim result.AppendWarningWithFormat( 622314564Sdim "Overwriting existing definition for '%s'.\n", 623314564Sdim alias_command.str().c_str()); 624314564Sdim } 625314564Sdim if (CommandAlias *alias = m_interpreter.AddAlias( 626314564Sdim alias_command, cmd_obj_sp, raw_command_string)) { 627314564Sdim if (m_command_options.m_help.OptionWasSet()) 628314564Sdim alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 629314564Sdim if (m_command_options.m_long_help.OptionWasSet()) 630314564Sdim alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 631314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 632314564Sdim } else { 633314564Sdim result.AppendError("Unable to create requested alias.\n"); 634314564Sdim result.SetStatus(eReturnStatusFailed); 635314564Sdim } 636254721Semaste 637314564Sdim } else { 638314564Sdim result.AppendError("Unable to create requested alias.\n"); 639314564Sdim result.SetStatus(eReturnStatusFailed); 640314564Sdim } 641254721Semaste 642314564Sdim return result.Succeeded(); 643314564Sdim } 644314564Sdim 645314564Sdim bool HandleAliasingNormalCommand(Args &args, CommandReturnObject &result) { 646314564Sdim size_t argc = args.GetArgumentCount(); 647314564Sdim 648314564Sdim if (argc < 2) { 649314564Sdim result.AppendError("'command alias' requires at least two arguments"); 650314564Sdim result.SetStatus(eReturnStatusFailed); 651314564Sdim return false; 652254721Semaste } 653254721Semaste 654314564Sdim // Save these in std::strings since we're going to shift them off. 655360784Sdim const std::string alias_command(args[0].ref()); 656360784Sdim const std::string actual_command(args[1].ref()); 657314564Sdim 658314564Sdim args.Shift(); // Shift the alias command word off the argument vector. 659314564Sdim args.Shift(); // Shift the old command word off the argument vector. 660314564Sdim 661314564Sdim // Verify that the command is alias'able, and get the appropriate command 662314564Sdim // object. 663314564Sdim 664314564Sdim if (m_interpreter.CommandExists(alias_command)) { 665314564Sdim result.AppendErrorWithFormat( 666314564Sdim "'%s' is a permanent debugger command and cannot be redefined.\n", 667314564Sdim alias_command.c_str()); 668314564Sdim result.SetStatus(eReturnStatusFailed); 669314564Sdim return false; 670314564Sdim } 671314564Sdim 672314564Sdim CommandObjectSP command_obj_sp( 673314564Sdim m_interpreter.GetCommandSPExact(actual_command, true)); 674314564Sdim CommandObjectSP subcommand_obj_sp; 675314564Sdim bool use_subcommand = false; 676314564Sdim if (!command_obj_sp) { 677314564Sdim result.AppendErrorWithFormat("'%s' is not an existing command.\n", 678314564Sdim actual_command.c_str()); 679314564Sdim result.SetStatus(eReturnStatusFailed); 680314564Sdim return false; 681314564Sdim } 682314564Sdim CommandObject *cmd_obj = command_obj_sp.get(); 683314564Sdim CommandObject *sub_cmd_obj = nullptr; 684314564Sdim OptionArgVectorSP option_arg_vector_sp = 685314564Sdim OptionArgVectorSP(new OptionArgVector); 686314564Sdim 687314564Sdim while (cmd_obj->IsMultiwordObject() && !args.empty()) { 688360784Sdim auto sub_command = args[0].ref(); 689314564Sdim assert(!sub_command.empty()); 690314564Sdim subcommand_obj_sp = cmd_obj->GetSubcommandSP(sub_command); 691314564Sdim if (!subcommand_obj_sp) { 692314564Sdim result.AppendErrorWithFormat( 693314564Sdim "'%s' is not a valid sub-command of '%s'. " 694314564Sdim "Unable to create alias.\n", 695314564Sdim args[0].c_str(), actual_command.c_str()); 696314564Sdim result.SetStatus(eReturnStatusFailed); 697314564Sdim return false; 698314564Sdim } 699314564Sdim 700314564Sdim sub_cmd_obj = subcommand_obj_sp.get(); 701314564Sdim use_subcommand = true; 702314564Sdim args.Shift(); // Shift the sub_command word off the argument vector. 703314564Sdim cmd_obj = sub_cmd_obj; 704314564Sdim } 705314564Sdim 706314564Sdim // Verify & handle any options/arguments passed to the alias command 707314564Sdim 708314564Sdim std::string args_string; 709314564Sdim 710314564Sdim if (!args.empty()) { 711314564Sdim CommandObjectSP tmp_sp = 712314564Sdim m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false); 713314564Sdim if (use_subcommand) 714314564Sdim tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), 715314564Sdim false); 716314564Sdim 717314564Sdim args.GetCommandString(args_string); 718314564Sdim } 719314564Sdim 720314564Sdim if (m_interpreter.AliasExists(alias_command) || 721314564Sdim m_interpreter.UserCommandExists(alias_command)) { 722314564Sdim result.AppendWarningWithFormat( 723314564Sdim "Overwriting existing definition for '%s'.\n", alias_command.c_str()); 724314564Sdim } 725314564Sdim 726314564Sdim if (CommandAlias *alias = m_interpreter.AddAlias( 727314564Sdim alias_command, use_subcommand ? subcommand_obj_sp : command_obj_sp, 728314564Sdim args_string)) { 729314564Sdim if (m_command_options.m_help.OptionWasSet()) 730314564Sdim alias->SetHelp(m_command_options.m_help.GetCurrentValue()); 731314564Sdim if (m_command_options.m_long_help.OptionWasSet()) 732314564Sdim alias->SetHelpLong(m_command_options.m_long_help.GetCurrentValue()); 733314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 734314564Sdim } else { 735314564Sdim result.AppendError("Unable to create requested alias.\n"); 736314564Sdim result.SetStatus(eReturnStatusFailed); 737314564Sdim return false; 738314564Sdim } 739314564Sdim 740314564Sdim return result.Succeeded(); 741314564Sdim } 742309124Sdim}; 743309124Sdim 744254721Semaste#pragma mark CommandObjectCommandsUnalias 745254721Semaste// CommandObjectCommandsUnalias 746254721Semaste 747314564Sdimclass CommandObjectCommandsUnalias : public CommandObjectParsed { 748254721Semastepublic: 749314564Sdim CommandObjectCommandsUnalias(CommandInterpreter &interpreter) 750314564Sdim : CommandObjectParsed( 751314564Sdim interpreter, "command unalias", 752314564Sdim "Delete one or more custom commands defined by 'command alias'.", 753314564Sdim nullptr) { 754314564Sdim CommandArgumentEntry arg; 755314564Sdim CommandArgumentData alias_arg; 756254721Semaste 757314564Sdim // Define the first (and only) variant of this arg. 758314564Sdim alias_arg.arg_type = eArgTypeAliasName; 759314564Sdim alias_arg.arg_repetition = eArgRepeatPlain; 760254721Semaste 761314564Sdim // There is only one variant this argument could be; put it into the 762314564Sdim // argument entry. 763314564Sdim arg.push_back(alias_arg); 764314564Sdim 765314564Sdim // Push the data for the first argument into the m_arguments vector. 766314564Sdim m_arguments.push_back(arg); 767314564Sdim } 768314564Sdim 769314564Sdim ~CommandObjectCommandsUnalias() override = default; 770314564Sdim 771254721Semasteprotected: 772314564Sdim bool DoExecute(Args &args, CommandReturnObject &result) override { 773314564Sdim CommandObject::CommandMap::iterator pos; 774314564Sdim CommandObject *cmd_obj; 775254721Semaste 776314564Sdim if (args.empty()) { 777314564Sdim result.AppendError("must call 'unalias' with a valid alias"); 778314564Sdim result.SetStatus(eReturnStatusFailed); 779314564Sdim return false; 780314564Sdim } 781254721Semaste 782360784Sdim auto command_name = args[0].ref(); 783314564Sdim cmd_obj = m_interpreter.GetCommandObject(command_name); 784314564Sdim if (!cmd_obj) { 785314564Sdim result.AppendErrorWithFormat( 786314564Sdim "'%s' is not a known command.\nTry 'help' to see a " 787314564Sdim "current list of commands.\n", 788314564Sdim args[0].c_str()); 789314564Sdim result.SetStatus(eReturnStatusFailed); 790314564Sdim return false; 791254721Semaste } 792314564Sdim 793314564Sdim if (m_interpreter.CommandExists(command_name)) { 794314564Sdim if (cmd_obj->IsRemovable()) { 795314564Sdim result.AppendErrorWithFormat( 796314564Sdim "'%s' is not an alias, it is a debugger command which can be " 797314564Sdim "removed using the 'command delete' command.\n", 798314564Sdim args[0].c_str()); 799314564Sdim } else { 800314564Sdim result.AppendErrorWithFormat( 801314564Sdim "'%s' is a permanent debugger command and cannot be removed.\n", 802314564Sdim args[0].c_str()); 803314564Sdim } 804314564Sdim result.SetStatus(eReturnStatusFailed); 805314564Sdim return false; 806314564Sdim } 807314564Sdim 808314564Sdim if (!m_interpreter.RemoveAlias(command_name)) { 809314564Sdim if (m_interpreter.AliasExists(command_name)) 810314564Sdim result.AppendErrorWithFormat( 811314564Sdim "Error occurred while attempting to unalias '%s'.\n", 812314564Sdim args[0].c_str()); 813314564Sdim else 814314564Sdim result.AppendErrorWithFormat("'%s' is not an existing alias.\n", 815314564Sdim args[0].c_str()); 816314564Sdim result.SetStatus(eReturnStatusFailed); 817314564Sdim return false; 818314564Sdim } 819314564Sdim 820314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 821314564Sdim return result.Succeeded(); 822314564Sdim } 823254721Semaste}; 824254721Semaste 825280031Sdim#pragma mark CommandObjectCommandsDelete 826280031Sdim// CommandObjectCommandsDelete 827280031Sdim 828314564Sdimclass CommandObjectCommandsDelete : public CommandObjectParsed { 829280031Sdimpublic: 830314564Sdim CommandObjectCommandsDelete(CommandInterpreter &interpreter) 831314564Sdim : CommandObjectParsed( 832314564Sdim interpreter, "command delete", 833314564Sdim "Delete one or more custom commands defined by 'command regex'.", 834314564Sdim nullptr) { 835314564Sdim CommandArgumentEntry arg; 836314564Sdim CommandArgumentData alias_arg; 837280031Sdim 838314564Sdim // Define the first (and only) variant of this arg. 839314564Sdim alias_arg.arg_type = eArgTypeCommandName; 840314564Sdim alias_arg.arg_repetition = eArgRepeatPlain; 841280031Sdim 842314564Sdim // There is only one variant this argument could be; put it into the 843314564Sdim // argument entry. 844314564Sdim arg.push_back(alias_arg); 845280031Sdim 846314564Sdim // Push the data for the first argument into the m_arguments vector. 847314564Sdim m_arguments.push_back(arg); 848314564Sdim } 849280031Sdim 850314564Sdim ~CommandObjectCommandsDelete() override = default; 851280031Sdim 852280031Sdimprotected: 853314564Sdim bool DoExecute(Args &args, CommandReturnObject &result) override { 854314564Sdim CommandObject::CommandMap::iterator pos; 855280031Sdim 856314564Sdim if (args.empty()) { 857314564Sdim result.AppendErrorWithFormat("must call '%s' with one or more valid user " 858314564Sdim "defined regular expression command names", 859314564Sdim GetCommandName().str().c_str()); 860314564Sdim result.SetStatus(eReturnStatusFailed); 861360784Sdim return false; 862314564Sdim } 863280031Sdim 864360784Sdim auto command_name = args[0].ref(); 865314564Sdim if (!m_interpreter.CommandExists(command_name)) { 866314564Sdim StreamString error_msg_stream; 867353358Sdim const bool generate_upropos = true; 868314564Sdim const bool generate_type_lookup = false; 869314564Sdim CommandObjectHelp::GenerateAdditionalHelpAvenuesMessage( 870314564Sdim &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), 871353358Sdim generate_upropos, generate_type_lookup); 872314564Sdim result.AppendError(error_msg_stream.GetString()); 873314564Sdim result.SetStatus(eReturnStatusFailed); 874314564Sdim return false; 875280031Sdim } 876314564Sdim 877314564Sdim if (!m_interpreter.RemoveCommand(command_name)) { 878314564Sdim result.AppendErrorWithFormat( 879314564Sdim "'%s' is a permanent debugger command and cannot be removed.\n", 880314564Sdim args[0].c_str()); 881314564Sdim result.SetStatus(eReturnStatusFailed); 882314564Sdim return false; 883314564Sdim } 884314564Sdim 885314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 886314564Sdim return true; 887314564Sdim } 888280031Sdim}; 889280031Sdim 890254721Semaste// CommandObjectCommandsAddRegex 891314564Sdim 892360784Sdim#define LLDB_OPTIONS_regex 893360784Sdim#include "CommandOptions.inc" 894314564Sdim 895254721Semaste#pragma mark CommandObjectCommandsAddRegex 896254721Semaste 897314564Sdimclass CommandObjectCommandsAddRegex : public CommandObjectParsed, 898314564Sdim public IOHandlerDelegateMultiline { 899254721Semastepublic: 900314564Sdim CommandObjectCommandsAddRegex(CommandInterpreter &interpreter) 901314564Sdim : CommandObjectParsed( 902360784Sdim interpreter, "command regex", 903360784Sdim "Define a custom command in terms of " 904360784Sdim "existing commands by matching " 905360784Sdim "regular expressions.", 906314564Sdim "command regex <cmd-name> [s/<regex>/<subst>/ ...]"), 907314564Sdim IOHandlerDelegateMultiline("", 908314564Sdim IOHandlerDelegate::Completion::LLDBCommand), 909314564Sdim m_options() { 910314564Sdim SetHelpLong( 911314564Sdim R"( 912314564Sdim)" 913314564Sdim "This command allows the user to create powerful regular expression commands \ 914288943Sdimwith substitutions. The regular expressions and substitutions are specified \ 915314564Sdimusing the regular expression substitution format of:" 916314564Sdim R"( 917288943Sdim 918288943Sdim s/<regex>/<subst>/ 919288943Sdim 920314564Sdim)" 921314564Sdim "<regex> is a regular expression that can use parenthesis to capture regular \ 922288943Sdimexpression input and substitute the captured matches in the output using %1 \ 923314564Sdimfor the first match, %2 for the second, and so on." 924314564Sdim R"( 925288943Sdim 926314564Sdim)" 927314564Sdim "The regular expressions can all be specified on the command line if more than \ 928288943Sdimone argument is provided. If just the command name is provided on the command \ 929288943Sdimline, then the regular expressions and substitutions can be entered on separate \ 930314564Sdimlines, followed by an empty line to terminate the command definition." 931314564Sdim R"( 932288943Sdim 933288943SdimEXAMPLES 934288943Sdim 935314564Sdim)" 936314564Sdim "The following example will define a regular expression command named 'f' that \ 937288943Sdimwill call 'finish' if there are no arguments, or 'frame select <frame-idx>' if \ 938314564Sdima number follows 'f':" 939314564Sdim R"( 940288943Sdim 941314564Sdim (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/')"); 942314564Sdim } 943309124Sdim 944314564Sdim ~CommandObjectCommandsAddRegex() override = default; 945309124Sdim 946254721Semasteprotected: 947353358Sdim void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 948360784Sdim StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 949353358Sdim if (output_sp && interactive) { 950353358Sdim output_sp->PutCString("Enter one or more sed substitution commands in " 951314564Sdim "the form: 's/<regex>/<subst>/'.\nTerminate the " 952314564Sdim "substitution list with an empty line.\n"); 953314564Sdim output_sp->Flush(); 954262528Semaste } 955314564Sdim } 956262528Semaste 957314564Sdim void IOHandlerInputComplete(IOHandler &io_handler, 958314564Sdim std::string &data) override { 959314564Sdim io_handler.SetIsDone(true); 960353358Sdim if (m_regex_cmd_up) { 961314564Sdim StringList lines; 962314564Sdim if (lines.SplitIntoLines(data)) { 963314564Sdim bool check_only = false; 964360784Sdim for (const std::string &line : lines) { 965360784Sdim Status error = AppendRegexSubstitution(line, check_only); 966314564Sdim if (error.Fail()) { 967353358Sdim if (!GetDebugger().GetCommandInterpreter().GetBatchCommandMode()) { 968353358Sdim StreamSP out_stream = GetDebugger().GetAsyncOutputStream(); 969314564Sdim out_stream->Printf("error: %s\n", error.AsCString()); 970262528Semaste } 971314564Sdim } 972262528Semaste } 973314564Sdim } 974353358Sdim if (m_regex_cmd_up->HasRegexEntries()) { 975353358Sdim CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 976314564Sdim m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 977314564Sdim } 978262528Semaste } 979314564Sdim } 980262528Semaste 981314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 982314564Sdim const size_t argc = command.GetArgumentCount(); 983314564Sdim if (argc == 0) { 984314564Sdim result.AppendError("usage: 'command regex <command-name> " 985314564Sdim "[s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n"); 986314564Sdim result.SetStatus(eReturnStatusFailed); 987314564Sdim return false; 988314564Sdim } 989254721Semaste 990321369Sdim Status error; 991360784Sdim auto name = command[0].ref(); 992360784Sdim m_regex_cmd_up = std::make_unique<CommandObjectRegexCommand>( 993314564Sdim m_interpreter, name, m_options.GetHelp(), m_options.GetSyntax(), 10, 0, 994314564Sdim true); 995254721Semaste 996314564Sdim if (argc == 1) { 997353358Sdim Debugger &debugger = GetDebugger(); 998314564Sdim bool color_prompt = debugger.GetUseColor(); 999314564Sdim const bool multiple_lines = true; // Get multiple lines 1000314564Sdim IOHandlerSP io_handler_sp(new IOHandlerEditline( 1001314564Sdim debugger, IOHandler::Type::Other, 1002314564Sdim "lldb-regex", // Name of input reader for history 1003314564Sdim llvm::StringRef("> "), // Prompt 1004314564Sdim llvm::StringRef(), // Continuation prompt 1005314564Sdim multiple_lines, color_prompt, 1006314564Sdim 0, // Don't show line numbers 1007353358Sdim *this, nullptr)); 1008314564Sdim 1009314564Sdim if (io_handler_sp) { 1010314564Sdim debugger.PushIOHandler(io_handler_sp); 1011314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1012314564Sdim } 1013314564Sdim } else { 1014314564Sdim for (auto &entry : command.entries().drop_front()) { 1015314564Sdim bool check_only = false; 1016360784Sdim error = AppendRegexSubstitution(entry.ref(), check_only); 1017314564Sdim if (error.Fail()) 1018314564Sdim break; 1019314564Sdim } 1020314564Sdim 1021314564Sdim if (error.Success()) { 1022314564Sdim AddRegexCommandToInterpreter(); 1023314564Sdim } 1024254721Semaste } 1025314564Sdim if (error.Fail()) { 1026314564Sdim result.AppendError(error.AsCString()); 1027314564Sdim result.SetStatus(eReturnStatusFailed); 1028314564Sdim } 1029254721Semaste 1030314564Sdim return result.Succeeded(); 1031314564Sdim } 1032254721Semaste 1033321369Sdim Status AppendRegexSubstitution(const llvm::StringRef ®ex_sed, 1034321369Sdim bool check_only) { 1035321369Sdim Status error; 1036254721Semaste 1037353358Sdim if (!m_regex_cmd_up) { 1038314564Sdim error.SetErrorStringWithFormat( 1039314564Sdim "invalid regular expression command object for: '%.*s'", 1040314564Sdim (int)regex_sed.size(), regex_sed.data()); 1041314564Sdim return error; 1042314564Sdim } 1043262528Semaste 1044314564Sdim size_t regex_sed_size = regex_sed.size(); 1045314564Sdim 1046314564Sdim if (regex_sed_size <= 1) { 1047314564Sdim error.SetErrorStringWithFormat( 1048314564Sdim "regular expression substitution string is too short: '%.*s'", 1049314564Sdim (int)regex_sed.size(), regex_sed.data()); 1050314564Sdim return error; 1051314564Sdim } 1052314564Sdim 1053314564Sdim if (regex_sed[0] != 's') { 1054314564Sdim error.SetErrorStringWithFormat("regular expression substitution string " 1055314564Sdim "doesn't start with 's': '%.*s'", 1056314564Sdim (int)regex_sed.size(), regex_sed.data()); 1057314564Sdim return error; 1058314564Sdim } 1059314564Sdim const size_t first_separator_char_pos = 1; 1060341825Sdim // use the char that follows 's' as the regex separator character so we can 1061341825Sdim // have "s/<regex>/<subst>/" or "s|<regex>|<subst>|" 1062314564Sdim const char separator_char = regex_sed[first_separator_char_pos]; 1063314564Sdim const size_t second_separator_char_pos = 1064314564Sdim regex_sed.find(separator_char, first_separator_char_pos + 1); 1065314564Sdim 1066314564Sdim if (second_separator_char_pos == std::string::npos) { 1067314564Sdim error.SetErrorStringWithFormat( 1068314564Sdim "missing second '%c' separator char after '%.*s' in '%.*s'", 1069314564Sdim separator_char, 1070314564Sdim (int)(regex_sed.size() - first_separator_char_pos - 1), 1071314564Sdim regex_sed.data() + (first_separator_char_pos + 1), 1072314564Sdim (int)regex_sed.size(), regex_sed.data()); 1073314564Sdim return error; 1074314564Sdim } 1075314564Sdim 1076314564Sdim const size_t third_separator_char_pos = 1077314564Sdim regex_sed.find(separator_char, second_separator_char_pos + 1); 1078314564Sdim 1079314564Sdim if (third_separator_char_pos == std::string::npos) { 1080314564Sdim error.SetErrorStringWithFormat( 1081314564Sdim "missing third '%c' separator char after '%.*s' in '%.*s'", 1082314564Sdim separator_char, 1083314564Sdim (int)(regex_sed.size() - second_separator_char_pos - 1), 1084314564Sdim regex_sed.data() + (second_separator_char_pos + 1), 1085314564Sdim (int)regex_sed.size(), regex_sed.data()); 1086314564Sdim return error; 1087314564Sdim } 1088314564Sdim 1089314564Sdim if (third_separator_char_pos != regex_sed_size - 1) { 1090341825Sdim // Make sure that everything that follows the last regex separator char 1091314564Sdim if (regex_sed.find_first_not_of("\t\n\v\f\r ", 1092314564Sdim third_separator_char_pos + 1) != 1093314564Sdim std::string::npos) { 1094314564Sdim error.SetErrorStringWithFormat( 1095314564Sdim "extra data found after the '%.*s' regular expression substitution " 1096314564Sdim "string: '%.*s'", 1097314564Sdim (int)third_separator_char_pos + 1, regex_sed.data(), 1098314564Sdim (int)(regex_sed.size() - third_separator_char_pos - 1), 1099314564Sdim regex_sed.data() + (third_separator_char_pos + 1)); 1100254721Semaste return error; 1101314564Sdim } 1102314564Sdim } else if (first_separator_char_pos + 1 == second_separator_char_pos) { 1103314564Sdim error.SetErrorStringWithFormat( 1104314564Sdim "<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1105314564Sdim separator_char, separator_char, separator_char, (int)regex_sed.size(), 1106314564Sdim regex_sed.data()); 1107314564Sdim return error; 1108314564Sdim } else if (second_separator_char_pos + 1 == third_separator_char_pos) { 1109314564Sdim error.SetErrorStringWithFormat( 1110314564Sdim "<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'", 1111314564Sdim separator_char, separator_char, separator_char, (int)regex_sed.size(), 1112314564Sdim regex_sed.data()); 1113314564Sdim return error; 1114254721Semaste } 1115314564Sdim 1116314564Sdim if (!check_only) { 1117314564Sdim std::string regex(regex_sed.substr(first_separator_char_pos + 1, 1118314564Sdim second_separator_char_pos - 1119314564Sdim first_separator_char_pos - 1)); 1120314564Sdim std::string subst(regex_sed.substr(second_separator_char_pos + 1, 1121314564Sdim third_separator_char_pos - 1122314564Sdim second_separator_char_pos - 1)); 1123353358Sdim m_regex_cmd_up->AddRegexCommand(regex.c_str(), subst.c_str()); 1124254721Semaste } 1125314564Sdim return error; 1126314564Sdim } 1127254721Semaste 1128314564Sdim void AddRegexCommandToInterpreter() { 1129353358Sdim if (m_regex_cmd_up) { 1130353358Sdim if (m_regex_cmd_up->HasRegexEntries()) { 1131353358Sdim CommandObjectSP cmd_sp(m_regex_cmd_up.release()); 1132314564Sdim m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true); 1133314564Sdim } 1134314564Sdim } 1135314564Sdim } 1136314564Sdim 1137254721Semasteprivate: 1138353358Sdim std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_up; 1139254721Semaste 1140314564Sdim class CommandOptions : public Options { 1141314564Sdim public: 1142314564Sdim CommandOptions() : Options() {} 1143309124Sdim 1144314564Sdim ~CommandOptions() override = default; 1145309124Sdim 1146321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1147321369Sdim ExecutionContext *execution_context) override { 1148321369Sdim Status error; 1149314564Sdim const int short_option = m_getopt_table[option_idx].val; 1150309124Sdim 1151314564Sdim switch (short_option) { 1152314564Sdim case 'h': 1153314564Sdim m_help.assign(option_arg); 1154314564Sdim break; 1155314564Sdim case 's': 1156314564Sdim m_syntax.assign(option_arg); 1157314564Sdim break; 1158314564Sdim default: 1159360784Sdim llvm_unreachable("Unimplemented option"); 1160314564Sdim } 1161309124Sdim 1162314564Sdim return error; 1163314564Sdim } 1164309124Sdim 1165314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 1166314564Sdim m_help.clear(); 1167314564Sdim m_syntax.clear(); 1168314564Sdim } 1169254721Semaste 1170314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1171314564Sdim return llvm::makeArrayRef(g_regex_options); 1172314564Sdim } 1173314564Sdim 1174314564Sdim // TODO: Convert these functions to return StringRefs. 1175314564Sdim const char *GetHelp() { 1176314564Sdim return (m_help.empty() ? nullptr : m_help.c_str()); 1177314564Sdim } 1178314564Sdim 1179314564Sdim const char *GetSyntax() { 1180314564Sdim return (m_syntax.empty() ? nullptr : m_syntax.c_str()); 1181314564Sdim } 1182314564Sdim 1183314564Sdim protected: 1184314564Sdim // Instance variables to hold the values for command options. 1185314564Sdim 1186314564Sdim std::string m_help; 1187314564Sdim std::string m_syntax; 1188314564Sdim }; 1189314564Sdim 1190314564Sdim Options *GetOptions() override { return &m_options; } 1191314564Sdim 1192314564Sdim CommandOptions m_options; 1193254721Semaste}; 1194254721Semaste 1195314564Sdimclass CommandObjectPythonFunction : public CommandObjectRaw { 1196254721Semastepublic: 1197314564Sdim CommandObjectPythonFunction(CommandInterpreter &interpreter, std::string name, 1198314564Sdim std::string funct, std::string help, 1199314564Sdim ScriptedCommandSynchronicity synch) 1200360784Sdim : CommandObjectRaw(interpreter, name), m_function_name(funct), 1201360784Sdim m_synchro(synch), m_fetched_help_long(false) { 1202314564Sdim if (!help.empty()) 1203314564Sdim SetHelp(help); 1204314564Sdim else { 1205314564Sdim StreamString stream; 1206314564Sdim stream.Printf("For more information run 'help %s'", name.c_str()); 1207314564Sdim SetHelp(stream.GetString()); 1208254721Semaste } 1209314564Sdim } 1210309124Sdim 1211314564Sdim ~CommandObjectPythonFunction() override = default; 1212309124Sdim 1213314564Sdim bool IsRemovable() const override { return true; } 1214254721Semaste 1215314564Sdim const std::string &GetFunctionName() { return m_function_name; } 1216254721Semaste 1217314564Sdim ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1218314564Sdim 1219314564Sdim llvm::StringRef GetHelpLong() override { 1220314564Sdim if (m_fetched_help_long) 1221314564Sdim return CommandObjectRaw::GetHelpLong(); 1222314564Sdim 1223353358Sdim ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1224314564Sdim if (!scripter) 1225314564Sdim return CommandObjectRaw::GetHelpLong(); 1226314564Sdim 1227314564Sdim std::string docstring; 1228314564Sdim m_fetched_help_long = 1229314564Sdim scripter->GetDocumentationForItem(m_function_name.c_str(), docstring); 1230314564Sdim if (!docstring.empty()) 1231314564Sdim SetHelpLong(docstring); 1232314564Sdim return CommandObjectRaw::GetHelpLong(); 1233314564Sdim } 1234314564Sdim 1235254721Semasteprotected: 1236341825Sdim bool DoExecute(llvm::StringRef raw_command_line, 1237314564Sdim CommandReturnObject &result) override { 1238353358Sdim ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1239314564Sdim 1240321369Sdim Status error; 1241314564Sdim 1242314564Sdim result.SetStatus(eReturnStatusInvalid); 1243314564Sdim 1244360784Sdim if (!scripter || !scripter->RunScriptBasedCommand( 1245360784Sdim m_function_name.c_str(), raw_command_line, m_synchro, 1246360784Sdim result, error, m_exe_ctx)) { 1247314564Sdim result.AppendError(error.AsCString()); 1248314564Sdim result.SetStatus(eReturnStatusFailed); 1249314564Sdim } else { 1250314564Sdim // Don't change the status if the command already set it... 1251314564Sdim if (result.GetStatus() == eReturnStatusInvalid) { 1252314564Sdim if (result.GetOutputData().empty()) 1253314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1254254721Semaste else 1255314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 1256314564Sdim } 1257254721Semaste } 1258309124Sdim 1259314564Sdim return result.Succeeded(); 1260314564Sdim } 1261314564Sdim 1262309124Sdimprivate: 1263314564Sdim std::string m_function_name; 1264314564Sdim ScriptedCommandSynchronicity m_synchro; 1265314564Sdim bool m_fetched_help_long; 1266254721Semaste}; 1267254721Semaste 1268314564Sdimclass CommandObjectScriptingObject : public CommandObjectRaw { 1269288943Sdimpublic: 1270314564Sdim CommandObjectScriptingObject(CommandInterpreter &interpreter, 1271314564Sdim std::string name, 1272314564Sdim StructuredData::GenericSP cmd_obj_sp, 1273314564Sdim ScriptedCommandSynchronicity synch) 1274360784Sdim : CommandObjectRaw(interpreter, name), m_cmd_obj_sp(cmd_obj_sp), 1275360784Sdim m_synchro(synch), m_fetched_help_short(false), 1276314564Sdim m_fetched_help_long(false) { 1277314564Sdim StreamString stream; 1278314564Sdim stream.Printf("For more information run 'help %s'", name.c_str()); 1279314564Sdim SetHelp(stream.GetString()); 1280353358Sdim if (ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter()) 1281314564Sdim GetFlags().Set(scripter->GetFlagsForCommandObject(cmd_obj_sp)); 1282314564Sdim } 1283309124Sdim 1284314564Sdim ~CommandObjectScriptingObject() override = default; 1285309124Sdim 1286314564Sdim bool IsRemovable() const override { return true; } 1287288943Sdim 1288314564Sdim ScriptedCommandSynchronicity GetSynchronicity() { return m_synchro; } 1289314564Sdim 1290314564Sdim llvm::StringRef GetHelp() override { 1291314564Sdim if (m_fetched_help_short) 1292314564Sdim return CommandObjectRaw::GetHelp(); 1293353358Sdim ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1294314564Sdim if (!scripter) 1295314564Sdim return CommandObjectRaw::GetHelp(); 1296314564Sdim std::string docstring; 1297314564Sdim m_fetched_help_short = 1298314564Sdim scripter->GetShortHelpForCommandObject(m_cmd_obj_sp, docstring); 1299314564Sdim if (!docstring.empty()) 1300314564Sdim SetHelp(docstring); 1301314564Sdim 1302314564Sdim return CommandObjectRaw::GetHelp(); 1303314564Sdim } 1304314564Sdim 1305314564Sdim llvm::StringRef GetHelpLong() override { 1306314564Sdim if (m_fetched_help_long) 1307314564Sdim return CommandObjectRaw::GetHelpLong(); 1308314564Sdim 1309353358Sdim ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1310314564Sdim if (!scripter) 1311314564Sdim return CommandObjectRaw::GetHelpLong(); 1312314564Sdim 1313314564Sdim std::string docstring; 1314314564Sdim m_fetched_help_long = 1315314564Sdim scripter->GetLongHelpForCommandObject(m_cmd_obj_sp, docstring); 1316314564Sdim if (!docstring.empty()) 1317314564Sdim SetHelpLong(docstring); 1318314564Sdim return CommandObjectRaw::GetHelpLong(); 1319314564Sdim } 1320314564Sdim 1321288943Sdimprotected: 1322341825Sdim bool DoExecute(llvm::StringRef raw_command_line, 1323314564Sdim CommandReturnObject &result) override { 1324353358Sdim ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter(); 1325314564Sdim 1326321369Sdim Status error; 1327314564Sdim 1328314564Sdim result.SetStatus(eReturnStatusInvalid); 1329314564Sdim 1330314564Sdim if (!scripter || 1331314564Sdim !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, 1332314564Sdim m_synchro, result, error, m_exe_ctx)) { 1333314564Sdim result.AppendError(error.AsCString()); 1334314564Sdim result.SetStatus(eReturnStatusFailed); 1335314564Sdim } else { 1336314564Sdim // Don't change the status if the command already set it... 1337314564Sdim if (result.GetStatus() == eReturnStatusInvalid) { 1338314564Sdim if (result.GetOutputData().empty()) 1339314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1340288943Sdim else 1341314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 1342314564Sdim } 1343288943Sdim } 1344309124Sdim 1345314564Sdim return result.Succeeded(); 1346314564Sdim } 1347314564Sdim 1348309124Sdimprivate: 1349314564Sdim StructuredData::GenericSP m_cmd_obj_sp; 1350314564Sdim ScriptedCommandSynchronicity m_synchro; 1351314564Sdim bool m_fetched_help_short : 1; 1352314564Sdim bool m_fetched_help_long : 1; 1353288943Sdim}; 1354288943Sdim 1355254721Semaste// CommandObjectCommandsScriptImport 1356360784Sdim#define LLDB_OPTIONS_script_import 1357360784Sdim#include "CommandOptions.inc" 1358254721Semaste 1359314564Sdimclass CommandObjectCommandsScriptImport : public CommandObjectParsed { 1360254721Semastepublic: 1361314564Sdim CommandObjectCommandsScriptImport(CommandInterpreter &interpreter) 1362314564Sdim : CommandObjectParsed(interpreter, "command script import", 1363314564Sdim "Import a scripting module in LLDB.", nullptr), 1364314564Sdim m_options() { 1365314564Sdim CommandArgumentEntry arg1; 1366314564Sdim CommandArgumentData cmd_arg; 1367309124Sdim 1368314564Sdim // Define the first (and only) variant of this arg. 1369314564Sdim cmd_arg.arg_type = eArgTypeFilename; 1370314564Sdim cmd_arg.arg_repetition = eArgRepeatPlus; 1371309124Sdim 1372314564Sdim // There is only one variant this argument could be; put it into the 1373314564Sdim // argument entry. 1374314564Sdim arg1.push_back(cmd_arg); 1375314564Sdim 1376314564Sdim // Push the data for the first argument into the m_arguments vector. 1377314564Sdim m_arguments.push_back(arg1); 1378314564Sdim } 1379314564Sdim 1380314564Sdim ~CommandObjectCommandsScriptImport() override = default; 1381314564Sdim 1382360784Sdim void 1383360784Sdim HandleArgumentCompletion(CompletionRequest &request, 1384360784Sdim OptionElementVector &opt_element_vector) override { 1385314564Sdim CommandCompletions::InvokeCommonCompletionCallbacks( 1386314564Sdim GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, 1387341825Sdim request, nullptr); 1388314564Sdim } 1389314564Sdim 1390314564Sdim Options *GetOptions() override { return &m_options; } 1391314564Sdim 1392314564Sdimprotected: 1393314564Sdim class CommandOptions : public Options { 1394314564Sdim public: 1395314564Sdim CommandOptions() : Options() {} 1396314564Sdim 1397314564Sdim ~CommandOptions() override = default; 1398314564Sdim 1399321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1400321369Sdim ExecutionContext *execution_context) override { 1401321369Sdim Status error; 1402314564Sdim const int short_option = m_getopt_table[option_idx].val; 1403314564Sdim 1404314564Sdim switch (short_option) { 1405314564Sdim case 'r': 1406360784Sdim // NO-OP 1407314564Sdim break; 1408314564Sdim default: 1409360784Sdim llvm_unreachable("Unimplemented option"); 1410314564Sdim } 1411314564Sdim 1412314564Sdim return error; 1413254721Semaste } 1414314564Sdim 1415314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 1416254721Semaste } 1417254721Semaste 1418314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1419314564Sdim return llvm::makeArrayRef(g_script_import_options); 1420314564Sdim } 1421314564Sdim }; 1422254721Semaste 1423314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 1424314564Sdim if (command.empty()) { 1425314564Sdim result.AppendError("command script import needs one or more arguments"); 1426314564Sdim result.SetStatus(eReturnStatusFailed); 1427314564Sdim return false; 1428314564Sdim } 1429314564Sdim 1430314564Sdim for (auto &entry : command.entries()) { 1431321369Sdim Status error; 1432314564Sdim 1433314564Sdim const bool init_session = true; 1434314564Sdim // FIXME: this is necessary because CommandObject::CheckRequirements() 1435314564Sdim // assumes that commands won't ever be recursively invoked, but it's 1436314564Sdim // actually possible to craft a Python script that does other "command 1437341825Sdim // script imports" in __lldb_init_module the real fix is to have 1438341825Sdim // recursive commands possible with a CommandInvocation object separate 1439341825Sdim // from the CommandObject itself, so that recursive command invocations 1440341825Sdim // won't stomp on each other (wrt to execution contents, options, and 1441341825Sdim // more) 1442314564Sdim m_exe_ctx.Clear(); 1443353358Sdim if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( 1444360784Sdim entry.c_str(), init_session, error)) { 1445314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1446314564Sdim } else { 1447314564Sdim result.AppendErrorWithFormat("module importing failed: %s", 1448314564Sdim error.AsCString()); 1449314564Sdim result.SetStatus(eReturnStatusFailed); 1450314564Sdim } 1451314564Sdim } 1452314564Sdim 1453314564Sdim return result.Succeeded(); 1454314564Sdim } 1455314564Sdim 1456314564Sdim CommandOptions m_options; 1457254721Semaste}; 1458254721Semaste 1459254721Semaste// CommandObjectCommandsScriptAdd 1460344779Sdimstatic constexpr OptionEnumValueElement g_script_synchro_type[] = { 1461360784Sdim { 1462360784Sdim eScriptedCommandSynchronicitySynchronous, 1463360784Sdim "synchronous", 1464360784Sdim "Run synchronous", 1465360784Sdim }, 1466360784Sdim { 1467360784Sdim eScriptedCommandSynchronicityAsynchronous, 1468360784Sdim "asynchronous", 1469360784Sdim "Run asynchronous", 1470360784Sdim }, 1471360784Sdim { 1472360784Sdim eScriptedCommandSynchronicityCurrentValue, 1473360784Sdim "current", 1474360784Sdim "Do not alter current setting", 1475360784Sdim }, 1476360784Sdim}; 1477254721Semaste 1478344779Sdimstatic constexpr OptionEnumValues ScriptSynchroType() { 1479344779Sdim return OptionEnumValues(g_script_synchro_type); 1480344779Sdim} 1481314564Sdim 1482360784Sdim#define LLDB_OPTIONS_script_add 1483360784Sdim#include "CommandOptions.inc" 1484314564Sdim 1485314564Sdimclass CommandObjectCommandsScriptAdd : public CommandObjectParsed, 1486314564Sdim public IOHandlerDelegateMultiline { 1487254721Semastepublic: 1488314564Sdim CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) 1489314564Sdim : CommandObjectParsed(interpreter, "command script add", 1490309124Sdim "Add a scripted function as an LLDB command.", 1491309124Sdim nullptr), 1492314564Sdim IOHandlerDelegateMultiline("DONE"), m_options() { 1493314564Sdim CommandArgumentEntry arg1; 1494314564Sdim CommandArgumentData cmd_arg; 1495314564Sdim 1496314564Sdim // Define the first (and only) variant of this arg. 1497314564Sdim cmd_arg.arg_type = eArgTypeCommandName; 1498314564Sdim cmd_arg.arg_repetition = eArgRepeatPlain; 1499314564Sdim 1500314564Sdim // There is only one variant this argument could be; put it into the 1501314564Sdim // argument entry. 1502314564Sdim arg1.push_back(cmd_arg); 1503314564Sdim 1504314564Sdim // Push the data for the first argument into the m_arguments vector. 1505314564Sdim m_arguments.push_back(arg1); 1506314564Sdim } 1507314564Sdim 1508314564Sdim ~CommandObjectCommandsScriptAdd() override = default; 1509314564Sdim 1510314564Sdim Options *GetOptions() override { return &m_options; } 1511314564Sdim 1512314564Sdimprotected: 1513314564Sdim class CommandOptions : public Options { 1514314564Sdim public: 1515314564Sdim CommandOptions() 1516314564Sdim : Options(), m_class_name(), m_funct_name(), m_short_help(), 1517314564Sdim m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} 1518314564Sdim 1519314564Sdim ~CommandOptions() override = default; 1520314564Sdim 1521321369Sdim Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1522321369Sdim ExecutionContext *execution_context) override { 1523321369Sdim Status error; 1524314564Sdim const int short_option = m_getopt_table[option_idx].val; 1525314564Sdim 1526314564Sdim switch (short_option) { 1527314564Sdim case 'f': 1528314564Sdim if (!option_arg.empty()) 1529314564Sdim m_funct_name = option_arg; 1530314564Sdim break; 1531314564Sdim case 'c': 1532314564Sdim if (!option_arg.empty()) 1533314564Sdim m_class_name = option_arg; 1534314564Sdim break; 1535314564Sdim case 'h': 1536314564Sdim if (!option_arg.empty()) 1537314564Sdim m_short_help = option_arg; 1538314564Sdim break; 1539314564Sdim case 's': 1540314564Sdim m_synchronicity = 1541341825Sdim (ScriptedCommandSynchronicity)OptionArgParser::ToOptionEnum( 1542314564Sdim option_arg, GetDefinitions()[option_idx].enum_values, 0, error); 1543314564Sdim if (!error.Success()) 1544314564Sdim error.SetErrorStringWithFormat( 1545314564Sdim "unrecognized value for synchronicity '%s'", 1546314564Sdim option_arg.str().c_str()); 1547314564Sdim break; 1548314564Sdim default: 1549360784Sdim llvm_unreachable("Unimplemented option"); 1550314564Sdim } 1551314564Sdim 1552314564Sdim return error; 1553254721Semaste } 1554309124Sdim 1555314564Sdim void OptionParsingStarting(ExecutionContext *execution_context) override { 1556314564Sdim m_class_name.clear(); 1557314564Sdim m_funct_name.clear(); 1558314564Sdim m_short_help.clear(); 1559314564Sdim m_synchronicity = eScriptedCommandSynchronicitySynchronous; 1560314564Sdim } 1561309124Sdim 1562314564Sdim llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1563314564Sdim return llvm::makeArrayRef(g_script_add_options); 1564254721Semaste } 1565309124Sdim 1566314564Sdim // Instance variables to hold the values for command options. 1567309124Sdim 1568314564Sdim std::string m_class_name; 1569314564Sdim std::string m_funct_name; 1570314564Sdim std::string m_short_help; 1571314564Sdim ScriptedCommandSynchronicity m_synchronicity; 1572314564Sdim }; 1573254721Semaste 1574353358Sdim void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { 1575360784Sdim StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); 1576353358Sdim if (output_sp && interactive) { 1577314564Sdim output_sp->PutCString(g_python_command_instructions); 1578314564Sdim output_sp->Flush(); 1579262528Semaste } 1580314564Sdim } 1581262528Semaste 1582314564Sdim void IOHandlerInputComplete(IOHandler &io_handler, 1583314564Sdim std::string &data) override { 1584360784Sdim StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); 1585314564Sdim 1586353358Sdim ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1587314564Sdim if (interpreter) { 1588314564Sdim 1589314564Sdim StringList lines; 1590314564Sdim lines.SplitIntoLines(data); 1591314564Sdim if (lines.GetSize() > 0) { 1592314564Sdim std::string funct_name_str; 1593314564Sdim if (interpreter->GenerateScriptAliasFunction(lines, funct_name_str)) { 1594314564Sdim if (funct_name_str.empty()) { 1595314564Sdim error_sp->Printf("error: unable to obtain a function name, didn't " 1596314564Sdim "add python command.\n"); 1597314564Sdim error_sp->Flush(); 1598314564Sdim } else { 1599314564Sdim // everything should be fine now, let's add this alias 1600314564Sdim 1601314564Sdim CommandObjectSP command_obj_sp(new CommandObjectPythonFunction( 1602314564Sdim m_interpreter, m_cmd_name, funct_name_str, m_short_help, 1603314564Sdim m_synchronicity)); 1604314564Sdim 1605314564Sdim if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, 1606314564Sdim true)) { 1607314564Sdim error_sp->Printf("error: unable to add selected command, didn't " 1608314564Sdim "add python command.\n"); 1609314564Sdim error_sp->Flush(); 1610254721Semaste } 1611314564Sdim } 1612314564Sdim } else { 1613314564Sdim error_sp->Printf( 1614314564Sdim "error: unable to create function, didn't add python command.\n"); 1615314564Sdim error_sp->Flush(); 1616254721Semaste } 1617314564Sdim } else { 1618314564Sdim error_sp->Printf("error: empty function, didn't add python command.\n"); 1619314564Sdim error_sp->Flush(); 1620314564Sdim } 1621314564Sdim } else { 1622314564Sdim error_sp->Printf( 1623314564Sdim "error: script interpreter missing, didn't add python command.\n"); 1624314564Sdim error_sp->Flush(); 1625314564Sdim } 1626262528Semaste 1627314564Sdim io_handler.SetIsDone(true); 1628314564Sdim } 1629314564Sdim 1630314564Sdimprotected: 1631314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 1632353358Sdim if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { 1633314564Sdim result.AppendError("only scripting language supported for scripted " 1634314564Sdim "commands is currently Python"); 1635314564Sdim result.SetStatus(eReturnStatusFailed); 1636314564Sdim return false; 1637262528Semaste } 1638262528Semaste 1639314564Sdim if (command.GetArgumentCount() != 1) { 1640314564Sdim result.AppendError("'command script add' requires one argument"); 1641314564Sdim result.SetStatus(eReturnStatusFailed); 1642314564Sdim return false; 1643314564Sdim } 1644314564Sdim 1645314564Sdim // Store the options in case we get multi-line input 1646360784Sdim m_cmd_name = command[0].ref(); 1647314564Sdim m_short_help.assign(m_options.m_short_help); 1648314564Sdim m_synchronicity = m_options.m_synchronicity; 1649314564Sdim 1650314564Sdim if (m_options.m_class_name.empty()) { 1651314564Sdim if (m_options.m_funct_name.empty()) { 1652314564Sdim m_interpreter.GetPythonCommandsFromIOHandler( 1653360784Sdim " ", // Prompt 1654360784Sdim *this); // IOHandlerDelegate 1655314564Sdim } else { 1656314564Sdim CommandObjectSP new_cmd(new CommandObjectPythonFunction( 1657314564Sdim m_interpreter, m_cmd_name, m_options.m_funct_name, 1658314564Sdim m_options.m_short_help, m_synchronicity)); 1659314564Sdim if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1660314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1661314564Sdim } else { 1662314564Sdim result.AppendError("cannot add command"); 1663314564Sdim result.SetStatus(eReturnStatusFailed); 1664254721Semaste } 1665314564Sdim } 1666314564Sdim } else { 1667353358Sdim ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); 1668314564Sdim if (!interpreter) { 1669314564Sdim result.AppendError("cannot find ScriptInterpreter"); 1670314564Sdim result.SetStatus(eReturnStatusFailed); 1671314564Sdim return false; 1672314564Sdim } 1673254721Semaste 1674314564Sdim auto cmd_obj_sp = interpreter->CreateScriptCommandObject( 1675314564Sdim m_options.m_class_name.c_str()); 1676314564Sdim if (!cmd_obj_sp) { 1677314564Sdim result.AppendError("cannot create helper object"); 1678314564Sdim result.SetStatus(eReturnStatusFailed); 1679314564Sdim return false; 1680314564Sdim } 1681314564Sdim 1682314564Sdim CommandObjectSP new_cmd(new CommandObjectScriptingObject( 1683314564Sdim m_interpreter, m_cmd_name, cmd_obj_sp, m_synchronicity)); 1684314564Sdim if (m_interpreter.AddUserCommand(m_cmd_name, new_cmd, true)) { 1685314564Sdim result.SetStatus(eReturnStatusSuccessFinishNoResult); 1686314564Sdim } else { 1687314564Sdim result.AppendError("cannot add command"); 1688314564Sdim result.SetStatus(eReturnStatusFailed); 1689314564Sdim } 1690254721Semaste } 1691254721Semaste 1692314564Sdim return result.Succeeded(); 1693314564Sdim } 1694254721Semaste 1695314564Sdim CommandOptions m_options; 1696314564Sdim std::string m_cmd_name; 1697314564Sdim std::string m_short_help; 1698314564Sdim ScriptedCommandSynchronicity m_synchronicity; 1699254721Semaste}; 1700254721Semaste 1701254721Semaste// CommandObjectCommandsScriptList 1702254721Semaste 1703314564Sdimclass CommandObjectCommandsScriptList : public CommandObjectParsed { 1704254721Semastepublic: 1705314564Sdim CommandObjectCommandsScriptList(CommandInterpreter &interpreter) 1706314564Sdim : CommandObjectParsed(interpreter, "command script list", 1707314564Sdim "List defined scripted commands.", nullptr) {} 1708309124Sdim 1709314564Sdim ~CommandObjectCommandsScriptList() override = default; 1710309124Sdim 1711314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 1712360784Sdim if (command.GetArgumentCount() != 0) { 1713360784Sdim result.AppendError("'command script list' doesn't take any arguments"); 1714360784Sdim result.SetStatus(eReturnStatusFailed); 1715360784Sdim return false; 1716360784Sdim } 1717360784Sdim 1718314564Sdim m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef); 1719314564Sdim 1720314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 1721314564Sdim 1722314564Sdim return true; 1723314564Sdim } 1724254721Semaste}; 1725254721Semaste 1726254721Semaste// CommandObjectCommandsScriptClear 1727254721Semaste 1728314564Sdimclass CommandObjectCommandsScriptClear : public CommandObjectParsed { 1729254721Semastepublic: 1730314564Sdim CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) 1731314564Sdim : CommandObjectParsed(interpreter, "command script clear", 1732314564Sdim "Delete all scripted commands.", nullptr) {} 1733309124Sdim 1734314564Sdim ~CommandObjectCommandsScriptClear() override = default; 1735309124Sdim 1736254721Semasteprotected: 1737314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 1738360784Sdim if (command.GetArgumentCount() != 0) { 1739360784Sdim result.AppendError("'command script clear' doesn't take any arguments"); 1740360784Sdim result.SetStatus(eReturnStatusFailed); 1741360784Sdim return false; 1742360784Sdim } 1743360784Sdim 1744314564Sdim m_interpreter.RemoveAllUser(); 1745314564Sdim 1746314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 1747314564Sdim 1748314564Sdim return true; 1749314564Sdim } 1750254721Semaste}; 1751254721Semaste 1752254721Semaste// CommandObjectCommandsScriptDelete 1753254721Semaste 1754314564Sdimclass CommandObjectCommandsScriptDelete : public CommandObjectParsed { 1755254721Semastepublic: 1756314564Sdim CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) 1757314564Sdim : CommandObjectParsed(interpreter, "command script delete", 1758314564Sdim "Delete a scripted command.", nullptr) { 1759314564Sdim CommandArgumentEntry arg1; 1760314564Sdim CommandArgumentData cmd_arg; 1761309124Sdim 1762314564Sdim // Define the first (and only) variant of this arg. 1763314564Sdim cmd_arg.arg_type = eArgTypeCommandName; 1764314564Sdim cmd_arg.arg_repetition = eArgRepeatPlain; 1765309124Sdim 1766314564Sdim // There is only one variant this argument could be; put it into the 1767314564Sdim // argument entry. 1768314564Sdim arg1.push_back(cmd_arg); 1769314564Sdim 1770314564Sdim // Push the data for the first argument into the m_arguments vector. 1771314564Sdim m_arguments.push_back(arg1); 1772314564Sdim } 1773314564Sdim 1774314564Sdim ~CommandObjectCommandsScriptDelete() override = default; 1775314564Sdim 1776254721Semasteprotected: 1777314564Sdim bool DoExecute(Args &command, CommandReturnObject &result) override { 1778314564Sdim 1779314564Sdim if (command.GetArgumentCount() != 1) { 1780314564Sdim result.AppendError("'command script delete' requires one argument"); 1781314564Sdim result.SetStatus(eReturnStatusFailed); 1782314564Sdim return false; 1783254721Semaste } 1784314564Sdim 1785360784Sdim auto cmd_name = command[0].ref(); 1786314564Sdim 1787314564Sdim if (cmd_name.empty() || !m_interpreter.HasUserCommands() || 1788314564Sdim !m_interpreter.UserCommandExists(cmd_name)) { 1789314564Sdim result.AppendErrorWithFormat("command %s not found", command[0].c_str()); 1790314564Sdim result.SetStatus(eReturnStatusFailed); 1791314564Sdim return false; 1792314564Sdim } 1793314564Sdim 1794314564Sdim m_interpreter.RemoveUser(cmd_name); 1795314564Sdim result.SetStatus(eReturnStatusSuccessFinishResult); 1796314564Sdim return true; 1797314564Sdim } 1798254721Semaste}; 1799254721Semaste 1800254721Semaste#pragma mark CommandObjectMultiwordCommandsScript 1801254721Semaste 1802254721Semaste// CommandObjectMultiwordCommandsScript 1803254721Semaste 1804314564Sdimclass CommandObjectMultiwordCommandsScript : public CommandObjectMultiword { 1805254721Semastepublic: 1806314564Sdim CommandObjectMultiwordCommandsScript(CommandInterpreter &interpreter) 1807314564Sdim : CommandObjectMultiword( 1808360784Sdim interpreter, "command script", 1809360784Sdim "Commands for managing custom " 1810360784Sdim "commands implemented by " 1811360784Sdim "interpreter scripts.", 1812314564Sdim "command script <subcommand> [<subcommand-options>]") { 1813314564Sdim LoadSubCommand("add", CommandObjectSP( 1814314564Sdim new CommandObjectCommandsScriptAdd(interpreter))); 1815314564Sdim LoadSubCommand( 1816314564Sdim "delete", 1817314564Sdim CommandObjectSP(new CommandObjectCommandsScriptDelete(interpreter))); 1818314564Sdim LoadSubCommand( 1819314564Sdim "clear", 1820314564Sdim CommandObjectSP(new CommandObjectCommandsScriptClear(interpreter))); 1821314564Sdim LoadSubCommand("list", CommandObjectSP(new CommandObjectCommandsScriptList( 1822314564Sdim interpreter))); 1823314564Sdim LoadSubCommand( 1824314564Sdim "import", 1825314564Sdim CommandObjectSP(new CommandObjectCommandsScriptImport(interpreter))); 1826314564Sdim } 1827254721Semaste 1828314564Sdim ~CommandObjectMultiwordCommandsScript() override = default; 1829254721Semaste}; 1830254721Semaste 1831254721Semaste#pragma mark CommandObjectMultiwordCommands 1832254721Semaste 1833254721Semaste// CommandObjectMultiwordCommands 1834254721Semaste 1835314564SdimCommandObjectMultiwordCommands::CommandObjectMultiwordCommands( 1836314564Sdim CommandInterpreter &interpreter) 1837314564Sdim : CommandObjectMultiword(interpreter, "command", 1838314564Sdim "Commands for managing custom LLDB commands.", 1839314564Sdim "command <subcommand> [<subcommand-options>]") { 1840314564Sdim LoadSubCommand("source", 1841314564Sdim CommandObjectSP(new CommandObjectCommandsSource(interpreter))); 1842314564Sdim LoadSubCommand("alias", 1843314564Sdim CommandObjectSP(new CommandObjectCommandsAlias(interpreter))); 1844314564Sdim LoadSubCommand("unalias", CommandObjectSP( 1845314564Sdim new CommandObjectCommandsUnalias(interpreter))); 1846314564Sdim LoadSubCommand("delete", 1847314564Sdim CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); 1848314564Sdim LoadSubCommand( 1849314564Sdim "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); 1850314564Sdim LoadSubCommand("history", CommandObjectSP( 1851314564Sdim new CommandObjectCommandsHistory(interpreter))); 1852314564Sdim LoadSubCommand( 1853314564Sdim "script", 1854314564Sdim CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); 1855254721Semaste} 1856254721Semaste 1857309124SdimCommandObjectMultiwordCommands::~CommandObjectMultiwordCommands() = default; 1858