xref: /freebsd-src/contrib/llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- CommandInterpreter.cpp --------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
9*0fca6ea1SDimitry Andric #include <chrono>
10fe6060f1SDimitry Andric #include <cstdlib>
11e8d8bef9SDimitry Andric #include <limits>
120b57cec5SDimitry Andric #include <memory>
13bdd1243dSDimitry Andric #include <optional>
140b57cec5SDimitry Andric #include <string>
150b57cec5SDimitry Andric #include <vector>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "Commands/CommandObjectApropos.h"
180b57cec5SDimitry Andric #include "Commands/CommandObjectBreakpoint.h"
190b57cec5SDimitry Andric #include "Commands/CommandObjectCommands.h"
20bdd1243dSDimitry Andric #include "Commands/CommandObjectDWIMPrint.h"
21bdd1243dSDimitry Andric #include "Commands/CommandObjectDiagnostics.h"
220b57cec5SDimitry Andric #include "Commands/CommandObjectDisassemble.h"
230b57cec5SDimitry Andric #include "Commands/CommandObjectExpression.h"
240b57cec5SDimitry Andric #include "Commands/CommandObjectFrame.h"
250b57cec5SDimitry Andric #include "Commands/CommandObjectGUI.h"
260b57cec5SDimitry Andric #include "Commands/CommandObjectHelp.h"
270b57cec5SDimitry Andric #include "Commands/CommandObjectLanguage.h"
280b57cec5SDimitry Andric #include "Commands/CommandObjectLog.h"
290b57cec5SDimitry Andric #include "Commands/CommandObjectMemory.h"
300b57cec5SDimitry Andric #include "Commands/CommandObjectPlatform.h"
310b57cec5SDimitry Andric #include "Commands/CommandObjectPlugin.h"
320b57cec5SDimitry Andric #include "Commands/CommandObjectProcess.h"
330b57cec5SDimitry Andric #include "Commands/CommandObjectQuit.h"
34e8d8bef9SDimitry Andric #include "Commands/CommandObjectRegexCommand.h"
350b57cec5SDimitry Andric #include "Commands/CommandObjectRegister.h"
36*0fca6ea1SDimitry Andric #include "Commands/CommandObjectScripting.h"
37e8d8bef9SDimitry Andric #include "Commands/CommandObjectSession.h"
380b57cec5SDimitry Andric #include "Commands/CommandObjectSettings.h"
390b57cec5SDimitry Andric #include "Commands/CommandObjectSource.h"
400b57cec5SDimitry Andric #include "Commands/CommandObjectStats.h"
410b57cec5SDimitry Andric #include "Commands/CommandObjectTarget.h"
420b57cec5SDimitry Andric #include "Commands/CommandObjectThread.h"
43e8d8bef9SDimitry Andric #include "Commands/CommandObjectTrace.h"
440b57cec5SDimitry Andric #include "Commands/CommandObjectType.h"
450b57cec5SDimitry Andric #include "Commands/CommandObjectVersion.h"
460b57cec5SDimitry Andric #include "Commands/CommandObjectWatchpoint.h"
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric #include "lldb/Core/Debugger.h"
490b57cec5SDimitry Andric #include "lldb/Core/PluginManager.h"
505f757f3fSDimitry Andric #include "lldb/Host/StreamFile.h"
51*0fca6ea1SDimitry Andric #include "lldb/Utility/ErrorMessages.h"
5281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
530b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
540b57cec5SDimitry Andric #include "lldb/Utility/State.h"
550b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
56*0fca6ea1SDimitry Andric #include "lldb/Utility/StructuredData.h"
570b57cec5SDimitry Andric #include "lldb/Utility/Timer.h"
580b57cec5SDimitry Andric 
59480093f4SDimitry Andric #include "lldb/Host/Config.h"
60480093f4SDimitry Andric #if LLDB_ENABLE_LIBEDIT
610b57cec5SDimitry Andric #include "lldb/Host/Editline.h"
620b57cec5SDimitry Andric #endif
63e8d8bef9SDimitry Andric #include "lldb/Host/File.h"
64e8d8bef9SDimitry Andric #include "lldb/Host/FileCache.h"
650b57cec5SDimitry Andric #include "lldb/Host/Host.h"
660b57cec5SDimitry Andric #include "lldb/Host/HostInfo.h"
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric #include "lldb/Interpreter/CommandCompletions.h"
690b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
700b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
710b57cec5SDimitry Andric #include "lldb/Interpreter/OptionValueProperties.h"
720b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
730b57cec5SDimitry Andric #include "lldb/Interpreter/Property.h"
740b57cec5SDimitry Andric #include "lldb/Utility/Args.h"
750b57cec5SDimitry Andric 
76e8d8bef9SDimitry Andric #include "lldb/Target/Language.h"
770b57cec5SDimitry Andric #include "lldb/Target/Process.h"
789dba64beSDimitry Andric #include "lldb/Target/StopInfo.h"
790b57cec5SDimitry Andric #include "lldb/Target/TargetList.h"
800b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
819dba64beSDimitry Andric #include "lldb/Target/UnixSignals.h"
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
84fe6060f1SDimitry Andric #include "llvm/ADT/ScopeExit.h"
850b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
869dba64beSDimitry Andric #include "llvm/Support/FormatAdapters.h"
870b57cec5SDimitry Andric #include "llvm/Support/Path.h"
880b57cec5SDimitry Andric #include "llvm/Support/PrettyStackTrace.h"
89e8d8bef9SDimitry Andric #include "llvm/Support/ScopedPrinter.h"
900b57cec5SDimitry Andric 
9181ad6265SDimitry Andric #if defined(__APPLE__)
9281ad6265SDimitry Andric #include <TargetConditionals.h>
9381ad6265SDimitry Andric #endif
9481ad6265SDimitry Andric 
950b57cec5SDimitry Andric using namespace lldb;
960b57cec5SDimitry Andric using namespace lldb_private;
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric static const char *k_white_space = " \t\v";
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric static constexpr const char *InitFileWarning =
1010b57cec5SDimitry Andric     "There is a .lldbinit file in the current directory which is not being "
1020b57cec5SDimitry Andric     "read.\n"
1030b57cec5SDimitry Andric     "To silence this warning without sourcing in the local .lldbinit,\n"
1040b57cec5SDimitry Andric     "add the following to the lldbinit file in your home directory:\n"
1050b57cec5SDimitry Andric     "    settings set target.load-cwd-lldbinit false\n"
1060b57cec5SDimitry Andric     "To allow lldb to source .lldbinit files in the current working "
1070b57cec5SDimitry Andric     "directory,\n"
1080b57cec5SDimitry Andric     "set the value of this variable to true.  Only do so if you understand "
1090b57cec5SDimitry Andric     "and\n"
1100b57cec5SDimitry Andric     "accept the security risk.";
1110b57cec5SDimitry Andric 
112bdd1243dSDimitry Andric const char *CommandInterpreter::g_no_argument = "<no-argument>";
113bdd1243dSDimitry Andric const char *CommandInterpreter::g_need_argument = "<need-argument>";
114bdd1243dSDimitry Andric const char *CommandInterpreter::g_argument = "<argument>";
115bdd1243dSDimitry Andric 
116bdd1243dSDimitry Andric 
1179dba64beSDimitry Andric #define LLDB_PROPERTIES_interpreter
1189dba64beSDimitry Andric #include "InterpreterProperties.inc"
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric enum {
1219dba64beSDimitry Andric #define LLDB_PROPERTIES_interpreter
1229dba64beSDimitry Andric #include "InterpreterPropertiesEnum.inc"
1230b57cec5SDimitry Andric };
1240b57cec5SDimitry Andric 
125*0fca6ea1SDimitry Andric llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() {
126*0fca6ea1SDimitry Andric   static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter");
1270b57cec5SDimitry Andric   return class_name;
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric CommandInterpreter::CommandInterpreter(Debugger &debugger,
1310b57cec5SDimitry Andric                                        bool synchronous_execution)
1320b57cec5SDimitry Andric     : Broadcaster(debugger.GetBroadcasterManager(),
133*0fca6ea1SDimitry Andric                   CommandInterpreter::GetStaticBroadcasterClass().str()),
1345f757f3fSDimitry Andric       Properties(
1355f757f3fSDimitry Andric           OptionValuePropertiesSP(new OptionValueProperties("interpreter"))),
1360b57cec5SDimitry Andric       IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
1379dba64beSDimitry Andric       m_debugger(debugger), m_synchronous_execution(true),
1380b57cec5SDimitry Andric       m_skip_lldbinit_files(false), m_skip_app_init_files(false),
139fe6060f1SDimitry Andric       m_comment_char('#'), m_batch_command_mode(false),
14081ad6265SDimitry Andric       m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
14181ad6265SDimitry Andric       m_command_source_depth(0) {
1420b57cec5SDimitry Andric   SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
1430b57cec5SDimitry Andric   SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
1440b57cec5SDimitry Andric   SetEventName(eBroadcastBitQuitCommandReceived, "quit");
1459dba64beSDimitry Andric   SetSynchronous(synchronous_execution);
1460b57cec5SDimitry Andric   CheckInWithManager();
1479dba64beSDimitry Andric   m_collection_sp->Initialize(g_interpreter_properties);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric bool CommandInterpreter::GetExpandRegexAliases() const {
1510b57cec5SDimitry Andric   const uint32_t idx = ePropertyExpandRegexAliases;
15206c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
15306c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric bool CommandInterpreter::GetPromptOnQuit() const {
1570b57cec5SDimitry Andric   const uint32_t idx = ePropertyPromptOnQuit;
15806c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
15906c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric 
162480093f4SDimitry Andric void CommandInterpreter::SetPromptOnQuit(bool enable) {
1630b57cec5SDimitry Andric   const uint32_t idx = ePropertyPromptOnQuit;
16406c3fb27SDimitry Andric   SetPropertyAtIndex(idx, enable);
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric 
167*0fca6ea1SDimitry Andric bool CommandInterpreter::GetSaveTranscript() const {
168*0fca6ea1SDimitry Andric   const uint32_t idx = ePropertySaveTranscript;
169*0fca6ea1SDimitry Andric   return GetPropertyAtIndexAs<bool>(
170*0fca6ea1SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
171*0fca6ea1SDimitry Andric }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric void CommandInterpreter::SetSaveTranscript(bool enable) {
174*0fca6ea1SDimitry Andric   const uint32_t idx = ePropertySaveTranscript;
175*0fca6ea1SDimitry Andric   SetPropertyAtIndex(idx, enable);
176*0fca6ea1SDimitry Andric }
177*0fca6ea1SDimitry Andric 
178e8d8bef9SDimitry Andric bool CommandInterpreter::GetSaveSessionOnQuit() const {
179e8d8bef9SDimitry Andric   const uint32_t idx = ePropertySaveSessionOnQuit;
18006c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
18106c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
182e8d8bef9SDimitry Andric }
183e8d8bef9SDimitry Andric 
184e8d8bef9SDimitry Andric void CommandInterpreter::SetSaveSessionOnQuit(bool enable) {
185e8d8bef9SDimitry Andric   const uint32_t idx = ePropertySaveSessionOnQuit;
18606c3fb27SDimitry Andric   SetPropertyAtIndex(idx, enable);
187e8d8bef9SDimitry Andric }
188e8d8bef9SDimitry Andric 
189bdd1243dSDimitry Andric bool CommandInterpreter::GetOpenTranscriptInEditor() const {
190bdd1243dSDimitry Andric   const uint32_t idx = ePropertyOpenTranscriptInEditor;
19106c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
19206c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
193bdd1243dSDimitry Andric }
194bdd1243dSDimitry Andric 
195bdd1243dSDimitry Andric void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) {
196bdd1243dSDimitry Andric   const uint32_t idx = ePropertyOpenTranscriptInEditor;
19706c3fb27SDimitry Andric   SetPropertyAtIndex(idx, enable);
198bdd1243dSDimitry Andric }
199bdd1243dSDimitry Andric 
200fe6060f1SDimitry Andric FileSpec CommandInterpreter::GetSaveSessionDirectory() const {
201fe6060f1SDimitry Andric   const uint32_t idx = ePropertySaveSessionDirectory;
20206c3fb27SDimitry Andric   return GetPropertyAtIndexAs<FileSpec>(idx, {});
203fe6060f1SDimitry Andric }
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) {
206fe6060f1SDimitry Andric   const uint32_t idx = ePropertySaveSessionDirectory;
20706c3fb27SDimitry Andric   SetPropertyAtIndex(idx, path);
208fe6060f1SDimitry Andric }
209fe6060f1SDimitry Andric 
2100b57cec5SDimitry Andric bool CommandInterpreter::GetEchoCommands() const {
2119dba64beSDimitry Andric   const uint32_t idx = ePropertyEchoCommands;
21206c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
21306c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
2140b57cec5SDimitry Andric }
2150b57cec5SDimitry Andric 
216480093f4SDimitry Andric void CommandInterpreter::SetEchoCommands(bool enable) {
2179dba64beSDimitry Andric   const uint32_t idx = ePropertyEchoCommands;
21806c3fb27SDimitry Andric   SetPropertyAtIndex(idx, enable);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric bool CommandInterpreter::GetEchoCommentCommands() const {
2229dba64beSDimitry Andric   const uint32_t idx = ePropertyEchoCommentCommands;
22306c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
22406c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
227480093f4SDimitry Andric void CommandInterpreter::SetEchoCommentCommands(bool enable) {
2289dba64beSDimitry Andric   const uint32_t idx = ePropertyEchoCommentCommands;
22906c3fb27SDimitry Andric   SetPropertyAtIndex(idx, enable);
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
2330b57cec5SDimitry Andric   m_allow_exit_code = allow;
2340b57cec5SDimitry Andric   if (!allow)
2350b57cec5SDimitry Andric     m_quit_exit_code.reset();
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric bool CommandInterpreter::SetQuitExitCode(int exit_code) {
2390b57cec5SDimitry Andric   if (!m_allow_exit_code)
2400b57cec5SDimitry Andric     return false;
2410b57cec5SDimitry Andric   m_quit_exit_code = exit_code;
2420b57cec5SDimitry Andric   return true;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric int CommandInterpreter::GetQuitExitCode(bool &exited) const {
24681ad6265SDimitry Andric   exited = m_quit_exit_code.has_value();
2470b57cec5SDimitry Andric   if (exited)
2480b57cec5SDimitry Andric     return *m_quit_exit_code;
2490b57cec5SDimitry Andric   return 0;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric void CommandInterpreter::ResolveCommand(const char *command_line,
2530b57cec5SDimitry Andric                                         CommandReturnObject &result) {
2540b57cec5SDimitry Andric   std::string command = command_line;
2550b57cec5SDimitry Andric   if (ResolveCommandImpl(command, result) != nullptr) {
2560b57cec5SDimitry Andric     result.AppendMessageWithFormat("%s", command.c_str());
2570b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishResult);
2580b57cec5SDimitry Andric   }
2590b57cec5SDimitry Andric }
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric bool CommandInterpreter::GetStopCmdSourceOnError() const {
2620b57cec5SDimitry Andric   const uint32_t idx = ePropertyStopCmdSourceOnError;
26306c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
26406c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
2650b57cec5SDimitry Andric }
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric bool CommandInterpreter::GetSpaceReplPrompts() const {
2689dba64beSDimitry Andric   const uint32_t idx = ePropertySpaceReplPrompts;
26906c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
27006c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
2710b57cec5SDimitry Andric }
2720b57cec5SDimitry Andric 
273fe6060f1SDimitry Andric bool CommandInterpreter::GetRepeatPreviousCommand() const {
274fe6060f1SDimitry Andric   const uint32_t idx = ePropertyRepeatPreviousCommand;
27506c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
27606c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
277fe6060f1SDimitry Andric }
278fe6060f1SDimitry Andric 
27981ad6265SDimitry Andric bool CommandInterpreter::GetRequireCommandOverwrite() const {
28081ad6265SDimitry Andric   const uint32_t idx = ePropertyRequireCommandOverwrite;
28106c3fb27SDimitry Andric   return GetPropertyAtIndexAs<bool>(
28206c3fb27SDimitry Andric       idx, g_interpreter_properties[idx].default_uint_value != 0);
28381ad6265SDimitry Andric }
28481ad6265SDimitry Andric 
2850b57cec5SDimitry Andric void CommandInterpreter::Initialize() {
286e8d8bef9SDimitry Andric   LLDB_SCOPED_TIMER();
2870b57cec5SDimitry Andric 
2885ffd83dbSDimitry Andric   CommandReturnObject result(m_debugger.GetUseColor());
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric   LoadCommandDictionary();
2910b57cec5SDimitry Andric 
2920b57cec5SDimitry Andric   // An alias arguments vector to reuse - reset it before use...
2930b57cec5SDimitry Andric   OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   // Set up some initial aliases.
296e8d8bef9SDimitry Andric   CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit");
2970b57cec5SDimitry Andric   if (cmd_obj_sp) {
2980b57cec5SDimitry Andric     AddAlias("q", cmd_obj_sp);
2990b57cec5SDimitry Andric     AddAlias("exit", cmd_obj_sp);
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
302e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-attach");
3030b57cec5SDimitry Andric   if (cmd_obj_sp)
3040b57cec5SDimitry Andric     AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3050b57cec5SDimitry Andric 
306e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("process detach");
3070b57cec5SDimitry Andric   if (cmd_obj_sp) {
3080b57cec5SDimitry Andric     AddAlias("detach", cmd_obj_sp);
3090b57cec5SDimitry Andric   }
3100b57cec5SDimitry Andric 
311e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("process continue");
3120b57cec5SDimitry Andric   if (cmd_obj_sp) {
3130b57cec5SDimitry Andric     AddAlias("c", cmd_obj_sp);
3140b57cec5SDimitry Andric     AddAlias("continue", cmd_obj_sp);
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric 
317e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-break");
3180b57cec5SDimitry Andric   if (cmd_obj_sp)
3190b57cec5SDimitry Andric     AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3200b57cec5SDimitry Andric 
321e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
3220b57cec5SDimitry Andric   if (cmd_obj_sp)
3230b57cec5SDimitry Andric     AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3240b57cec5SDimitry Andric 
325e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread step-inst");
3260b57cec5SDimitry Andric   if (cmd_obj_sp) {
3270b57cec5SDimitry Andric     AddAlias("stepi", cmd_obj_sp);
3280b57cec5SDimitry Andric     AddAlias("si", cmd_obj_sp);
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric 
331e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
3320b57cec5SDimitry Andric   if (cmd_obj_sp) {
3330b57cec5SDimitry Andric     AddAlias("nexti", cmd_obj_sp);
3340b57cec5SDimitry Andric     AddAlias("ni", cmd_obj_sp);
3350b57cec5SDimitry Andric   }
3360b57cec5SDimitry Andric 
337e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread step-in");
3380b57cec5SDimitry Andric   if (cmd_obj_sp) {
3390b57cec5SDimitry Andric     AddAlias("s", cmd_obj_sp);
3400b57cec5SDimitry Andric     AddAlias("step", cmd_obj_sp);
3410b57cec5SDimitry Andric     CommandAlias *sif_alias = AddAlias(
3420b57cec5SDimitry Andric         "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
3430b57cec5SDimitry Andric     if (sif_alias) {
3440b57cec5SDimitry Andric       sif_alias->SetHelp("Step through the current block, stopping if you step "
3450b57cec5SDimitry Andric                          "directly into a function whose name matches the "
3460b57cec5SDimitry Andric                          "TargetFunctionName.");
3470b57cec5SDimitry Andric       sif_alias->SetSyntax("sif <TargetFunctionName>");
3480b57cec5SDimitry Andric     }
3490b57cec5SDimitry Andric   }
3500b57cec5SDimitry Andric 
351e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread step-over");
3520b57cec5SDimitry Andric   if (cmd_obj_sp) {
3530b57cec5SDimitry Andric     AddAlias("n", cmd_obj_sp);
3540b57cec5SDimitry Andric     AddAlias("next", cmd_obj_sp);
3550b57cec5SDimitry Andric   }
3560b57cec5SDimitry Andric 
357e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread step-out");
3580b57cec5SDimitry Andric   if (cmd_obj_sp) {
3590b57cec5SDimitry Andric     AddAlias("finish", cmd_obj_sp);
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric 
362e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("frame select");
3630b57cec5SDimitry Andric   if (cmd_obj_sp) {
3640b57cec5SDimitry Andric     AddAlias("f", cmd_obj_sp);
3650b57cec5SDimitry Andric   }
3660b57cec5SDimitry Andric 
367e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("thread select");
3680b57cec5SDimitry Andric   if (cmd_obj_sp) {
3690b57cec5SDimitry Andric     AddAlias("t", cmd_obj_sp);
3700b57cec5SDimitry Andric   }
3710b57cec5SDimitry Andric 
372e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-jump");
3730b57cec5SDimitry Andric   if (cmd_obj_sp) {
3740b57cec5SDimitry Andric     AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3750b57cec5SDimitry Andric     AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3760b57cec5SDimitry Andric   }
3770b57cec5SDimitry Andric 
378e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-list");
3790b57cec5SDimitry Andric   if (cmd_obj_sp) {
3800b57cec5SDimitry Andric     AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3810b57cec5SDimitry Andric     AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3820b57cec5SDimitry Andric   }
3830b57cec5SDimitry Andric 
384e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-env");
3850b57cec5SDimitry Andric   if (cmd_obj_sp)
3860b57cec5SDimitry Andric     AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3870b57cec5SDimitry Andric 
388e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("memory read");
3890b57cec5SDimitry Andric   if (cmd_obj_sp)
3900b57cec5SDimitry Andric     AddAlias("x", cmd_obj_sp);
3910b57cec5SDimitry Andric 
392e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-up");
3930b57cec5SDimitry Andric   if (cmd_obj_sp)
3940b57cec5SDimitry Andric     AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3950b57cec5SDimitry Andric 
396e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-down");
3970b57cec5SDimitry Andric   if (cmd_obj_sp)
3980b57cec5SDimitry Andric     AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
3990b57cec5SDimitry Andric 
400e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-display");
4010b57cec5SDimitry Andric   if (cmd_obj_sp)
4020b57cec5SDimitry Andric     AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
4030b57cec5SDimitry Andric 
404e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("disassemble");
4050b57cec5SDimitry Andric   if (cmd_obj_sp)
4060b57cec5SDimitry Andric     AddAlias("dis", cmd_obj_sp);
4070b57cec5SDimitry Andric 
408e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("disassemble");
4090b57cec5SDimitry Andric   if (cmd_obj_sp)
4100b57cec5SDimitry Andric     AddAlias("di", cmd_obj_sp);
4110b57cec5SDimitry Andric 
412e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
4130b57cec5SDimitry Andric   if (cmd_obj_sp)
4140b57cec5SDimitry Andric     AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
4150b57cec5SDimitry Andric 
416e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("_regexp-bt");
4170b57cec5SDimitry Andric   if (cmd_obj_sp)
4180b57cec5SDimitry Andric     AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
4190b57cec5SDimitry Andric 
420e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("target create");
4210b57cec5SDimitry Andric   if (cmd_obj_sp)
4220b57cec5SDimitry Andric     AddAlias("file", cmd_obj_sp);
4230b57cec5SDimitry Andric 
424e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("target modules");
4250b57cec5SDimitry Andric   if (cmd_obj_sp)
4260b57cec5SDimitry Andric     AddAlias("image", cmd_obj_sp);
4270b57cec5SDimitry Andric 
4280b57cec5SDimitry Andric   alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
4290b57cec5SDimitry Andric 
43006c3fb27SDimitry Andric   cmd_obj_sp = GetCommandSPExact("dwim-print");
4310b57cec5SDimitry Andric   if (cmd_obj_sp) {
4320b57cec5SDimitry Andric     AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
4330b57cec5SDimitry Andric     AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
4345ffd83dbSDimitry Andric     if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) {
4350b57cec5SDimitry Andric       po->SetHelp("Evaluate an expression on the current thread.  Displays any "
4360b57cec5SDimitry Andric                   "returned value with formatting "
4370b57cec5SDimitry Andric                   "controlled by the type's author.");
4380b57cec5SDimitry Andric       po->SetHelpLong("");
4390b57cec5SDimitry Andric     }
44006c3fb27SDimitry Andric   }
44106c3fb27SDimitry Andric 
44206c3fb27SDimitry Andric   cmd_obj_sp = GetCommandSPExact("expression");
44306c3fb27SDimitry Andric   if (cmd_obj_sp) {
44406c3fb27SDimitry Andric     AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
445480093f4SDimitry Andric     CommandAlias *parray_alias =
446480093f4SDimitry Andric         AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
447480093f4SDimitry Andric     if (parray_alias) {
448480093f4SDimitry Andric         parray_alias->SetHelp
449480093f4SDimitry Andric           ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
450480093f4SDimitry Andric            "to get a typed-pointer-to-an-array in memory, and will display "
451480093f4SDimitry Andric            "COUNT elements of that type from the array.");
452480093f4SDimitry Andric         parray_alias->SetHelpLong("");
453480093f4SDimitry Andric     }
454480093f4SDimitry Andric     CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
455480093f4SDimitry Andric              "--object-description --element-count %1 --");
456480093f4SDimitry Andric     if (poarray_alias) {
457480093f4SDimitry Andric       poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
458480093f4SDimitry Andric           "evaluate EXPRESSION to get the address of an array of COUNT "
459480093f4SDimitry Andric           "objects in memory, and will call po on them.");
460480093f4SDimitry Andric       poarray_alias->SetHelpLong("");
461480093f4SDimitry Andric     }
4620b57cec5SDimitry Andric   }
4630b57cec5SDimitry Andric 
464e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("platform shell");
4655ffd83dbSDimitry Andric   if (cmd_obj_sp) {
4665ffd83dbSDimitry Andric     CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
4675ffd83dbSDimitry Andric     if (shell_alias) {
4685ffd83dbSDimitry Andric       shell_alias->SetHelp("Run a shell command on the host.");
4695ffd83dbSDimitry Andric       shell_alias->SetHelpLong("");
4705ffd83dbSDimitry Andric       shell_alias->SetSyntax("shell <shell-command>");
4715ffd83dbSDimitry Andric     }
4725ffd83dbSDimitry Andric   }
4735ffd83dbSDimitry Andric 
474e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("process kill");
4750b57cec5SDimitry Andric   if (cmd_obj_sp) {
4760b57cec5SDimitry Andric     AddAlias("kill", cmd_obj_sp);
4770b57cec5SDimitry Andric   }
4780b57cec5SDimitry Andric 
479e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("process launch");
4800b57cec5SDimitry Andric   if (cmd_obj_sp) {
4810b57cec5SDimitry Andric     alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
482fe6060f1SDimitry Andric #if defined(__APPLE__)
48381ad6265SDimitry Andric #if TARGET_OS_IPHONE
4840b57cec5SDimitry Andric     AddAlias("r", cmd_obj_sp, "--");
4850b57cec5SDimitry Andric     AddAlias("run", cmd_obj_sp, "--");
4860b57cec5SDimitry Andric #else
4870b57cec5SDimitry Andric     AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
4880b57cec5SDimitry Andric     AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
489fe6060f1SDimitry Andric #endif
4900b57cec5SDimitry Andric #else
4910b57cec5SDimitry Andric     StreamString defaultshell;
4920b57cec5SDimitry Andric     defaultshell.Printf("--shell=%s --",
4930b57cec5SDimitry Andric                         HostInfo::GetDefaultShell().GetPath().c_str());
4940b57cec5SDimitry Andric     AddAlias("r", cmd_obj_sp, defaultshell.GetString());
4950b57cec5SDimitry Andric     AddAlias("run", cmd_obj_sp, defaultshell.GetString());
4960b57cec5SDimitry Andric #endif
4970b57cec5SDimitry Andric   }
4980b57cec5SDimitry Andric 
499e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("target symbols add");
5000b57cec5SDimitry Andric   if (cmd_obj_sp) {
5010b57cec5SDimitry Andric     AddAlias("add-dsym", cmd_obj_sp);
5020b57cec5SDimitry Andric   }
5030b57cec5SDimitry Andric 
504e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("breakpoint set");
5050b57cec5SDimitry Andric   if (cmd_obj_sp) {
5060b57cec5SDimitry Andric     AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
5070b57cec5SDimitry Andric   }
5080b57cec5SDimitry Andric 
509e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("frame variable");
5100b57cec5SDimitry Andric   if (cmd_obj_sp) {
5110b57cec5SDimitry Andric     AddAlias("v", cmd_obj_sp);
5120b57cec5SDimitry Andric     AddAlias("var", cmd_obj_sp);
5130b57cec5SDimitry Andric     AddAlias("vo", cmd_obj_sp, "--object-description");
5140b57cec5SDimitry Andric   }
5150b57cec5SDimitry Andric 
516e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("register");
5170b57cec5SDimitry Andric   if (cmd_obj_sp) {
5180b57cec5SDimitry Andric     AddAlias("re", cmd_obj_sp);
5190b57cec5SDimitry Andric   }
520e8d8bef9SDimitry Andric 
521*0fca6ea1SDimitry Andric   cmd_obj_sp = GetCommandSPExact("scripting run");
522*0fca6ea1SDimitry Andric   if (cmd_obj_sp) {
523*0fca6ea1SDimitry Andric     AddAlias("sc", cmd_obj_sp);
524*0fca6ea1SDimitry Andric     AddAlias("scr", cmd_obj_sp);
525*0fca6ea1SDimitry Andric     AddAlias("scri", cmd_obj_sp);
526*0fca6ea1SDimitry Andric     AddAlias("scrip", cmd_obj_sp);
527*0fca6ea1SDimitry Andric     AddAlias("script", cmd_obj_sp);
528*0fca6ea1SDimitry Andric   }
529*0fca6ea1SDimitry Andric 
530e8d8bef9SDimitry Andric   cmd_obj_sp = GetCommandSPExact("session history");
531e8d8bef9SDimitry Andric   if (cmd_obj_sp) {
532e8d8bef9SDimitry Andric     AddAlias("history", cmd_obj_sp);
533e8d8bef9SDimitry Andric   }
5345f757f3fSDimitry Andric 
5355f757f3fSDimitry Andric   cmd_obj_sp = GetCommandSPExact("help");
5365f757f3fSDimitry Andric   if (cmd_obj_sp) {
5375f757f3fSDimitry Andric     AddAlias("h", cmd_obj_sp);
5385f757f3fSDimitry Andric   }
5390b57cec5SDimitry Andric }
5400b57cec5SDimitry Andric 
5410b57cec5SDimitry Andric void CommandInterpreter::Clear() {
5420b57cec5SDimitry Andric   m_command_io_handler_sp.reset();
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
5460b57cec5SDimitry Andric   // This function has not yet been implemented.
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric   // Look for any embedded script command
5490b57cec5SDimitry Andric   // If found,
5500b57cec5SDimitry Andric   //    get interpreter object from the command dictionary,
5510b57cec5SDimitry Andric   //    call execute_one_command on it,
5520b57cec5SDimitry Andric   //    get the results as a string,
5530b57cec5SDimitry Andric   //    substitute that string for current stuff.
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric   return arg;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric 
558e8d8bef9SDimitry Andric #define REGISTER_COMMAND_OBJECT(NAME, CLASS)                                   \
559e8d8bef9SDimitry Andric   m_command_dict[NAME] = std::make_shared<CLASS>(*this);
560e8d8bef9SDimitry Andric 
5610b57cec5SDimitry Andric void CommandInterpreter::LoadCommandDictionary() {
562e8d8bef9SDimitry Andric   LLDB_SCOPED_TIMER();
5630b57cec5SDimitry Andric 
564e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
565e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
566e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
567bdd1243dSDimitry Andric   REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
568e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
569bdd1243dSDimitry Andric   REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
570e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
571e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
572e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
573e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("help", CommandObjectHelp);
574e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("log", CommandObjectLog);
575e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory);
576e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform);
577e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin);
578e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
579e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
580e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
581*0fca6ea1SDimitry Andric   REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting);
582e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
583e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
584e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
585e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats);
586e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget);
587e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread);
588e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace);
589e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("type", CommandObjectType);
590e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("version", CommandObjectVersion);
591e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint);
592e8d8bef9SDimitry Andric   REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage);
5930b57cec5SDimitry Andric 
5945ffd83dbSDimitry Andric   // clang-format off
5950b57cec5SDimitry Andric   const char *break_regexes[][2] = {
5965ffd83dbSDimitry Andric       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
5975ffd83dbSDimitry Andric        "breakpoint set --file '%1' --line %2 --column %3"},
5980b57cec5SDimitry Andric       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
5990b57cec5SDimitry Andric        "breakpoint set --file '%1' --line %2"},
6000b57cec5SDimitry Andric       {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
6010b57cec5SDimitry Andric       {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
6020b57cec5SDimitry Andric       {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
6030b57cec5SDimitry Andric       {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
6040b57cec5SDimitry Andric        "breakpoint set --name '%1'"},
6050b57cec5SDimitry Andric       {"^(-.*)$", "breakpoint set %1"},
6060b57cec5SDimitry Andric       {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
6070b57cec5SDimitry Andric        "breakpoint set --name '%2' --shlib '%1'"},
6080b57cec5SDimitry Andric       {"^\\&(.*[^[:space:]])[[:space:]]*$",
6090b57cec5SDimitry Andric        "breakpoint set --name '%1' --skip-prologue=0"},
6100b57cec5SDimitry Andric       {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
6110b57cec5SDimitry Andric        "breakpoint set --name '%1'"}};
6125ffd83dbSDimitry Andric   // clang-format on
6130b57cec5SDimitry Andric 
614bdd1243dSDimitry Andric   size_t num_regexes = std::size(break_regexes);
6150b57cec5SDimitry Andric 
6160b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
6170b57cec5SDimitry Andric       new CommandObjectRegexCommand(
6180b57cec5SDimitry Andric           *this, "_regexp-break",
6190b57cec5SDimitry Andric           "Set a breakpoint using one of several shorthand formats.",
6200b57cec5SDimitry Andric           "\n"
6215ffd83dbSDimitry Andric           "_regexp-break <filename>:<linenum>:<colnum>\n"
6225ffd83dbSDimitry Andric           "              main.c:12:21          // Break at line 12 and column "
6235ffd83dbSDimitry Andric           "21 of main.c\n\n"
6240b57cec5SDimitry Andric           "_regexp-break <filename>:<linenum>\n"
6250b57cec5SDimitry Andric           "              main.c:12             // Break at line 12 of "
6260b57cec5SDimitry Andric           "main.c\n\n"
6270b57cec5SDimitry Andric           "_regexp-break <linenum>\n"
6280b57cec5SDimitry Andric           "              12                    // Break at line 12 of current "
6290b57cec5SDimitry Andric           "file\n\n"
6300b57cec5SDimitry Andric           "_regexp-break 0x<address>\n"
6310b57cec5SDimitry Andric           "              0x1234000             // Break at address "
6320b57cec5SDimitry Andric           "0x1234000\n\n"
6330b57cec5SDimitry Andric           "_regexp-break <name>\n"
6340b57cec5SDimitry Andric           "              main                  // Break in 'main' after the "
6350b57cec5SDimitry Andric           "prologue\n\n"
6360b57cec5SDimitry Andric           "_regexp-break &<name>\n"
6370b57cec5SDimitry Andric           "              &main                 // Break at first instruction "
6380b57cec5SDimitry Andric           "in 'main'\n\n"
6390b57cec5SDimitry Andric           "_regexp-break <module>`<name>\n"
6400b57cec5SDimitry Andric           "              libc.so`malloc        // Break in 'malloc' from "
6410b57cec5SDimitry Andric           "'libc.so'\n\n"
6420b57cec5SDimitry Andric           "_regexp-break /<source-regex>/\n"
6430b57cec5SDimitry Andric           "              /break here/          // Break on source lines in "
6440b57cec5SDimitry Andric           "current file\n"
6450b57cec5SDimitry Andric           "                                    // containing text 'break "
6460b57cec5SDimitry Andric           "here'.\n",
64706c3fb27SDimitry Andric           lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
6480b57cec5SDimitry Andric 
6490b57cec5SDimitry Andric   if (break_regex_cmd_up) {
6500b57cec5SDimitry Andric     bool success = true;
6510b57cec5SDimitry Andric     for (size_t i = 0; i < num_regexes; i++) {
6520b57cec5SDimitry Andric       success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
6530b57cec5SDimitry Andric                                                     break_regexes[i][1]);
6540b57cec5SDimitry Andric       if (!success)
6550b57cec5SDimitry Andric         break;
6560b57cec5SDimitry Andric     }
6570b57cec5SDimitry Andric     success =
6580b57cec5SDimitry Andric         break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric     if (success) {
6610b57cec5SDimitry Andric       CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
6625ffd83dbSDimitry Andric       m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
6635ffd83dbSDimitry Andric           break_regex_cmd_sp;
6640b57cec5SDimitry Andric     }
6650b57cec5SDimitry Andric   }
6660b57cec5SDimitry Andric 
6670b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
6680b57cec5SDimitry Andric       new CommandObjectRegexCommand(
6690b57cec5SDimitry Andric           *this, "_regexp-tbreak",
6700b57cec5SDimitry Andric           "Set a one-shot breakpoint using one of several shorthand formats.",
6710b57cec5SDimitry Andric           "\n"
6725ffd83dbSDimitry Andric           "_regexp-break <filename>:<linenum>:<colnum>\n"
6735ffd83dbSDimitry Andric           "              main.c:12:21          // Break at line 12 and column "
6745ffd83dbSDimitry Andric           "21 of main.c\n\n"
6750b57cec5SDimitry Andric           "_regexp-break <filename>:<linenum>\n"
6760b57cec5SDimitry Andric           "              main.c:12             // Break at line 12 of "
6770b57cec5SDimitry Andric           "main.c\n\n"
6780b57cec5SDimitry Andric           "_regexp-break <linenum>\n"
6790b57cec5SDimitry Andric           "              12                    // Break at line 12 of current "
6800b57cec5SDimitry Andric           "file\n\n"
6810b57cec5SDimitry Andric           "_regexp-break 0x<address>\n"
6820b57cec5SDimitry Andric           "              0x1234000             // Break at address "
6830b57cec5SDimitry Andric           "0x1234000\n\n"
6840b57cec5SDimitry Andric           "_regexp-break <name>\n"
6850b57cec5SDimitry Andric           "              main                  // Break in 'main' after the "
6860b57cec5SDimitry Andric           "prologue\n\n"
6870b57cec5SDimitry Andric           "_regexp-break &<name>\n"
6880b57cec5SDimitry Andric           "              &main                 // Break at first instruction "
6890b57cec5SDimitry Andric           "in 'main'\n\n"
6900b57cec5SDimitry Andric           "_regexp-break <module>`<name>\n"
6910b57cec5SDimitry Andric           "              libc.so`malloc        // Break in 'malloc' from "
6920b57cec5SDimitry Andric           "'libc.so'\n\n"
6930b57cec5SDimitry Andric           "_regexp-break /<source-regex>/\n"
6940b57cec5SDimitry Andric           "              /break here/          // Break on source lines in "
6950b57cec5SDimitry Andric           "current file\n"
6960b57cec5SDimitry Andric           "                                    // containing text 'break "
6970b57cec5SDimitry Andric           "here'.\n",
69806c3fb27SDimitry Andric           lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
6990b57cec5SDimitry Andric 
7000b57cec5SDimitry Andric   if (tbreak_regex_cmd_up) {
7010b57cec5SDimitry Andric     bool success = true;
7020b57cec5SDimitry Andric     for (size_t i = 0; i < num_regexes; i++) {
703e8d8bef9SDimitry Andric       std::string command = break_regexes[i][1];
704e8d8bef9SDimitry Andric       command += " -o 1";
7050b57cec5SDimitry Andric       success =
706e8d8bef9SDimitry Andric           tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
7070b57cec5SDimitry Andric       if (!success)
7080b57cec5SDimitry Andric         break;
7090b57cec5SDimitry Andric     }
7100b57cec5SDimitry Andric     success =
7110b57cec5SDimitry Andric         tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
7120b57cec5SDimitry Andric 
7130b57cec5SDimitry Andric     if (success) {
7140b57cec5SDimitry Andric       CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
7155ffd83dbSDimitry Andric       m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
7160b57cec5SDimitry Andric           tbreak_regex_cmd_sp;
7170b57cec5SDimitry Andric     }
7180b57cec5SDimitry Andric   }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
7210b57cec5SDimitry Andric       new CommandObjectRegexCommand(
7220b57cec5SDimitry Andric           *this, "_regexp-attach", "Attach to process by ID or name.",
72306c3fb27SDimitry Andric           "_regexp-attach <pid> | <process-name>", 0, false));
7240b57cec5SDimitry Andric   if (attach_regex_cmd_up) {
7250b57cec5SDimitry Andric     if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
7260b57cec5SDimitry Andric                                              "process attach --pid %1") &&
7270b57cec5SDimitry Andric         attach_regex_cmd_up->AddRegexCommand(
7280b57cec5SDimitry Andric             "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
7290b57cec5SDimitry Andric                                                       // specified get passed to
7300b57cec5SDimitry Andric                                                       // 'process attach'
7310b57cec5SDimitry Andric         attach_regex_cmd_up->AddRegexCommand("^(.+)$",
7320b57cec5SDimitry Andric                                              "process attach --name '%1'") &&
7330b57cec5SDimitry Andric         attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
7340b57cec5SDimitry Andric       CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
7355ffd83dbSDimitry Andric       m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
7360b57cec5SDimitry Andric           attach_regex_cmd_sp;
7370b57cec5SDimitry Andric     }
7380b57cec5SDimitry Andric   }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
7410b57cec5SDimitry Andric       new CommandObjectRegexCommand(*this, "_regexp-down",
7420b57cec5SDimitry Andric                                     "Select a newer stack frame.  Defaults to "
7430b57cec5SDimitry Andric                                     "moving one frame, a numeric argument can "
7440b57cec5SDimitry Andric                                     "specify an arbitrary number.",
74506c3fb27SDimitry Andric                                     "_regexp-down [<count>]", 0, false));
7460b57cec5SDimitry Andric   if (down_regex_cmd_up) {
7470b57cec5SDimitry Andric     if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
7480b57cec5SDimitry Andric         down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
7490b57cec5SDimitry Andric                                            "frame select -r -%1")) {
7500b57cec5SDimitry Andric       CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
7515ffd83dbSDimitry Andric       m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
7525ffd83dbSDimitry Andric           down_regex_cmd_sp;
7530b57cec5SDimitry Andric     }
7540b57cec5SDimitry Andric   }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
7570b57cec5SDimitry Andric       new CommandObjectRegexCommand(
7580b57cec5SDimitry Andric           *this, "_regexp-up",
7590b57cec5SDimitry Andric           "Select an older stack frame.  Defaults to moving one "
7600b57cec5SDimitry Andric           "frame, a numeric argument can specify an arbitrary number.",
76106c3fb27SDimitry Andric           "_regexp-up [<count>]", 0, false));
7620b57cec5SDimitry Andric   if (up_regex_cmd_up) {
7630b57cec5SDimitry Andric     if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
7640b57cec5SDimitry Andric         up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
7650b57cec5SDimitry Andric       CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
7665ffd83dbSDimitry Andric       m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
7675ffd83dbSDimitry Andric           up_regex_cmd_sp;
7680b57cec5SDimitry Andric     }
7690b57cec5SDimitry Andric   }
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
7720b57cec5SDimitry Andric       new CommandObjectRegexCommand(
7730b57cec5SDimitry Andric           *this, "_regexp-display",
7740b57cec5SDimitry Andric           "Evaluate an expression at every stop (see 'help target stop-hook'.)",
77506c3fb27SDimitry Andric           "_regexp-display expression", 0, false));
7760b57cec5SDimitry Andric   if (display_regex_cmd_up) {
7770b57cec5SDimitry Andric     if (display_regex_cmd_up->AddRegexCommand(
7780b57cec5SDimitry Andric             "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
7790b57cec5SDimitry Andric       CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
7805ffd83dbSDimitry Andric       m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
7810b57cec5SDimitry Andric           display_regex_cmd_sp;
7820b57cec5SDimitry Andric     }
7830b57cec5SDimitry Andric   }
7840b57cec5SDimitry Andric 
7850b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
7860b57cec5SDimitry Andric       new CommandObjectRegexCommand(*this, "_regexp-undisplay",
7870b57cec5SDimitry Andric                                     "Stop displaying expression at every "
7880b57cec5SDimitry Andric                                     "stop (specified by stop-hook index.)",
78906c3fb27SDimitry Andric                                     "_regexp-undisplay stop-hook-number", 0,
7900b57cec5SDimitry Andric                                     false));
7910b57cec5SDimitry Andric   if (undisplay_regex_cmd_up) {
7920b57cec5SDimitry Andric     if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
7930b57cec5SDimitry Andric                                                 "target stop-hook delete %1")) {
7940b57cec5SDimitry Andric       CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
7955ffd83dbSDimitry Andric       m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
7960b57cec5SDimitry Andric           undisplay_regex_cmd_sp;
7970b57cec5SDimitry Andric     }
7980b57cec5SDimitry Andric   }
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
8010b57cec5SDimitry Andric       new CommandObjectRegexCommand(
8020b57cec5SDimitry Andric           *this, "gdb-remote",
803349cc55cSDimitry Andric           "Connect to a process via remote GDB server.\n"
804349cc55cSDimitry Andric           "If no host is specifed, localhost is assumed.\n"
805349cc55cSDimitry Andric           "gdb-remote is an abbreviation for 'process connect --plugin "
806349cc55cSDimitry Andric           "gdb-remote connect://<hostname>:<port>'\n",
80706c3fb27SDimitry Andric           "gdb-remote [<hostname>:]<portnum>", 0, false));
8080b57cec5SDimitry Andric   if (connect_gdb_remote_cmd_up) {
8090b57cec5SDimitry Andric     if (connect_gdb_remote_cmd_up->AddRegexCommand(
8100b57cec5SDimitry Andric             "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
8110b57cec5SDimitry Andric             "process connect --plugin gdb-remote connect://%1:%2") &&
8120b57cec5SDimitry Andric         connect_gdb_remote_cmd_up->AddRegexCommand(
8130b57cec5SDimitry Andric             "^([[:digit:]]+)$",
8140b57cec5SDimitry Andric             "process connect --plugin gdb-remote connect://localhost:%1")) {
8150b57cec5SDimitry Andric       CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
8165ffd83dbSDimitry Andric       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
8170b57cec5SDimitry Andric     }
8180b57cec5SDimitry Andric   }
8190b57cec5SDimitry Andric 
8200b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
8210b57cec5SDimitry Andric       new CommandObjectRegexCommand(
8220b57cec5SDimitry Andric           *this, "kdp-remote",
823349cc55cSDimitry Andric           "Connect to a process via remote KDP server.\n"
824349cc55cSDimitry Andric           "If no UDP port is specified, port 41139 is assumed.\n"
825349cc55cSDimitry Andric           "kdp-remote is an abbreviation for 'process connect --plugin "
826349cc55cSDimitry Andric           "kdp-remote udp://<hostname>:<port>'\n",
82706c3fb27SDimitry Andric           "kdp-remote <hostname>[:<portnum>]", 0, false));
8280b57cec5SDimitry Andric   if (connect_kdp_remote_cmd_up) {
8290b57cec5SDimitry Andric     if (connect_kdp_remote_cmd_up->AddRegexCommand(
8300b57cec5SDimitry Andric             "^([^:]+:[[:digit:]]+)$",
8310b57cec5SDimitry Andric             "process connect --plugin kdp-remote udp://%1") &&
8320b57cec5SDimitry Andric         connect_kdp_remote_cmd_up->AddRegexCommand(
8330b57cec5SDimitry Andric             "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
8340b57cec5SDimitry Andric       CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
8355ffd83dbSDimitry Andric       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
8360b57cec5SDimitry Andric     }
8370b57cec5SDimitry Andric   }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
8400b57cec5SDimitry Andric       new CommandObjectRegexCommand(
8410b57cec5SDimitry Andric           *this, "_regexp-bt",
842*0fca6ea1SDimitry Andric           "Show backtrace of the current thread's call stack.  Any numeric "
843*0fca6ea1SDimitry Andric           "argument displays at most that many frames.  The argument 'all' "
844*0fca6ea1SDimitry Andric           "displays all threads.  Use 'settings set frame-format' to customize "
845*0fca6ea1SDimitry Andric           "the printing of individual frames and 'settings set thread-format' "
846*0fca6ea1SDimitry Andric           "to customize the thread header.",
84706c3fb27SDimitry Andric           "bt [<digit> | all]", 0, false));
8480b57cec5SDimitry Andric   if (bt_regex_cmd_up) {
8490b57cec5SDimitry Andric     // accept but don't document "bt -c <number>" -- before bt was a regex
8500b57cec5SDimitry Andric     // command if you wanted to backtrace three frames you would do "bt -c 3"
8510b57cec5SDimitry Andric     // but the intention is to have this emulate the gdb "bt" command and so
8520b57cec5SDimitry Andric     // now "bt 3" is the preferred form, in line with gdb.
8530b57cec5SDimitry Andric     if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
8540b57cec5SDimitry Andric                                          "thread backtrace -c %1") &&
8550b57cec5SDimitry Andric         bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
8560b57cec5SDimitry Andric                                          "thread backtrace -c %1") &&
8570b57cec5SDimitry Andric         bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
8580b57cec5SDimitry Andric         bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
8590b57cec5SDimitry Andric       CommandObjectSP command_sp(bt_regex_cmd_up.release());
8605ffd83dbSDimitry Andric       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
8610b57cec5SDimitry Andric     }
8620b57cec5SDimitry Andric   }
8630b57cec5SDimitry Andric 
8640b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
8650b57cec5SDimitry Andric       new CommandObjectRegexCommand(
8660b57cec5SDimitry Andric           *this, "_regexp-list",
8670b57cec5SDimitry Andric           "List relevant source code using one of several shorthand formats.",
8680b57cec5SDimitry Andric           "\n"
8690b57cec5SDimitry Andric           "_regexp-list <file>:<line>   // List around specific file/line\n"
8700b57cec5SDimitry Andric           "_regexp-list <line>          // List current file around specified "
8710b57cec5SDimitry Andric           "line\n"
8720b57cec5SDimitry Andric           "_regexp-list <function-name> // List specified function\n"
8730b57cec5SDimitry Andric           "_regexp-list 0x<address>     // List around specified address\n"
8740b57cec5SDimitry Andric           "_regexp-list -[<count>]      // List previous <count> lines\n"
8750b57cec5SDimitry Andric           "_regexp-list                 // List subsequent lines",
87606c3fb27SDimitry Andric           lldb::eSourceFileCompletion, false));
8770b57cec5SDimitry Andric   if (list_regex_cmd_up) {
8780b57cec5SDimitry Andric     if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
8790b57cec5SDimitry Andric                                            "source list --line %1") &&
8800b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand(
8810b57cec5SDimitry Andric             "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
8820b57cec5SDimitry Andric             "]*$",
8830b57cec5SDimitry Andric             "source list --file '%1' --line %2") &&
8840b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand(
8850b57cec5SDimitry Andric             "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
8860b57cec5SDimitry Andric             "source list --address %1") &&
8870b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
8880b57cec5SDimitry Andric                                            "source list --reverse") &&
8890b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand(
8900b57cec5SDimitry Andric             "^-([[:digit:]]+)[[:space:]]*$",
8910b57cec5SDimitry Andric             "source list --reverse --count %1") &&
8920b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand("^(.+)$",
8930b57cec5SDimitry Andric                                            "source list --name \"%1\"") &&
8940b57cec5SDimitry Andric         list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
8950b57cec5SDimitry Andric       CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
8965ffd83dbSDimitry Andric       m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
8975ffd83dbSDimitry Andric           list_regex_cmd_sp;
8980b57cec5SDimitry Andric     }
8990b57cec5SDimitry Andric   }
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
9020b57cec5SDimitry Andric       new CommandObjectRegexCommand(
9030b57cec5SDimitry Andric           *this, "_regexp-env",
9040b57cec5SDimitry Andric           "Shorthand for viewing and setting environment variables.",
9050b57cec5SDimitry Andric           "\n"
9060b57cec5SDimitry Andric           "_regexp-env                  // Show environment\n"
9070b57cec5SDimitry Andric           "_regexp-env <name>=<value>   // Set an environment variable",
90806c3fb27SDimitry Andric           0, false));
9090b57cec5SDimitry Andric   if (env_regex_cmd_up) {
9100b57cec5SDimitry Andric     if (env_regex_cmd_up->AddRegexCommand("^$",
9110b57cec5SDimitry Andric                                           "settings show target.env-vars") &&
9120b57cec5SDimitry Andric         env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
9130b57cec5SDimitry Andric                                           "settings set target.env-vars %1")) {
9140b57cec5SDimitry Andric       CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
9155ffd83dbSDimitry Andric       m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
9165ffd83dbSDimitry Andric           env_regex_cmd_sp;
9170b57cec5SDimitry Andric     }
9180b57cec5SDimitry Andric   }
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric   std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
9210b57cec5SDimitry Andric       new CommandObjectRegexCommand(
9220b57cec5SDimitry Andric           *this, "_regexp-jump", "Set the program counter to a new address.",
9230b57cec5SDimitry Andric           "\n"
9240b57cec5SDimitry Andric           "_regexp-jump <line>\n"
9250b57cec5SDimitry Andric           "_regexp-jump +<line-offset> | -<line-offset>\n"
9260b57cec5SDimitry Andric           "_regexp-jump <file>:<line>\n"
9270b57cec5SDimitry Andric           "_regexp-jump *<addr>\n",
92806c3fb27SDimitry Andric           0, false));
9290b57cec5SDimitry Andric   if (jump_regex_cmd_up) {
9300b57cec5SDimitry Andric     if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
9310b57cec5SDimitry Andric                                            "thread jump --addr %1") &&
9320b57cec5SDimitry Andric         jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
9330b57cec5SDimitry Andric                                            "thread jump --line %1") &&
9340b57cec5SDimitry Andric         jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
9350b57cec5SDimitry Andric                                            "thread jump --file %1 --line %2") &&
9360b57cec5SDimitry Andric         jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
9370b57cec5SDimitry Andric                                            "thread jump --by %1")) {
9380b57cec5SDimitry Andric       CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
9395ffd83dbSDimitry Andric       m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
9405ffd83dbSDimitry Andric           jump_regex_cmd_sp;
9410b57cec5SDimitry Andric     }
9420b57cec5SDimitry Andric   }
9430b57cec5SDimitry Andric }
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric int CommandInterpreter::GetCommandNamesMatchingPartialString(
9460b57cec5SDimitry Andric     const char *cmd_str, bool include_aliases, StringList &matches,
9470b57cec5SDimitry Andric     StringList &descriptions) {
9480b57cec5SDimitry Andric   AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
9490b57cec5SDimitry Andric                                 &descriptions);
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric   if (include_aliases) {
9520b57cec5SDimitry Andric     AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
9530b57cec5SDimitry Andric                                   &descriptions);
9540b57cec5SDimitry Andric   }
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   return matches.GetSize();
9570b57cec5SDimitry Andric }
9580b57cec5SDimitry Andric 
959349cc55cSDimitry Andric CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath(
960349cc55cSDimitry Andric     Args &path, bool leaf_is_command, Status &result) {
961349cc55cSDimitry Andric   result.Clear();
962349cc55cSDimitry Andric 
963349cc55cSDimitry Andric   auto get_multi_or_report_error =
964349cc55cSDimitry Andric       [&result](CommandObjectSP cmd_sp,
965349cc55cSDimitry Andric                            const char *name) -> CommandObjectMultiword * {
966349cc55cSDimitry Andric     if (!cmd_sp) {
967349cc55cSDimitry Andric       result.SetErrorStringWithFormat("Path component: '%s' not found", name);
968349cc55cSDimitry Andric       return nullptr;
969349cc55cSDimitry Andric     }
970349cc55cSDimitry Andric     if (!cmd_sp->IsUserCommand()) {
971349cc55cSDimitry Andric       result.SetErrorStringWithFormat("Path component: '%s' is not a user "
972349cc55cSDimitry Andric                                       "command",
973349cc55cSDimitry Andric                                       name);
974349cc55cSDimitry Andric       return nullptr;
975349cc55cSDimitry Andric     }
976349cc55cSDimitry Andric     CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
977349cc55cSDimitry Andric     if (!cmd_as_multi) {
978349cc55cSDimitry Andric       result.SetErrorStringWithFormat("Path component: '%s' is not a container "
979349cc55cSDimitry Andric                                       "command",
980349cc55cSDimitry Andric                                       name);
981349cc55cSDimitry Andric       return nullptr;
982349cc55cSDimitry Andric     }
983349cc55cSDimitry Andric     return cmd_as_multi;
984349cc55cSDimitry Andric   };
985349cc55cSDimitry Andric 
986349cc55cSDimitry Andric   size_t num_args = path.GetArgumentCount();
987349cc55cSDimitry Andric   if (num_args == 0) {
988349cc55cSDimitry Andric     result.SetErrorString("empty command path");
989349cc55cSDimitry Andric     return nullptr;
990349cc55cSDimitry Andric   }
991349cc55cSDimitry Andric 
992349cc55cSDimitry Andric   if (num_args == 1 && leaf_is_command) {
993349cc55cSDimitry Andric     // We just got a leaf command to be added to the root.  That's not an error,
994349cc55cSDimitry Andric     // just return null for the container.
995349cc55cSDimitry Andric     return nullptr;
996349cc55cSDimitry Andric   }
997349cc55cSDimitry Andric 
998349cc55cSDimitry Andric   // Start by getting the root command from the interpreter.
999349cc55cSDimitry Andric   const char *cur_name = path.GetArgumentAtIndex(0);
1000349cc55cSDimitry Andric   CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
1001349cc55cSDimitry Andric   CommandObjectMultiword *cur_as_multi =
1002349cc55cSDimitry Andric       get_multi_or_report_error(cur_cmd_sp, cur_name);
1003349cc55cSDimitry Andric   if (cur_as_multi == nullptr)
1004349cc55cSDimitry Andric     return nullptr;
1005349cc55cSDimitry Andric 
1006349cc55cSDimitry Andric   size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
1007349cc55cSDimitry Andric   for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
1008349cc55cSDimitry Andric        cursor++) {
1009349cc55cSDimitry Andric     cur_name = path.GetArgumentAtIndex(cursor);
1010349cc55cSDimitry Andric     cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
1011349cc55cSDimitry Andric     cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
1012349cc55cSDimitry Andric   }
1013349cc55cSDimitry Andric   return cur_as_multi;
1014349cc55cSDimitry Andric }
1015349cc55cSDimitry Andric 
10160b57cec5SDimitry Andric CommandObjectSP
10170b57cec5SDimitry Andric CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
10180b57cec5SDimitry Andric                                  bool exact, StringList *matches,
10190b57cec5SDimitry Andric                                  StringList *descriptions) const {
10200b57cec5SDimitry Andric   CommandObjectSP command_sp;
10210b57cec5SDimitry Andric 
10225ffd83dbSDimitry Andric   std::string cmd = std::string(cmd_str);
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric   if (HasCommands()) {
10250b57cec5SDimitry Andric     auto pos = m_command_dict.find(cmd);
10260b57cec5SDimitry Andric     if (pos != m_command_dict.end())
10270b57cec5SDimitry Andric       command_sp = pos->second;
10280b57cec5SDimitry Andric   }
10290b57cec5SDimitry Andric 
10300b57cec5SDimitry Andric   if (include_aliases && HasAliases()) {
10310b57cec5SDimitry Andric     auto alias_pos = m_alias_dict.find(cmd);
10320b57cec5SDimitry Andric     if (alias_pos != m_alias_dict.end())
10330b57cec5SDimitry Andric       command_sp = alias_pos->second;
10340b57cec5SDimitry Andric   }
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric   if (HasUserCommands()) {
10370b57cec5SDimitry Andric     auto pos = m_user_dict.find(cmd);
10380b57cec5SDimitry Andric     if (pos != m_user_dict.end())
10390b57cec5SDimitry Andric       command_sp = pos->second;
10400b57cec5SDimitry Andric   }
10410b57cec5SDimitry Andric 
1042349cc55cSDimitry Andric   if (HasUserMultiwordCommands()) {
1043349cc55cSDimitry Andric     auto pos = m_user_mw_dict.find(cmd);
1044349cc55cSDimitry Andric     if (pos != m_user_mw_dict.end())
1045349cc55cSDimitry Andric       command_sp = pos->second;
1046349cc55cSDimitry Andric   }
1047349cc55cSDimitry Andric 
10480b57cec5SDimitry Andric   if (!exact && !command_sp) {
10490b57cec5SDimitry Andric     // We will only get into here if we didn't find any exact matches.
10500b57cec5SDimitry Andric 
1051349cc55cSDimitry Andric     CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1052349cc55cSDimitry Andric         real_match_sp;
10530b57cec5SDimitry Andric 
10540b57cec5SDimitry Andric     StringList local_matches;
10550b57cec5SDimitry Andric     if (matches == nullptr)
10560b57cec5SDimitry Andric       matches = &local_matches;
10570b57cec5SDimitry Andric 
10580b57cec5SDimitry Andric     unsigned int num_cmd_matches = 0;
10590b57cec5SDimitry Andric     unsigned int num_alias_matches = 0;
10600b57cec5SDimitry Andric     unsigned int num_user_matches = 0;
1061349cc55cSDimitry Andric     unsigned int num_user_mw_matches = 0;
10620b57cec5SDimitry Andric 
10630b57cec5SDimitry Andric     // Look through the command dictionaries one by one, and if we get only one
10640b57cec5SDimitry Andric     // match from any of them in toto, then return that, otherwise return an
10650b57cec5SDimitry Andric     // empty CommandObjectSP and the list of matches.
10660b57cec5SDimitry Andric 
10670b57cec5SDimitry Andric     if (HasCommands()) {
10680b57cec5SDimitry Andric       num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
10690b57cec5SDimitry Andric                                                       *matches, descriptions);
10700b57cec5SDimitry Andric     }
10710b57cec5SDimitry Andric 
10720b57cec5SDimitry Andric     if (num_cmd_matches == 1) {
10730b57cec5SDimitry Andric       cmd.assign(matches->GetStringAtIndex(0));
10740b57cec5SDimitry Andric       auto pos = m_command_dict.find(cmd);
10750b57cec5SDimitry Andric       if (pos != m_command_dict.end())
10760b57cec5SDimitry Andric         real_match_sp = pos->second;
10770b57cec5SDimitry Andric     }
10780b57cec5SDimitry Andric 
10790b57cec5SDimitry Andric     if (include_aliases && HasAliases()) {
10800b57cec5SDimitry Andric       num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
10810b57cec5SDimitry Andric                                                         *matches, descriptions);
10820b57cec5SDimitry Andric     }
10830b57cec5SDimitry Andric 
10840b57cec5SDimitry Andric     if (num_alias_matches == 1) {
10850b57cec5SDimitry Andric       cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
10860b57cec5SDimitry Andric       auto alias_pos = m_alias_dict.find(cmd);
10870b57cec5SDimitry Andric       if (alias_pos != m_alias_dict.end())
10880b57cec5SDimitry Andric         alias_match_sp = alias_pos->second;
10890b57cec5SDimitry Andric     }
10900b57cec5SDimitry Andric 
10910b57cec5SDimitry Andric     if (HasUserCommands()) {
10920b57cec5SDimitry Andric       num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
10930b57cec5SDimitry Andric                                                        *matches, descriptions);
10940b57cec5SDimitry Andric     }
10950b57cec5SDimitry Andric 
10960b57cec5SDimitry Andric     if (num_user_matches == 1) {
10970b57cec5SDimitry Andric       cmd.assign(
10980b57cec5SDimitry Andric           matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric       auto pos = m_user_dict.find(cmd);
11010b57cec5SDimitry Andric       if (pos != m_user_dict.end())
11020b57cec5SDimitry Andric         user_match_sp = pos->second;
11030b57cec5SDimitry Andric     }
11040b57cec5SDimitry Andric 
1105349cc55cSDimitry Andric     if (HasUserMultiwordCommands()) {
1106349cc55cSDimitry Andric       num_user_mw_matches = AddNamesMatchingPartialString(
1107349cc55cSDimitry Andric           m_user_mw_dict, cmd_str, *matches, descriptions);
1108349cc55cSDimitry Andric     }
1109349cc55cSDimitry Andric 
1110349cc55cSDimitry Andric     if (num_user_mw_matches == 1) {
1111349cc55cSDimitry Andric       cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1112349cc55cSDimitry Andric                                            num_user_matches));
1113349cc55cSDimitry Andric 
1114349cc55cSDimitry Andric       auto pos = m_user_mw_dict.find(cmd);
1115349cc55cSDimitry Andric       if (pos != m_user_mw_dict.end())
1116349cc55cSDimitry Andric         user_mw_match_sp = pos->second;
1117349cc55cSDimitry Andric     }
1118349cc55cSDimitry Andric 
11190b57cec5SDimitry Andric     // If we got exactly one match, return that, otherwise return the match
11200b57cec5SDimitry Andric     // list.
11210b57cec5SDimitry Andric 
1122349cc55cSDimitry Andric     if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1123349cc55cSDimitry Andric             num_alias_matches ==
1124349cc55cSDimitry Andric         1) {
11250b57cec5SDimitry Andric       if (num_cmd_matches)
11260b57cec5SDimitry Andric         return real_match_sp;
11270b57cec5SDimitry Andric       else if (num_alias_matches)
11280b57cec5SDimitry Andric         return alias_match_sp;
1129349cc55cSDimitry Andric       else if (num_user_mw_matches)
1130349cc55cSDimitry Andric         return user_mw_match_sp;
11310b57cec5SDimitry Andric       else
11320b57cec5SDimitry Andric         return user_match_sp;
11330b57cec5SDimitry Andric     }
11340b57cec5SDimitry Andric   } else if (matches && command_sp) {
11350b57cec5SDimitry Andric     matches->AppendString(cmd_str);
11360b57cec5SDimitry Andric     if (descriptions)
11370b57cec5SDimitry Andric       descriptions->AppendString(command_sp->GetHelp());
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric 
11400b57cec5SDimitry Andric   return command_sp;
11410b57cec5SDimitry Andric }
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric bool CommandInterpreter::AddCommand(llvm::StringRef name,
11440b57cec5SDimitry Andric                                     const lldb::CommandObjectSP &cmd_sp,
11450b57cec5SDimitry Andric                                     bool can_replace) {
11460b57cec5SDimitry Andric   if (cmd_sp.get())
11470b57cec5SDimitry Andric     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
11480b57cec5SDimitry Andric                "tried to add a CommandObject from a different interpreter");
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric   if (name.empty())
11510b57cec5SDimitry Andric     return false;
11520b57cec5SDimitry Andric 
1153349cc55cSDimitry Andric   cmd_sp->SetIsUserCommand(false);
1154349cc55cSDimitry Andric 
11550b57cec5SDimitry Andric   std::string name_sstr(name);
11560b57cec5SDimitry Andric   auto name_iter = m_command_dict.find(name_sstr);
11570b57cec5SDimitry Andric   if (name_iter != m_command_dict.end()) {
11580b57cec5SDimitry Andric     if (!can_replace || !name_iter->second->IsRemovable())
11590b57cec5SDimitry Andric       return false;
11600b57cec5SDimitry Andric     name_iter->second = cmd_sp;
11610b57cec5SDimitry Andric   } else {
11620b57cec5SDimitry Andric     m_command_dict[name_sstr] = cmd_sp;
11630b57cec5SDimitry Andric   }
11640b57cec5SDimitry Andric   return true;
11650b57cec5SDimitry Andric }
11660b57cec5SDimitry Andric 
1167349cc55cSDimitry Andric Status CommandInterpreter::AddUserCommand(llvm::StringRef name,
11680b57cec5SDimitry Andric                                           const lldb::CommandObjectSP &cmd_sp,
11690b57cec5SDimitry Andric                                           bool can_replace) {
1170349cc55cSDimitry Andric   Status result;
11710b57cec5SDimitry Andric   if (cmd_sp.get())
11720b57cec5SDimitry Andric     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
11730b57cec5SDimitry Andric                "tried to add a CommandObject from a different interpreter");
1174349cc55cSDimitry Andric   if (name.empty()) {
1175349cc55cSDimitry Andric     result.SetErrorString("can't use the empty string for a command name");
1176349cc55cSDimitry Andric     return result;
1177349cc55cSDimitry Andric   }
11780b57cec5SDimitry Andric   // do not allow replacement of internal commands
11790b57cec5SDimitry Andric   if (CommandExists(name)) {
1180349cc55cSDimitry Andric     result.SetErrorString("can't replace builtin command");
1181349cc55cSDimitry Andric     return result;
11820b57cec5SDimitry Andric   }
11830b57cec5SDimitry Andric 
11840b57cec5SDimitry Andric   if (UserCommandExists(name)) {
1185349cc55cSDimitry Andric     if (!can_replace) {
1186cb14a3feSDimitry Andric       result.SetErrorStringWithFormatv(
1187cb14a3feSDimitry Andric           "user command \"{0}\" already exists and force replace was not set "
1188cb14a3feSDimitry Andric           "by --overwrite or 'settings set interpreter.require-overwrite "
1189cb14a3feSDimitry Andric           "false'",
1190cb14a3feSDimitry Andric           name);
1191349cc55cSDimitry Andric       return result;
1192349cc55cSDimitry Andric     }
1193349cc55cSDimitry Andric     if (cmd_sp->IsMultiwordObject()) {
1194349cc55cSDimitry Andric       if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1195349cc55cSDimitry Andric         result.SetErrorString(
1196349cc55cSDimitry Andric             "can't replace explicitly non-removable multi-word command");
1197349cc55cSDimitry Andric         return result;
1198349cc55cSDimitry Andric       }
1199349cc55cSDimitry Andric     } else {
1200349cc55cSDimitry Andric       if (!m_user_dict[std::string(name)]->IsRemovable()) {
1201349cc55cSDimitry Andric         result.SetErrorString("can't replace explicitly non-removable command");
1202349cc55cSDimitry Andric         return result;
1203349cc55cSDimitry Andric       }
1204349cc55cSDimitry Andric     }
12050b57cec5SDimitry Andric   }
12060b57cec5SDimitry Andric 
1207349cc55cSDimitry Andric   cmd_sp->SetIsUserCommand(true);
1208349cc55cSDimitry Andric 
1209349cc55cSDimitry Andric   if (cmd_sp->IsMultiwordObject())
1210349cc55cSDimitry Andric     m_user_mw_dict[std::string(name)] = cmd_sp;
1211349cc55cSDimitry Andric   else
12125ffd83dbSDimitry Andric     m_user_dict[std::string(name)] = cmd_sp;
1213349cc55cSDimitry Andric   return result;
12140b57cec5SDimitry Andric }
12150b57cec5SDimitry Andric 
1216e8d8bef9SDimitry Andric CommandObjectSP
1217e8d8bef9SDimitry Andric CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
12180b57cec5SDimitry Andric                                       bool include_aliases) const {
1219e8d8bef9SDimitry Andric   // Break up the command string into words, in case it's a multi-word command.
1220e8d8bef9SDimitry Andric   Args cmd_words(cmd_str);
12210b57cec5SDimitry Andric 
12220b57cec5SDimitry Andric   if (cmd_str.empty())
1223e8d8bef9SDimitry Andric     return {};
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   if (cmd_words.GetArgumentCount() == 1)
1226e8d8bef9SDimitry Andric     return GetCommandSP(cmd_str, include_aliases, true);
1227e8d8bef9SDimitry Andric 
12280b57cec5SDimitry Andric   // We have a multi-word command (seemingly), so we need to do more work.
12290b57cec5SDimitry Andric   // First, get the cmd_obj_sp for the first word in the command.
1230e8d8bef9SDimitry Andric   CommandObjectSP cmd_obj_sp =
1231e8d8bef9SDimitry Andric       GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1232e8d8bef9SDimitry Andric   if (!cmd_obj_sp)
1233e8d8bef9SDimitry Andric     return {};
1234e8d8bef9SDimitry Andric 
1235e8d8bef9SDimitry Andric   // Loop through the rest of the words in the command (everything passed in
1236e8d8bef9SDimitry Andric   // was supposed to be part of a command name), and find the appropriate
1237e8d8bef9SDimitry Andric   // sub-command SP for each command word....
12380b57cec5SDimitry Andric   size_t end = cmd_words.GetArgumentCount();
1239e8d8bef9SDimitry Andric   for (size_t i = 1; i < end; ++i) {
1240e8d8bef9SDimitry Andric     if (!cmd_obj_sp->IsMultiwordObject()) {
12410b57cec5SDimitry Andric       // We have more words in the command name, but we don't have a
1242e8d8bef9SDimitry Andric       // multiword object. Fail and return.
1243e8d8bef9SDimitry Andric       return {};
12440b57cec5SDimitry Andric     }
1245e8d8bef9SDimitry Andric 
1246e8d8bef9SDimitry Andric     cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1247e8d8bef9SDimitry Andric     if (!cmd_obj_sp) {
1248e8d8bef9SDimitry Andric       // The sub-command name was invalid.  Fail and return.
1249e8d8bef9SDimitry Andric       return {};
1250e8d8bef9SDimitry Andric     }
1251e8d8bef9SDimitry Andric   }
1252e8d8bef9SDimitry Andric 
12530b57cec5SDimitry Andric   // We successfully looped through all the command words and got valid
1254e8d8bef9SDimitry Andric   // command objects for them.
1255e8d8bef9SDimitry Andric   return cmd_obj_sp;
12560b57cec5SDimitry Andric }
12570b57cec5SDimitry Andric 
12580b57cec5SDimitry Andric CommandObject *
12590b57cec5SDimitry Andric CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
12600b57cec5SDimitry Andric                                      StringList *matches,
12610b57cec5SDimitry Andric                                      StringList *descriptions) const {
12625f757f3fSDimitry Andric   // Try to find a match among commands and aliases. Allowing inexact matches,
12635f757f3fSDimitry Andric   // but perferring exact matches.
12645f757f3fSDimitry Andric   return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
12655f757f3fSDimitry Andric                              matches, descriptions)
12665f757f3fSDimitry Andric                     .get();
12670b57cec5SDimitry Andric }
12680b57cec5SDimitry Andric 
1269349cc55cSDimitry Andric CommandObject *CommandInterpreter::GetUserCommandObject(
1270349cc55cSDimitry Andric     llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1271349cc55cSDimitry Andric   std::string cmd_str(cmd);
1272349cc55cSDimitry Andric   auto find_exact = [&](const CommandObject::CommandMap &map) {
1273349cc55cSDimitry Andric     auto found_elem = map.find(std::string(cmd));
1274349cc55cSDimitry Andric     if (found_elem == map.end())
1275349cc55cSDimitry Andric       return (CommandObject *)nullptr;
1276349cc55cSDimitry Andric     CommandObject *exact_cmd = found_elem->second.get();
1277349cc55cSDimitry Andric     if (exact_cmd) {
1278349cc55cSDimitry Andric       if (matches)
1279349cc55cSDimitry Andric         matches->AppendString(exact_cmd->GetCommandName());
1280349cc55cSDimitry Andric       if (descriptions)
1281349cc55cSDimitry Andric         descriptions->AppendString(exact_cmd->GetHelp());
1282349cc55cSDimitry Andric       return exact_cmd;
1283349cc55cSDimitry Andric     }
1284349cc55cSDimitry Andric     return (CommandObject *)nullptr;
1285349cc55cSDimitry Andric   };
1286349cc55cSDimitry Andric 
1287349cc55cSDimitry Andric   CommandObject *exact_cmd = find_exact(GetUserCommands());
1288349cc55cSDimitry Andric   if (exact_cmd)
1289349cc55cSDimitry Andric     return exact_cmd;
1290349cc55cSDimitry Andric 
1291349cc55cSDimitry Andric   exact_cmd = find_exact(GetUserMultiwordCommands());
1292349cc55cSDimitry Andric   if (exact_cmd)
1293349cc55cSDimitry Andric     return exact_cmd;
1294349cc55cSDimitry Andric 
1295349cc55cSDimitry Andric   // We didn't have an exact command, so now look for partial matches.
1296349cc55cSDimitry Andric   StringList tmp_list;
1297349cc55cSDimitry Andric   StringList *matches_ptr = matches ? matches : &tmp_list;
1298349cc55cSDimitry Andric   AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1299349cc55cSDimitry Andric   AddNamesMatchingPartialString(GetUserMultiwordCommands(),
1300349cc55cSDimitry Andric                                 cmd_str, *matches_ptr);
1301349cc55cSDimitry Andric 
1302349cc55cSDimitry Andric   return {};
1303349cc55cSDimitry Andric }
1304349cc55cSDimitry Andric 
13050b57cec5SDimitry Andric bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
13065ffd83dbSDimitry Andric   return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
13070b57cec5SDimitry Andric }
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
13100b57cec5SDimitry Andric                                           std::string &full_name) const {
13115ffd83dbSDimitry Andric   bool exact_match =
13125ffd83dbSDimitry Andric       (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
13130b57cec5SDimitry Andric   if (exact_match) {
13145ffd83dbSDimitry Andric     full_name.assign(std::string(cmd));
13150b57cec5SDimitry Andric     return exact_match;
13160b57cec5SDimitry Andric   } else {
13170b57cec5SDimitry Andric     StringList matches;
13180b57cec5SDimitry Andric     size_t num_alias_matches;
13190b57cec5SDimitry Andric     num_alias_matches =
13200b57cec5SDimitry Andric         AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
13210b57cec5SDimitry Andric     if (num_alias_matches == 1) {
13220b57cec5SDimitry Andric       // Make sure this isn't shadowing a command in the regular command space:
13230b57cec5SDimitry Andric       StringList regular_matches;
13240b57cec5SDimitry Andric       const bool include_aliases = false;
13250b57cec5SDimitry Andric       const bool exact = false;
13260b57cec5SDimitry Andric       CommandObjectSP cmd_obj_sp(
13270b57cec5SDimitry Andric           GetCommandSP(cmd, include_aliases, exact, &regular_matches));
13280b57cec5SDimitry Andric       if (cmd_obj_sp || regular_matches.GetSize() > 0)
13290b57cec5SDimitry Andric         return false;
13300b57cec5SDimitry Andric       else {
13310b57cec5SDimitry Andric         full_name.assign(matches.GetStringAtIndex(0));
13320b57cec5SDimitry Andric         return true;
13330b57cec5SDimitry Andric       }
13340b57cec5SDimitry Andric     } else
13350b57cec5SDimitry Andric       return false;
13360b57cec5SDimitry Andric   }
13370b57cec5SDimitry Andric }
13380b57cec5SDimitry Andric 
13390b57cec5SDimitry Andric bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
13405ffd83dbSDimitry Andric   return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
13410b57cec5SDimitry Andric }
13420b57cec5SDimitry Andric 
13430b57cec5SDimitry Andric bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
13445ffd83dbSDimitry Andric   return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
13450b57cec5SDimitry Andric }
13460b57cec5SDimitry Andric 
1347349cc55cSDimitry Andric bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1348349cc55cSDimitry Andric   return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
1349349cc55cSDimitry Andric }
1350349cc55cSDimitry Andric 
13510b57cec5SDimitry Andric CommandAlias *
13520b57cec5SDimitry Andric CommandInterpreter::AddAlias(llvm::StringRef alias_name,
13530b57cec5SDimitry Andric                              lldb::CommandObjectSP &command_obj_sp,
13540b57cec5SDimitry Andric                              llvm::StringRef args_string) {
13550b57cec5SDimitry Andric   if (command_obj_sp.get())
13560b57cec5SDimitry Andric     lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
13570b57cec5SDimitry Andric                "tried to add a CommandObject from a different interpreter");
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric   std::unique_ptr<CommandAlias> command_alias_up(
13600b57cec5SDimitry Andric       new CommandAlias(*this, command_obj_sp, args_string, alias_name));
13610b57cec5SDimitry Andric 
13620b57cec5SDimitry Andric   if (command_alias_up && command_alias_up->IsValid()) {
13635ffd83dbSDimitry Andric     m_alias_dict[std::string(alias_name)] =
13645ffd83dbSDimitry Andric         CommandObjectSP(command_alias_up.get());
13650b57cec5SDimitry Andric     return command_alias_up.release();
13660b57cec5SDimitry Andric   }
13670b57cec5SDimitry Andric 
13680b57cec5SDimitry Andric   return nullptr;
13690b57cec5SDimitry Andric }
13700b57cec5SDimitry Andric 
13710b57cec5SDimitry Andric bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
13725ffd83dbSDimitry Andric   auto pos = m_alias_dict.find(std::string(alias_name));
13730b57cec5SDimitry Andric   if (pos != m_alias_dict.end()) {
13740b57cec5SDimitry Andric     m_alias_dict.erase(pos);
13750b57cec5SDimitry Andric     return true;
13760b57cec5SDimitry Andric   }
13770b57cec5SDimitry Andric   return false;
13780b57cec5SDimitry Andric }
13790b57cec5SDimitry Andric 
138006c3fb27SDimitry Andric bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
13815ffd83dbSDimitry Andric   auto pos = m_command_dict.find(std::string(cmd));
13820b57cec5SDimitry Andric   if (pos != m_command_dict.end()) {
138306c3fb27SDimitry Andric     if (force || pos->second->IsRemovable()) {
138406c3fb27SDimitry Andric       // Only regular expression objects or python commands are removable under
138506c3fb27SDimitry Andric       // normal circumstances.
13860b57cec5SDimitry Andric       m_command_dict.erase(pos);
13870b57cec5SDimitry Andric       return true;
13880b57cec5SDimitry Andric     }
13890b57cec5SDimitry Andric   }
13900b57cec5SDimitry Andric   return false;
13910b57cec5SDimitry Andric }
1392349cc55cSDimitry Andric 
1393349cc55cSDimitry Andric bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
13945ffd83dbSDimitry Andric   CommandObject::CommandMap::iterator pos =
1395349cc55cSDimitry Andric       m_user_dict.find(std::string(user_name));
13960b57cec5SDimitry Andric   if (pos != m_user_dict.end()) {
13970b57cec5SDimitry Andric     m_user_dict.erase(pos);
13980b57cec5SDimitry Andric     return true;
13990b57cec5SDimitry Andric   }
14000b57cec5SDimitry Andric   return false;
14010b57cec5SDimitry Andric }
14020b57cec5SDimitry Andric 
1403349cc55cSDimitry Andric bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1404349cc55cSDimitry Andric   CommandObject::CommandMap::iterator pos =
1405349cc55cSDimitry Andric       m_user_mw_dict.find(std::string(multi_name));
1406349cc55cSDimitry Andric   if (pos != m_user_mw_dict.end()) {
1407349cc55cSDimitry Andric     m_user_mw_dict.erase(pos);
1408349cc55cSDimitry Andric     return true;
1409349cc55cSDimitry Andric   }
1410349cc55cSDimitry Andric   return false;
1411349cc55cSDimitry Andric }
1412349cc55cSDimitry Andric 
14130b57cec5SDimitry Andric void CommandInterpreter::GetHelp(CommandReturnObject &result,
14140b57cec5SDimitry Andric                                  uint32_t cmd_types) {
14150b57cec5SDimitry Andric   llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
14160b57cec5SDimitry Andric   if (!help_prologue.empty()) {
14170b57cec5SDimitry Andric     OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
14180b57cec5SDimitry Andric                             help_prologue);
14190b57cec5SDimitry Andric   }
14200b57cec5SDimitry Andric 
14210b57cec5SDimitry Andric   CommandObject::CommandMap::const_iterator pos;
14220b57cec5SDimitry Andric   size_t max_len = FindLongestCommandWord(m_command_dict);
14230b57cec5SDimitry Andric 
14240b57cec5SDimitry Andric   if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
14250b57cec5SDimitry Andric     result.AppendMessage("Debugger commands:");
14260b57cec5SDimitry Andric     result.AppendMessage("");
14270b57cec5SDimitry Andric 
14280b57cec5SDimitry Andric     for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
14290b57cec5SDimitry Andric       if (!(cmd_types & eCommandTypesHidden) &&
14300b57cec5SDimitry Andric           (pos->first.compare(0, 1, "_") == 0))
14310b57cec5SDimitry Andric         continue;
14320b57cec5SDimitry Andric 
14330b57cec5SDimitry Andric       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
14340b57cec5SDimitry Andric                               pos->second->GetHelp(), max_len);
14350b57cec5SDimitry Andric     }
14360b57cec5SDimitry Andric     result.AppendMessage("");
14370b57cec5SDimitry Andric   }
14380b57cec5SDimitry Andric 
14390b57cec5SDimitry Andric   if (!m_alias_dict.empty() &&
14400b57cec5SDimitry Andric       ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
14410b57cec5SDimitry Andric     result.AppendMessageWithFormat(
14420b57cec5SDimitry Andric         "Current command abbreviations "
14430b57cec5SDimitry Andric         "(type '%shelp command alias' for more info):\n",
14440b57cec5SDimitry Andric         GetCommandPrefix());
14450b57cec5SDimitry Andric     result.AppendMessage("");
14460b57cec5SDimitry Andric     max_len = FindLongestCommandWord(m_alias_dict);
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric     for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
14490b57cec5SDimitry Andric          ++alias_pos) {
14500b57cec5SDimitry Andric       OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
14510b57cec5SDimitry Andric                               alias_pos->second->GetHelp(), max_len);
14520b57cec5SDimitry Andric     }
14530b57cec5SDimitry Andric     result.AppendMessage("");
14540b57cec5SDimitry Andric   }
14550b57cec5SDimitry Andric 
14560b57cec5SDimitry Andric   if (!m_user_dict.empty() &&
14570b57cec5SDimitry Andric       ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
14580b57cec5SDimitry Andric     result.AppendMessage("Current user-defined commands:");
14590b57cec5SDimitry Andric     result.AppendMessage("");
14600b57cec5SDimitry Andric     max_len = FindLongestCommandWord(m_user_dict);
14610b57cec5SDimitry Andric     for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
14620b57cec5SDimitry Andric       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
14630b57cec5SDimitry Andric                               pos->second->GetHelp(), max_len);
14640b57cec5SDimitry Andric     }
14650b57cec5SDimitry Andric     result.AppendMessage("");
14660b57cec5SDimitry Andric   }
14670b57cec5SDimitry Andric 
1468349cc55cSDimitry Andric   if (!m_user_mw_dict.empty() &&
1469349cc55cSDimitry Andric       ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1470349cc55cSDimitry Andric     result.AppendMessage("Current user-defined container commands:");
1471349cc55cSDimitry Andric     result.AppendMessage("");
1472349cc55cSDimitry Andric     max_len = FindLongestCommandWord(m_user_mw_dict);
147381ad6265SDimitry Andric     for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1474349cc55cSDimitry Andric       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1475349cc55cSDimitry Andric                               pos->second->GetHelp(), max_len);
1476349cc55cSDimitry Andric     }
1477349cc55cSDimitry Andric     result.AppendMessage("");
1478349cc55cSDimitry Andric   }
1479349cc55cSDimitry Andric 
14800b57cec5SDimitry Andric   result.AppendMessageWithFormat(
14810b57cec5SDimitry Andric       "For more information on any command, type '%shelp <command-name>'.\n",
14820b57cec5SDimitry Andric       GetCommandPrefix());
14830b57cec5SDimitry Andric }
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric CommandObject *CommandInterpreter::GetCommandObjectForCommand(
14860b57cec5SDimitry Andric     llvm::StringRef &command_string) {
14870b57cec5SDimitry Andric   // This function finds the final, lowest-level, alias-resolved command object
14880b57cec5SDimitry Andric   // whose 'Execute' function will eventually be invoked by the given command
14890b57cec5SDimitry Andric   // line.
14900b57cec5SDimitry Andric 
14910b57cec5SDimitry Andric   CommandObject *cmd_obj = nullptr;
14920b57cec5SDimitry Andric   size_t start = command_string.find_first_not_of(k_white_space);
14930b57cec5SDimitry Andric   size_t end = 0;
14940b57cec5SDimitry Andric   bool done = false;
14950b57cec5SDimitry Andric   while (!done) {
14960b57cec5SDimitry Andric     if (start != std::string::npos) {
14970b57cec5SDimitry Andric       // Get the next word from command_string.
14980b57cec5SDimitry Andric       end = command_string.find_first_of(k_white_space, start);
14990b57cec5SDimitry Andric       if (end == std::string::npos)
15000b57cec5SDimitry Andric         end = command_string.size();
15015ffd83dbSDimitry Andric       std::string cmd_word =
15025ffd83dbSDimitry Andric           std::string(command_string.substr(start, end - start));
15030b57cec5SDimitry Andric 
15040b57cec5SDimitry Andric       if (cmd_obj == nullptr)
15050b57cec5SDimitry Andric         // Since cmd_obj is NULL we are on our first time through this loop.
15060b57cec5SDimitry Andric         // Check to see if cmd_word is a valid command or alias.
15070b57cec5SDimitry Andric         cmd_obj = GetCommandObject(cmd_word);
15080b57cec5SDimitry Andric       else if (cmd_obj->IsMultiwordObject()) {
15090b57cec5SDimitry Andric         // Our current object is a multi-word object; see if the cmd_word is a
15100b57cec5SDimitry Andric         // valid sub-command for our object.
15110b57cec5SDimitry Andric         CommandObject *sub_cmd_obj =
15120b57cec5SDimitry Andric             cmd_obj->GetSubcommandObject(cmd_word.c_str());
15130b57cec5SDimitry Andric         if (sub_cmd_obj)
15140b57cec5SDimitry Andric           cmd_obj = sub_cmd_obj;
15150b57cec5SDimitry Andric         else // cmd_word was not a valid sub-command word, so we are done
15160b57cec5SDimitry Andric           done = true;
15170b57cec5SDimitry Andric       } else
15180b57cec5SDimitry Andric         // We have a cmd_obj and it is not a multi-word object, so we are done.
15190b57cec5SDimitry Andric         done = true;
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric       // If we didn't find a valid command object, or our command object is not
15220b57cec5SDimitry Andric       // a multi-word object, or we are at the end of the command_string, then
15230b57cec5SDimitry Andric       // we are done.  Otherwise, find the start of the next word.
15240b57cec5SDimitry Andric 
15250b57cec5SDimitry Andric       if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
15260b57cec5SDimitry Andric           end >= command_string.size())
15270b57cec5SDimitry Andric         done = true;
15280b57cec5SDimitry Andric       else
15290b57cec5SDimitry Andric         start = command_string.find_first_not_of(k_white_space, end);
15300b57cec5SDimitry Andric     } else
15310b57cec5SDimitry Andric       // Unable to find any more words.
15320b57cec5SDimitry Andric       done = true;
15330b57cec5SDimitry Andric   }
15340b57cec5SDimitry Andric 
15350b57cec5SDimitry Andric   command_string = command_string.substr(end);
15360b57cec5SDimitry Andric   return cmd_obj;
15370b57cec5SDimitry Andric }
15380b57cec5SDimitry Andric 
15390b57cec5SDimitry Andric static const char *k_valid_command_chars =
15400b57cec5SDimitry Andric     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
15410b57cec5SDimitry Andric static void StripLeadingSpaces(std::string &s) {
15420b57cec5SDimitry Andric   if (!s.empty()) {
15430b57cec5SDimitry Andric     size_t pos = s.find_first_not_of(k_white_space);
15440b57cec5SDimitry Andric     if (pos == std::string::npos)
15450b57cec5SDimitry Andric       s.clear();
15460b57cec5SDimitry Andric     else if (pos == 0)
15470b57cec5SDimitry Andric       return;
15480b57cec5SDimitry Andric     s.erase(0, pos);
15490b57cec5SDimitry Andric   }
15500b57cec5SDimitry Andric }
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric static size_t FindArgumentTerminator(const std::string &s) {
15530b57cec5SDimitry Andric   const size_t s_len = s.size();
15540b57cec5SDimitry Andric   size_t offset = 0;
15550b57cec5SDimitry Andric   while (offset < s_len) {
15560b57cec5SDimitry Andric     size_t pos = s.find("--", offset);
15570b57cec5SDimitry Andric     if (pos == std::string::npos)
15580b57cec5SDimitry Andric       break;
15590b57cec5SDimitry Andric     if (pos > 0) {
15605ffd83dbSDimitry Andric       if (llvm::isSpace(s[pos - 1])) {
15610b57cec5SDimitry Andric         // Check if the string ends "\s--" (where \s is a space character) or
15620b57cec5SDimitry Andric         // if we have "\s--\s".
15635ffd83dbSDimitry Andric         if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
15640b57cec5SDimitry Andric           return pos;
15650b57cec5SDimitry Andric         }
15660b57cec5SDimitry Andric       }
15670b57cec5SDimitry Andric     }
15680b57cec5SDimitry Andric     offset = pos + 2;
15690b57cec5SDimitry Andric   }
15700b57cec5SDimitry Andric   return std::string::npos;
15710b57cec5SDimitry Andric }
15720b57cec5SDimitry Andric 
15730b57cec5SDimitry Andric static bool ExtractCommand(std::string &command_string, std::string &command,
15740b57cec5SDimitry Andric                            std::string &suffix, char &quote_char) {
15750b57cec5SDimitry Andric   command.clear();
15760b57cec5SDimitry Andric   suffix.clear();
15770b57cec5SDimitry Andric   StripLeadingSpaces(command_string);
15780b57cec5SDimitry Andric 
15790b57cec5SDimitry Andric   bool result = false;
15800b57cec5SDimitry Andric   quote_char = '\0';
15810b57cec5SDimitry Andric 
15820b57cec5SDimitry Andric   if (!command_string.empty()) {
15830b57cec5SDimitry Andric     const char first_char = command_string[0];
15840b57cec5SDimitry Andric     if (first_char == '\'' || first_char == '"') {
15850b57cec5SDimitry Andric       quote_char = first_char;
15860b57cec5SDimitry Andric       const size_t end_quote_pos = command_string.find(quote_char, 1);
15870b57cec5SDimitry Andric       if (end_quote_pos == std::string::npos) {
15880b57cec5SDimitry Andric         command.swap(command_string);
15890b57cec5SDimitry Andric         command_string.erase();
15900b57cec5SDimitry Andric       } else {
15910b57cec5SDimitry Andric         command.assign(command_string, 1, end_quote_pos - 1);
15920b57cec5SDimitry Andric         if (end_quote_pos + 1 < command_string.size())
15930b57cec5SDimitry Andric           command_string.erase(0, command_string.find_first_not_of(
15940b57cec5SDimitry Andric                                       k_white_space, end_quote_pos + 1));
15950b57cec5SDimitry Andric         else
15960b57cec5SDimitry Andric           command_string.erase();
15970b57cec5SDimitry Andric       }
15980b57cec5SDimitry Andric     } else {
15990b57cec5SDimitry Andric       const size_t first_space_pos =
16000b57cec5SDimitry Andric           command_string.find_first_of(k_white_space);
16010b57cec5SDimitry Andric       if (first_space_pos == std::string::npos) {
16020b57cec5SDimitry Andric         command.swap(command_string);
16030b57cec5SDimitry Andric         command_string.erase();
16040b57cec5SDimitry Andric       } else {
16050b57cec5SDimitry Andric         command.assign(command_string, 0, first_space_pos);
16060b57cec5SDimitry Andric         command_string.erase(0, command_string.find_first_not_of(
16070b57cec5SDimitry Andric                                     k_white_space, first_space_pos));
16080b57cec5SDimitry Andric       }
16090b57cec5SDimitry Andric     }
16100b57cec5SDimitry Andric     result = true;
16110b57cec5SDimitry Andric   }
16120b57cec5SDimitry Andric 
16130b57cec5SDimitry Andric   if (!command.empty()) {
16140b57cec5SDimitry Andric     // actual commands can't start with '-' or '_'
16150b57cec5SDimitry Andric     if (command[0] != '-' && command[0] != '_') {
16160b57cec5SDimitry Andric       size_t pos = command.find_first_not_of(k_valid_command_chars);
16170b57cec5SDimitry Andric       if (pos > 0 && pos != std::string::npos) {
16180b57cec5SDimitry Andric         suffix.assign(command.begin() + pos, command.end());
16190b57cec5SDimitry Andric         command.erase(pos);
16200b57cec5SDimitry Andric       }
16210b57cec5SDimitry Andric     }
16220b57cec5SDimitry Andric   }
16230b57cec5SDimitry Andric 
16240b57cec5SDimitry Andric   return result;
16250b57cec5SDimitry Andric }
16260b57cec5SDimitry Andric 
16270b57cec5SDimitry Andric CommandObject *CommandInterpreter::BuildAliasResult(
16280b57cec5SDimitry Andric     llvm::StringRef alias_name, std::string &raw_input_string,
16290b57cec5SDimitry Andric     std::string &alias_result, CommandReturnObject &result) {
16300b57cec5SDimitry Andric   CommandObject *alias_cmd_obj = nullptr;
16310b57cec5SDimitry Andric   Args cmd_args(raw_input_string);
16320b57cec5SDimitry Andric   alias_cmd_obj = GetCommandObject(alias_name);
16330b57cec5SDimitry Andric   StreamString result_str;
16340b57cec5SDimitry Andric 
16350b57cec5SDimitry Andric   if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
16360b57cec5SDimitry Andric     alias_result.clear();
16370b57cec5SDimitry Andric     return alias_cmd_obj;
16380b57cec5SDimitry Andric   }
16390b57cec5SDimitry Andric   std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
16400b57cec5SDimitry Andric       ((CommandAlias *)alias_cmd_obj)->Desugar();
16410b57cec5SDimitry Andric   OptionArgVectorSP option_arg_vector_sp = desugared.second;
16420b57cec5SDimitry Andric   alias_cmd_obj = desugared.first.get();
16435ffd83dbSDimitry Andric   std::string alias_name_str = std::string(alias_name);
16440b57cec5SDimitry Andric   if ((cmd_args.GetArgumentCount() == 0) ||
16450b57cec5SDimitry Andric       (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
16460b57cec5SDimitry Andric     cmd_args.Unshift(alias_name_str);
16470b57cec5SDimitry Andric 
16480b57cec5SDimitry Andric   result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
16490b57cec5SDimitry Andric 
16500b57cec5SDimitry Andric   if (!option_arg_vector_sp.get()) {
16515ffd83dbSDimitry Andric     alias_result = std::string(result_str.GetString());
16520b57cec5SDimitry Andric     return alias_cmd_obj;
16530b57cec5SDimitry Andric   }
16540b57cec5SDimitry Andric   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
16550b57cec5SDimitry Andric 
16560b57cec5SDimitry Andric   int value_type;
16570b57cec5SDimitry Andric   std::string option;
16580b57cec5SDimitry Andric   std::string value;
16590b57cec5SDimitry Andric   for (const auto &entry : *option_arg_vector) {
16600b57cec5SDimitry Andric     std::tie(option, value_type, value) = entry;
1661bdd1243dSDimitry Andric     if (option == g_argument) {
16620b57cec5SDimitry Andric       result_str.Printf(" %s", value.c_str());
16630b57cec5SDimitry Andric       continue;
16640b57cec5SDimitry Andric     }
16650b57cec5SDimitry Andric 
16660b57cec5SDimitry Andric     result_str.Printf(" %s", option.c_str());
16670b57cec5SDimitry Andric     if (value_type == OptionParser::eNoArgument)
16680b57cec5SDimitry Andric       continue;
16690b57cec5SDimitry Andric 
16700b57cec5SDimitry Andric     if (value_type != OptionParser::eOptionalArgument)
16710b57cec5SDimitry Andric       result_str.Printf(" ");
16720b57cec5SDimitry Andric     int index = GetOptionArgumentPosition(value.c_str());
16730b57cec5SDimitry Andric     if (index == 0)
16740b57cec5SDimitry Andric       result_str.Printf("%s", value.c_str());
16750b57cec5SDimitry Andric     else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
16760b57cec5SDimitry Andric 
16770b57cec5SDimitry Andric       result.AppendErrorWithFormat("Not enough arguments provided; you "
16780b57cec5SDimitry Andric                                    "need at least %d arguments to use "
16790b57cec5SDimitry Andric                                    "this alias.\n",
16800b57cec5SDimitry Andric                                    index);
16810b57cec5SDimitry Andric       return nullptr;
16820b57cec5SDimitry Andric     } else {
1683bdd1243dSDimitry Andric       const Args::ArgEntry &entry = cmd_args[index];
1684bdd1243dSDimitry Andric       size_t strpos = raw_input_string.find(entry.c_str());
1685bdd1243dSDimitry Andric       const char quote_char = entry.GetQuoteChar();
1686bdd1243dSDimitry Andric       if (strpos != std::string::npos) {
1687bdd1243dSDimitry Andric         const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1688bdd1243dSDimitry Andric         const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1689bdd1243dSDimitry Andric 
1690bdd1243dSDimitry Andric         // Make sure we aren't going outside the bounds of the cmd string:
1691bdd1243dSDimitry Andric         if (strpos < start_fudge) {
1692bdd1243dSDimitry Andric           result.AppendError("Unmatched quote at command beginning.");
1693bdd1243dSDimitry Andric           return nullptr;
1694bdd1243dSDimitry Andric         }
1695bdd1243dSDimitry Andric         llvm::StringRef arg_text = entry.ref();
169606c3fb27SDimitry Andric         if (strpos - start_fudge + arg_text.size() + len_fudge >
169706c3fb27SDimitry Andric             raw_input_string.size()) {
1698bdd1243dSDimitry Andric           result.AppendError("Unmatched quote at command end.");
1699bdd1243dSDimitry Andric           return nullptr;
1700bdd1243dSDimitry Andric         }
17010b57cec5SDimitry Andric         raw_input_string = raw_input_string.erase(
1702bdd1243dSDimitry Andric             strpos - start_fudge,
1703bdd1243dSDimitry Andric             strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1704bdd1243dSDimitry Andric       }
1705bdd1243dSDimitry Andric       if (quote_char == '\0')
17060b57cec5SDimitry Andric         result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1707bdd1243dSDimitry Andric       else
170806c3fb27SDimitry Andric         result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
17090b57cec5SDimitry Andric     }
17100b57cec5SDimitry Andric   }
17110b57cec5SDimitry Andric 
17125ffd83dbSDimitry Andric   alias_result = std::string(result_str.GetString());
17130b57cec5SDimitry Andric   return alias_cmd_obj;
17140b57cec5SDimitry Andric }
17150b57cec5SDimitry Andric 
17160b57cec5SDimitry Andric Status CommandInterpreter::PreprocessCommand(std::string &command) {
17170b57cec5SDimitry Andric   // The command preprocessor needs to do things to the command line before any
17180b57cec5SDimitry Andric   // parsing of arguments or anything else is done. The only current stuff that
17190b57cec5SDimitry Andric   // gets preprocessed is anything enclosed in backtick ('`') characters is
17200b57cec5SDimitry Andric   // evaluated as an expression and the result of the expression must be a
17210b57cec5SDimitry Andric   // scalar that can be substituted into the command. An example would be:
17220b57cec5SDimitry Andric   // (lldb) memory read `$rsp + 20`
17230b57cec5SDimitry Andric   Status error; // Status for any expressions that might not evaluate
17240b57cec5SDimitry Andric   size_t start_backtick;
17250b57cec5SDimitry Andric   size_t pos = 0;
17260b57cec5SDimitry Andric   while ((start_backtick = command.find('`', pos)) != std::string::npos) {
17270b57cec5SDimitry Andric     // Stop if an error was encountered during the previous iteration.
17280b57cec5SDimitry Andric     if (error.Fail())
17290b57cec5SDimitry Andric       break;
17300b57cec5SDimitry Andric 
17310b57cec5SDimitry Andric     if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
17320b57cec5SDimitry Andric       // The backtick was preceded by a '\' character, remove the slash and
17330b57cec5SDimitry Andric       // don't treat the backtick as the start of an expression.
17340b57cec5SDimitry Andric       command.erase(start_backtick - 1, 1);
17350b57cec5SDimitry Andric       // No need to add one to start_backtick since we just deleted a char.
17360b57cec5SDimitry Andric       pos = start_backtick;
17370b57cec5SDimitry Andric       continue;
17380b57cec5SDimitry Andric     }
17390b57cec5SDimitry Andric 
17400b57cec5SDimitry Andric     const size_t expr_content_start = start_backtick + 1;
17410b57cec5SDimitry Andric     const size_t end_backtick = command.find('`', expr_content_start);
17420b57cec5SDimitry Andric 
17430b57cec5SDimitry Andric     if (end_backtick == std::string::npos) {
17440b57cec5SDimitry Andric       // Stop if there's no end backtick.
17450b57cec5SDimitry Andric       break;
17460b57cec5SDimitry Andric     }
17470b57cec5SDimitry Andric 
17480b57cec5SDimitry Andric     if (end_backtick == expr_content_start) {
17490b57cec5SDimitry Andric       // Skip over empty expression. (two backticks in a row)
17500b57cec5SDimitry Andric       command.erase(start_backtick, 2);
17510b57cec5SDimitry Andric       continue;
17520b57cec5SDimitry Andric     }
17530b57cec5SDimitry Andric 
17540b57cec5SDimitry Andric     std::string expr_str(command, expr_content_start,
17550b57cec5SDimitry Andric                          end_backtick - expr_content_start);
175606c3fb27SDimitry Andric     error = PreprocessToken(expr_str);
175706c3fb27SDimitry Andric     // We always stop at the first error:
175806c3fb27SDimitry Andric     if (error.Fail())
175906c3fb27SDimitry Andric       break;
17600b57cec5SDimitry Andric 
176106c3fb27SDimitry Andric     command.erase(start_backtick, end_backtick - start_backtick + 1);
176206c3fb27SDimitry Andric     command.insert(start_backtick, std::string(expr_str));
176306c3fb27SDimitry Andric     pos = start_backtick + expr_str.size();
176406c3fb27SDimitry Andric   }
176506c3fb27SDimitry Andric   return error;
176606c3fb27SDimitry Andric }
176706c3fb27SDimitry Andric 
176806c3fb27SDimitry Andric Status
176906c3fb27SDimitry Andric CommandInterpreter::PreprocessToken(std::string &expr_str) {
177006c3fb27SDimitry Andric   Status error;
17710b57cec5SDimitry Andric   ExecutionContext exe_ctx(GetExecutionContext());
17720b57cec5SDimitry Andric 
17730b57cec5SDimitry Andric   // Get a dummy target to allow for calculator mode while processing
17740b57cec5SDimitry Andric   // backticks. This also helps break the infinite loop caused when target is
17750b57cec5SDimitry Andric   // null.
1776e8d8bef9SDimitry Andric   Target *exe_target = exe_ctx.GetTargetPtr();
1777e8d8bef9SDimitry Andric   Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
17780b57cec5SDimitry Andric 
17790b57cec5SDimitry Andric   ValueObjectSP expr_result_valobj_sp;
17800b57cec5SDimitry Andric 
17810b57cec5SDimitry Andric   EvaluateExpressionOptions options;
17820b57cec5SDimitry Andric   options.SetCoerceToId(false);
17830b57cec5SDimitry Andric   options.SetUnwindOnError(true);
17840b57cec5SDimitry Andric   options.SetIgnoreBreakpoints(true);
17850b57cec5SDimitry Andric   options.SetKeepInMemory(false);
17860b57cec5SDimitry Andric   options.SetTryAllThreads(true);
1787bdd1243dSDimitry Andric   options.SetTimeout(std::nullopt);
17880b57cec5SDimitry Andric 
17890b57cec5SDimitry Andric   ExpressionResults expr_result =
1790e8d8bef9SDimitry Andric       target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
17910b57cec5SDimitry Andric                                 expr_result_valobj_sp, options);
17920b57cec5SDimitry Andric 
17930b57cec5SDimitry Andric   if (expr_result == eExpressionCompleted) {
17940b57cec5SDimitry Andric     Scalar scalar;
17950b57cec5SDimitry Andric     if (expr_result_valobj_sp)
17960b57cec5SDimitry Andric       expr_result_valobj_sp =
17970b57cec5SDimitry Andric           expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
17980b57cec5SDimitry Andric               expr_result_valobj_sp->GetDynamicValueType(), true);
17990b57cec5SDimitry Andric     if (expr_result_valobj_sp->ResolveValue(scalar)) {
180006c3fb27SDimitry Andric 
18010b57cec5SDimitry Andric       StreamString value_strm;
18020b57cec5SDimitry Andric       const bool show_type = false;
18035f757f3fSDimitry Andric       scalar.GetValue(value_strm, show_type);
18040b57cec5SDimitry Andric       size_t value_string_size = value_strm.GetSize();
18050b57cec5SDimitry Andric       if (value_string_size) {
180606c3fb27SDimitry Andric         expr_str = value_strm.GetData();
18070b57cec5SDimitry Andric       } else {
18080b57cec5SDimitry Andric         error.SetErrorStringWithFormat("expression value didn't result "
18090b57cec5SDimitry Andric                                        "in a scalar value for the "
18100b57cec5SDimitry Andric                                        "expression '%s'",
18110b57cec5SDimitry Andric                                        expr_str.c_str());
18120b57cec5SDimitry Andric       }
18130b57cec5SDimitry Andric     } else {
18140b57cec5SDimitry Andric       error.SetErrorStringWithFormat("expression value didn't result "
18150b57cec5SDimitry Andric                                      "in a scalar value for the "
18160b57cec5SDimitry Andric                                      "expression '%s'",
18170b57cec5SDimitry Andric                                      expr_str.c_str());
181806c3fb27SDimitry Andric     }
181906c3fb27SDimitry Andric     return error;
18200b57cec5SDimitry Andric   }
18210b57cec5SDimitry Andric 
182206c3fb27SDimitry Andric   // If we have an error from the expression evaluation it will be in the
182306c3fb27SDimitry Andric   // ValueObject error, which won't be success and we will just report it.
182406c3fb27SDimitry Andric   // But if for some reason we didn't get a value object at all, then we will
182506c3fb27SDimitry Andric   // make up some helpful errors from the expression result.
18260b57cec5SDimitry Andric   if (expr_result_valobj_sp)
18270b57cec5SDimitry Andric     error = expr_result_valobj_sp->GetError();
18280b57cec5SDimitry Andric 
18290b57cec5SDimitry Andric   if (error.Success()) {
1830*0fca6ea1SDimitry Andric     std::string result = lldb_private::toString(expr_result);
1831*0fca6ea1SDimitry Andric     error.SetErrorString(result + "for the expression '" + expr_str + "'");
18320b57cec5SDimitry Andric   }
18330b57cec5SDimitry Andric   return error;
18340b57cec5SDimitry Andric }
18350b57cec5SDimitry Andric 
18360b57cec5SDimitry Andric bool CommandInterpreter::HandleCommand(const char *command_line,
18370b57cec5SDimitry Andric                                        LazyBool lazy_add_to_history,
1838fe6060f1SDimitry Andric                                        const ExecutionContext &override_context,
1839fe6060f1SDimitry Andric                                        CommandReturnObject &result) {
18400b57cec5SDimitry Andric 
1841fe6060f1SDimitry Andric   OverrideExecutionContext(override_context);
1842fe6060f1SDimitry Andric   bool status = HandleCommand(command_line, lazy_add_to_history, result);
1843fe6060f1SDimitry Andric   RestoreExecutionContext();
1844fe6060f1SDimitry Andric   return status;
1845fe6060f1SDimitry Andric }
1846fe6060f1SDimitry Andric 
1847fe6060f1SDimitry Andric bool CommandInterpreter::HandleCommand(const char *command_line,
1848fe6060f1SDimitry Andric                                        LazyBool lazy_add_to_history,
184906c3fb27SDimitry Andric                                        CommandReturnObject &result,
185006c3fb27SDimitry Andric                                        bool force_repeat_command) {
18510b57cec5SDimitry Andric   std::string command_string(command_line);
18520b57cec5SDimitry Andric   std::string original_command_string(command_line);
18530b57cec5SDimitry Andric 
185481ad6265SDimitry Andric   Log *log = GetLog(LLDBLog::Commands);
18550b57cec5SDimitry Andric   llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
18560b57cec5SDimitry Andric                                    command_line);
18570b57cec5SDimitry Andric 
18589dba64beSDimitry Andric   LLDB_LOGF(log, "Processing command: %s", command_line);
1859e8d8bef9SDimitry Andric   LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
18600b57cec5SDimitry Andric 
186106c3fb27SDimitry Andric   if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
186206c3fb27SDimitry Andric     result.AppendError("... Interrupted");
18630b57cec5SDimitry Andric     return false;
18640b57cec5SDimitry Andric   }
18650b57cec5SDimitry Andric 
18660b57cec5SDimitry Andric   bool add_to_history;
18670b57cec5SDimitry Andric   if (lazy_add_to_history == eLazyBoolCalculate)
18680b57cec5SDimitry Andric     add_to_history = (m_command_source_depth == 0);
18690b57cec5SDimitry Andric   else
18700b57cec5SDimitry Andric     add_to_history = (lazy_add_to_history == eLazyBoolYes);
18710b57cec5SDimitry Andric 
1872*0fca6ea1SDimitry Andric   // The same `transcript_item` will be used below to add output and error of
1873*0fca6ea1SDimitry Andric   // the command.
1874*0fca6ea1SDimitry Andric   StructuredData::DictionarySP transcript_item;
1875*0fca6ea1SDimitry Andric   if (GetSaveTranscript()) {
1876e8d8bef9SDimitry Andric     m_transcript_stream << "(lldb) " << command_line << '\n';
1877e8d8bef9SDimitry Andric 
1878*0fca6ea1SDimitry Andric     transcript_item = std::make_shared<StructuredData::Dictionary>();
1879*0fca6ea1SDimitry Andric     transcript_item->AddStringItem("command", command_line);
1880*0fca6ea1SDimitry Andric     transcript_item->AddIntegerItem(
1881*0fca6ea1SDimitry Andric         "timestampInEpochSeconds",
1882*0fca6ea1SDimitry Andric         std::chrono::duration_cast<std::chrono::seconds>(
1883*0fca6ea1SDimitry Andric             std::chrono::system_clock::now().time_since_epoch())
1884*0fca6ea1SDimitry Andric             .count());
1885*0fca6ea1SDimitry Andric     m_transcript.AddItem(transcript_item);
1886*0fca6ea1SDimitry Andric   }
1887*0fca6ea1SDimitry Andric 
18880b57cec5SDimitry Andric   bool empty_command = false;
18890b57cec5SDimitry Andric   bool comment_command = false;
18900b57cec5SDimitry Andric   if (command_string.empty())
18910b57cec5SDimitry Andric     empty_command = true;
18920b57cec5SDimitry Andric   else {
18930b57cec5SDimitry Andric     const char *k_space_characters = "\t\n\v\f\r ";
18940b57cec5SDimitry Andric 
18950b57cec5SDimitry Andric     size_t non_space = command_string.find_first_not_of(k_space_characters);
18960b57cec5SDimitry Andric     // Check for empty line or comment line (lines whose first non-space
18970b57cec5SDimitry Andric     // character is the comment character for this interpreter)
18980b57cec5SDimitry Andric     if (non_space == std::string::npos)
18990b57cec5SDimitry Andric       empty_command = true;
19000b57cec5SDimitry Andric     else if (command_string[non_space] == m_comment_char)
19010b57cec5SDimitry Andric       comment_command = true;
19020b57cec5SDimitry Andric     else if (command_string[non_space] == CommandHistory::g_repeat_char) {
19030b57cec5SDimitry Andric       llvm::StringRef search_str(command_string);
19040b57cec5SDimitry Andric       search_str = search_str.drop_front(non_space);
19050b57cec5SDimitry Andric       if (auto hist_str = m_command_history.FindString(search_str)) {
19060b57cec5SDimitry Andric         add_to_history = false;
19075ffd83dbSDimitry Andric         command_string = std::string(*hist_str);
19085ffd83dbSDimitry Andric         original_command_string = std::string(*hist_str);
19090b57cec5SDimitry Andric       } else {
19100b57cec5SDimitry Andric         result.AppendErrorWithFormat("Could not find entry: %s in history",
19110b57cec5SDimitry Andric                                      command_string.c_str());
19120b57cec5SDimitry Andric         return false;
19130b57cec5SDimitry Andric       }
19140b57cec5SDimitry Andric     }
19150b57cec5SDimitry Andric   }
19160b57cec5SDimitry Andric 
19170b57cec5SDimitry Andric   if (empty_command) {
1918fe6060f1SDimitry Andric     if (!GetRepeatPreviousCommand()) {
1919fe6060f1SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1920fe6060f1SDimitry Andric       return true;
1921fe6060f1SDimitry Andric     }
1922fe6060f1SDimitry Andric 
19230b57cec5SDimitry Andric     if (m_command_history.IsEmpty()) {
19240b57cec5SDimitry Andric       result.AppendError("empty command");
19250b57cec5SDimitry Andric       return false;
1926fe6060f1SDimitry Andric     }
1927fe6060f1SDimitry Andric 
19280b57cec5SDimitry Andric     command_line = m_repeat_command.c_str();
19290b57cec5SDimitry Andric     command_string = command_line;
19300b57cec5SDimitry Andric     original_command_string = command_line;
19310b57cec5SDimitry Andric     if (m_repeat_command.empty()) {
1932e8d8bef9SDimitry Andric       result.AppendError("No auto repeat.");
19330b57cec5SDimitry Andric       return false;
19340b57cec5SDimitry Andric     }
1935fe6060f1SDimitry Andric 
19360b57cec5SDimitry Andric     add_to_history = false;
19370b57cec5SDimitry Andric   } else if (comment_command) {
19380b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
19390b57cec5SDimitry Andric     return true;
19400b57cec5SDimitry Andric   }
19410b57cec5SDimitry Andric 
19420b57cec5SDimitry Andric   // Phase 1.
19430b57cec5SDimitry Andric 
19440b57cec5SDimitry Andric   // Before we do ANY kind of argument processing, we need to figure out what
19450b57cec5SDimitry Andric   // the real/final command object is for the specified command.  This gets
19460b57cec5SDimitry Andric   // complicated by the fact that the user could have specified an alias, and,
19470b57cec5SDimitry Andric   // in translating the alias, there may also be command options and/or even
19480b57cec5SDimitry Andric   // data (including raw text strings) that need to be found and inserted into
19490b57cec5SDimitry Andric   // the command line as part of the translation.  So this first step is plain
19500b57cec5SDimitry Andric   // look-up and replacement, resulting in:
19510b57cec5SDimitry Andric   //    1. the command object whose Execute method will actually be called
19520b57cec5SDimitry Andric   //    2. a revised command string, with all substitutions and replacements
19530b57cec5SDimitry Andric   //       taken care of
19540b57cec5SDimitry Andric   // From 1 above, we can determine whether the Execute function wants raw
19550b57cec5SDimitry Andric   // input or not.
19560b57cec5SDimitry Andric 
19570b57cec5SDimitry Andric   CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
19580b57cec5SDimitry Andric 
1959bdd1243dSDimitry Andric   // We have to preprocess the whole command string for Raw commands, since we
1960bdd1243dSDimitry Andric   // don't know the structure of the command.  For parsed commands, we only
1961bdd1243dSDimitry Andric   // treat backticks as quote characters specially.
1962bdd1243dSDimitry Andric   // FIXME: We probably want to have raw commands do their own preprocessing.
1963bdd1243dSDimitry Andric   // For instance, I don't think people expect substitution in expr expressions.
1964bdd1243dSDimitry Andric   if (cmd_obj && cmd_obj->WantsRawCommandString()) {
1965bdd1243dSDimitry Andric     Status error(PreprocessCommand(command_string));
1966bdd1243dSDimitry Andric 
1967bdd1243dSDimitry Andric     if (error.Fail()) {
1968bdd1243dSDimitry Andric       result.AppendError(error.AsCString());
1969bdd1243dSDimitry Andric       return false;
1970bdd1243dSDimitry Andric     }
1971bdd1243dSDimitry Andric   }
1972bdd1243dSDimitry Andric 
19730b57cec5SDimitry Andric   // Although the user may have abbreviated the command, the command_string now
19740b57cec5SDimitry Andric   // has the command expanded to the full name.  For example, if the input was
19750b57cec5SDimitry Andric   // "br s -n main", command_string is now "breakpoint set -n main".
19760b57cec5SDimitry Andric   if (log) {
19770b57cec5SDimitry Andric     llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
19789dba64beSDimitry Andric     LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
19799dba64beSDimitry Andric     LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
19800b57cec5SDimitry Andric               command_string.c_str());
19810b57cec5SDimitry Andric     const bool wants_raw_input =
19820b57cec5SDimitry Andric         (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
19839dba64beSDimitry Andric     LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
19840b57cec5SDimitry Andric               wants_raw_input ? "True" : "False");
19850b57cec5SDimitry Andric   }
19860b57cec5SDimitry Andric 
19870b57cec5SDimitry Andric   // Phase 2.
19880b57cec5SDimitry Andric   // Take care of things like setting up the history command & calling the
19890b57cec5SDimitry Andric   // appropriate Execute method on the CommandObject, with the appropriate
19900b57cec5SDimitry Andric   // arguments.
1991*0fca6ea1SDimitry Andric   StatsDuration execute_time;
19920b57cec5SDimitry Andric   if (cmd_obj != nullptr) {
199306c3fb27SDimitry Andric     bool generate_repeat_command = add_to_history;
199481ad6265SDimitry Andric     // If we got here when empty_command was true, then this command is a
199581ad6265SDimitry Andric     // stored "repeat command" which we should give a chance to produce it's
199681ad6265SDimitry Andric     // repeat command, even though we don't add repeat commands to the history.
199706c3fb27SDimitry Andric     generate_repeat_command |= empty_command;
199806c3fb27SDimitry Andric     // For `command regex`, the regex command (ex `bt`) is added to history, but
199906c3fb27SDimitry Andric     // the resolved command (ex `thread backtrace`) is _not_ added to history.
200006c3fb27SDimitry Andric     // However, the resolved command must be given the opportunity to provide a
200106c3fb27SDimitry Andric     // repeat command. `force_repeat_command` supports this case.
200206c3fb27SDimitry Andric     generate_repeat_command |= force_repeat_command;
200306c3fb27SDimitry Andric     if (generate_repeat_command) {
20040b57cec5SDimitry Andric       Args command_args(command_string);
2005bdd1243dSDimitry Andric       std::optional<std::string> repeat_command =
200681ad6265SDimitry Andric           cmd_obj->GetRepeatCommand(command_args, 0);
200706c3fb27SDimitry Andric       if (repeat_command) {
200806c3fb27SDimitry Andric         LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
200981ad6265SDimitry Andric         m_repeat_command.assign(*repeat_command);
201006c3fb27SDimitry Andric       } else {
20110b57cec5SDimitry Andric         m_repeat_command.assign(original_command_string);
20120b57cec5SDimitry Andric       }
201306c3fb27SDimitry Andric     }
20140b57cec5SDimitry Andric 
201581ad6265SDimitry Andric     if (add_to_history)
201681ad6265SDimitry Andric       m_command_history.AppendString(original_command_string);
201781ad6265SDimitry Andric 
20180b57cec5SDimitry Andric     std::string remainder;
20190b57cec5SDimitry Andric     const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
20200b57cec5SDimitry Andric     if (actual_cmd_name_len < command_string.length())
20210b57cec5SDimitry Andric       remainder = command_string.substr(actual_cmd_name_len);
20220b57cec5SDimitry Andric 
20230b57cec5SDimitry Andric     // Remove any initial spaces
20240b57cec5SDimitry Andric     size_t pos = remainder.find_first_not_of(k_white_space);
20250b57cec5SDimitry Andric     if (pos != 0 && pos != std::string::npos)
20260b57cec5SDimitry Andric       remainder.erase(0, pos);
20270b57cec5SDimitry Andric 
20289dba64beSDimitry Andric     LLDB_LOGF(
20299dba64beSDimitry Andric         log, "HandleCommand, command line after removing command name(s): '%s'",
20300b57cec5SDimitry Andric         remainder.c_str());
20310b57cec5SDimitry Andric 
2032*0fca6ea1SDimitry Andric     // To test whether or not transcript should be saved, `transcript_item` is
2033*0fca6ea1SDimitry Andric     // used instead of `GetSaveTrasncript()`. This is because the latter will
2034*0fca6ea1SDimitry Andric     // fail when the command is "settings set interpreter.save-transcript true".
2035*0fca6ea1SDimitry Andric     if (transcript_item) {
2036*0fca6ea1SDimitry Andric       transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName());
2037*0fca6ea1SDimitry Andric       transcript_item->AddStringItem("commandArguments", remainder);
2038*0fca6ea1SDimitry Andric     }
2039*0fca6ea1SDimitry Andric 
2040*0fca6ea1SDimitry Andric     ElapsedTime elapsed(execute_time);
20410b57cec5SDimitry Andric     cmd_obj->Execute(remainder.c_str(), result);
20420b57cec5SDimitry Andric   }
20430b57cec5SDimitry Andric 
20449dba64beSDimitry Andric   LLDB_LOGF(log, "HandleCommand, command %s",
20450b57cec5SDimitry Andric             (result.Succeeded() ? "succeeded" : "did not succeed"));
20460b57cec5SDimitry Andric 
2047*0fca6ea1SDimitry Andric   // To test whether or not transcript should be saved, `transcript_item` is
2048*0fca6ea1SDimitry Andric   // used instead of `GetSaveTrasncript()`. This is because the latter will
2049*0fca6ea1SDimitry Andric   // fail when the command is "settings set interpreter.save-transcript true".
2050*0fca6ea1SDimitry Andric   if (transcript_item) {
2051e8d8bef9SDimitry Andric     m_transcript_stream << result.GetOutputData();
2052e8d8bef9SDimitry Andric     m_transcript_stream << result.GetErrorData();
2053e8d8bef9SDimitry Andric 
2054*0fca6ea1SDimitry Andric     transcript_item->AddStringItem("output", result.GetOutputData());
2055*0fca6ea1SDimitry Andric     transcript_item->AddStringItem("error", result.GetErrorData());
2056*0fca6ea1SDimitry Andric     transcript_item->AddFloatItem("durationInSeconds",
2057*0fca6ea1SDimitry Andric                                   execute_time.get().count());
2058*0fca6ea1SDimitry Andric   }
2059*0fca6ea1SDimitry Andric 
20600b57cec5SDimitry Andric   return result.Succeeded();
20610b57cec5SDimitry Andric }
20620b57cec5SDimitry Andric 
20639dba64beSDimitry Andric void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
20640b57cec5SDimitry Andric   bool look_for_subcommand = false;
20650b57cec5SDimitry Andric 
20660b57cec5SDimitry Andric   // For any of the command completions a unique match will be a complete word.
20670b57cec5SDimitry Andric 
20689dba64beSDimitry Andric   if (request.GetParsedLine().GetArgumentCount() == 0) {
20690b57cec5SDimitry Andric     // We got nothing on the command line, so return the list of commands
20700b57cec5SDimitry Andric     bool include_aliases = true;
20710b57cec5SDimitry Andric     StringList new_matches, descriptions;
20729dba64beSDimitry Andric     GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
20739dba64beSDimitry Andric                                          descriptions);
20740b57cec5SDimitry Andric     request.AddCompletions(new_matches, descriptions);
20750b57cec5SDimitry Andric   } else if (request.GetCursorIndex() == 0) {
20760b57cec5SDimitry Andric     // The cursor is in the first argument, so just do a lookup in the
20770b57cec5SDimitry Andric     // dictionary.
20780b57cec5SDimitry Andric     StringList new_matches, new_descriptions;
20790b57cec5SDimitry Andric     CommandObject *cmd_obj =
20800b57cec5SDimitry Andric         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
20810b57cec5SDimitry Andric                          &new_matches, &new_descriptions);
20820b57cec5SDimitry Andric 
20839dba64beSDimitry Andric     if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
20840b57cec5SDimitry Andric         new_matches.GetStringAtIndex(0) != nullptr &&
20850b57cec5SDimitry Andric         strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
20860b57cec5SDimitry Andric                new_matches.GetStringAtIndex(0)) == 0) {
20879dba64beSDimitry Andric       if (request.GetParsedLine().GetArgumentCount() != 1) {
20880b57cec5SDimitry Andric         look_for_subcommand = true;
20890b57cec5SDimitry Andric         new_matches.DeleteStringAtIndex(0);
20900b57cec5SDimitry Andric         new_descriptions.DeleteStringAtIndex(0);
20919dba64beSDimitry Andric         request.AppendEmptyArgument();
20920b57cec5SDimitry Andric       }
20930b57cec5SDimitry Andric     }
20940b57cec5SDimitry Andric     request.AddCompletions(new_matches, new_descriptions);
20950b57cec5SDimitry Andric   }
20960b57cec5SDimitry Andric 
20970b57cec5SDimitry Andric   if (request.GetCursorIndex() > 0 || look_for_subcommand) {
20980b57cec5SDimitry Andric     // We are completing further on into a commands arguments, so find the
20990b57cec5SDimitry Andric     // command and tell it to complete the command. First see if there is a
21000b57cec5SDimitry Andric     // matching initial command:
21010b57cec5SDimitry Andric     CommandObject *command_object =
21020b57cec5SDimitry Andric         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
21039dba64beSDimitry Andric     if (command_object) {
21049dba64beSDimitry Andric       request.ShiftArguments();
21059dba64beSDimitry Andric       command_object->HandleCompletion(request);
21069dba64beSDimitry Andric     }
21070b57cec5SDimitry Andric   }
21080b57cec5SDimitry Andric }
21090b57cec5SDimitry Andric 
21109dba64beSDimitry Andric void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
21110b57cec5SDimitry Andric 
21120b57cec5SDimitry Andric   // Don't complete comments, and if the line we are completing is just the
21130b57cec5SDimitry Andric   // history repeat character, substitute the appropriate history line.
21149dba64beSDimitry Andric   llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
21159dba64beSDimitry Andric 
21169dba64beSDimitry Andric   if (!first_arg.empty()) {
21179dba64beSDimitry Andric     if (first_arg.front() == m_comment_char)
21189dba64beSDimitry Andric       return;
21199dba64beSDimitry Andric     if (first_arg.front() == CommandHistory::g_repeat_char) {
21209dba64beSDimitry Andric       if (auto hist_str = m_command_history.FindString(first_arg))
21219dba64beSDimitry Andric         request.AddCompletion(*hist_str, "Previous command history event",
21229dba64beSDimitry Andric                               CompletionMode::RewriteLine);
21239dba64beSDimitry Andric       return;
21240b57cec5SDimitry Andric     }
21250b57cec5SDimitry Andric   }
21260b57cec5SDimitry Andric 
21279dba64beSDimitry Andric   HandleCompletionMatches(request);
21280b57cec5SDimitry Andric }
21290b57cec5SDimitry Andric 
2130bdd1243dSDimitry Andric std::optional<std::string>
2131e8d8bef9SDimitry Andric CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) {
2132e8d8bef9SDimitry Andric   if (line.empty())
2133bdd1243dSDimitry Andric     return std::nullopt;
2134e8d8bef9SDimitry Andric   const size_t s = m_command_history.GetSize();
2135e8d8bef9SDimitry Andric   for (int i = s - 1; i >= 0; --i) {
2136e8d8bef9SDimitry Andric     llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2137e8d8bef9SDimitry Andric     if (entry.consume_front(line))
2138e8d8bef9SDimitry Andric       return entry.str();
2139e8d8bef9SDimitry Andric   }
2140bdd1243dSDimitry Andric   return std::nullopt;
2141e8d8bef9SDimitry Andric }
2142e8d8bef9SDimitry Andric 
21430b57cec5SDimitry Andric void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
21440b57cec5SDimitry Andric   EventSP prompt_change_event_sp(
21450b57cec5SDimitry Andric       new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
21460b57cec5SDimitry Andric   ;
21470b57cec5SDimitry Andric   BroadcastEvent(prompt_change_event_sp);
21480b57cec5SDimitry Andric   if (m_command_io_handler_sp)
21490b57cec5SDimitry Andric     m_command_io_handler_sp->SetPrompt(new_prompt);
21500b57cec5SDimitry Andric }
21510b57cec5SDimitry Andric 
21520b57cec5SDimitry Andric bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
21530b57cec5SDimitry Andric   // Check AutoConfirm first:
21540b57cec5SDimitry Andric   if (m_debugger.GetAutoConfirm())
21550b57cec5SDimitry Andric     return default_answer;
21560b57cec5SDimitry Andric 
21570b57cec5SDimitry Andric   IOHandlerConfirm *confirm =
21580b57cec5SDimitry Andric       new IOHandlerConfirm(m_debugger, message, default_answer);
21590b57cec5SDimitry Andric   IOHandlerSP io_handler_sp(confirm);
21605ffd83dbSDimitry Andric   m_debugger.RunIOHandlerSync(io_handler_sp);
21610b57cec5SDimitry Andric   return confirm->GetResponse();
21620b57cec5SDimitry Andric }
21630b57cec5SDimitry Andric 
21640b57cec5SDimitry Andric const CommandAlias *
21650b57cec5SDimitry Andric CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
21660b57cec5SDimitry Andric   OptionArgVectorSP ret_val;
21670b57cec5SDimitry Andric 
21685ffd83dbSDimitry Andric   auto pos = m_alias_dict.find(std::string(alias_name));
21690b57cec5SDimitry Andric   if (pos != m_alias_dict.end())
21700b57cec5SDimitry Andric     return (CommandAlias *)pos->second.get();
21710b57cec5SDimitry Andric 
21720b57cec5SDimitry Andric   return nullptr;
21730b57cec5SDimitry Andric }
21740b57cec5SDimitry Andric 
21750b57cec5SDimitry Andric bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
21760b57cec5SDimitry Andric 
21770b57cec5SDimitry Andric bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
21780b57cec5SDimitry Andric 
21790b57cec5SDimitry Andric bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
21800b57cec5SDimitry Andric 
2181349cc55cSDimitry Andric bool CommandInterpreter::HasUserMultiwordCommands() const {
2182349cc55cSDimitry Andric   return (!m_user_mw_dict.empty());
2183349cc55cSDimitry Andric }
2184349cc55cSDimitry Andric 
21850b57cec5SDimitry Andric bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
21860b57cec5SDimitry Andric 
21870b57cec5SDimitry Andric void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
21880b57cec5SDimitry Andric                                                const char *alias_name,
21890b57cec5SDimitry Andric                                                Args &cmd_args,
21900b57cec5SDimitry Andric                                                std::string &raw_input_string,
21910b57cec5SDimitry Andric                                                CommandReturnObject &result) {
21920b57cec5SDimitry Andric   OptionArgVectorSP option_arg_vector_sp =
21930b57cec5SDimitry Andric       GetAlias(alias_name)->GetOptionArguments();
21940b57cec5SDimitry Andric 
21950b57cec5SDimitry Andric   bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
21960b57cec5SDimitry Andric 
21970b57cec5SDimitry Andric   // Make sure that the alias name is the 0th element in cmd_args
21980b57cec5SDimitry Andric   std::string alias_name_str = alias_name;
21990b57cec5SDimitry Andric   if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
22000b57cec5SDimitry Andric     cmd_args.Unshift(alias_name_str);
22010b57cec5SDimitry Andric 
22020b57cec5SDimitry Andric   Args new_args(alias_cmd_obj->GetCommandName());
22030b57cec5SDimitry Andric   if (new_args.GetArgumentCount() == 2)
22040b57cec5SDimitry Andric     new_args.Shift();
22050b57cec5SDimitry Andric 
22060b57cec5SDimitry Andric   if (option_arg_vector_sp.get()) {
22070b57cec5SDimitry Andric     if (wants_raw_input) {
22080b57cec5SDimitry Andric       // We have a command that both has command options and takes raw input.
22090b57cec5SDimitry Andric       // Make *sure* it has a " -- " in the right place in the
22100b57cec5SDimitry Andric       // raw_input_string.
22110b57cec5SDimitry Andric       size_t pos = raw_input_string.find(" -- ");
22120b57cec5SDimitry Andric       if (pos == std::string::npos) {
22130b57cec5SDimitry Andric         // None found; assume it goes at the beginning of the raw input string
22140b57cec5SDimitry Andric         raw_input_string.insert(0, " -- ");
22150b57cec5SDimitry Andric       }
22160b57cec5SDimitry Andric     }
22170b57cec5SDimitry Andric 
22180b57cec5SDimitry Andric     OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
22190b57cec5SDimitry Andric     const size_t old_size = cmd_args.GetArgumentCount();
22200b57cec5SDimitry Andric     std::vector<bool> used(old_size + 1, false);
22210b57cec5SDimitry Andric 
22220b57cec5SDimitry Andric     used[0] = true;
22230b57cec5SDimitry Andric 
22240b57cec5SDimitry Andric     int value_type;
22250b57cec5SDimitry Andric     std::string option;
22260b57cec5SDimitry Andric     std::string value;
22270b57cec5SDimitry Andric     for (const auto &option_entry : *option_arg_vector) {
22280b57cec5SDimitry Andric       std::tie(option, value_type, value) = option_entry;
2229bdd1243dSDimitry Andric       if (option == g_argument) {
22300b57cec5SDimitry Andric         if (!wants_raw_input || (value != "--")) {
22310b57cec5SDimitry Andric           // Since we inserted this above, make sure we don't insert it twice
22320b57cec5SDimitry Andric           new_args.AppendArgument(value);
22330b57cec5SDimitry Andric         }
22340b57cec5SDimitry Andric         continue;
22350b57cec5SDimitry Andric       }
22360b57cec5SDimitry Andric 
22370b57cec5SDimitry Andric       if (value_type != OptionParser::eOptionalArgument)
22380b57cec5SDimitry Andric         new_args.AppendArgument(option);
22390b57cec5SDimitry Andric 
2240bdd1243dSDimitry Andric       if (value == g_no_argument)
22410b57cec5SDimitry Andric         continue;
22420b57cec5SDimitry Andric 
22430b57cec5SDimitry Andric       int index = GetOptionArgumentPosition(value.c_str());
22440b57cec5SDimitry Andric       if (index == 0) {
22450b57cec5SDimitry Andric         // value was NOT a positional argument; must be a real value
22460b57cec5SDimitry Andric         if (value_type != OptionParser::eOptionalArgument)
22470b57cec5SDimitry Andric           new_args.AppendArgument(value);
22480b57cec5SDimitry Andric         else {
2249e8d8bef9SDimitry Andric           new_args.AppendArgument(option + value);
22500b57cec5SDimitry Andric         }
22510b57cec5SDimitry Andric 
22520b57cec5SDimitry Andric       } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
22530b57cec5SDimitry Andric         result.AppendErrorWithFormat("Not enough arguments provided; you "
22540b57cec5SDimitry Andric                                      "need at least %d arguments to use "
22550b57cec5SDimitry Andric                                      "this alias.\n",
22560b57cec5SDimitry Andric                                      index);
22570b57cec5SDimitry Andric         return;
22580b57cec5SDimitry Andric       } else {
22590b57cec5SDimitry Andric         // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
22600b57cec5SDimitry Andric         size_t strpos =
22610b57cec5SDimitry Andric             raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
22620b57cec5SDimitry Andric         if (strpos != std::string::npos) {
22630b57cec5SDimitry Andric           raw_input_string = raw_input_string.erase(
22640b57cec5SDimitry Andric               strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
22650b57cec5SDimitry Andric         }
22660b57cec5SDimitry Andric 
22670b57cec5SDimitry Andric         if (value_type != OptionParser::eOptionalArgument)
22680b57cec5SDimitry Andric           new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
22690b57cec5SDimitry Andric         else {
2270e8d8bef9SDimitry Andric           new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
22710b57cec5SDimitry Andric         }
22720b57cec5SDimitry Andric         used[index] = true;
22730b57cec5SDimitry Andric       }
22740b57cec5SDimitry Andric     }
22750b57cec5SDimitry Andric 
22760b57cec5SDimitry Andric     for (auto entry : llvm::enumerate(cmd_args.entries())) {
22770b57cec5SDimitry Andric       if (!used[entry.index()] && !wants_raw_input)
22789dba64beSDimitry Andric         new_args.AppendArgument(entry.value().ref());
22790b57cec5SDimitry Andric     }
22800b57cec5SDimitry Andric 
22810b57cec5SDimitry Andric     cmd_args.Clear();
22820b57cec5SDimitry Andric     cmd_args.SetArguments(new_args.GetArgumentCount(),
22830b57cec5SDimitry Andric                           new_args.GetConstArgumentVector());
22840b57cec5SDimitry Andric   } else {
22850b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
22860b57cec5SDimitry Andric     // This alias was not created with any options; nothing further needs to be
22870b57cec5SDimitry Andric     // done, unless it is a command that wants raw input, in which case we need
22880b57cec5SDimitry Andric     // to clear the rest of the data from cmd_args, since its in the raw input
22890b57cec5SDimitry Andric     // string.
22900b57cec5SDimitry Andric     if (wants_raw_input) {
22910b57cec5SDimitry Andric       cmd_args.Clear();
22920b57cec5SDimitry Andric       cmd_args.SetArguments(new_args.GetArgumentCount(),
22930b57cec5SDimitry Andric                             new_args.GetConstArgumentVector());
22940b57cec5SDimitry Andric     }
22950b57cec5SDimitry Andric     return;
22960b57cec5SDimitry Andric   }
22970b57cec5SDimitry Andric 
22980b57cec5SDimitry Andric   result.SetStatus(eReturnStatusSuccessFinishNoResult);
22990b57cec5SDimitry Andric }
23000b57cec5SDimitry Andric 
23010b57cec5SDimitry Andric int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
23020b57cec5SDimitry Andric   int position = 0; // Any string that isn't an argument position, i.e. '%'
23030b57cec5SDimitry Andric                     // followed by an integer, gets a position
23040b57cec5SDimitry Andric                     // of zero.
23050b57cec5SDimitry Andric 
23060b57cec5SDimitry Andric   const char *cptr = in_string;
23070b57cec5SDimitry Andric 
23080b57cec5SDimitry Andric   // Does it start with '%'
23090b57cec5SDimitry Andric   if (cptr[0] == '%') {
23100b57cec5SDimitry Andric     ++cptr;
23110b57cec5SDimitry Andric 
23120b57cec5SDimitry Andric     // Is the rest of it entirely digits?
23130b57cec5SDimitry Andric     if (isdigit(cptr[0])) {
23140b57cec5SDimitry Andric       const char *start = cptr;
23150b57cec5SDimitry Andric       while (isdigit(cptr[0]))
23160b57cec5SDimitry Andric         ++cptr;
23170b57cec5SDimitry Andric 
23180b57cec5SDimitry Andric       // We've gotten to the end of the digits; are we at the end of the
23190b57cec5SDimitry Andric       // string?
23200b57cec5SDimitry Andric       if (cptr[0] == '\0')
23210b57cec5SDimitry Andric         position = atoi(start);
23220b57cec5SDimitry Andric     }
23230b57cec5SDimitry Andric   }
23240b57cec5SDimitry Andric 
23250b57cec5SDimitry Andric   return position;
23260b57cec5SDimitry Andric }
23270b57cec5SDimitry Andric 
23280b57cec5SDimitry Andric static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
23290b57cec5SDimitry Andric                             llvm::StringRef suffix = {}) {
23300b57cec5SDimitry Andric   std::string init_file_name = ".lldbinit";
23310b57cec5SDimitry Andric   if (!suffix.empty()) {
23320b57cec5SDimitry Andric     init_file_name.append("-");
23330b57cec5SDimitry Andric     init_file_name.append(suffix.str());
23340b57cec5SDimitry Andric   }
23350b57cec5SDimitry Andric 
2336e8d8bef9SDimitry Andric   FileSystem::Instance().GetHomeDirectory(init_file);
23370b57cec5SDimitry Andric   llvm::sys::path::append(init_file, init_file_name);
23380b57cec5SDimitry Andric 
23390b57cec5SDimitry Andric   FileSystem::Instance().Resolve(init_file);
23400b57cec5SDimitry Andric }
23410b57cec5SDimitry Andric 
234204eeddc0SDimitry Andric static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
234304eeddc0SDimitry Andric                                 LanguageType language) {
234404eeddc0SDimitry Andric   if (language == eLanguageTypeUnknown) {
2345e8d8bef9SDimitry Andric     LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
2346e8d8bef9SDimitry Andric     if (auto main_repl_language = repl_languages.GetSingularLanguage())
2347e8d8bef9SDimitry Andric       language = *main_repl_language;
2348e8d8bef9SDimitry Andric     else
2349e8d8bef9SDimitry Andric       return;
235004eeddc0SDimitry Andric   }
2351e8d8bef9SDimitry Andric 
2352e8d8bef9SDimitry Andric   std::string init_file_name =
2353e8d8bef9SDimitry Andric       (llvm::Twine(".lldbinit-") +
2354e8d8bef9SDimitry Andric        llvm::Twine(Language::GetNameForLanguageType(language)) +
2355e8d8bef9SDimitry Andric        llvm::Twine("-repl"))
2356e8d8bef9SDimitry Andric           .str();
2357e8d8bef9SDimitry Andric   FileSystem::Instance().GetHomeDirectory(init_file);
2358e8d8bef9SDimitry Andric   llvm::sys::path::append(init_file, init_file_name);
2359e8d8bef9SDimitry Andric   FileSystem::Instance().Resolve(init_file);
2360e8d8bef9SDimitry Andric }
2361e8d8bef9SDimitry Andric 
23620b57cec5SDimitry Andric static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
23630b57cec5SDimitry Andric   llvm::StringRef s = ".lldbinit";
23640b57cec5SDimitry Andric   init_file.assign(s.begin(), s.end());
23650b57cec5SDimitry Andric   FileSystem::Instance().Resolve(init_file);
23660b57cec5SDimitry Andric }
23670b57cec5SDimitry Andric 
23680b57cec5SDimitry Andric void CommandInterpreter::SourceInitFile(FileSpec file,
23690b57cec5SDimitry Andric                                         CommandReturnObject &result) {
23700b57cec5SDimitry Andric   assert(!m_skip_lldbinit_files);
23710b57cec5SDimitry Andric 
23720b57cec5SDimitry Andric   if (!FileSystem::Instance().Exists(file)) {
23730b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
23740b57cec5SDimitry Andric     return;
23750b57cec5SDimitry Andric   }
23760b57cec5SDimitry Andric 
23770b57cec5SDimitry Andric   // Use HandleCommand to 'source' the given file; this will do the actual
23780b57cec5SDimitry Andric   // broadcasting of the commands back to any appropriate listener (see
23790b57cec5SDimitry Andric   // CommandObjectSource::Execute for more details).
23800b57cec5SDimitry Andric   const bool saved_batch = SetBatchCommandMode(true);
23810b57cec5SDimitry Andric   CommandInterpreterRunOptions options;
23820b57cec5SDimitry Andric   options.SetSilent(true);
23830b57cec5SDimitry Andric   options.SetPrintErrors(true);
23840b57cec5SDimitry Andric   options.SetStopOnError(false);
23850b57cec5SDimitry Andric   options.SetStopOnContinue(true);
2386fe6060f1SDimitry Andric   HandleCommandsFromFile(file, options, result);
23870b57cec5SDimitry Andric   SetBatchCommandMode(saved_batch);
23880b57cec5SDimitry Andric }
23890b57cec5SDimitry Andric 
23900b57cec5SDimitry Andric void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
23910b57cec5SDimitry Andric   if (m_skip_lldbinit_files) {
23920b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
23930b57cec5SDimitry Andric     return;
23940b57cec5SDimitry Andric   }
23950b57cec5SDimitry Andric 
23960b57cec5SDimitry Andric   llvm::SmallString<128> init_file;
23970b57cec5SDimitry Andric   GetCwdInitFile(init_file);
23980b57cec5SDimitry Andric   if (!FileSystem::Instance().Exists(init_file)) {
23990b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
24000b57cec5SDimitry Andric     return;
24010b57cec5SDimitry Andric   }
24020b57cec5SDimitry Andric 
2403349cc55cSDimitry Andric   LoadCWDlldbinitFile should_load =
2404349cc55cSDimitry Andric       Target::GetGlobalProperties().GetLoadCWDlldbinitFile();
24050b57cec5SDimitry Andric 
24060b57cec5SDimitry Andric   switch (should_load) {
24070b57cec5SDimitry Andric   case eLoadCWDlldbinitFalse:
24080b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
24090b57cec5SDimitry Andric     break;
24100b57cec5SDimitry Andric   case eLoadCWDlldbinitTrue:
24110b57cec5SDimitry Andric     SourceInitFile(FileSpec(init_file.str()), result);
24120b57cec5SDimitry Andric     break;
24130b57cec5SDimitry Andric   case eLoadCWDlldbinitWarn: {
24140b57cec5SDimitry Andric     llvm::SmallString<128> home_init_file;
24150b57cec5SDimitry Andric     GetHomeInitFile(home_init_file);
24160b57cec5SDimitry Andric     if (llvm::sys::path::parent_path(init_file) ==
24170b57cec5SDimitry Andric         llvm::sys::path::parent_path(home_init_file)) {
24180b57cec5SDimitry Andric       result.SetStatus(eReturnStatusSuccessFinishNoResult);
24190b57cec5SDimitry Andric     } else {
2420e8d8bef9SDimitry Andric       result.AppendError(InitFileWarning);
24210b57cec5SDimitry Andric     }
24220b57cec5SDimitry Andric   }
24230b57cec5SDimitry Andric   }
24240b57cec5SDimitry Andric }
24250b57cec5SDimitry Andric 
24260b57cec5SDimitry Andric /// We will first see if there is an application specific ".lldbinit" file
24270b57cec5SDimitry Andric /// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2428e8d8bef9SDimitry Andric /// If this file doesn't exist, we fall back to the REPL init file or the
2429e8d8bef9SDimitry Andric /// default home init file in "~/.lldbinit".
2430e8d8bef9SDimitry Andric void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
2431e8d8bef9SDimitry Andric                                             bool is_repl) {
24320b57cec5SDimitry Andric   if (m_skip_lldbinit_files) {
24330b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
24340b57cec5SDimitry Andric     return;
24350b57cec5SDimitry Andric   }
24360b57cec5SDimitry Andric 
24370b57cec5SDimitry Andric   llvm::SmallString<128> init_file;
2438e8d8bef9SDimitry Andric 
2439e8d8bef9SDimitry Andric   if (is_repl)
244004eeddc0SDimitry Andric     GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2441e8d8bef9SDimitry Andric 
2442e8d8bef9SDimitry Andric   if (init_file.empty())
24430b57cec5SDimitry Andric     GetHomeInitFile(init_file);
24440b57cec5SDimitry Andric 
24450b57cec5SDimitry Andric   if (!m_skip_app_init_files) {
24460b57cec5SDimitry Andric     llvm::StringRef program_name =
24470b57cec5SDimitry Andric         HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
24480b57cec5SDimitry Andric     llvm::SmallString<128> program_init_file;
24490b57cec5SDimitry Andric     GetHomeInitFile(program_init_file, program_name);
24500b57cec5SDimitry Andric     if (FileSystem::Instance().Exists(program_init_file))
24510b57cec5SDimitry Andric       init_file = program_init_file;
24520b57cec5SDimitry Andric   }
24530b57cec5SDimitry Andric 
24540b57cec5SDimitry Andric   SourceInitFile(FileSpec(init_file.str()), result);
24550b57cec5SDimitry Andric }
24560b57cec5SDimitry Andric 
245781ad6265SDimitry Andric void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
245881ad6265SDimitry Andric #ifdef LLDB_GLOBAL_INIT_DIRECTORY
245981ad6265SDimitry Andric   if (!m_skip_lldbinit_files) {
246081ad6265SDimitry Andric     FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
246181ad6265SDimitry Andric     if (init_file)
246281ad6265SDimitry Andric       init_file.MakeAbsolute(HostInfo::GetShlibDir());
246381ad6265SDimitry Andric 
246481ad6265SDimitry Andric     init_file.AppendPathComponent("lldbinit");
246581ad6265SDimitry Andric     SourceInitFile(init_file, result);
246681ad6265SDimitry Andric     return;
246781ad6265SDimitry Andric   }
246881ad6265SDimitry Andric #endif
246981ad6265SDimitry Andric   result.SetStatus(eReturnStatusSuccessFinishNoResult);
247081ad6265SDimitry Andric }
247181ad6265SDimitry Andric 
24720b57cec5SDimitry Andric const char *CommandInterpreter::GetCommandPrefix() {
24730b57cec5SDimitry Andric   const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
24740b57cec5SDimitry Andric   return prefix == nullptr ? "" : prefix;
24750b57cec5SDimitry Andric }
24760b57cec5SDimitry Andric 
24770b57cec5SDimitry Andric PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
24780b57cec5SDimitry Andric   PlatformSP platform_sp;
24790b57cec5SDimitry Andric   if (prefer_target_platform) {
24800b57cec5SDimitry Andric     ExecutionContext exe_ctx(GetExecutionContext());
24810b57cec5SDimitry Andric     Target *target = exe_ctx.GetTargetPtr();
24820b57cec5SDimitry Andric     if (target)
24830b57cec5SDimitry Andric       platform_sp = target->GetPlatform();
24840b57cec5SDimitry Andric   }
24850b57cec5SDimitry Andric 
24860b57cec5SDimitry Andric   if (!platform_sp)
24870b57cec5SDimitry Andric     platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
24880b57cec5SDimitry Andric   return platform_sp;
24890b57cec5SDimitry Andric }
24900b57cec5SDimitry Andric 
24919dba64beSDimitry Andric bool CommandInterpreter::DidProcessStopAbnormally() const {
2492fe6060f1SDimitry Andric   auto exe_ctx = GetExecutionContext();
2493fe6060f1SDimitry Andric   TargetSP target_sp = exe_ctx.GetTargetSP();
24949dba64beSDimitry Andric   if (!target_sp)
24959dba64beSDimitry Andric     return false;
24969dba64beSDimitry Andric 
24979dba64beSDimitry Andric   ProcessSP process_sp(target_sp->GetProcessSP());
24989dba64beSDimitry Andric   if (!process_sp)
24999dba64beSDimitry Andric     return false;
25009dba64beSDimitry Andric 
25019dba64beSDimitry Andric   if (eStateStopped != process_sp->GetState())
25029dba64beSDimitry Andric     return false;
25039dba64beSDimitry Andric 
25049dba64beSDimitry Andric   for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
25059dba64beSDimitry Andric     StopInfoSP stop_info = thread_sp->GetStopInfo();
2506bdd1243dSDimitry Andric     if (!stop_info) {
2507bdd1243dSDimitry Andric       // If there's no stop_info, keep iterating through the other threads;
2508bdd1243dSDimitry Andric       // it's enough that any thread has got a stop_info that indicates
2509bdd1243dSDimitry Andric       // an abnormal stop, to consider the process to be stopped abnormally.
2510bdd1243dSDimitry Andric       continue;
2511bdd1243dSDimitry Andric     }
25129dba64beSDimitry Andric 
25139dba64beSDimitry Andric     const StopReason reason = stop_info->GetStopReason();
2514fe6060f1SDimitry Andric     if (reason == eStopReasonException ||
2515fe6060f1SDimitry Andric         reason == eStopReasonInstrumentation ||
2516fe6060f1SDimitry Andric         reason == eStopReasonProcessorTrace)
25179dba64beSDimitry Andric       return true;
25189dba64beSDimitry Andric 
25199dba64beSDimitry Andric     if (reason == eStopReasonSignal) {
25209dba64beSDimitry Andric       const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
25219dba64beSDimitry Andric       UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
25229dba64beSDimitry Andric       if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
25239dba64beSDimitry Andric         // The signal is unknown, treat it as abnormal.
25249dba64beSDimitry Andric         return true;
25259dba64beSDimitry Andric 
25269dba64beSDimitry Andric       const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
25279dba64beSDimitry Andric       const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
25289dba64beSDimitry Andric       if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
25299dba64beSDimitry Andric         // The signal very likely implies a crash.
25309dba64beSDimitry Andric         return true;
25319dba64beSDimitry Andric     }
25329dba64beSDimitry Andric   }
25339dba64beSDimitry Andric 
25349dba64beSDimitry Andric   return false;
25359dba64beSDimitry Andric }
25369dba64beSDimitry Andric 
2537fe6060f1SDimitry Andric void
2538fe6060f1SDimitry Andric CommandInterpreter::HandleCommands(const StringList &commands,
2539fe6060f1SDimitry Andric                                    const ExecutionContext &override_context,
2540fe6060f1SDimitry Andric                                    const CommandInterpreterRunOptions &options,
2541fe6060f1SDimitry Andric                                    CommandReturnObject &result) {
2542fe6060f1SDimitry Andric 
2543fe6060f1SDimitry Andric   OverrideExecutionContext(override_context);
2544fe6060f1SDimitry Andric   HandleCommands(commands, options, result);
2545fe6060f1SDimitry Andric   RestoreExecutionContext();
2546fe6060f1SDimitry Andric }
2547fe6060f1SDimitry Andric 
25480b57cec5SDimitry Andric void CommandInterpreter::HandleCommands(const StringList &commands,
2549fe6060f1SDimitry Andric                                         const CommandInterpreterRunOptions &options,
25500b57cec5SDimitry Andric                                         CommandReturnObject &result) {
25510b57cec5SDimitry Andric   size_t num_lines = commands.GetSize();
25520b57cec5SDimitry Andric 
25530b57cec5SDimitry Andric   // If we are going to continue past a "continue" then we need to run the
25540b57cec5SDimitry Andric   // commands synchronously. Make sure you reset this value anywhere you return
25550b57cec5SDimitry Andric   // from the function.
25560b57cec5SDimitry Andric 
25570b57cec5SDimitry Andric   bool old_async_execution = m_debugger.GetAsyncExecution();
25580b57cec5SDimitry Andric 
25590b57cec5SDimitry Andric   if (!options.GetStopOnContinue()) {
25600b57cec5SDimitry Andric     m_debugger.SetAsyncExecution(false);
25610b57cec5SDimitry Andric   }
25620b57cec5SDimitry Andric 
256306c3fb27SDimitry Andric   for (size_t idx = 0; idx < num_lines; idx++) {
25640b57cec5SDimitry Andric     const char *cmd = commands.GetStringAtIndex(idx);
25650b57cec5SDimitry Andric     if (cmd[0] == '\0')
25660b57cec5SDimitry Andric       continue;
25670b57cec5SDimitry Andric 
25680b57cec5SDimitry Andric     if (options.GetEchoCommands()) {
25690b57cec5SDimitry Andric       // TODO: Add Stream support.
25700b57cec5SDimitry Andric       result.AppendMessageWithFormat("%s %s\n",
25710b57cec5SDimitry Andric                                      m_debugger.GetPrompt().str().c_str(), cmd);
25720b57cec5SDimitry Andric     }
25730b57cec5SDimitry Andric 
25745ffd83dbSDimitry Andric     CommandReturnObject tmp_result(m_debugger.GetUseColor());
2575e8d8bef9SDimitry Andric     tmp_result.SetInteractive(result.GetInteractive());
2576fe6060f1SDimitry Andric     tmp_result.SetSuppressImmediateOutput(true);
25770b57cec5SDimitry Andric 
25780b57cec5SDimitry Andric     // We might call into a regex or alias command, in which case the
25790b57cec5SDimitry Andric     // add_to_history will get lost.  This m_command_source_depth dingus is the
25800b57cec5SDimitry Andric     // way we turn off adding to the history in that case, so set it up here.
25810b57cec5SDimitry Andric     if (!options.GetAddToHistory())
25820b57cec5SDimitry Andric       m_command_source_depth++;
2583fe6060f1SDimitry Andric     bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
25840b57cec5SDimitry Andric     if (!options.GetAddToHistory())
25850b57cec5SDimitry Andric       m_command_source_depth--;
25860b57cec5SDimitry Andric 
25870b57cec5SDimitry Andric     if (options.GetPrintResults()) {
25880b57cec5SDimitry Andric       if (tmp_result.Succeeded())
25890b57cec5SDimitry Andric         result.AppendMessage(tmp_result.GetOutputData());
25900b57cec5SDimitry Andric     }
25910b57cec5SDimitry Andric 
25920b57cec5SDimitry Andric     if (!success || !tmp_result.Succeeded()) {
25930b57cec5SDimitry Andric       llvm::StringRef error_msg = tmp_result.GetErrorData();
25940b57cec5SDimitry Andric       if (error_msg.empty())
25950b57cec5SDimitry Andric         error_msg = "<unknown error>.\n";
25960b57cec5SDimitry Andric       if (options.GetStopOnError()) {
25970b57cec5SDimitry Andric         result.AppendErrorWithFormat(
25980b57cec5SDimitry Andric             "Aborting reading of commands after command #%" PRIu64
25990b57cec5SDimitry Andric             ": '%s' failed with %s",
26000b57cec5SDimitry Andric             (uint64_t)idx, cmd, error_msg.str().c_str());
26010b57cec5SDimitry Andric         m_debugger.SetAsyncExecution(old_async_execution);
26020b57cec5SDimitry Andric         return;
26030b57cec5SDimitry Andric       } else if (options.GetPrintResults()) {
26040b57cec5SDimitry Andric         result.AppendMessageWithFormat(
26050b57cec5SDimitry Andric             "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
26060b57cec5SDimitry Andric             error_msg.str().c_str());
26070b57cec5SDimitry Andric       }
26080b57cec5SDimitry Andric     }
26090b57cec5SDimitry Andric 
26100b57cec5SDimitry Andric     if (result.GetImmediateOutputStream())
26110b57cec5SDimitry Andric       result.GetImmediateOutputStream()->Flush();
26120b57cec5SDimitry Andric 
26130b57cec5SDimitry Andric     if (result.GetImmediateErrorStream())
26140b57cec5SDimitry Andric       result.GetImmediateErrorStream()->Flush();
26150b57cec5SDimitry Andric 
26160b57cec5SDimitry Andric     // N.B. Can't depend on DidChangeProcessState, because the state coming
26170b57cec5SDimitry Andric     // into the command execution could be running (for instance in Breakpoint
26180b57cec5SDimitry Andric     // Commands. So we check the return value to see if it is has running in
26190b57cec5SDimitry Andric     // it.
26200b57cec5SDimitry Andric     if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
26210b57cec5SDimitry Andric         (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
26220b57cec5SDimitry Andric       if (options.GetStopOnContinue()) {
26230b57cec5SDimitry Andric         // If we caused the target to proceed, and we're going to stop in that
26240b57cec5SDimitry Andric         // case, set the status in our real result before returning.  This is
26250b57cec5SDimitry Andric         // an error if the continue was not the last command in the set of
26260b57cec5SDimitry Andric         // commands to be run.
26270b57cec5SDimitry Andric         if (idx != num_lines - 1)
26280b57cec5SDimitry Andric           result.AppendErrorWithFormat(
26290b57cec5SDimitry Andric               "Aborting reading of commands after command #%" PRIu64
26300b57cec5SDimitry Andric               ": '%s' continued the target.\n",
26310b57cec5SDimitry Andric               (uint64_t)idx + 1, cmd);
26320b57cec5SDimitry Andric         else
26330b57cec5SDimitry Andric           result.AppendMessageWithFormat("Command #%" PRIu64
26340b57cec5SDimitry Andric                                          " '%s' continued the target.\n",
26350b57cec5SDimitry Andric                                          (uint64_t)idx + 1, cmd);
26360b57cec5SDimitry Andric 
26370b57cec5SDimitry Andric         result.SetStatus(tmp_result.GetStatus());
26380b57cec5SDimitry Andric         m_debugger.SetAsyncExecution(old_async_execution);
26390b57cec5SDimitry Andric 
26400b57cec5SDimitry Andric         return;
26410b57cec5SDimitry Andric       }
26420b57cec5SDimitry Andric     }
26430b57cec5SDimitry Andric 
26440b57cec5SDimitry Andric     // Also check for "stop on crash here:
26459dba64beSDimitry Andric     if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
26469dba64beSDimitry Andric         DidProcessStopAbnormally()) {
26470b57cec5SDimitry Andric       if (idx != num_lines - 1)
26480b57cec5SDimitry Andric         result.AppendErrorWithFormat(
26490b57cec5SDimitry Andric             "Aborting reading of commands after command #%" PRIu64
26500b57cec5SDimitry Andric             ": '%s' stopped with a signal or exception.\n",
26510b57cec5SDimitry Andric             (uint64_t)idx + 1, cmd);
26520b57cec5SDimitry Andric       else
26530b57cec5SDimitry Andric         result.AppendMessageWithFormat(
26540b57cec5SDimitry Andric             "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
26550b57cec5SDimitry Andric             (uint64_t)idx + 1, cmd);
26560b57cec5SDimitry Andric 
26570b57cec5SDimitry Andric       result.SetStatus(tmp_result.GetStatus());
26580b57cec5SDimitry Andric       m_debugger.SetAsyncExecution(old_async_execution);
26590b57cec5SDimitry Andric 
26600b57cec5SDimitry Andric       return;
26610b57cec5SDimitry Andric     }
26620b57cec5SDimitry Andric   }
26630b57cec5SDimitry Andric 
26640b57cec5SDimitry Andric   result.SetStatus(eReturnStatusSuccessFinishResult);
26650b57cec5SDimitry Andric   m_debugger.SetAsyncExecution(old_async_execution);
26660b57cec5SDimitry Andric }
26670b57cec5SDimitry Andric 
26680b57cec5SDimitry Andric // Make flags that we can pass into the IOHandler so our delegates can do the
26690b57cec5SDimitry Andric // right thing
26700b57cec5SDimitry Andric enum {
26710b57cec5SDimitry Andric   eHandleCommandFlagStopOnContinue = (1u << 0),
26720b57cec5SDimitry Andric   eHandleCommandFlagStopOnError = (1u << 1),
26730b57cec5SDimitry Andric   eHandleCommandFlagEchoCommand = (1u << 2),
26740b57cec5SDimitry Andric   eHandleCommandFlagEchoCommentCommand = (1u << 3),
26750b57cec5SDimitry Andric   eHandleCommandFlagPrintResult = (1u << 4),
26760b57cec5SDimitry Andric   eHandleCommandFlagPrintErrors = (1u << 5),
2677*0fca6ea1SDimitry Andric   eHandleCommandFlagStopOnCrash = (1u << 6),
2678*0fca6ea1SDimitry Andric   eHandleCommandFlagAllowRepeats = (1u << 7)
26790b57cec5SDimitry Andric };
26800b57cec5SDimitry Andric 
26810b57cec5SDimitry Andric void CommandInterpreter::HandleCommandsFromFile(
2682fe6060f1SDimitry Andric     FileSpec &cmd_file, const ExecutionContext &context,
2683fe6060f1SDimitry Andric     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2684fe6060f1SDimitry Andric   OverrideExecutionContext(context);
2685fe6060f1SDimitry Andric   HandleCommandsFromFile(cmd_file, options, result);
2686fe6060f1SDimitry Andric   RestoreExecutionContext();
2687fe6060f1SDimitry Andric }
2688fe6060f1SDimitry Andric 
2689fe6060f1SDimitry Andric void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
2690fe6060f1SDimitry Andric     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
26910b57cec5SDimitry Andric   if (!FileSystem::Instance().Exists(cmd_file)) {
26920b57cec5SDimitry Andric     result.AppendErrorWithFormat(
26930b57cec5SDimitry Andric         "Error reading commands from file %s - file not found.\n",
26940b57cec5SDimitry Andric         cmd_file.GetFilename().AsCString("<Unknown>"));
26950b57cec5SDimitry Andric     return;
26960b57cec5SDimitry Andric   }
26970b57cec5SDimitry Andric 
26980b57cec5SDimitry Andric   std::string cmd_file_path = cmd_file.GetPath();
26999dba64beSDimitry Andric   auto input_file_up =
2700349cc55cSDimitry Andric       FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly);
27019dba64beSDimitry Andric   if (!input_file_up) {
27029dba64beSDimitry Andric     std::string error = llvm::toString(input_file_up.takeError());
27039dba64beSDimitry Andric     result.AppendErrorWithFormatv(
27049dba64beSDimitry Andric         "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
27059dba64beSDimitry Andric         llvm::fmt_consume(input_file_up.takeError()));
27060b57cec5SDimitry Andric     return;
27070b57cec5SDimitry Andric   }
27089dba64beSDimitry Andric   FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
27090b57cec5SDimitry Andric 
27100b57cec5SDimitry Andric   Debugger &debugger = GetDebugger();
27110b57cec5SDimitry Andric 
27120b57cec5SDimitry Andric   uint32_t flags = 0;
27130b57cec5SDimitry Andric 
27140b57cec5SDimitry Andric   if (options.m_stop_on_continue == eLazyBoolCalculate) {
27150b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27160b57cec5SDimitry Andric       // Stop on continue by default
27170b57cec5SDimitry Andric       flags |= eHandleCommandFlagStopOnContinue;
27180b57cec5SDimitry Andric     } else if (m_command_source_flags.back() &
27190b57cec5SDimitry Andric                eHandleCommandFlagStopOnContinue) {
27200b57cec5SDimitry Andric       flags |= eHandleCommandFlagStopOnContinue;
27210b57cec5SDimitry Andric     }
27220b57cec5SDimitry Andric   } else if (options.m_stop_on_continue == eLazyBoolYes) {
27230b57cec5SDimitry Andric     flags |= eHandleCommandFlagStopOnContinue;
27240b57cec5SDimitry Andric   }
27250b57cec5SDimitry Andric 
27260b57cec5SDimitry Andric   if (options.m_stop_on_error == eLazyBoolCalculate) {
27270b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27280b57cec5SDimitry Andric       if (GetStopCmdSourceOnError())
27290b57cec5SDimitry Andric         flags |= eHandleCommandFlagStopOnError;
27300b57cec5SDimitry Andric     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
27310b57cec5SDimitry Andric       flags |= eHandleCommandFlagStopOnError;
27320b57cec5SDimitry Andric     }
27330b57cec5SDimitry Andric   } else if (options.m_stop_on_error == eLazyBoolYes) {
27340b57cec5SDimitry Andric     flags |= eHandleCommandFlagStopOnError;
27350b57cec5SDimitry Andric   }
27360b57cec5SDimitry Andric 
27370b57cec5SDimitry Andric   // stop-on-crash can only be set, if it is present in all levels of
27380b57cec5SDimitry Andric   // pushed flag sets.
27390b57cec5SDimitry Andric   if (options.GetStopOnCrash()) {
27400b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27410b57cec5SDimitry Andric       flags |= eHandleCommandFlagStopOnCrash;
27420b57cec5SDimitry Andric     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
27430b57cec5SDimitry Andric       flags |= eHandleCommandFlagStopOnCrash;
27440b57cec5SDimitry Andric     }
27450b57cec5SDimitry Andric   }
27460b57cec5SDimitry Andric 
27470b57cec5SDimitry Andric   if (options.m_echo_commands == eLazyBoolCalculate) {
27480b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27490b57cec5SDimitry Andric       // Echo command by default
27500b57cec5SDimitry Andric       flags |= eHandleCommandFlagEchoCommand;
27510b57cec5SDimitry Andric     } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
27520b57cec5SDimitry Andric       flags |= eHandleCommandFlagEchoCommand;
27530b57cec5SDimitry Andric     }
27540b57cec5SDimitry Andric   } else if (options.m_echo_commands == eLazyBoolYes) {
27550b57cec5SDimitry Andric     flags |= eHandleCommandFlagEchoCommand;
27560b57cec5SDimitry Andric   }
27570b57cec5SDimitry Andric 
27580b57cec5SDimitry Andric   // We will only ever ask for this flag, if we echo commands in general.
27590b57cec5SDimitry Andric   if (options.m_echo_comment_commands == eLazyBoolCalculate) {
27600b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27610b57cec5SDimitry Andric       // Echo comments by default
27620b57cec5SDimitry Andric       flags |= eHandleCommandFlagEchoCommentCommand;
27630b57cec5SDimitry Andric     } else if (m_command_source_flags.back() &
27640b57cec5SDimitry Andric                eHandleCommandFlagEchoCommentCommand) {
27650b57cec5SDimitry Andric       flags |= eHandleCommandFlagEchoCommentCommand;
27660b57cec5SDimitry Andric     }
27670b57cec5SDimitry Andric   } else if (options.m_echo_comment_commands == eLazyBoolYes) {
27680b57cec5SDimitry Andric     flags |= eHandleCommandFlagEchoCommentCommand;
27690b57cec5SDimitry Andric   }
27700b57cec5SDimitry Andric 
27710b57cec5SDimitry Andric   if (options.m_print_results == eLazyBoolCalculate) {
27720b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27730b57cec5SDimitry Andric       // Print output by default
27740b57cec5SDimitry Andric       flags |= eHandleCommandFlagPrintResult;
27750b57cec5SDimitry Andric     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
27760b57cec5SDimitry Andric       flags |= eHandleCommandFlagPrintResult;
27770b57cec5SDimitry Andric     }
27780b57cec5SDimitry Andric   } else if (options.m_print_results == eLazyBoolYes) {
27790b57cec5SDimitry Andric     flags |= eHandleCommandFlagPrintResult;
27800b57cec5SDimitry Andric   }
27810b57cec5SDimitry Andric 
27820b57cec5SDimitry Andric   if (options.m_print_errors == eLazyBoolCalculate) {
27830b57cec5SDimitry Andric     if (m_command_source_flags.empty()) {
27840b57cec5SDimitry Andric       // Print output by default
27850b57cec5SDimitry Andric       flags |= eHandleCommandFlagPrintErrors;
27860b57cec5SDimitry Andric     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
27870b57cec5SDimitry Andric       flags |= eHandleCommandFlagPrintErrors;
27880b57cec5SDimitry Andric     }
27890b57cec5SDimitry Andric   } else if (options.m_print_errors == eLazyBoolYes) {
27900b57cec5SDimitry Andric     flags |= eHandleCommandFlagPrintErrors;
27910b57cec5SDimitry Andric   }
27920b57cec5SDimitry Andric 
27930b57cec5SDimitry Andric   if (flags & eHandleCommandFlagPrintResult) {
27949dba64beSDimitry Andric     debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
27950b57cec5SDimitry Andric                                     cmd_file_path.c_str());
27960b57cec5SDimitry Andric   }
27970b57cec5SDimitry Andric 
27980b57cec5SDimitry Andric   // Used for inheriting the right settings when "command source" might
27990b57cec5SDimitry Andric   // have nested "command source" commands
28000b57cec5SDimitry Andric   lldb::StreamFileSP empty_stream_sp;
28010b57cec5SDimitry Andric   m_command_source_flags.push_back(flags);
28020b57cec5SDimitry Andric   IOHandlerSP io_handler_sp(new IOHandlerEditline(
28030b57cec5SDimitry Andric       debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
28040b57cec5SDimitry Andric       empty_stream_sp, // Pass in an empty stream so we inherit the top
28050b57cec5SDimitry Andric                        // input reader output stream
28060b57cec5SDimitry Andric       empty_stream_sp, // Pass in an empty stream so we inherit the top
28070b57cec5SDimitry Andric                        // input reader error stream
28080b57cec5SDimitry Andric       flags,
28090b57cec5SDimitry Andric       nullptr, // Pass in NULL for "editline_name" so no history is saved,
28100b57cec5SDimitry Andric                // or written
28110b57cec5SDimitry Andric       debugger.GetPrompt(), llvm::StringRef(),
28120b57cec5SDimitry Andric       false, // Not multi-line
2813bdd1243dSDimitry Andric       debugger.GetUseColor(), 0, *this));
28140b57cec5SDimitry Andric   const bool old_async_execution = debugger.GetAsyncExecution();
28150b57cec5SDimitry Andric 
28160b57cec5SDimitry Andric   // Set synchronous execution if we are not stopping on continue
28170b57cec5SDimitry Andric   if ((flags & eHandleCommandFlagStopOnContinue) == 0)
28180b57cec5SDimitry Andric     debugger.SetAsyncExecution(false);
28190b57cec5SDimitry Andric 
28200b57cec5SDimitry Andric   m_command_source_depth++;
2821e8d8bef9SDimitry Andric   m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent());
28220b57cec5SDimitry Andric 
28235ffd83dbSDimitry Andric   debugger.RunIOHandlerSync(io_handler_sp);
28240b57cec5SDimitry Andric   if (!m_command_source_flags.empty())
28250b57cec5SDimitry Andric     m_command_source_flags.pop_back();
2826e8d8bef9SDimitry Andric 
2827e8d8bef9SDimitry Andric   m_command_source_dirs.pop_back();
28280b57cec5SDimitry Andric   m_command_source_depth--;
2829e8d8bef9SDimitry Andric 
28300b57cec5SDimitry Andric   result.SetStatus(eReturnStatusSuccessFinishNoResult);
28310b57cec5SDimitry Andric   debugger.SetAsyncExecution(old_async_execution);
28320b57cec5SDimitry Andric }
28330b57cec5SDimitry Andric 
28340b57cec5SDimitry Andric bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
28350b57cec5SDimitry Andric 
28360b57cec5SDimitry Andric void CommandInterpreter::SetSynchronous(bool value) {
28370b57cec5SDimitry Andric   m_synchronous_execution = value;
28380b57cec5SDimitry Andric }
28390b57cec5SDimitry Andric 
28400b57cec5SDimitry Andric void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
28410b57cec5SDimitry Andric                                                  llvm::StringRef prefix,
28420b57cec5SDimitry Andric                                                  llvm::StringRef help_text) {
28430b57cec5SDimitry Andric   const uint32_t max_columns = m_debugger.GetTerminalWidth();
28440b57cec5SDimitry Andric 
28450b57cec5SDimitry Andric   size_t line_width_max = max_columns - prefix.size();
28460b57cec5SDimitry Andric   if (line_width_max < 16)
28470b57cec5SDimitry Andric     line_width_max = help_text.size() + prefix.size();
28480b57cec5SDimitry Andric 
28490b57cec5SDimitry Andric   strm.IndentMore(prefix.size());
28500b57cec5SDimitry Andric   bool prefixed_yet = false;
2851349cc55cSDimitry Andric   // Even if we have no help text we still want to emit the command name.
2852349cc55cSDimitry Andric   if (help_text.empty())
2853349cc55cSDimitry Andric     help_text = "No help text";
28540b57cec5SDimitry Andric   while (!help_text.empty()) {
28550b57cec5SDimitry Andric     // Prefix the first line, indent subsequent lines to line up
28560b57cec5SDimitry Andric     if (!prefixed_yet) {
28570b57cec5SDimitry Andric       strm << prefix;
28580b57cec5SDimitry Andric       prefixed_yet = true;
28590b57cec5SDimitry Andric     } else
28600b57cec5SDimitry Andric       strm.Indent();
28610b57cec5SDimitry Andric 
28620b57cec5SDimitry Andric     // Never print more than the maximum on one line.
28630b57cec5SDimitry Andric     llvm::StringRef this_line = help_text.substr(0, line_width_max);
28640b57cec5SDimitry Andric 
28650b57cec5SDimitry Andric     // Always break on an explicit newline.
28660b57cec5SDimitry Andric     std::size_t first_newline = this_line.find_first_of("\n");
28670b57cec5SDimitry Andric 
28680b57cec5SDimitry Andric     // Don't break on space/tab unless the text is too long to fit on one line.
28690b57cec5SDimitry Andric     std::size_t last_space = llvm::StringRef::npos;
28700b57cec5SDimitry Andric     if (this_line.size() != help_text.size())
28710b57cec5SDimitry Andric       last_space = this_line.find_last_of(" \t");
28720b57cec5SDimitry Andric 
28730b57cec5SDimitry Andric     // Break at whichever condition triggered first.
28740b57cec5SDimitry Andric     this_line = this_line.substr(0, std::min(first_newline, last_space));
28750b57cec5SDimitry Andric     strm.PutCString(this_line);
28760b57cec5SDimitry Andric     strm.EOL();
28770b57cec5SDimitry Andric 
28780b57cec5SDimitry Andric     // Remove whitespace / newlines after breaking.
28790b57cec5SDimitry Andric     help_text = help_text.drop_front(this_line.size()).ltrim();
28800b57cec5SDimitry Andric   }
28810b57cec5SDimitry Andric   strm.IndentLess(prefix.size());
28820b57cec5SDimitry Andric }
28830b57cec5SDimitry Andric 
28840b57cec5SDimitry Andric void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
28850b57cec5SDimitry Andric                                                  llvm::StringRef word_text,
28860b57cec5SDimitry Andric                                                  llvm::StringRef separator,
28870b57cec5SDimitry Andric                                                  llvm::StringRef help_text,
28880b57cec5SDimitry Andric                                                  size_t max_word_len) {
28890b57cec5SDimitry Andric   StreamString prefix_stream;
28900b57cec5SDimitry Andric   prefix_stream.Printf("  %-*s %*s ", (int)max_word_len, word_text.data(),
28910b57cec5SDimitry Andric                        (int)separator.size(), separator.data());
28920b57cec5SDimitry Andric   OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
28930b57cec5SDimitry Andric }
28940b57cec5SDimitry Andric 
28950b57cec5SDimitry Andric void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
28960b57cec5SDimitry Andric                                         llvm::StringRef separator,
28970b57cec5SDimitry Andric                                         llvm::StringRef help_text,
28980b57cec5SDimitry Andric                                         uint32_t max_word_len) {
28990b57cec5SDimitry Andric   int indent_size = max_word_len + separator.size() + 2;
29000b57cec5SDimitry Andric 
29010b57cec5SDimitry Andric   strm.IndentMore(indent_size);
29020b57cec5SDimitry Andric 
29030b57cec5SDimitry Andric   StreamString text_strm;
29040b57cec5SDimitry Andric   text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
29050b57cec5SDimitry Andric   text_strm << separator << " " << help_text;
29060b57cec5SDimitry Andric 
29070b57cec5SDimitry Andric   const uint32_t max_columns = m_debugger.GetTerminalWidth();
29080b57cec5SDimitry Andric 
29090b57cec5SDimitry Andric   llvm::StringRef text = text_strm.GetString();
29100b57cec5SDimitry Andric 
29110b57cec5SDimitry Andric   uint32_t chars_left = max_columns;
29120b57cec5SDimitry Andric 
29130b57cec5SDimitry Andric   auto nextWordLength = [](llvm::StringRef S) {
29140b57cec5SDimitry Andric     size_t pos = S.find(' ');
29150b57cec5SDimitry Andric     return pos == llvm::StringRef::npos ? S.size() : pos;
29160b57cec5SDimitry Andric   };
29170b57cec5SDimitry Andric 
29180b57cec5SDimitry Andric   while (!text.empty()) {
29190b57cec5SDimitry Andric     if (text.front() == '\n' ||
29200b57cec5SDimitry Andric         (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
29210b57cec5SDimitry Andric       strm.EOL();
29220b57cec5SDimitry Andric       strm.Indent();
29230b57cec5SDimitry Andric       chars_left = max_columns - indent_size;
29240b57cec5SDimitry Andric       if (text.front() == '\n')
29250b57cec5SDimitry Andric         text = text.drop_front();
29260b57cec5SDimitry Andric       else
29270b57cec5SDimitry Andric         text = text.ltrim(' ');
29280b57cec5SDimitry Andric     } else {
29290b57cec5SDimitry Andric       strm.PutChar(text.front());
29300b57cec5SDimitry Andric       --chars_left;
29310b57cec5SDimitry Andric       text = text.drop_front();
29320b57cec5SDimitry Andric     }
29330b57cec5SDimitry Andric   }
29340b57cec5SDimitry Andric 
29350b57cec5SDimitry Andric   strm.EOL();
29360b57cec5SDimitry Andric   strm.IndentLess(indent_size);
29370b57cec5SDimitry Andric }
29380b57cec5SDimitry Andric 
29390b57cec5SDimitry Andric void CommandInterpreter::FindCommandsForApropos(
29400b57cec5SDimitry Andric     llvm::StringRef search_word, StringList &commands_found,
294104eeddc0SDimitry Andric     StringList &commands_help, const CommandObject::CommandMap &command_map) {
294204eeddc0SDimitry Andric   for (const auto &pair : command_map) {
294304eeddc0SDimitry Andric     llvm::StringRef command_name = pair.first;
294404eeddc0SDimitry Andric     CommandObject *cmd_obj = pair.second.get();
29450b57cec5SDimitry Andric 
29460b57cec5SDimitry Andric     const bool search_short_help = true;
29470b57cec5SDimitry Andric     const bool search_long_help = false;
29480b57cec5SDimitry Andric     const bool search_syntax = false;
29490b57cec5SDimitry Andric     const bool search_options = false;
2950fe6060f1SDimitry Andric     if (command_name.contains_insensitive(search_word) ||
29510b57cec5SDimitry Andric         cmd_obj->HelpTextContainsWord(search_word, search_short_help,
29520b57cec5SDimitry Andric                                       search_long_help, search_syntax,
29530b57cec5SDimitry Andric                                       search_options)) {
295404eeddc0SDimitry Andric       commands_found.AppendString(command_name);
29550b57cec5SDimitry Andric       commands_help.AppendString(cmd_obj->GetHelp());
29560b57cec5SDimitry Andric     }
29570b57cec5SDimitry Andric 
295804eeddc0SDimitry Andric     if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
295904eeddc0SDimitry Andric       StringList subcommands_found;
296004eeddc0SDimitry Andric       FindCommandsForApropos(search_word, subcommands_found, commands_help,
296104eeddc0SDimitry Andric                              multiword_cmd->GetSubcommandDictionary());
296204eeddc0SDimitry Andric       for (const auto &subcommand_name : subcommands_found) {
296304eeddc0SDimitry Andric         std::string qualified_name =
296404eeddc0SDimitry Andric             (command_name + " " + subcommand_name).str();
296504eeddc0SDimitry Andric         commands_found.AppendString(qualified_name);
296604eeddc0SDimitry Andric       }
29670b57cec5SDimitry Andric     }
29680b57cec5SDimitry Andric   }
29690b57cec5SDimitry Andric }
29700b57cec5SDimitry Andric 
29710b57cec5SDimitry Andric void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
29720b57cec5SDimitry Andric                                                 StringList &commands_found,
29730b57cec5SDimitry Andric                                                 StringList &commands_help,
29740b57cec5SDimitry Andric                                                 bool search_builtin_commands,
29750b57cec5SDimitry Andric                                                 bool search_user_commands,
2976349cc55cSDimitry Andric                                                 bool search_alias_commands,
2977349cc55cSDimitry Andric                                                 bool search_user_mw_commands) {
29780b57cec5SDimitry Andric   CommandObject::CommandMap::const_iterator pos;
29790b57cec5SDimitry Andric 
29800b57cec5SDimitry Andric   if (search_builtin_commands)
29810b57cec5SDimitry Andric     FindCommandsForApropos(search_word, commands_found, commands_help,
29820b57cec5SDimitry Andric                            m_command_dict);
29830b57cec5SDimitry Andric 
29840b57cec5SDimitry Andric   if (search_user_commands)
29850b57cec5SDimitry Andric     FindCommandsForApropos(search_word, commands_found, commands_help,
29860b57cec5SDimitry Andric                            m_user_dict);
29870b57cec5SDimitry Andric 
2988349cc55cSDimitry Andric   if (search_user_mw_commands)
2989349cc55cSDimitry Andric     FindCommandsForApropos(search_word, commands_found, commands_help,
2990349cc55cSDimitry Andric                            m_user_mw_dict);
2991349cc55cSDimitry Andric 
29920b57cec5SDimitry Andric   if (search_alias_commands)
29930b57cec5SDimitry Andric     FindCommandsForApropos(search_word, commands_found, commands_help,
29940b57cec5SDimitry Andric                            m_alias_dict);
29950b57cec5SDimitry Andric }
29960b57cec5SDimitry Andric 
2997fe6060f1SDimitry Andric ExecutionContext CommandInterpreter::GetExecutionContext() const {
2998fe6060f1SDimitry Andric   return !m_overriden_exe_contexts.empty()
2999fe6060f1SDimitry Andric              ? m_overriden_exe_contexts.top()
3000fe6060f1SDimitry Andric              : m_debugger.GetSelectedExecutionContext();
30010b57cec5SDimitry Andric }
3002fe6060f1SDimitry Andric 
3003fe6060f1SDimitry Andric void CommandInterpreter::OverrideExecutionContext(
3004fe6060f1SDimitry Andric     const ExecutionContext &override_context) {
3005fe6060f1SDimitry Andric   m_overriden_exe_contexts.push(override_context);
3006fe6060f1SDimitry Andric }
3007fe6060f1SDimitry Andric 
3008fe6060f1SDimitry Andric void CommandInterpreter::RestoreExecutionContext() {
3009fe6060f1SDimitry Andric   if (!m_overriden_exe_contexts.empty())
3010fe6060f1SDimitry Andric     m_overriden_exe_contexts.pop();
30110b57cec5SDimitry Andric }
30120b57cec5SDimitry Andric 
30139dba64beSDimitry Andric void CommandInterpreter::GetProcessOutput() {
3014fe6060f1SDimitry Andric   if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
30159dba64beSDimitry Andric     m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
30169dba64beSDimitry Andric                                   /*flush_stderr*/ true);
30170b57cec5SDimitry Andric }
30180b57cec5SDimitry Andric 
30190b57cec5SDimitry Andric void CommandInterpreter::StartHandlingCommand() {
30200b57cec5SDimitry Andric   auto idle_state = CommandHandlingState::eIdle;
30210b57cec5SDimitry Andric   if (m_command_state.compare_exchange_strong(
30220b57cec5SDimitry Andric           idle_state, CommandHandlingState::eInProgress))
30230b57cec5SDimitry Andric     lldbassert(m_iohandler_nesting_level == 0);
30240b57cec5SDimitry Andric   else
30250b57cec5SDimitry Andric     lldbassert(m_iohandler_nesting_level > 0);
30260b57cec5SDimitry Andric   ++m_iohandler_nesting_level;
30270b57cec5SDimitry Andric }
30280b57cec5SDimitry Andric 
30290b57cec5SDimitry Andric void CommandInterpreter::FinishHandlingCommand() {
30300b57cec5SDimitry Andric   lldbassert(m_iohandler_nesting_level > 0);
30310b57cec5SDimitry Andric   if (--m_iohandler_nesting_level == 0) {
30320b57cec5SDimitry Andric     auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
30330b57cec5SDimitry Andric     lldbassert(prev_state != CommandHandlingState::eIdle);
30340b57cec5SDimitry Andric   }
30350b57cec5SDimitry Andric }
30360b57cec5SDimitry Andric 
30370b57cec5SDimitry Andric bool CommandInterpreter::InterruptCommand() {
30380b57cec5SDimitry Andric   auto in_progress = CommandHandlingState::eInProgress;
30390b57cec5SDimitry Andric   return m_command_state.compare_exchange_strong(
30400b57cec5SDimitry Andric       in_progress, CommandHandlingState::eInterrupted);
30410b57cec5SDimitry Andric }
30420b57cec5SDimitry Andric 
30430b57cec5SDimitry Andric bool CommandInterpreter::WasInterrupted() const {
304406c3fb27SDimitry Andric   if (!m_debugger.IsIOHandlerThreadCurrentThread())
304506c3fb27SDimitry Andric     return false;
304606c3fb27SDimitry Andric 
30470b57cec5SDimitry Andric   bool was_interrupted =
30480b57cec5SDimitry Andric       (m_command_state == CommandHandlingState::eInterrupted);
30490b57cec5SDimitry Andric   lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
30500b57cec5SDimitry Andric   return was_interrupted;
30510b57cec5SDimitry Andric }
30520b57cec5SDimitry Andric 
305381ad6265SDimitry Andric void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
305481ad6265SDimitry Andric                                             llvm::StringRef str,
305581ad6265SDimitry Andric                                             bool is_stdout) {
305681ad6265SDimitry Andric 
305781ad6265SDimitry Andric   lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
305881ad6265SDimitry Andric                                         : io_handler.GetErrorStreamFileSP();
30590b57cec5SDimitry Andric   // Split the output into lines and poll for interrupt requests
306006c3fb27SDimitry Andric   bool had_output = !str.empty();
306106c3fb27SDimitry Andric   while (!str.empty()) {
306281ad6265SDimitry Andric     llvm::StringRef line;
306381ad6265SDimitry Andric     std::tie(line, str) = str.split('\n');
306481ad6265SDimitry Andric     {
306581ad6265SDimitry Andric       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
306681ad6265SDimitry Andric       stream->Write(line.data(), line.size());
306781ad6265SDimitry Andric       stream->Write("\n", 1);
30680b57cec5SDimitry Andric     }
30690b57cec5SDimitry Andric   }
307081ad6265SDimitry Andric 
307181ad6265SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3072*0fca6ea1SDimitry Andric   if (had_output &&
3073*0fca6ea1SDimitry Andric       INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output"))
307481ad6265SDimitry Andric     stream->Printf("\n... Interrupted.\n");
307581ad6265SDimitry Andric   stream->Flush();
30760b57cec5SDimitry Andric }
30770b57cec5SDimitry Andric 
30780b57cec5SDimitry Andric bool CommandInterpreter::EchoCommandNonInteractive(
30790b57cec5SDimitry Andric     llvm::StringRef line, const Flags &io_handler_flags) const {
30800b57cec5SDimitry Andric   if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
30810b57cec5SDimitry Andric     return false;
30820b57cec5SDimitry Andric 
30830b57cec5SDimitry Andric   llvm::StringRef command = line.trim();
30840b57cec5SDimitry Andric   if (command.empty())
30850b57cec5SDimitry Andric     return true;
30860b57cec5SDimitry Andric 
30870b57cec5SDimitry Andric   if (command.front() == m_comment_char)
30880b57cec5SDimitry Andric     return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
30890b57cec5SDimitry Andric 
30900b57cec5SDimitry Andric   return true;
30910b57cec5SDimitry Andric }
30920b57cec5SDimitry Andric 
30930b57cec5SDimitry Andric void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
30940b57cec5SDimitry Andric                                                 std::string &line) {
30950b57cec5SDimitry Andric     // If we were interrupted, bail out...
30960b57cec5SDimitry Andric     if (WasInterrupted())
30970b57cec5SDimitry Andric       return;
30980b57cec5SDimitry Andric 
30990b57cec5SDimitry Andric   const bool is_interactive = io_handler.GetIsInteractive();
3100*0fca6ea1SDimitry Andric   const bool allow_repeats =
3101*0fca6ea1SDimitry Andric       io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats);
3102*0fca6ea1SDimitry Andric 
3103*0fca6ea1SDimitry Andric   if (!is_interactive && !allow_repeats) {
31040b57cec5SDimitry Andric     // When we are not interactive, don't execute blank lines. This will happen
31050b57cec5SDimitry Andric     // sourcing a commands file. We don't want blank lines to repeat the
31060b57cec5SDimitry Andric     // previous command and cause any errors to occur (like redefining an
31070b57cec5SDimitry Andric     // alias, get an error and stop parsing the commands file).
3108*0fca6ea1SDimitry Andric     // But obey the AllowRepeats flag if the user has set it.
31090b57cec5SDimitry Andric     if (line.empty())
31100b57cec5SDimitry Andric       return;
3111*0fca6ea1SDimitry Andric   }
3112*0fca6ea1SDimitry Andric   if (!is_interactive) {
31130b57cec5SDimitry Andric     // When using a non-interactive file handle (like when sourcing commands
31140b57cec5SDimitry Andric     // from a file) we need to echo the command out so we don't just see the
31150b57cec5SDimitry Andric     // command output and no command...
311681ad6265SDimitry Andric     if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
311781ad6265SDimitry Andric       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
31189dba64beSDimitry Andric       io_handler.GetOutputStreamFileSP()->Printf(
31199dba64beSDimitry Andric           "%s%s\n", io_handler.GetPrompt(), line.c_str());
31200b57cec5SDimitry Andric     }
312181ad6265SDimitry Andric   }
31220b57cec5SDimitry Andric 
31230b57cec5SDimitry Andric   StartHandlingCommand();
31240b57cec5SDimitry Andric 
312581ad6265SDimitry Andric   ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
312681ad6265SDimitry Andric   bool pushed_exe_ctx = false;
312781ad6265SDimitry Andric   if (exe_ctx.HasTargetScope()) {
312881ad6265SDimitry Andric     OverrideExecutionContext(exe_ctx);
312981ad6265SDimitry Andric     pushed_exe_ctx = true;
313081ad6265SDimitry Andric   }
313181ad6265SDimitry Andric   auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
313281ad6265SDimitry Andric     if (pushed_exe_ctx)
3133fe6060f1SDimitry Andric       RestoreExecutionContext();
3134fe6060f1SDimitry Andric   });
3135fe6060f1SDimitry Andric 
31365ffd83dbSDimitry Andric   lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
31370b57cec5SDimitry Andric   HandleCommand(line.c_str(), eLazyBoolCalculate, result);
31380b57cec5SDimitry Andric 
31390b57cec5SDimitry Andric   // Now emit the command output text from the command we just executed
31400b57cec5SDimitry Andric   if ((result.Succeeded() &&
31410b57cec5SDimitry Andric        io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
31420b57cec5SDimitry Andric       io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
31430b57cec5SDimitry Andric     // Display any STDOUT/STDERR _prior_ to emitting the command result text
31440b57cec5SDimitry Andric     GetProcessOutput();
31450b57cec5SDimitry Andric 
31460b57cec5SDimitry Andric     if (!result.GetImmediateOutputStream()) {
31470b57cec5SDimitry Andric       llvm::StringRef output = result.GetOutputData();
314881ad6265SDimitry Andric       PrintCommandOutput(io_handler, output, true);
31490b57cec5SDimitry Andric     }
31500b57cec5SDimitry Andric 
31510b57cec5SDimitry Andric     // Now emit the command error text from the command we just executed
31520b57cec5SDimitry Andric     if (!result.GetImmediateErrorStream()) {
31530b57cec5SDimitry Andric       llvm::StringRef error = result.GetErrorData();
315481ad6265SDimitry Andric       PrintCommandOutput(io_handler, error, false);
31550b57cec5SDimitry Andric     }
31560b57cec5SDimitry Andric   }
31570b57cec5SDimitry Andric 
31580b57cec5SDimitry Andric   FinishHandlingCommand();
31590b57cec5SDimitry Andric 
31600b57cec5SDimitry Andric   switch (result.GetStatus()) {
31610b57cec5SDimitry Andric   case eReturnStatusInvalid:
31620b57cec5SDimitry Andric   case eReturnStatusSuccessFinishNoResult:
31630b57cec5SDimitry Andric   case eReturnStatusSuccessFinishResult:
31640b57cec5SDimitry Andric   case eReturnStatusStarted:
31650b57cec5SDimitry Andric     break;
31660b57cec5SDimitry Andric 
31670b57cec5SDimitry Andric   case eReturnStatusSuccessContinuingNoResult:
31680b57cec5SDimitry Andric   case eReturnStatusSuccessContinuingResult:
31690b57cec5SDimitry Andric     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
31700b57cec5SDimitry Andric       io_handler.SetIsDone(true);
31710b57cec5SDimitry Andric     break;
31720b57cec5SDimitry Andric 
31730b57cec5SDimitry Andric   case eReturnStatusFailed:
31745ffd83dbSDimitry Andric     m_result.IncrementNumberOfErrors();
31755ffd83dbSDimitry Andric     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
31765ffd83dbSDimitry Andric       m_result.SetResult(lldb::eCommandInterpreterResultCommandError);
31770b57cec5SDimitry Andric       io_handler.SetIsDone(true);
31785ffd83dbSDimitry Andric     }
31790b57cec5SDimitry Andric     break;
31800b57cec5SDimitry Andric 
31810b57cec5SDimitry Andric   case eReturnStatusQuit:
31825ffd83dbSDimitry Andric     m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested);
31830b57cec5SDimitry Andric     io_handler.SetIsDone(true);
31840b57cec5SDimitry Andric     break;
31850b57cec5SDimitry Andric   }
31860b57cec5SDimitry Andric 
31870b57cec5SDimitry Andric   // Finally, if we're going to stop on crash, check that here:
31885ffd83dbSDimitry Andric   if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) &&
31895ffd83dbSDimitry Andric       result.GetDidChangeProcessState() &&
31909dba64beSDimitry Andric       io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
31919dba64beSDimitry Andric       DidProcessStopAbnormally()) {
31920b57cec5SDimitry Andric     io_handler.SetIsDone(true);
31935ffd83dbSDimitry Andric     m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash);
31940b57cec5SDimitry Andric   }
31950b57cec5SDimitry Andric }
31960b57cec5SDimitry Andric 
31970b57cec5SDimitry Andric bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
31980b57cec5SDimitry Andric   ExecutionContext exe_ctx(GetExecutionContext());
31990b57cec5SDimitry Andric   Process *process = exe_ctx.GetProcessPtr();
32000b57cec5SDimitry Andric 
32010b57cec5SDimitry Andric   if (InterruptCommand())
32020b57cec5SDimitry Andric     return true;
32030b57cec5SDimitry Andric 
32040b57cec5SDimitry Andric   if (process) {
32050b57cec5SDimitry Andric     StateType state = process->GetState();
32060b57cec5SDimitry Andric     if (StateIsRunningState(state)) {
32070b57cec5SDimitry Andric       process->Halt();
32080b57cec5SDimitry Andric       return true; // Don't do any updating when we are running
32090b57cec5SDimitry Andric     }
32100b57cec5SDimitry Andric   }
32110b57cec5SDimitry Andric 
32120b57cec5SDimitry Andric   ScriptInterpreter *script_interpreter =
32130b57cec5SDimitry Andric       m_debugger.GetScriptInterpreter(false);
32140b57cec5SDimitry Andric   if (script_interpreter) {
32150b57cec5SDimitry Andric     if (script_interpreter->Interrupt())
32160b57cec5SDimitry Andric       return true;
32170b57cec5SDimitry Andric   }
32180b57cec5SDimitry Andric   return false;
32190b57cec5SDimitry Andric }
32200b57cec5SDimitry Andric 
3221e8d8bef9SDimitry Andric bool CommandInterpreter::SaveTranscript(
3222bdd1243dSDimitry Andric     CommandReturnObject &result, std::optional<std::string> output_file) {
3223bdd1243dSDimitry Andric   if (output_file == std::nullopt || output_file->empty()) {
3224e8d8bef9SDimitry Andric     std::string now = llvm::to_string(std::chrono::system_clock::now());
3225e8d8bef9SDimitry Andric     std::replace(now.begin(), now.end(), ' ', '_');
3226*0fca6ea1SDimitry Andric     // Can't have file name with colons on Windows
3227*0fca6ea1SDimitry Andric     std::replace(now.begin(), now.end(), ':', '-');
3228e8d8bef9SDimitry Andric     const std::string file_name = "lldb_session_" + now + ".log";
3229fe6060f1SDimitry Andric 
3230fe6060f1SDimitry Andric     FileSpec save_location = GetSaveSessionDirectory();
3231fe6060f1SDimitry Andric 
3232fe6060f1SDimitry Andric     if (!save_location)
3233fe6060f1SDimitry Andric       save_location = HostInfo::GetGlobalTempDir();
3234fe6060f1SDimitry Andric 
3235fe6060f1SDimitry Andric     FileSystem::Instance().Resolve(save_location);
3236fe6060f1SDimitry Andric     save_location.AppendPathComponent(file_name);
3237fe6060f1SDimitry Andric     output_file = save_location.GetPath();
3238e8d8bef9SDimitry Andric   }
3239e8d8bef9SDimitry Andric 
3240e8d8bef9SDimitry Andric   auto error_out = [&](llvm::StringRef error_message, std::string description) {
324181ad6265SDimitry Andric     LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
324281ad6265SDimitry Andric              output_file, description);
3243e8d8bef9SDimitry Andric     result.AppendErrorWithFormatv(
3244e8d8bef9SDimitry Andric         "Failed to save session's transcripts to {0}!", *output_file);
3245e8d8bef9SDimitry Andric     return false;
3246e8d8bef9SDimitry Andric   };
3247e8d8bef9SDimitry Andric 
3248349cc55cSDimitry Andric   File::OpenOptions flags = File::eOpenOptionWriteOnly |
3249e8d8bef9SDimitry Andric                             File::eOpenOptionCanCreate |
3250e8d8bef9SDimitry Andric                             File::eOpenOptionTruncate;
3251e8d8bef9SDimitry Andric 
3252e8d8bef9SDimitry Andric   auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3253e8d8bef9SDimitry Andric 
3254e8d8bef9SDimitry Andric   if (!opened_file)
3255e8d8bef9SDimitry Andric     return error_out("Unable to create file",
3256e8d8bef9SDimitry Andric                      llvm::toString(opened_file.takeError()));
3257e8d8bef9SDimitry Andric 
3258e8d8bef9SDimitry Andric   FileUP file = std::move(opened_file.get());
3259e8d8bef9SDimitry Andric 
3260e8d8bef9SDimitry Andric   size_t byte_size = m_transcript_stream.GetSize();
3261e8d8bef9SDimitry Andric 
3262e8d8bef9SDimitry Andric   Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3263e8d8bef9SDimitry Andric 
3264e8d8bef9SDimitry Andric   if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3265e8d8bef9SDimitry Andric     return error_out("Unable to write to destination file",
3266e8d8bef9SDimitry Andric                      "Bytes written do not match transcript size.");
3267e8d8bef9SDimitry Andric 
3268fe6060f1SDimitry Andric   result.SetStatus(eReturnStatusSuccessFinishNoResult);
3269e8d8bef9SDimitry Andric   result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3270e8d8bef9SDimitry Andric                                  output_file->c_str());
3271e8d8bef9SDimitry Andric 
3272bdd1243dSDimitry Andric   if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) {
3273bdd1243dSDimitry Andric     const FileSpec file_spec;
3274bdd1243dSDimitry Andric     error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
327506c3fb27SDimitry Andric     if (error.Success()) {
327606c3fb27SDimitry Andric       if (llvm::Error e = Host::OpenFileInExternalEditor(
327706c3fb27SDimitry Andric               m_debugger.GetExternalEditor(), file_spec, 1))
327806c3fb27SDimitry Andric         result.AppendError(llvm::toString(std::move(e)));
327906c3fb27SDimitry Andric     }
3280bdd1243dSDimitry Andric   }
3281bdd1243dSDimitry Andric 
3282e8d8bef9SDimitry Andric   return true;
3283e8d8bef9SDimitry Andric }
3284e8d8bef9SDimitry Andric 
328581ad6265SDimitry Andric bool CommandInterpreter::IsInteractive() {
328681ad6265SDimitry Andric   return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
328781ad6265SDimitry Andric }
328881ad6265SDimitry Andric 
3289e8d8bef9SDimitry Andric FileSpec CommandInterpreter::GetCurrentSourceDir() {
3290e8d8bef9SDimitry Andric   if (m_command_source_dirs.empty())
3291e8d8bef9SDimitry Andric     return {};
3292e8d8bef9SDimitry Andric   return m_command_source_dirs.back();
3293e8d8bef9SDimitry Andric }
3294e8d8bef9SDimitry Andric 
32950b57cec5SDimitry Andric void CommandInterpreter::GetLLDBCommandsFromIOHandler(
3296480093f4SDimitry Andric     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
32970b57cec5SDimitry Andric   Debugger &debugger = GetDebugger();
32980b57cec5SDimitry Andric   IOHandlerSP io_handler_sp(
32990b57cec5SDimitry Andric       new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
33000b57cec5SDimitry Andric                             "lldb", // Name of input reader for history
3301fe6060f1SDimitry Andric                             llvm::StringRef(prompt), // Prompt
33020b57cec5SDimitry Andric                             llvm::StringRef(),       // Continuation prompt
33030b57cec5SDimitry Andric                             true,                    // Get multiple lines
33040b57cec5SDimitry Andric                             debugger.GetUseColor(),
33050b57cec5SDimitry Andric                             0,          // Don't show line numbers
3306bdd1243dSDimitry Andric                             delegate)); // IOHandlerDelegate
33070b57cec5SDimitry Andric 
33080b57cec5SDimitry Andric   if (io_handler_sp) {
33090b57cec5SDimitry Andric     io_handler_sp->SetUserData(baton);
33105ffd83dbSDimitry Andric     debugger.RunIOHandlerAsync(io_handler_sp);
33110b57cec5SDimitry Andric   }
33120b57cec5SDimitry Andric }
33130b57cec5SDimitry Andric 
33140b57cec5SDimitry Andric void CommandInterpreter::GetPythonCommandsFromIOHandler(
3315480093f4SDimitry Andric     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
33160b57cec5SDimitry Andric   Debugger &debugger = GetDebugger();
33170b57cec5SDimitry Andric   IOHandlerSP io_handler_sp(
33180b57cec5SDimitry Andric       new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
33190b57cec5SDimitry Andric                             "lldb-python", // Name of input reader for history
3320fe6060f1SDimitry Andric                             llvm::StringRef(prompt), // Prompt
33210b57cec5SDimitry Andric                             llvm::StringRef(),       // Continuation prompt
33220b57cec5SDimitry Andric                             true,                    // Get multiple lines
33230b57cec5SDimitry Andric                             debugger.GetUseColor(),
33240b57cec5SDimitry Andric                             0,          // Don't show line numbers
3325bdd1243dSDimitry Andric                             delegate)); // IOHandlerDelegate
33260b57cec5SDimitry Andric 
33270b57cec5SDimitry Andric   if (io_handler_sp) {
33280b57cec5SDimitry Andric     io_handler_sp->SetUserData(baton);
33295ffd83dbSDimitry Andric     debugger.RunIOHandlerAsync(io_handler_sp);
33300b57cec5SDimitry Andric   }
33310b57cec5SDimitry Andric }
33320b57cec5SDimitry Andric 
33330b57cec5SDimitry Andric bool CommandInterpreter::IsActive() {
33340b57cec5SDimitry Andric   return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
33350b57cec5SDimitry Andric }
33360b57cec5SDimitry Andric 
33370b57cec5SDimitry Andric lldb::IOHandlerSP
33380b57cec5SDimitry Andric CommandInterpreter::GetIOHandler(bool force_create,
33390b57cec5SDimitry Andric                                  CommandInterpreterRunOptions *options) {
33400b57cec5SDimitry Andric   // Always re-create the IOHandlerEditline in case the input changed. The old
33410b57cec5SDimitry Andric   // instance might have had a non-interactive input and now it does or vice
33420b57cec5SDimitry Andric   // versa.
33430b57cec5SDimitry Andric   if (force_create || !m_command_io_handler_sp) {
33440b57cec5SDimitry Andric     // Always re-create the IOHandlerEditline in case the input changed. The
33450b57cec5SDimitry Andric     // old instance might have had a non-interactive input and now it does or
33460b57cec5SDimitry Andric     // vice versa.
33470b57cec5SDimitry Andric     uint32_t flags = 0;
33480b57cec5SDimitry Andric 
33490b57cec5SDimitry Andric     if (options) {
33500b57cec5SDimitry Andric       if (options->m_stop_on_continue == eLazyBoolYes)
33510b57cec5SDimitry Andric         flags |= eHandleCommandFlagStopOnContinue;
33520b57cec5SDimitry Andric       if (options->m_stop_on_error == eLazyBoolYes)
33530b57cec5SDimitry Andric         flags |= eHandleCommandFlagStopOnError;
33540b57cec5SDimitry Andric       if (options->m_stop_on_crash == eLazyBoolYes)
33550b57cec5SDimitry Andric         flags |= eHandleCommandFlagStopOnCrash;
33560b57cec5SDimitry Andric       if (options->m_echo_commands != eLazyBoolNo)
33570b57cec5SDimitry Andric         flags |= eHandleCommandFlagEchoCommand;
33580b57cec5SDimitry Andric       if (options->m_echo_comment_commands != eLazyBoolNo)
33590b57cec5SDimitry Andric         flags |= eHandleCommandFlagEchoCommentCommand;
33600b57cec5SDimitry Andric       if (options->m_print_results != eLazyBoolNo)
33610b57cec5SDimitry Andric         flags |= eHandleCommandFlagPrintResult;
33620b57cec5SDimitry Andric       if (options->m_print_errors != eLazyBoolNo)
33630b57cec5SDimitry Andric         flags |= eHandleCommandFlagPrintErrors;
3364*0fca6ea1SDimitry Andric       if (options->m_allow_repeats == eLazyBoolYes)
3365*0fca6ea1SDimitry Andric         flags |= eHandleCommandFlagAllowRepeats;
33660b57cec5SDimitry Andric     } else {
33670b57cec5SDimitry Andric       flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
33680b57cec5SDimitry Andric               eHandleCommandFlagPrintErrors;
33690b57cec5SDimitry Andric     }
33700b57cec5SDimitry Andric 
33710b57cec5SDimitry Andric     m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
33720b57cec5SDimitry Andric         m_debugger, IOHandler::Type::CommandInterpreter,
33739dba64beSDimitry Andric         m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(),
33749dba64beSDimitry Andric         m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
33750b57cec5SDimitry Andric         llvm::StringRef(), // Continuation prompt
33760b57cec5SDimitry Andric         false, // Don't enable multiple line input, just single line commands
33770b57cec5SDimitry Andric         m_debugger.GetUseColor(),
33780b57cec5SDimitry Andric         0,      // Don't show line numbers
3379bdd1243dSDimitry Andric         *this); // IOHandlerDelegate
33800b57cec5SDimitry Andric   }
33810b57cec5SDimitry Andric   return m_command_io_handler_sp;
33820b57cec5SDimitry Andric }
33830b57cec5SDimitry Andric 
33845ffd83dbSDimitry Andric CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter(
33850b57cec5SDimitry Andric     CommandInterpreterRunOptions &options) {
33860b57cec5SDimitry Andric   // Always re-create the command interpreter when we run it in case any file
33870b57cec5SDimitry Andric   // handles have changed.
33880b57cec5SDimitry Andric   bool force_create = true;
33895ffd83dbSDimitry Andric   m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
33905ffd83dbSDimitry Andric   m_result = CommandInterpreterRunResult();
33910b57cec5SDimitry Andric 
33925ffd83dbSDimitry Andric   if (options.GetAutoHandleEvents())
33930b57cec5SDimitry Andric     m_debugger.StartEventHandlerThread();
33940b57cec5SDimitry Andric 
33955ffd83dbSDimitry Andric   if (options.GetSpawnThread()) {
33960b57cec5SDimitry Andric     m_debugger.StartIOHandlerThread();
33970b57cec5SDimitry Andric   } else {
339806c3fb27SDimitry Andric     // If the current thread is not managed by a host thread, we won't detect
339906c3fb27SDimitry Andric     // that this IS the CommandInterpreter IOHandler thread, so make it so:
340006c3fb27SDimitry Andric     HostThread new_io_handler_thread(Host::GetCurrentThread());
340106c3fb27SDimitry Andric     HostThread old_io_handler_thread =
340206c3fb27SDimitry Andric         m_debugger.SetIOHandlerThread(new_io_handler_thread);
34035ffd83dbSDimitry Andric     m_debugger.RunIOHandlers();
340406c3fb27SDimitry Andric     m_debugger.SetIOHandlerThread(old_io_handler_thread);
34050b57cec5SDimitry Andric 
34065ffd83dbSDimitry Andric     if (options.GetAutoHandleEvents())
34070b57cec5SDimitry Andric       m_debugger.StopEventHandlerThread();
34080b57cec5SDimitry Andric   }
34095ffd83dbSDimitry Andric 
34105ffd83dbSDimitry Andric   return m_result;
34110b57cec5SDimitry Andric }
34120b57cec5SDimitry Andric 
34130b57cec5SDimitry Andric CommandObject *
34140b57cec5SDimitry Andric CommandInterpreter::ResolveCommandImpl(std::string &command_line,
34150b57cec5SDimitry Andric                                        CommandReturnObject &result) {
34160b57cec5SDimitry Andric   std::string scratch_command(command_line); // working copy so we don't modify
34170b57cec5SDimitry Andric                                              // command_line unless we succeed
34180b57cec5SDimitry Andric   CommandObject *cmd_obj = nullptr;
34190b57cec5SDimitry Andric   StreamString revised_command_line;
34200b57cec5SDimitry Andric   bool wants_raw_input = false;
34210b57cec5SDimitry Andric   std::string next_word;
34220b57cec5SDimitry Andric   StringList matches;
34230b57cec5SDimitry Andric   bool done = false;
34240b57cec5SDimitry Andric   while (!done) {
34250b57cec5SDimitry Andric     char quote_char = '\0';
34260b57cec5SDimitry Andric     std::string suffix;
34270b57cec5SDimitry Andric     ExtractCommand(scratch_command, next_word, suffix, quote_char);
34280b57cec5SDimitry Andric     if (cmd_obj == nullptr) {
34290b57cec5SDimitry Andric       std::string full_name;
34300b57cec5SDimitry Andric       bool is_alias = GetAliasFullName(next_word, full_name);
34310b57cec5SDimitry Andric       cmd_obj = GetCommandObject(next_word, &matches);
34320b57cec5SDimitry Andric       bool is_real_command =
34330b57cec5SDimitry Andric           (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
34340b57cec5SDimitry Andric       if (!is_real_command) {
34350b57cec5SDimitry Andric         matches.Clear();
34360b57cec5SDimitry Andric         std::string alias_result;
34370b57cec5SDimitry Andric         cmd_obj =
34380b57cec5SDimitry Andric             BuildAliasResult(full_name, scratch_command, alias_result, result);
34390b57cec5SDimitry Andric         revised_command_line.Printf("%s", alias_result.c_str());
34400b57cec5SDimitry Andric         if (cmd_obj) {
34410b57cec5SDimitry Andric           wants_raw_input = cmd_obj->WantsRawCommandString();
34420b57cec5SDimitry Andric         }
34430b57cec5SDimitry Andric       } else {
34440b57cec5SDimitry Andric         if (cmd_obj) {
34450b57cec5SDimitry Andric           llvm::StringRef cmd_name = cmd_obj->GetCommandName();
34460b57cec5SDimitry Andric           revised_command_line.Printf("%s", cmd_name.str().c_str());
34470b57cec5SDimitry Andric           wants_raw_input = cmd_obj->WantsRawCommandString();
34480b57cec5SDimitry Andric         } else {
34490b57cec5SDimitry Andric           revised_command_line.Printf("%s", next_word.c_str());
34500b57cec5SDimitry Andric         }
34510b57cec5SDimitry Andric       }
34520b57cec5SDimitry Andric     } else {
34530b57cec5SDimitry Andric       if (cmd_obj->IsMultiwordObject()) {
34540b57cec5SDimitry Andric         CommandObject *sub_cmd_obj =
34550b57cec5SDimitry Andric             cmd_obj->GetSubcommandObject(next_word.c_str());
34560b57cec5SDimitry Andric         if (sub_cmd_obj) {
34570b57cec5SDimitry Andric           // The subcommand's name includes the parent command's name, so
34580b57cec5SDimitry Andric           // restart rather than append to the revised_command_line.
34590b57cec5SDimitry Andric           llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
34600b57cec5SDimitry Andric           revised_command_line.Clear();
34610b57cec5SDimitry Andric           revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
34620b57cec5SDimitry Andric           cmd_obj = sub_cmd_obj;
34630b57cec5SDimitry Andric           wants_raw_input = cmd_obj->WantsRawCommandString();
34640b57cec5SDimitry Andric         } else {
34650b57cec5SDimitry Andric           if (quote_char)
34660b57cec5SDimitry Andric             revised_command_line.Printf(" %c%s%s%c", quote_char,
34670b57cec5SDimitry Andric                                         next_word.c_str(), suffix.c_str(),
34680b57cec5SDimitry Andric                                         quote_char);
34690b57cec5SDimitry Andric           else
34700b57cec5SDimitry Andric             revised_command_line.Printf(" %s%s", next_word.c_str(),
34710b57cec5SDimitry Andric                                         suffix.c_str());
34720b57cec5SDimitry Andric           done = true;
34730b57cec5SDimitry Andric         }
34740b57cec5SDimitry Andric       } else {
34750b57cec5SDimitry Andric         if (quote_char)
34760b57cec5SDimitry Andric           revised_command_line.Printf(" %c%s%s%c", quote_char,
34770b57cec5SDimitry Andric                                       next_word.c_str(), suffix.c_str(),
34780b57cec5SDimitry Andric                                       quote_char);
34790b57cec5SDimitry Andric         else
34800b57cec5SDimitry Andric           revised_command_line.Printf(" %s%s", next_word.c_str(),
34810b57cec5SDimitry Andric                                       suffix.c_str());
34820b57cec5SDimitry Andric         done = true;
34830b57cec5SDimitry Andric       }
34840b57cec5SDimitry Andric     }
34850b57cec5SDimitry Andric 
34860b57cec5SDimitry Andric     if (cmd_obj == nullptr) {
34870b57cec5SDimitry Andric       const size_t num_matches = matches.GetSize();
34880b57cec5SDimitry Andric       if (matches.GetSize() > 1) {
34890b57cec5SDimitry Andric         StreamString error_msg;
34900b57cec5SDimitry Andric         error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
34910b57cec5SDimitry Andric                          next_word.c_str());
34920b57cec5SDimitry Andric 
34930b57cec5SDimitry Andric         for (uint32_t i = 0; i < num_matches; ++i) {
34940b57cec5SDimitry Andric           error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
34950b57cec5SDimitry Andric         }
34960b57cec5SDimitry Andric         result.AppendRawError(error_msg.GetString());
34970b57cec5SDimitry Andric       } else {
34980b57cec5SDimitry Andric         // We didn't have only one match, otherwise we wouldn't get here.
34990b57cec5SDimitry Andric         lldbassert(num_matches == 0);
35000b57cec5SDimitry Andric         result.AppendErrorWithFormat("'%s' is not a valid command.\n",
35010b57cec5SDimitry Andric                                      next_word.c_str());
35020b57cec5SDimitry Andric       }
35030b57cec5SDimitry Andric       return nullptr;
35040b57cec5SDimitry Andric     }
35050b57cec5SDimitry Andric 
35060b57cec5SDimitry Andric     if (cmd_obj->IsMultiwordObject()) {
35070b57cec5SDimitry Andric       if (!suffix.empty()) {
35080b57cec5SDimitry Andric         result.AppendErrorWithFormat(
35090b57cec5SDimitry Andric             "command '%s' did not recognize '%s%s%s' as valid (subcommand "
35100b57cec5SDimitry Andric             "might be invalid).\n",
35110b57cec5SDimitry Andric             cmd_obj->GetCommandName().str().c_str(),
35120b57cec5SDimitry Andric             next_word.empty() ? "" : next_word.c_str(),
35130b57cec5SDimitry Andric             next_word.empty() ? " -- " : " ", suffix.c_str());
35140b57cec5SDimitry Andric         return nullptr;
35150b57cec5SDimitry Andric       }
35160b57cec5SDimitry Andric     } else {
35170b57cec5SDimitry Andric       // If we found a normal command, we are done
35180b57cec5SDimitry Andric       done = true;
35190b57cec5SDimitry Andric       if (!suffix.empty()) {
35200b57cec5SDimitry Andric         switch (suffix[0]) {
35210b57cec5SDimitry Andric         case '/':
35220b57cec5SDimitry Andric           // GDB format suffixes
35230b57cec5SDimitry Andric           {
35240b57cec5SDimitry Andric             Options *command_options = cmd_obj->GetOptions();
35250b57cec5SDimitry Andric             if (command_options &&
35260b57cec5SDimitry Andric                 command_options->SupportsLongOption("gdb-format")) {
35270b57cec5SDimitry Andric               std::string gdb_format_option("--gdb-format=");
35280b57cec5SDimitry Andric               gdb_format_option += (suffix.c_str() + 1);
35290b57cec5SDimitry Andric 
35305ffd83dbSDimitry Andric               std::string cmd = std::string(revised_command_line.GetString());
35310b57cec5SDimitry Andric               size_t arg_terminator_idx = FindArgumentTerminator(cmd);
35320b57cec5SDimitry Andric               if (arg_terminator_idx != std::string::npos) {
35330b57cec5SDimitry Andric                 // Insert the gdb format option before the "--" that terminates
35340b57cec5SDimitry Andric                 // options
35350b57cec5SDimitry Andric                 gdb_format_option.append(1, ' ');
35360b57cec5SDimitry Andric                 cmd.insert(arg_terminator_idx, gdb_format_option);
35370b57cec5SDimitry Andric                 revised_command_line.Clear();
35380b57cec5SDimitry Andric                 revised_command_line.PutCString(cmd);
35390b57cec5SDimitry Andric               } else
35400b57cec5SDimitry Andric                 revised_command_line.Printf(" %s", gdb_format_option.c_str());
35410b57cec5SDimitry Andric 
35420b57cec5SDimitry Andric               if (wants_raw_input &&
35430b57cec5SDimitry Andric                   FindArgumentTerminator(cmd) == std::string::npos)
35440b57cec5SDimitry Andric                 revised_command_line.PutCString(" --");
35450b57cec5SDimitry Andric             } else {
35460b57cec5SDimitry Andric               result.AppendErrorWithFormat(
35470b57cec5SDimitry Andric                   "the '%s' command doesn't support the --gdb-format option\n",
35480b57cec5SDimitry Andric                   cmd_obj->GetCommandName().str().c_str());
35490b57cec5SDimitry Andric               return nullptr;
35500b57cec5SDimitry Andric             }
35510b57cec5SDimitry Andric           }
35520b57cec5SDimitry Andric           break;
35530b57cec5SDimitry Andric 
35540b57cec5SDimitry Andric         default:
35550b57cec5SDimitry Andric           result.AppendErrorWithFormat(
35560b57cec5SDimitry Andric               "unknown command shorthand suffix: '%s'\n", suffix.c_str());
35570b57cec5SDimitry Andric           return nullptr;
35580b57cec5SDimitry Andric         }
35590b57cec5SDimitry Andric       }
35600b57cec5SDimitry Andric     }
35610b57cec5SDimitry Andric     if (scratch_command.empty())
35620b57cec5SDimitry Andric       done = true;
35630b57cec5SDimitry Andric   }
35640b57cec5SDimitry Andric 
35650b57cec5SDimitry Andric   if (!scratch_command.empty())
35660b57cec5SDimitry Andric     revised_command_line.Printf(" %s", scratch_command.c_str());
35670b57cec5SDimitry Andric 
35680b57cec5SDimitry Andric   if (cmd_obj != nullptr)
35695ffd83dbSDimitry Andric     command_line = std::string(revised_command_line.GetString());
35700b57cec5SDimitry Andric 
35710b57cec5SDimitry Andric   return cmd_obj;
35720b57cec5SDimitry Andric }
3573*0fca6ea1SDimitry Andric 
3574*0fca6ea1SDimitry Andric llvm::json::Value CommandInterpreter::GetStatistics() {
3575*0fca6ea1SDimitry Andric   llvm::json::Object stats;
3576*0fca6ea1SDimitry Andric   for (const auto &command_usage : m_command_usages)
3577*0fca6ea1SDimitry Andric     stats.try_emplace(command_usage.getKey(), command_usage.getValue());
3578*0fca6ea1SDimitry Andric   return stats;
3579*0fca6ea1SDimitry Andric }
3580*0fca6ea1SDimitry Andric 
3581*0fca6ea1SDimitry Andric const StructuredData::Array &CommandInterpreter::GetTranscript() const {
3582*0fca6ea1SDimitry Andric   return m_transcript;
3583*0fca6ea1SDimitry Andric }
3584