xref: /openbsd-src/gnu/llvm/lldb/source/Interpreter/CommandInterpreter.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- CommandInterpreter.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9be691f3bSpatrick #include <cstdlib>
10be691f3bSpatrick #include <limits>
11061da546Spatrick #include <memory>
12*f6aab3d8Srobert #include <optional>
13061da546Spatrick #include <string>
14061da546Spatrick #include <vector>
15061da546Spatrick 
16061da546Spatrick #include "Commands/CommandObjectApropos.h"
17061da546Spatrick #include "Commands/CommandObjectBreakpoint.h"
18061da546Spatrick #include "Commands/CommandObjectCommands.h"
19*f6aab3d8Srobert #include "Commands/CommandObjectDWIMPrint.h"
20*f6aab3d8Srobert #include "Commands/CommandObjectDiagnostics.h"
21061da546Spatrick #include "Commands/CommandObjectDisassemble.h"
22061da546Spatrick #include "Commands/CommandObjectExpression.h"
23061da546Spatrick #include "Commands/CommandObjectFrame.h"
24061da546Spatrick #include "Commands/CommandObjectGUI.h"
25061da546Spatrick #include "Commands/CommandObjectHelp.h"
26061da546Spatrick #include "Commands/CommandObjectLanguage.h"
27061da546Spatrick #include "Commands/CommandObjectLog.h"
28061da546Spatrick #include "Commands/CommandObjectMemory.h"
29061da546Spatrick #include "Commands/CommandObjectPlatform.h"
30061da546Spatrick #include "Commands/CommandObjectPlugin.h"
31061da546Spatrick #include "Commands/CommandObjectProcess.h"
32061da546Spatrick #include "Commands/CommandObjectQuit.h"
33be691f3bSpatrick #include "Commands/CommandObjectRegexCommand.h"
34061da546Spatrick #include "Commands/CommandObjectRegister.h"
35be691f3bSpatrick #include "Commands/CommandObjectScript.h"
36be691f3bSpatrick #include "Commands/CommandObjectSession.h"
37061da546Spatrick #include "Commands/CommandObjectSettings.h"
38061da546Spatrick #include "Commands/CommandObjectSource.h"
39061da546Spatrick #include "Commands/CommandObjectStats.h"
40061da546Spatrick #include "Commands/CommandObjectTarget.h"
41061da546Spatrick #include "Commands/CommandObjectThread.h"
42be691f3bSpatrick #include "Commands/CommandObjectTrace.h"
43061da546Spatrick #include "Commands/CommandObjectType.h"
44061da546Spatrick #include "Commands/CommandObjectVersion.h"
45061da546Spatrick #include "Commands/CommandObjectWatchpoint.h"
46061da546Spatrick 
47061da546Spatrick #include "lldb/Core/Debugger.h"
48061da546Spatrick #include "lldb/Core/PluginManager.h"
49061da546Spatrick #include "lldb/Core/StreamFile.h"
50*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
51061da546Spatrick #include "lldb/Utility/Log.h"
52061da546Spatrick #include "lldb/Utility/State.h"
53061da546Spatrick #include "lldb/Utility/Stream.h"
54061da546Spatrick #include "lldb/Utility/Timer.h"
55061da546Spatrick 
56061da546Spatrick #include "lldb/Host/Config.h"
57061da546Spatrick #if LLDB_ENABLE_LIBEDIT
58061da546Spatrick #include "lldb/Host/Editline.h"
59061da546Spatrick #endif
60be691f3bSpatrick #include "lldb/Host/File.h"
61be691f3bSpatrick #include "lldb/Host/FileCache.h"
62061da546Spatrick #include "lldb/Host/Host.h"
63061da546Spatrick #include "lldb/Host/HostInfo.h"
64061da546Spatrick 
65061da546Spatrick #include "lldb/Interpreter/CommandCompletions.h"
66061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
67061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
68061da546Spatrick #include "lldb/Interpreter/OptionValueProperties.h"
69061da546Spatrick #include "lldb/Interpreter/Options.h"
70061da546Spatrick #include "lldb/Interpreter/Property.h"
71061da546Spatrick #include "lldb/Utility/Args.h"
72061da546Spatrick 
73be691f3bSpatrick #include "lldb/Target/Language.h"
74061da546Spatrick #include "lldb/Target/Process.h"
75061da546Spatrick #include "lldb/Target/StopInfo.h"
76061da546Spatrick #include "lldb/Target/TargetList.h"
77061da546Spatrick #include "lldb/Target/Thread.h"
78061da546Spatrick #include "lldb/Target/UnixSignals.h"
79061da546Spatrick 
80061da546Spatrick #include "llvm/ADT/STLExtras.h"
81be691f3bSpatrick #include "llvm/ADT/ScopeExit.h"
82061da546Spatrick #include "llvm/ADT/SmallString.h"
83061da546Spatrick #include "llvm/Support/FormatAdapters.h"
84061da546Spatrick #include "llvm/Support/Path.h"
85061da546Spatrick #include "llvm/Support/PrettyStackTrace.h"
86be691f3bSpatrick #include "llvm/Support/ScopedPrinter.h"
87061da546Spatrick 
88*f6aab3d8Srobert #if defined(__APPLE__)
89*f6aab3d8Srobert #include <TargetConditionals.h>
90*f6aab3d8Srobert #endif
91*f6aab3d8Srobert 
92061da546Spatrick using namespace lldb;
93061da546Spatrick using namespace lldb_private;
94061da546Spatrick 
95061da546Spatrick static const char *k_white_space = " \t\v";
96061da546Spatrick 
97061da546Spatrick static constexpr const char *InitFileWarning =
98061da546Spatrick     "There is a .lldbinit file in the current directory which is not being "
99061da546Spatrick     "read.\n"
100061da546Spatrick     "To silence this warning without sourcing in the local .lldbinit,\n"
101061da546Spatrick     "add the following to the lldbinit file in your home directory:\n"
102061da546Spatrick     "    settings set target.load-cwd-lldbinit false\n"
103061da546Spatrick     "To allow lldb to source .lldbinit files in the current working "
104061da546Spatrick     "directory,\n"
105061da546Spatrick     "set the value of this variable to true.  Only do so if you understand "
106061da546Spatrick     "and\n"
107061da546Spatrick     "accept the security risk.";
108061da546Spatrick 
109*f6aab3d8Srobert const char *CommandInterpreter::g_no_argument = "<no-argument>";
110*f6aab3d8Srobert const char *CommandInterpreter::g_need_argument = "<need-argument>";
111*f6aab3d8Srobert const char *CommandInterpreter::g_argument = "<argument>";
112*f6aab3d8Srobert 
113*f6aab3d8Srobert 
114061da546Spatrick #define LLDB_PROPERTIES_interpreter
115061da546Spatrick #include "InterpreterProperties.inc"
116061da546Spatrick 
117061da546Spatrick enum {
118061da546Spatrick #define LLDB_PROPERTIES_interpreter
119061da546Spatrick #include "InterpreterPropertiesEnum.inc"
120061da546Spatrick };
121061da546Spatrick 
GetStaticBroadcasterClass()122061da546Spatrick ConstString &CommandInterpreter::GetStaticBroadcasterClass() {
123061da546Spatrick   static ConstString class_name("lldb.commandInterpreter");
124061da546Spatrick   return class_name;
125061da546Spatrick }
126061da546Spatrick 
CommandInterpreter(Debugger & debugger,bool synchronous_execution)127061da546Spatrick CommandInterpreter::CommandInterpreter(Debugger &debugger,
128061da546Spatrick                                        bool synchronous_execution)
129061da546Spatrick     : Broadcaster(debugger.GetBroadcasterManager(),
130061da546Spatrick                   CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
131061da546Spatrick       Properties(OptionValuePropertiesSP(
132061da546Spatrick           new OptionValueProperties(ConstString("interpreter")))),
133061da546Spatrick       IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
134061da546Spatrick       m_debugger(debugger), m_synchronous_execution(true),
135061da546Spatrick       m_skip_lldbinit_files(false), m_skip_app_init_files(false),
136be691f3bSpatrick       m_comment_char('#'), m_batch_command_mode(false),
137*f6aab3d8Srobert       m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
138*f6aab3d8Srobert       m_command_source_depth(0) {
139061da546Spatrick   SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
140061da546Spatrick   SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
141061da546Spatrick   SetEventName(eBroadcastBitQuitCommandReceived, "quit");
142061da546Spatrick   SetSynchronous(synchronous_execution);
143061da546Spatrick   CheckInWithManager();
144061da546Spatrick   m_collection_sp->Initialize(g_interpreter_properties);
145061da546Spatrick }
146061da546Spatrick 
GetExpandRegexAliases() const147061da546Spatrick bool CommandInterpreter::GetExpandRegexAliases() const {
148061da546Spatrick   const uint32_t idx = ePropertyExpandRegexAliases;
149061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
150061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
151061da546Spatrick }
152061da546Spatrick 
GetPromptOnQuit() const153061da546Spatrick bool CommandInterpreter::GetPromptOnQuit() const {
154061da546Spatrick   const uint32_t idx = ePropertyPromptOnQuit;
155061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
156061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
157061da546Spatrick }
158061da546Spatrick 
SetPromptOnQuit(bool enable)159061da546Spatrick void CommandInterpreter::SetPromptOnQuit(bool enable) {
160061da546Spatrick   const uint32_t idx = ePropertyPromptOnQuit;
161061da546Spatrick   m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
162061da546Spatrick }
163061da546Spatrick 
GetSaveSessionOnQuit() const164be691f3bSpatrick bool CommandInterpreter::GetSaveSessionOnQuit() const {
165be691f3bSpatrick   const uint32_t idx = ePropertySaveSessionOnQuit;
166be691f3bSpatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
167be691f3bSpatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
168be691f3bSpatrick }
169be691f3bSpatrick 
SetSaveSessionOnQuit(bool enable)170be691f3bSpatrick void CommandInterpreter::SetSaveSessionOnQuit(bool enable) {
171be691f3bSpatrick   const uint32_t idx = ePropertySaveSessionOnQuit;
172be691f3bSpatrick   m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
173be691f3bSpatrick }
174be691f3bSpatrick 
GetOpenTranscriptInEditor() const175*f6aab3d8Srobert bool CommandInterpreter::GetOpenTranscriptInEditor() const {
176*f6aab3d8Srobert   const uint32_t idx = ePropertyOpenTranscriptInEditor;
177*f6aab3d8Srobert   return m_collection_sp->GetPropertyAtIndexAsBoolean(
178*f6aab3d8Srobert       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
179*f6aab3d8Srobert }
180*f6aab3d8Srobert 
SetOpenTranscriptInEditor(bool enable)181*f6aab3d8Srobert void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) {
182*f6aab3d8Srobert   const uint32_t idx = ePropertyOpenTranscriptInEditor;
183*f6aab3d8Srobert   m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
184*f6aab3d8Srobert }
185*f6aab3d8Srobert 
GetSaveSessionDirectory() const186be691f3bSpatrick FileSpec CommandInterpreter::GetSaveSessionDirectory() const {
187be691f3bSpatrick   const uint32_t idx = ePropertySaveSessionDirectory;
188be691f3bSpatrick   return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx);
189be691f3bSpatrick }
190be691f3bSpatrick 
SetSaveSessionDirectory(llvm::StringRef path)191be691f3bSpatrick void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) {
192be691f3bSpatrick   const uint32_t idx = ePropertySaveSessionDirectory;
193be691f3bSpatrick   m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path);
194be691f3bSpatrick }
195be691f3bSpatrick 
GetEchoCommands() const196061da546Spatrick bool CommandInterpreter::GetEchoCommands() const {
197061da546Spatrick   const uint32_t idx = ePropertyEchoCommands;
198061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
199061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
200061da546Spatrick }
201061da546Spatrick 
SetEchoCommands(bool enable)202061da546Spatrick void CommandInterpreter::SetEchoCommands(bool enable) {
203061da546Spatrick   const uint32_t idx = ePropertyEchoCommands;
204061da546Spatrick   m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
205061da546Spatrick }
206061da546Spatrick 
GetEchoCommentCommands() const207061da546Spatrick bool CommandInterpreter::GetEchoCommentCommands() const {
208061da546Spatrick   const uint32_t idx = ePropertyEchoCommentCommands;
209061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
210061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
211061da546Spatrick }
212061da546Spatrick 
SetEchoCommentCommands(bool enable)213061da546Spatrick void CommandInterpreter::SetEchoCommentCommands(bool enable) {
214061da546Spatrick   const uint32_t idx = ePropertyEchoCommentCommands;
215061da546Spatrick   m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
216061da546Spatrick }
217061da546Spatrick 
AllowExitCodeOnQuit(bool allow)218061da546Spatrick void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
219061da546Spatrick   m_allow_exit_code = allow;
220061da546Spatrick   if (!allow)
221061da546Spatrick     m_quit_exit_code.reset();
222061da546Spatrick }
223061da546Spatrick 
SetQuitExitCode(int exit_code)224061da546Spatrick bool CommandInterpreter::SetQuitExitCode(int exit_code) {
225061da546Spatrick   if (!m_allow_exit_code)
226061da546Spatrick     return false;
227061da546Spatrick   m_quit_exit_code = exit_code;
228061da546Spatrick   return true;
229061da546Spatrick }
230061da546Spatrick 
GetQuitExitCode(bool & exited) const231061da546Spatrick int CommandInterpreter::GetQuitExitCode(bool &exited) const {
232*f6aab3d8Srobert   exited = m_quit_exit_code.has_value();
233061da546Spatrick   if (exited)
234061da546Spatrick     return *m_quit_exit_code;
235061da546Spatrick   return 0;
236061da546Spatrick }
237061da546Spatrick 
ResolveCommand(const char * command_line,CommandReturnObject & result)238061da546Spatrick void CommandInterpreter::ResolveCommand(const char *command_line,
239061da546Spatrick                                         CommandReturnObject &result) {
240061da546Spatrick   std::string command = command_line;
241061da546Spatrick   if (ResolveCommandImpl(command, result) != nullptr) {
242061da546Spatrick     result.AppendMessageWithFormat("%s", command.c_str());
243061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishResult);
244061da546Spatrick   }
245061da546Spatrick }
246061da546Spatrick 
GetStopCmdSourceOnError() const247061da546Spatrick bool CommandInterpreter::GetStopCmdSourceOnError() const {
248061da546Spatrick   const uint32_t idx = ePropertyStopCmdSourceOnError;
249061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
250061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
251061da546Spatrick }
252061da546Spatrick 
GetSpaceReplPrompts() const253061da546Spatrick bool CommandInterpreter::GetSpaceReplPrompts() const {
254061da546Spatrick   const uint32_t idx = ePropertySpaceReplPrompts;
255061da546Spatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
256061da546Spatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
257061da546Spatrick }
258061da546Spatrick 
GetRepeatPreviousCommand() const259be691f3bSpatrick bool CommandInterpreter::GetRepeatPreviousCommand() const {
260be691f3bSpatrick   const uint32_t idx = ePropertyRepeatPreviousCommand;
261be691f3bSpatrick   return m_collection_sp->GetPropertyAtIndexAsBoolean(
262be691f3bSpatrick       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
263be691f3bSpatrick }
264be691f3bSpatrick 
GetRequireCommandOverwrite() const265*f6aab3d8Srobert bool CommandInterpreter::GetRequireCommandOverwrite() const {
266*f6aab3d8Srobert   const uint32_t idx = ePropertyRequireCommandOverwrite;
267*f6aab3d8Srobert   return m_collection_sp->GetPropertyAtIndexAsBoolean(
268*f6aab3d8Srobert       nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
269*f6aab3d8Srobert }
270*f6aab3d8Srobert 
Initialize()271061da546Spatrick void CommandInterpreter::Initialize() {
272be691f3bSpatrick   LLDB_SCOPED_TIMER();
273061da546Spatrick 
274dda28197Spatrick   CommandReturnObject result(m_debugger.GetUseColor());
275061da546Spatrick 
276061da546Spatrick   LoadCommandDictionary();
277061da546Spatrick 
278061da546Spatrick   // An alias arguments vector to reuse - reset it before use...
279061da546Spatrick   OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
280061da546Spatrick 
281061da546Spatrick   // Set up some initial aliases.
282be691f3bSpatrick   CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit");
283061da546Spatrick   if (cmd_obj_sp) {
284061da546Spatrick     AddAlias("q", cmd_obj_sp);
285061da546Spatrick     AddAlias("exit", cmd_obj_sp);
286061da546Spatrick   }
287061da546Spatrick 
288be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-attach");
289061da546Spatrick   if (cmd_obj_sp)
290061da546Spatrick     AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
291061da546Spatrick 
292be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("process detach");
293061da546Spatrick   if (cmd_obj_sp) {
294061da546Spatrick     AddAlias("detach", cmd_obj_sp);
295061da546Spatrick   }
296061da546Spatrick 
297be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("process continue");
298061da546Spatrick   if (cmd_obj_sp) {
299061da546Spatrick     AddAlias("c", cmd_obj_sp);
300061da546Spatrick     AddAlias("continue", cmd_obj_sp);
301061da546Spatrick   }
302061da546Spatrick 
303be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-break");
304061da546Spatrick   if (cmd_obj_sp)
305061da546Spatrick     AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
306061da546Spatrick 
307be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
308061da546Spatrick   if (cmd_obj_sp)
309061da546Spatrick     AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
310061da546Spatrick 
311be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread step-inst");
312061da546Spatrick   if (cmd_obj_sp) {
313061da546Spatrick     AddAlias("stepi", cmd_obj_sp);
314061da546Spatrick     AddAlias("si", cmd_obj_sp);
315061da546Spatrick   }
316061da546Spatrick 
317be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
318061da546Spatrick   if (cmd_obj_sp) {
319061da546Spatrick     AddAlias("nexti", cmd_obj_sp);
320061da546Spatrick     AddAlias("ni", cmd_obj_sp);
321061da546Spatrick   }
322061da546Spatrick 
323be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread step-in");
324061da546Spatrick   if (cmd_obj_sp) {
325061da546Spatrick     AddAlias("s", cmd_obj_sp);
326061da546Spatrick     AddAlias("step", cmd_obj_sp);
327061da546Spatrick     CommandAlias *sif_alias = AddAlias(
328061da546Spatrick         "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
329061da546Spatrick     if (sif_alias) {
330061da546Spatrick       sif_alias->SetHelp("Step through the current block, stopping if you step "
331061da546Spatrick                          "directly into a function whose name matches the "
332061da546Spatrick                          "TargetFunctionName.");
333061da546Spatrick       sif_alias->SetSyntax("sif <TargetFunctionName>");
334061da546Spatrick     }
335061da546Spatrick   }
336061da546Spatrick 
337be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread step-over");
338061da546Spatrick   if (cmd_obj_sp) {
339061da546Spatrick     AddAlias("n", cmd_obj_sp);
340061da546Spatrick     AddAlias("next", cmd_obj_sp);
341061da546Spatrick   }
342061da546Spatrick 
343be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread step-out");
344061da546Spatrick   if (cmd_obj_sp) {
345061da546Spatrick     AddAlias("finish", cmd_obj_sp);
346061da546Spatrick   }
347061da546Spatrick 
348be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("frame select");
349061da546Spatrick   if (cmd_obj_sp) {
350061da546Spatrick     AddAlias("f", cmd_obj_sp);
351061da546Spatrick   }
352061da546Spatrick 
353be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("thread select");
354061da546Spatrick   if (cmd_obj_sp) {
355061da546Spatrick     AddAlias("t", cmd_obj_sp);
356061da546Spatrick   }
357061da546Spatrick 
358be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-jump");
359061da546Spatrick   if (cmd_obj_sp) {
360061da546Spatrick     AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
361061da546Spatrick     AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
362061da546Spatrick   }
363061da546Spatrick 
364be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-list");
365061da546Spatrick   if (cmd_obj_sp) {
366061da546Spatrick     AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
367061da546Spatrick     AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
368061da546Spatrick   }
369061da546Spatrick 
370be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-env");
371061da546Spatrick   if (cmd_obj_sp)
372061da546Spatrick     AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
373061da546Spatrick 
374be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("memory read");
375061da546Spatrick   if (cmd_obj_sp)
376061da546Spatrick     AddAlias("x", cmd_obj_sp);
377061da546Spatrick 
378be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-up");
379061da546Spatrick   if (cmd_obj_sp)
380061da546Spatrick     AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
381061da546Spatrick 
382be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-down");
383061da546Spatrick   if (cmd_obj_sp)
384061da546Spatrick     AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
385061da546Spatrick 
386be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-display");
387061da546Spatrick   if (cmd_obj_sp)
388061da546Spatrick     AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
389061da546Spatrick 
390be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("disassemble");
391061da546Spatrick   if (cmd_obj_sp)
392061da546Spatrick     AddAlias("dis", cmd_obj_sp);
393061da546Spatrick 
394be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("disassemble");
395061da546Spatrick   if (cmd_obj_sp)
396061da546Spatrick     AddAlias("di", cmd_obj_sp);
397061da546Spatrick 
398be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
399061da546Spatrick   if (cmd_obj_sp)
400061da546Spatrick     AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
401061da546Spatrick 
402be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("_regexp-bt");
403061da546Spatrick   if (cmd_obj_sp)
404061da546Spatrick     AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
405061da546Spatrick 
406be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("target create");
407061da546Spatrick   if (cmd_obj_sp)
408061da546Spatrick     AddAlias("file", cmd_obj_sp);
409061da546Spatrick 
410be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("target modules");
411061da546Spatrick   if (cmd_obj_sp)
412061da546Spatrick     AddAlias("image", cmd_obj_sp);
413061da546Spatrick 
414061da546Spatrick   alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
415061da546Spatrick 
416be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("expression");
417061da546Spatrick   if (cmd_obj_sp) {
418061da546Spatrick     AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
419061da546Spatrick     AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
420061da546Spatrick     AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
421dda28197Spatrick     if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) {
422061da546Spatrick       po->SetHelp("Evaluate an expression on the current thread.  Displays any "
423061da546Spatrick                   "returned value with formatting "
424061da546Spatrick                   "controlled by the type's author.");
425061da546Spatrick       po->SetHelpLong("");
426061da546Spatrick     }
427061da546Spatrick     CommandAlias *parray_alias =
428061da546Spatrick         AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
429061da546Spatrick     if (parray_alias) {
430061da546Spatrick         parray_alias->SetHelp
431061da546Spatrick           ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
432061da546Spatrick            "to get a typed-pointer-to-an-array in memory, and will display "
433061da546Spatrick            "COUNT elements of that type from the array.");
434061da546Spatrick         parray_alias->SetHelpLong("");
435061da546Spatrick     }
436061da546Spatrick     CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
437061da546Spatrick              "--object-description --element-count %1 --");
438061da546Spatrick     if (poarray_alias) {
439061da546Spatrick       poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
440061da546Spatrick           "evaluate EXPRESSION to get the address of an array of COUNT "
441061da546Spatrick           "objects in memory, and will call po on them.");
442061da546Spatrick       poarray_alias->SetHelpLong("");
443061da546Spatrick     }
444061da546Spatrick   }
445061da546Spatrick 
446be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("platform shell");
447dda28197Spatrick   if (cmd_obj_sp) {
448dda28197Spatrick     CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
449dda28197Spatrick     if (shell_alias) {
450dda28197Spatrick       shell_alias->SetHelp("Run a shell command on the host.");
451dda28197Spatrick       shell_alias->SetHelpLong("");
452dda28197Spatrick       shell_alias->SetSyntax("shell <shell-command>");
453dda28197Spatrick     }
454dda28197Spatrick   }
455dda28197Spatrick 
456be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("process kill");
457061da546Spatrick   if (cmd_obj_sp) {
458061da546Spatrick     AddAlias("kill", cmd_obj_sp);
459061da546Spatrick   }
460061da546Spatrick 
461be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("process launch");
462061da546Spatrick   if (cmd_obj_sp) {
463061da546Spatrick     alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
464be691f3bSpatrick #if defined(__APPLE__)
465*f6aab3d8Srobert #if TARGET_OS_IPHONE
466061da546Spatrick     AddAlias("r", cmd_obj_sp, "--");
467061da546Spatrick     AddAlias("run", cmd_obj_sp, "--");
468061da546Spatrick #else
469061da546Spatrick     AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
470061da546Spatrick     AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
471be691f3bSpatrick #endif
472061da546Spatrick #else
473061da546Spatrick     StreamString defaultshell;
474061da546Spatrick     defaultshell.Printf("--shell=%s --",
475061da546Spatrick                         HostInfo::GetDefaultShell().GetPath().c_str());
476061da546Spatrick     AddAlias("r", cmd_obj_sp, defaultshell.GetString());
477061da546Spatrick     AddAlias("run", cmd_obj_sp, defaultshell.GetString());
478061da546Spatrick #endif
479061da546Spatrick   }
480061da546Spatrick 
481be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("target symbols add");
482061da546Spatrick   if (cmd_obj_sp) {
483061da546Spatrick     AddAlias("add-dsym", cmd_obj_sp);
484061da546Spatrick   }
485061da546Spatrick 
486be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("breakpoint set");
487061da546Spatrick   if (cmd_obj_sp) {
488061da546Spatrick     AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
489061da546Spatrick   }
490061da546Spatrick 
491be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("frame variable");
492061da546Spatrick   if (cmd_obj_sp) {
493061da546Spatrick     AddAlias("v", cmd_obj_sp);
494061da546Spatrick     AddAlias("var", cmd_obj_sp);
495061da546Spatrick     AddAlias("vo", cmd_obj_sp, "--object-description");
496061da546Spatrick   }
497061da546Spatrick 
498be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("register");
499061da546Spatrick   if (cmd_obj_sp) {
500061da546Spatrick     AddAlias("re", cmd_obj_sp);
501061da546Spatrick   }
502be691f3bSpatrick 
503be691f3bSpatrick   cmd_obj_sp = GetCommandSPExact("session history");
504be691f3bSpatrick   if (cmd_obj_sp) {
505be691f3bSpatrick     AddAlias("history", cmd_obj_sp);
506be691f3bSpatrick   }
507061da546Spatrick }
508061da546Spatrick 
Clear()509061da546Spatrick void CommandInterpreter::Clear() {
510061da546Spatrick   m_command_io_handler_sp.reset();
511061da546Spatrick }
512061da546Spatrick 
ProcessEmbeddedScriptCommands(const char * arg)513061da546Spatrick const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
514061da546Spatrick   // This function has not yet been implemented.
515061da546Spatrick 
516061da546Spatrick   // Look for any embedded script command
517061da546Spatrick   // If found,
518061da546Spatrick   //    get interpreter object from the command dictionary,
519061da546Spatrick   //    call execute_one_command on it,
520061da546Spatrick   //    get the results as a string,
521061da546Spatrick   //    substitute that string for current stuff.
522061da546Spatrick 
523061da546Spatrick   return arg;
524061da546Spatrick }
525061da546Spatrick 
526be691f3bSpatrick #define REGISTER_COMMAND_OBJECT(NAME, CLASS)                                   \
527be691f3bSpatrick   m_command_dict[NAME] = std::make_shared<CLASS>(*this);
528be691f3bSpatrick 
LoadCommandDictionary()529061da546Spatrick void CommandInterpreter::LoadCommandDictionary() {
530be691f3bSpatrick   LLDB_SCOPED_TIMER();
531061da546Spatrick 
532be691f3bSpatrick   REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
533be691f3bSpatrick   REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
534be691f3bSpatrick   REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
535*f6aab3d8Srobert   REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
536be691f3bSpatrick   REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
537*f6aab3d8Srobert   REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
538be691f3bSpatrick   REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
539be691f3bSpatrick   REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
540be691f3bSpatrick   REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
541be691f3bSpatrick   REGISTER_COMMAND_OBJECT("help", CommandObjectHelp);
542be691f3bSpatrick   REGISTER_COMMAND_OBJECT("log", CommandObjectLog);
543be691f3bSpatrick   REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory);
544be691f3bSpatrick   REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform);
545be691f3bSpatrick   REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin);
546be691f3bSpatrick   REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
547be691f3bSpatrick   REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
548be691f3bSpatrick   REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
549be691f3bSpatrick   REGISTER_COMMAND_OBJECT("script", CommandObjectScript);
550be691f3bSpatrick   REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
551be691f3bSpatrick   REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
552be691f3bSpatrick   REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
553be691f3bSpatrick   REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats);
554be691f3bSpatrick   REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget);
555be691f3bSpatrick   REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread);
556be691f3bSpatrick   REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace);
557be691f3bSpatrick   REGISTER_COMMAND_OBJECT("type", CommandObjectType);
558be691f3bSpatrick   REGISTER_COMMAND_OBJECT("version", CommandObjectVersion);
559be691f3bSpatrick   REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint);
560be691f3bSpatrick   REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage);
561061da546Spatrick 
562dda28197Spatrick   // clang-format off
563061da546Spatrick   const char *break_regexes[][2] = {
564dda28197Spatrick       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
565dda28197Spatrick        "breakpoint set --file '%1' --line %2 --column %3"},
566061da546Spatrick       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
567061da546Spatrick        "breakpoint set --file '%1' --line %2"},
568061da546Spatrick       {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
569061da546Spatrick       {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
570061da546Spatrick       {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
571061da546Spatrick       {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
572061da546Spatrick        "breakpoint set --name '%1'"},
573061da546Spatrick       {"^(-.*)$", "breakpoint set %1"},
574061da546Spatrick       {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
575061da546Spatrick        "breakpoint set --name '%2' --shlib '%1'"},
576061da546Spatrick       {"^\\&(.*[^[:space:]])[[:space:]]*$",
577061da546Spatrick        "breakpoint set --name '%1' --skip-prologue=0"},
578061da546Spatrick       {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
579061da546Spatrick        "breakpoint set --name '%1'"}};
580dda28197Spatrick   // clang-format on
581061da546Spatrick 
582*f6aab3d8Srobert   size_t num_regexes = std::size(break_regexes);
583061da546Spatrick 
584061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
585061da546Spatrick       new CommandObjectRegexCommand(
586061da546Spatrick           *this, "_regexp-break",
587061da546Spatrick           "Set a breakpoint using one of several shorthand formats.",
588061da546Spatrick           "\n"
589dda28197Spatrick           "_regexp-break <filename>:<linenum>:<colnum>\n"
590dda28197Spatrick           "              main.c:12:21          // Break at line 12 and column "
591dda28197Spatrick           "21 of main.c\n\n"
592061da546Spatrick           "_regexp-break <filename>:<linenum>\n"
593061da546Spatrick           "              main.c:12             // Break at line 12 of "
594061da546Spatrick           "main.c\n\n"
595061da546Spatrick           "_regexp-break <linenum>\n"
596061da546Spatrick           "              12                    // Break at line 12 of current "
597061da546Spatrick           "file\n\n"
598061da546Spatrick           "_regexp-break 0x<address>\n"
599061da546Spatrick           "              0x1234000             // Break at address "
600061da546Spatrick           "0x1234000\n\n"
601061da546Spatrick           "_regexp-break <name>\n"
602061da546Spatrick           "              main                  // Break in 'main' after the "
603061da546Spatrick           "prologue\n\n"
604061da546Spatrick           "_regexp-break &<name>\n"
605061da546Spatrick           "              &main                 // Break at first instruction "
606061da546Spatrick           "in 'main'\n\n"
607061da546Spatrick           "_regexp-break <module>`<name>\n"
608061da546Spatrick           "              libc.so`malloc        // Break in 'malloc' from "
609061da546Spatrick           "'libc.so'\n\n"
610061da546Spatrick           "_regexp-break /<source-regex>/\n"
611061da546Spatrick           "              /break here/          // Break on source lines in "
612061da546Spatrick           "current file\n"
613061da546Spatrick           "                                    // containing text 'break "
614061da546Spatrick           "here'.\n",
615dda28197Spatrick           3,
616061da546Spatrick           CommandCompletions::eSymbolCompletion |
617061da546Spatrick               CommandCompletions::eSourceFileCompletion,
618061da546Spatrick           false));
619061da546Spatrick 
620061da546Spatrick   if (break_regex_cmd_up) {
621061da546Spatrick     bool success = true;
622061da546Spatrick     for (size_t i = 0; i < num_regexes; i++) {
623061da546Spatrick       success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
624061da546Spatrick                                                     break_regexes[i][1]);
625061da546Spatrick       if (!success)
626061da546Spatrick         break;
627061da546Spatrick     }
628061da546Spatrick     success =
629061da546Spatrick         break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
630061da546Spatrick 
631061da546Spatrick     if (success) {
632061da546Spatrick       CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
633dda28197Spatrick       m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
634dda28197Spatrick           break_regex_cmd_sp;
635061da546Spatrick     }
636061da546Spatrick   }
637061da546Spatrick 
638061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
639061da546Spatrick       new CommandObjectRegexCommand(
640061da546Spatrick           *this, "_regexp-tbreak",
641061da546Spatrick           "Set a one-shot breakpoint using one of several shorthand formats.",
642061da546Spatrick           "\n"
643dda28197Spatrick           "_regexp-break <filename>:<linenum>:<colnum>\n"
644dda28197Spatrick           "              main.c:12:21          // Break at line 12 and column "
645dda28197Spatrick           "21 of main.c\n\n"
646061da546Spatrick           "_regexp-break <filename>:<linenum>\n"
647061da546Spatrick           "              main.c:12             // Break at line 12 of "
648061da546Spatrick           "main.c\n\n"
649061da546Spatrick           "_regexp-break <linenum>\n"
650061da546Spatrick           "              12                    // Break at line 12 of current "
651061da546Spatrick           "file\n\n"
652061da546Spatrick           "_regexp-break 0x<address>\n"
653061da546Spatrick           "              0x1234000             // Break at address "
654061da546Spatrick           "0x1234000\n\n"
655061da546Spatrick           "_regexp-break <name>\n"
656061da546Spatrick           "              main                  // Break in 'main' after the "
657061da546Spatrick           "prologue\n\n"
658061da546Spatrick           "_regexp-break &<name>\n"
659061da546Spatrick           "              &main                 // Break at first instruction "
660061da546Spatrick           "in 'main'\n\n"
661061da546Spatrick           "_regexp-break <module>`<name>\n"
662061da546Spatrick           "              libc.so`malloc        // Break in 'malloc' from "
663061da546Spatrick           "'libc.so'\n\n"
664061da546Spatrick           "_regexp-break /<source-regex>/\n"
665061da546Spatrick           "              /break here/          // Break on source lines in "
666061da546Spatrick           "current file\n"
667061da546Spatrick           "                                    // containing text 'break "
668061da546Spatrick           "here'.\n",
669061da546Spatrick           2,
670061da546Spatrick           CommandCompletions::eSymbolCompletion |
671061da546Spatrick               CommandCompletions::eSourceFileCompletion,
672061da546Spatrick           false));
673061da546Spatrick 
674061da546Spatrick   if (tbreak_regex_cmd_up) {
675061da546Spatrick     bool success = true;
676061da546Spatrick     for (size_t i = 0; i < num_regexes; i++) {
677be691f3bSpatrick       std::string command = break_regexes[i][1];
678be691f3bSpatrick       command += " -o 1";
679061da546Spatrick       success =
680be691f3bSpatrick           tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
681061da546Spatrick       if (!success)
682061da546Spatrick         break;
683061da546Spatrick     }
684061da546Spatrick     success =
685061da546Spatrick         tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
686061da546Spatrick 
687061da546Spatrick     if (success) {
688061da546Spatrick       CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
689dda28197Spatrick       m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
690061da546Spatrick           tbreak_regex_cmd_sp;
691061da546Spatrick     }
692061da546Spatrick   }
693061da546Spatrick 
694061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
695061da546Spatrick       new CommandObjectRegexCommand(
696061da546Spatrick           *this, "_regexp-attach", "Attach to process by ID or name.",
697061da546Spatrick           "_regexp-attach <pid> | <process-name>", 2, 0, false));
698061da546Spatrick   if (attach_regex_cmd_up) {
699061da546Spatrick     if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
700061da546Spatrick                                              "process attach --pid %1") &&
701061da546Spatrick         attach_regex_cmd_up->AddRegexCommand(
702061da546Spatrick             "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
703061da546Spatrick                                                       // specified get passed to
704061da546Spatrick                                                       // 'process attach'
705061da546Spatrick         attach_regex_cmd_up->AddRegexCommand("^(.+)$",
706061da546Spatrick                                              "process attach --name '%1'") &&
707061da546Spatrick         attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
708061da546Spatrick       CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
709dda28197Spatrick       m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
710061da546Spatrick           attach_regex_cmd_sp;
711061da546Spatrick     }
712061da546Spatrick   }
713061da546Spatrick 
714061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
715061da546Spatrick       new CommandObjectRegexCommand(*this, "_regexp-down",
716061da546Spatrick                                     "Select a newer stack frame.  Defaults to "
717061da546Spatrick                                     "moving one frame, a numeric argument can "
718061da546Spatrick                                     "specify an arbitrary number.",
719061da546Spatrick                                     "_regexp-down [<count>]", 2, 0, false));
720061da546Spatrick   if (down_regex_cmd_up) {
721061da546Spatrick     if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
722061da546Spatrick         down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
723061da546Spatrick                                            "frame select -r -%1")) {
724061da546Spatrick       CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
725dda28197Spatrick       m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
726dda28197Spatrick           down_regex_cmd_sp;
727061da546Spatrick     }
728061da546Spatrick   }
729061da546Spatrick 
730061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
731061da546Spatrick       new CommandObjectRegexCommand(
732061da546Spatrick           *this, "_regexp-up",
733061da546Spatrick           "Select an older stack frame.  Defaults to moving one "
734061da546Spatrick           "frame, a numeric argument can specify an arbitrary number.",
735061da546Spatrick           "_regexp-up [<count>]", 2, 0, false));
736061da546Spatrick   if (up_regex_cmd_up) {
737061da546Spatrick     if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
738061da546Spatrick         up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
739061da546Spatrick       CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
740dda28197Spatrick       m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
741dda28197Spatrick           up_regex_cmd_sp;
742061da546Spatrick     }
743061da546Spatrick   }
744061da546Spatrick 
745061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
746061da546Spatrick       new CommandObjectRegexCommand(
747061da546Spatrick           *this, "_regexp-display",
748061da546Spatrick           "Evaluate an expression at every stop (see 'help target stop-hook'.)",
749061da546Spatrick           "_regexp-display expression", 2, 0, false));
750061da546Spatrick   if (display_regex_cmd_up) {
751061da546Spatrick     if (display_regex_cmd_up->AddRegexCommand(
752061da546Spatrick             "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
753061da546Spatrick       CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
754dda28197Spatrick       m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
755061da546Spatrick           display_regex_cmd_sp;
756061da546Spatrick     }
757061da546Spatrick   }
758061da546Spatrick 
759061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
760061da546Spatrick       new CommandObjectRegexCommand(*this, "_regexp-undisplay",
761061da546Spatrick                                     "Stop displaying expression at every "
762061da546Spatrick                                     "stop (specified by stop-hook index.)",
763061da546Spatrick                                     "_regexp-undisplay stop-hook-number", 2, 0,
764061da546Spatrick                                     false));
765061da546Spatrick   if (undisplay_regex_cmd_up) {
766061da546Spatrick     if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
767061da546Spatrick                                                 "target stop-hook delete %1")) {
768061da546Spatrick       CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
769dda28197Spatrick       m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
770061da546Spatrick           undisplay_regex_cmd_sp;
771061da546Spatrick     }
772061da546Spatrick   }
773061da546Spatrick 
774061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
775061da546Spatrick       new CommandObjectRegexCommand(
776061da546Spatrick           *this, "gdb-remote",
777*f6aab3d8Srobert           "Connect to a process via remote GDB server.\n"
778*f6aab3d8Srobert           "If no host is specifed, localhost is assumed.\n"
779*f6aab3d8Srobert           "gdb-remote is an abbreviation for 'process connect --plugin "
780*f6aab3d8Srobert           "gdb-remote connect://<hostname>:<port>'\n",
781061da546Spatrick           "gdb-remote [<hostname>:]<portnum>", 2, 0, false));
782061da546Spatrick   if (connect_gdb_remote_cmd_up) {
783061da546Spatrick     if (connect_gdb_remote_cmd_up->AddRegexCommand(
784061da546Spatrick             "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
785061da546Spatrick             "process connect --plugin gdb-remote connect://%1:%2") &&
786061da546Spatrick         connect_gdb_remote_cmd_up->AddRegexCommand(
787061da546Spatrick             "^([[:digit:]]+)$",
788061da546Spatrick             "process connect --plugin gdb-remote connect://localhost:%1")) {
789061da546Spatrick       CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
790dda28197Spatrick       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
791061da546Spatrick     }
792061da546Spatrick   }
793061da546Spatrick 
794061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
795061da546Spatrick       new CommandObjectRegexCommand(
796061da546Spatrick           *this, "kdp-remote",
797*f6aab3d8Srobert           "Connect to a process via remote KDP server.\n"
798*f6aab3d8Srobert           "If no UDP port is specified, port 41139 is assumed.\n"
799*f6aab3d8Srobert           "kdp-remote is an abbreviation for 'process connect --plugin "
800*f6aab3d8Srobert           "kdp-remote udp://<hostname>:<port>'\n",
801061da546Spatrick           "kdp-remote <hostname>[:<portnum>]", 2, 0, false));
802061da546Spatrick   if (connect_kdp_remote_cmd_up) {
803061da546Spatrick     if (connect_kdp_remote_cmd_up->AddRegexCommand(
804061da546Spatrick             "^([^:]+:[[:digit:]]+)$",
805061da546Spatrick             "process connect --plugin kdp-remote udp://%1") &&
806061da546Spatrick         connect_kdp_remote_cmd_up->AddRegexCommand(
807061da546Spatrick             "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
808061da546Spatrick       CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
809dda28197Spatrick       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
810061da546Spatrick     }
811061da546Spatrick   }
812061da546Spatrick 
813061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
814061da546Spatrick       new CommandObjectRegexCommand(
815061da546Spatrick           *this, "_regexp-bt",
816061da546Spatrick           "Show the current thread's call stack.  Any numeric argument "
817061da546Spatrick           "displays at most that many "
818061da546Spatrick           "frames.  The argument 'all' displays all threads.  Use 'settings"
819061da546Spatrick           " set frame-format' to customize the printing of individual frames "
820061da546Spatrick           "and 'settings set thread-format' to customize the thread header.",
821061da546Spatrick           "bt [<digit> | all]", 2, 0, false));
822061da546Spatrick   if (bt_regex_cmd_up) {
823061da546Spatrick     // accept but don't document "bt -c <number>" -- before bt was a regex
824061da546Spatrick     // command if you wanted to backtrace three frames you would do "bt -c 3"
825061da546Spatrick     // but the intention is to have this emulate the gdb "bt" command and so
826061da546Spatrick     // now "bt 3" is the preferred form, in line with gdb.
827061da546Spatrick     if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
828061da546Spatrick                                          "thread backtrace -c %1") &&
829061da546Spatrick         bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
830061da546Spatrick                                          "thread backtrace -c %1") &&
831061da546Spatrick         bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
832061da546Spatrick         bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
833061da546Spatrick       CommandObjectSP command_sp(bt_regex_cmd_up.release());
834dda28197Spatrick       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
835061da546Spatrick     }
836061da546Spatrick   }
837061da546Spatrick 
838061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
839061da546Spatrick       new CommandObjectRegexCommand(
840061da546Spatrick           *this, "_regexp-list",
841061da546Spatrick           "List relevant source code using one of several shorthand formats.",
842061da546Spatrick           "\n"
843061da546Spatrick           "_regexp-list <file>:<line>   // List around specific file/line\n"
844061da546Spatrick           "_regexp-list <line>          // List current file around specified "
845061da546Spatrick           "line\n"
846061da546Spatrick           "_regexp-list <function-name> // List specified function\n"
847061da546Spatrick           "_regexp-list 0x<address>     // List around specified address\n"
848061da546Spatrick           "_regexp-list -[<count>]      // List previous <count> lines\n"
849061da546Spatrick           "_regexp-list                 // List subsequent lines",
850061da546Spatrick           2, CommandCompletions::eSourceFileCompletion, false));
851061da546Spatrick   if (list_regex_cmd_up) {
852061da546Spatrick     if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
853061da546Spatrick                                            "source list --line %1") &&
854061da546Spatrick         list_regex_cmd_up->AddRegexCommand(
855061da546Spatrick             "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
856061da546Spatrick             "]*$",
857061da546Spatrick             "source list --file '%1' --line %2") &&
858061da546Spatrick         list_regex_cmd_up->AddRegexCommand(
859061da546Spatrick             "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
860061da546Spatrick             "source list --address %1") &&
861061da546Spatrick         list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
862061da546Spatrick                                            "source list --reverse") &&
863061da546Spatrick         list_regex_cmd_up->AddRegexCommand(
864061da546Spatrick             "^-([[:digit:]]+)[[:space:]]*$",
865061da546Spatrick             "source list --reverse --count %1") &&
866061da546Spatrick         list_regex_cmd_up->AddRegexCommand("^(.+)$",
867061da546Spatrick                                            "source list --name \"%1\"") &&
868061da546Spatrick         list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
869061da546Spatrick       CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
870dda28197Spatrick       m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
871dda28197Spatrick           list_regex_cmd_sp;
872061da546Spatrick     }
873061da546Spatrick   }
874061da546Spatrick 
875061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
876061da546Spatrick       new CommandObjectRegexCommand(
877061da546Spatrick           *this, "_regexp-env",
878061da546Spatrick           "Shorthand for viewing and setting environment variables.",
879061da546Spatrick           "\n"
880061da546Spatrick           "_regexp-env                  // Show environment\n"
881061da546Spatrick           "_regexp-env <name>=<value>   // Set an environment variable",
882061da546Spatrick           2, 0, false));
883061da546Spatrick   if (env_regex_cmd_up) {
884061da546Spatrick     if (env_regex_cmd_up->AddRegexCommand("^$",
885061da546Spatrick                                           "settings show target.env-vars") &&
886061da546Spatrick         env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
887061da546Spatrick                                           "settings set target.env-vars %1")) {
888061da546Spatrick       CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
889dda28197Spatrick       m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
890dda28197Spatrick           env_regex_cmd_sp;
891061da546Spatrick     }
892061da546Spatrick   }
893061da546Spatrick 
894061da546Spatrick   std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
895061da546Spatrick       new CommandObjectRegexCommand(
896061da546Spatrick           *this, "_regexp-jump", "Set the program counter to a new address.",
897061da546Spatrick           "\n"
898061da546Spatrick           "_regexp-jump <line>\n"
899061da546Spatrick           "_regexp-jump +<line-offset> | -<line-offset>\n"
900061da546Spatrick           "_regexp-jump <file>:<line>\n"
901061da546Spatrick           "_regexp-jump *<addr>\n",
902061da546Spatrick           2, 0, false));
903061da546Spatrick   if (jump_regex_cmd_up) {
904061da546Spatrick     if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
905061da546Spatrick                                            "thread jump --addr %1") &&
906061da546Spatrick         jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
907061da546Spatrick                                            "thread jump --line %1") &&
908061da546Spatrick         jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
909061da546Spatrick                                            "thread jump --file %1 --line %2") &&
910061da546Spatrick         jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
911061da546Spatrick                                            "thread jump --by %1")) {
912061da546Spatrick       CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
913dda28197Spatrick       m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
914dda28197Spatrick           jump_regex_cmd_sp;
915061da546Spatrick     }
916061da546Spatrick   }
917061da546Spatrick }
918061da546Spatrick 
GetCommandNamesMatchingPartialString(const char * cmd_str,bool include_aliases,StringList & matches,StringList & descriptions)919061da546Spatrick int CommandInterpreter::GetCommandNamesMatchingPartialString(
920061da546Spatrick     const char *cmd_str, bool include_aliases, StringList &matches,
921061da546Spatrick     StringList &descriptions) {
922061da546Spatrick   AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
923061da546Spatrick                                 &descriptions);
924061da546Spatrick 
925061da546Spatrick   if (include_aliases) {
926061da546Spatrick     AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
927061da546Spatrick                                   &descriptions);
928061da546Spatrick   }
929061da546Spatrick 
930061da546Spatrick   return matches.GetSize();
931061da546Spatrick }
932061da546Spatrick 
VerifyUserMultiwordCmdPath(Args & path,bool leaf_is_command,Status & result)933*f6aab3d8Srobert CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath(
934*f6aab3d8Srobert     Args &path, bool leaf_is_command, Status &result) {
935*f6aab3d8Srobert   result.Clear();
936*f6aab3d8Srobert 
937*f6aab3d8Srobert   auto get_multi_or_report_error =
938*f6aab3d8Srobert       [&result](CommandObjectSP cmd_sp,
939*f6aab3d8Srobert                            const char *name) -> CommandObjectMultiword * {
940*f6aab3d8Srobert     if (!cmd_sp) {
941*f6aab3d8Srobert       result.SetErrorStringWithFormat("Path component: '%s' not found", name);
942*f6aab3d8Srobert       return nullptr;
943*f6aab3d8Srobert     }
944*f6aab3d8Srobert     if (!cmd_sp->IsUserCommand()) {
945*f6aab3d8Srobert       result.SetErrorStringWithFormat("Path component: '%s' is not a user "
946*f6aab3d8Srobert                                       "command",
947*f6aab3d8Srobert                                       name);
948*f6aab3d8Srobert       return nullptr;
949*f6aab3d8Srobert     }
950*f6aab3d8Srobert     CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
951*f6aab3d8Srobert     if (!cmd_as_multi) {
952*f6aab3d8Srobert       result.SetErrorStringWithFormat("Path component: '%s' is not a container "
953*f6aab3d8Srobert                                       "command",
954*f6aab3d8Srobert                                       name);
955*f6aab3d8Srobert       return nullptr;
956*f6aab3d8Srobert     }
957*f6aab3d8Srobert     return cmd_as_multi;
958*f6aab3d8Srobert   };
959*f6aab3d8Srobert 
960*f6aab3d8Srobert   size_t num_args = path.GetArgumentCount();
961*f6aab3d8Srobert   if (num_args == 0) {
962*f6aab3d8Srobert     result.SetErrorString("empty command path");
963*f6aab3d8Srobert     return nullptr;
964*f6aab3d8Srobert   }
965*f6aab3d8Srobert 
966*f6aab3d8Srobert   if (num_args == 1 && leaf_is_command) {
967*f6aab3d8Srobert     // We just got a leaf command to be added to the root.  That's not an error,
968*f6aab3d8Srobert     // just return null for the container.
969*f6aab3d8Srobert     return nullptr;
970*f6aab3d8Srobert   }
971*f6aab3d8Srobert 
972*f6aab3d8Srobert   // Start by getting the root command from the interpreter.
973*f6aab3d8Srobert   const char *cur_name = path.GetArgumentAtIndex(0);
974*f6aab3d8Srobert   CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
975*f6aab3d8Srobert   CommandObjectMultiword *cur_as_multi =
976*f6aab3d8Srobert       get_multi_or_report_error(cur_cmd_sp, cur_name);
977*f6aab3d8Srobert   if (cur_as_multi == nullptr)
978*f6aab3d8Srobert     return nullptr;
979*f6aab3d8Srobert 
980*f6aab3d8Srobert   size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
981*f6aab3d8Srobert   for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
982*f6aab3d8Srobert        cursor++) {
983*f6aab3d8Srobert     cur_name = path.GetArgumentAtIndex(cursor);
984*f6aab3d8Srobert     cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
985*f6aab3d8Srobert     cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
986*f6aab3d8Srobert   }
987*f6aab3d8Srobert   return cur_as_multi;
988*f6aab3d8Srobert }
989*f6aab3d8Srobert 
990061da546Spatrick CommandObjectSP
GetCommandSP(llvm::StringRef cmd_str,bool include_aliases,bool exact,StringList * matches,StringList * descriptions) const991061da546Spatrick CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
992061da546Spatrick                                  bool exact, StringList *matches,
993061da546Spatrick                                  StringList *descriptions) const {
994061da546Spatrick   CommandObjectSP command_sp;
995061da546Spatrick 
996dda28197Spatrick   std::string cmd = std::string(cmd_str);
997061da546Spatrick 
998061da546Spatrick   if (HasCommands()) {
999061da546Spatrick     auto pos = m_command_dict.find(cmd);
1000061da546Spatrick     if (pos != m_command_dict.end())
1001061da546Spatrick       command_sp = pos->second;
1002061da546Spatrick   }
1003061da546Spatrick 
1004061da546Spatrick   if (include_aliases && HasAliases()) {
1005061da546Spatrick     auto alias_pos = m_alias_dict.find(cmd);
1006061da546Spatrick     if (alias_pos != m_alias_dict.end())
1007061da546Spatrick       command_sp = alias_pos->second;
1008061da546Spatrick   }
1009061da546Spatrick 
1010061da546Spatrick   if (HasUserCommands()) {
1011061da546Spatrick     auto pos = m_user_dict.find(cmd);
1012061da546Spatrick     if (pos != m_user_dict.end())
1013061da546Spatrick       command_sp = pos->second;
1014061da546Spatrick   }
1015061da546Spatrick 
1016*f6aab3d8Srobert   if (HasUserMultiwordCommands()) {
1017*f6aab3d8Srobert     auto pos = m_user_mw_dict.find(cmd);
1018*f6aab3d8Srobert     if (pos != m_user_mw_dict.end())
1019*f6aab3d8Srobert       command_sp = pos->second;
1020*f6aab3d8Srobert   }
1021*f6aab3d8Srobert 
1022061da546Spatrick   if (!exact && !command_sp) {
1023061da546Spatrick     // We will only get into here if we didn't find any exact matches.
1024061da546Spatrick 
1025*f6aab3d8Srobert     CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1026*f6aab3d8Srobert         real_match_sp;
1027061da546Spatrick 
1028061da546Spatrick     StringList local_matches;
1029061da546Spatrick     if (matches == nullptr)
1030061da546Spatrick       matches = &local_matches;
1031061da546Spatrick 
1032061da546Spatrick     unsigned int num_cmd_matches = 0;
1033061da546Spatrick     unsigned int num_alias_matches = 0;
1034061da546Spatrick     unsigned int num_user_matches = 0;
1035*f6aab3d8Srobert     unsigned int num_user_mw_matches = 0;
1036061da546Spatrick 
1037061da546Spatrick     // Look through the command dictionaries one by one, and if we get only one
1038061da546Spatrick     // match from any of them in toto, then return that, otherwise return an
1039061da546Spatrick     // empty CommandObjectSP and the list of matches.
1040061da546Spatrick 
1041061da546Spatrick     if (HasCommands()) {
1042061da546Spatrick       num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
1043061da546Spatrick                                                       *matches, descriptions);
1044061da546Spatrick     }
1045061da546Spatrick 
1046061da546Spatrick     if (num_cmd_matches == 1) {
1047061da546Spatrick       cmd.assign(matches->GetStringAtIndex(0));
1048061da546Spatrick       auto pos = m_command_dict.find(cmd);
1049061da546Spatrick       if (pos != m_command_dict.end())
1050061da546Spatrick         real_match_sp = pos->second;
1051061da546Spatrick     }
1052061da546Spatrick 
1053061da546Spatrick     if (include_aliases && HasAliases()) {
1054061da546Spatrick       num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
1055061da546Spatrick                                                         *matches, descriptions);
1056061da546Spatrick     }
1057061da546Spatrick 
1058061da546Spatrick     if (num_alias_matches == 1) {
1059061da546Spatrick       cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
1060061da546Spatrick       auto alias_pos = m_alias_dict.find(cmd);
1061061da546Spatrick       if (alias_pos != m_alias_dict.end())
1062061da546Spatrick         alias_match_sp = alias_pos->second;
1063061da546Spatrick     }
1064061da546Spatrick 
1065061da546Spatrick     if (HasUserCommands()) {
1066061da546Spatrick       num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
1067061da546Spatrick                                                        *matches, descriptions);
1068061da546Spatrick     }
1069061da546Spatrick 
1070061da546Spatrick     if (num_user_matches == 1) {
1071061da546Spatrick       cmd.assign(
1072061da546Spatrick           matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
1073061da546Spatrick 
1074061da546Spatrick       auto pos = m_user_dict.find(cmd);
1075061da546Spatrick       if (pos != m_user_dict.end())
1076061da546Spatrick         user_match_sp = pos->second;
1077061da546Spatrick     }
1078061da546Spatrick 
1079*f6aab3d8Srobert     if (HasUserMultiwordCommands()) {
1080*f6aab3d8Srobert       num_user_mw_matches = AddNamesMatchingPartialString(
1081*f6aab3d8Srobert           m_user_mw_dict, cmd_str, *matches, descriptions);
1082*f6aab3d8Srobert     }
1083*f6aab3d8Srobert 
1084*f6aab3d8Srobert     if (num_user_mw_matches == 1) {
1085*f6aab3d8Srobert       cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1086*f6aab3d8Srobert                                            num_user_matches));
1087*f6aab3d8Srobert 
1088*f6aab3d8Srobert       auto pos = m_user_mw_dict.find(cmd);
1089*f6aab3d8Srobert       if (pos != m_user_mw_dict.end())
1090*f6aab3d8Srobert         user_mw_match_sp = pos->second;
1091*f6aab3d8Srobert     }
1092*f6aab3d8Srobert 
1093061da546Spatrick     // If we got exactly one match, return that, otherwise return the match
1094061da546Spatrick     // list.
1095061da546Spatrick 
1096*f6aab3d8Srobert     if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1097*f6aab3d8Srobert             num_alias_matches ==
1098*f6aab3d8Srobert         1) {
1099061da546Spatrick       if (num_cmd_matches)
1100061da546Spatrick         return real_match_sp;
1101061da546Spatrick       else if (num_alias_matches)
1102061da546Spatrick         return alias_match_sp;
1103*f6aab3d8Srobert       else if (num_user_mw_matches)
1104*f6aab3d8Srobert         return user_mw_match_sp;
1105061da546Spatrick       else
1106061da546Spatrick         return user_match_sp;
1107061da546Spatrick     }
1108061da546Spatrick   } else if (matches && command_sp) {
1109061da546Spatrick     matches->AppendString(cmd_str);
1110061da546Spatrick     if (descriptions)
1111061da546Spatrick       descriptions->AppendString(command_sp->GetHelp());
1112061da546Spatrick   }
1113061da546Spatrick 
1114061da546Spatrick   return command_sp;
1115061da546Spatrick }
1116061da546Spatrick 
AddCommand(llvm::StringRef name,const lldb::CommandObjectSP & cmd_sp,bool can_replace)1117061da546Spatrick bool CommandInterpreter::AddCommand(llvm::StringRef name,
1118061da546Spatrick                                     const lldb::CommandObjectSP &cmd_sp,
1119061da546Spatrick                                     bool can_replace) {
1120061da546Spatrick   if (cmd_sp.get())
1121061da546Spatrick     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1122061da546Spatrick                "tried to add a CommandObject from a different interpreter");
1123061da546Spatrick 
1124061da546Spatrick   if (name.empty())
1125061da546Spatrick     return false;
1126061da546Spatrick 
1127*f6aab3d8Srobert   cmd_sp->SetIsUserCommand(false);
1128*f6aab3d8Srobert 
1129061da546Spatrick   std::string name_sstr(name);
1130061da546Spatrick   auto name_iter = m_command_dict.find(name_sstr);
1131061da546Spatrick   if (name_iter != m_command_dict.end()) {
1132061da546Spatrick     if (!can_replace || !name_iter->second->IsRemovable())
1133061da546Spatrick       return false;
1134061da546Spatrick     name_iter->second = cmd_sp;
1135061da546Spatrick   } else {
1136061da546Spatrick     m_command_dict[name_sstr] = cmd_sp;
1137061da546Spatrick   }
1138061da546Spatrick   return true;
1139061da546Spatrick }
1140061da546Spatrick 
AddUserCommand(llvm::StringRef name,const lldb::CommandObjectSP & cmd_sp,bool can_replace)1141*f6aab3d8Srobert Status CommandInterpreter::AddUserCommand(llvm::StringRef name,
1142061da546Spatrick                                           const lldb::CommandObjectSP &cmd_sp,
1143061da546Spatrick                                           bool can_replace) {
1144*f6aab3d8Srobert   Status result;
1145061da546Spatrick   if (cmd_sp.get())
1146061da546Spatrick     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1147061da546Spatrick                "tried to add a CommandObject from a different interpreter");
1148*f6aab3d8Srobert   if (name.empty()) {
1149*f6aab3d8Srobert     result.SetErrorString("can't use the empty string for a command name");
1150*f6aab3d8Srobert     return result;
1151*f6aab3d8Srobert   }
1152061da546Spatrick   // do not allow replacement of internal commands
1153061da546Spatrick   if (CommandExists(name)) {
1154*f6aab3d8Srobert     result.SetErrorString("can't replace builtin command");
1155*f6aab3d8Srobert     return result;
1156061da546Spatrick   }
1157061da546Spatrick 
1158061da546Spatrick   if (UserCommandExists(name)) {
1159*f6aab3d8Srobert     if (!can_replace) {
1160*f6aab3d8Srobert       result.SetErrorString("user command exists and force replace not set");
1161*f6aab3d8Srobert       return result;
1162*f6aab3d8Srobert     }
1163*f6aab3d8Srobert     if (cmd_sp->IsMultiwordObject()) {
1164*f6aab3d8Srobert       if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1165*f6aab3d8Srobert         result.SetErrorString(
1166*f6aab3d8Srobert             "can't replace explicitly non-removable multi-word command");
1167*f6aab3d8Srobert         return result;
1168*f6aab3d8Srobert       }
1169*f6aab3d8Srobert     } else {
1170*f6aab3d8Srobert       if (!m_user_dict[std::string(name)]->IsRemovable()) {
1171*f6aab3d8Srobert         result.SetErrorString("can't replace explicitly non-removable command");
1172*f6aab3d8Srobert         return result;
1173*f6aab3d8Srobert       }
1174*f6aab3d8Srobert     }
1175061da546Spatrick   }
1176061da546Spatrick 
1177*f6aab3d8Srobert   cmd_sp->SetIsUserCommand(true);
1178*f6aab3d8Srobert 
1179*f6aab3d8Srobert   if (cmd_sp->IsMultiwordObject())
1180*f6aab3d8Srobert     m_user_mw_dict[std::string(name)] = cmd_sp;
1181*f6aab3d8Srobert   else
1182dda28197Spatrick     m_user_dict[std::string(name)] = cmd_sp;
1183*f6aab3d8Srobert   return result;
1184061da546Spatrick }
1185061da546Spatrick 
1186be691f3bSpatrick CommandObjectSP
GetCommandSPExact(llvm::StringRef cmd_str,bool include_aliases) const1187be691f3bSpatrick CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1188061da546Spatrick                                       bool include_aliases) const {
1189be691f3bSpatrick   // Break up the command string into words, in case it's a multi-word command.
1190be691f3bSpatrick   Args cmd_words(cmd_str);
1191061da546Spatrick 
1192061da546Spatrick   if (cmd_str.empty())
1193be691f3bSpatrick     return {};
1194061da546Spatrick 
1195061da546Spatrick   if (cmd_words.GetArgumentCount() == 1)
1196be691f3bSpatrick     return GetCommandSP(cmd_str, include_aliases, true);
1197be691f3bSpatrick 
1198061da546Spatrick   // We have a multi-word command (seemingly), so we need to do more work.
1199061da546Spatrick   // First, get the cmd_obj_sp for the first word in the command.
1200be691f3bSpatrick   CommandObjectSP cmd_obj_sp =
1201be691f3bSpatrick       GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1202be691f3bSpatrick   if (!cmd_obj_sp)
1203be691f3bSpatrick     return {};
1204be691f3bSpatrick 
1205be691f3bSpatrick   // Loop through the rest of the words in the command (everything passed in
1206be691f3bSpatrick   // was supposed to be part of a command name), and find the appropriate
1207be691f3bSpatrick   // sub-command SP for each command word....
1208061da546Spatrick   size_t end = cmd_words.GetArgumentCount();
1209be691f3bSpatrick   for (size_t i = 1; i < end; ++i) {
1210be691f3bSpatrick     if (!cmd_obj_sp->IsMultiwordObject()) {
1211061da546Spatrick       // We have more words in the command name, but we don't have a
1212be691f3bSpatrick       // multiword object. Fail and return.
1213be691f3bSpatrick       return {};
1214061da546Spatrick     }
1215be691f3bSpatrick 
1216be691f3bSpatrick     cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1217be691f3bSpatrick     if (!cmd_obj_sp) {
1218be691f3bSpatrick       // The sub-command name was invalid.  Fail and return.
1219be691f3bSpatrick       return {};
1220be691f3bSpatrick     }
1221be691f3bSpatrick   }
1222be691f3bSpatrick 
1223061da546Spatrick   // We successfully looped through all the command words and got valid
1224be691f3bSpatrick   // command objects for them.
1225be691f3bSpatrick   return cmd_obj_sp;
1226061da546Spatrick }
1227061da546Spatrick 
1228061da546Spatrick CommandObject *
GetCommandObject(llvm::StringRef cmd_str,StringList * matches,StringList * descriptions) const1229061da546Spatrick CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1230061da546Spatrick                                      StringList *matches,
1231061da546Spatrick                                      StringList *descriptions) const {
1232061da546Spatrick   CommandObject *command_obj =
1233061da546Spatrick       GetCommandSP(cmd_str, false, true, matches, descriptions).get();
1234061da546Spatrick 
1235061da546Spatrick   // If we didn't find an exact match to the command string in the commands,
1236061da546Spatrick   // look in the aliases.
1237061da546Spatrick 
1238061da546Spatrick   if (command_obj)
1239061da546Spatrick     return command_obj;
1240061da546Spatrick 
1241061da546Spatrick   command_obj = GetCommandSP(cmd_str, true, true, matches, descriptions).get();
1242061da546Spatrick 
1243061da546Spatrick   if (command_obj)
1244061da546Spatrick     return command_obj;
1245061da546Spatrick 
1246061da546Spatrick   // If there wasn't an exact match then look for an inexact one in just the
1247061da546Spatrick   // commands
1248061da546Spatrick   command_obj = GetCommandSP(cmd_str, false, false, nullptr).get();
1249061da546Spatrick 
1250061da546Spatrick   // Finally, if there wasn't an inexact match among the commands, look for an
1251061da546Spatrick   // inexact match in both the commands and aliases.
1252061da546Spatrick 
1253061da546Spatrick   if (command_obj) {
1254061da546Spatrick     if (matches)
1255061da546Spatrick       matches->AppendString(command_obj->GetCommandName());
1256061da546Spatrick     if (descriptions)
1257061da546Spatrick       descriptions->AppendString(command_obj->GetHelp());
1258061da546Spatrick     return command_obj;
1259061da546Spatrick   }
1260061da546Spatrick 
1261061da546Spatrick   return GetCommandSP(cmd_str, true, false, matches, descriptions).get();
1262061da546Spatrick }
1263061da546Spatrick 
GetUserCommandObject(llvm::StringRef cmd,StringList * matches,StringList * descriptions) const1264*f6aab3d8Srobert CommandObject *CommandInterpreter::GetUserCommandObject(
1265*f6aab3d8Srobert     llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1266*f6aab3d8Srobert   std::string cmd_str(cmd);
1267*f6aab3d8Srobert   auto find_exact = [&](const CommandObject::CommandMap &map) {
1268*f6aab3d8Srobert     auto found_elem = map.find(std::string(cmd));
1269*f6aab3d8Srobert     if (found_elem == map.end())
1270*f6aab3d8Srobert       return (CommandObject *)nullptr;
1271*f6aab3d8Srobert     CommandObject *exact_cmd = found_elem->second.get();
1272*f6aab3d8Srobert     if (exact_cmd) {
1273*f6aab3d8Srobert       if (matches)
1274*f6aab3d8Srobert         matches->AppendString(exact_cmd->GetCommandName());
1275*f6aab3d8Srobert       if (descriptions)
1276*f6aab3d8Srobert         descriptions->AppendString(exact_cmd->GetHelp());
1277*f6aab3d8Srobert       return exact_cmd;
1278*f6aab3d8Srobert     }
1279*f6aab3d8Srobert     return (CommandObject *)nullptr;
1280*f6aab3d8Srobert   };
1281*f6aab3d8Srobert 
1282*f6aab3d8Srobert   CommandObject *exact_cmd = find_exact(GetUserCommands());
1283*f6aab3d8Srobert   if (exact_cmd)
1284*f6aab3d8Srobert     return exact_cmd;
1285*f6aab3d8Srobert 
1286*f6aab3d8Srobert   exact_cmd = find_exact(GetUserMultiwordCommands());
1287*f6aab3d8Srobert   if (exact_cmd)
1288*f6aab3d8Srobert     return exact_cmd;
1289*f6aab3d8Srobert 
1290*f6aab3d8Srobert   // We didn't have an exact command, so now look for partial matches.
1291*f6aab3d8Srobert   StringList tmp_list;
1292*f6aab3d8Srobert   StringList *matches_ptr = matches ? matches : &tmp_list;
1293*f6aab3d8Srobert   AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1294*f6aab3d8Srobert   AddNamesMatchingPartialString(GetUserMultiwordCommands(),
1295*f6aab3d8Srobert                                 cmd_str, *matches_ptr);
1296*f6aab3d8Srobert 
1297*f6aab3d8Srobert   return {};
1298*f6aab3d8Srobert }
1299*f6aab3d8Srobert 
CommandExists(llvm::StringRef cmd) const1300061da546Spatrick bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1301dda28197Spatrick   return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
1302061da546Spatrick }
1303061da546Spatrick 
GetAliasFullName(llvm::StringRef cmd,std::string & full_name) const1304061da546Spatrick bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1305061da546Spatrick                                           std::string &full_name) const {
1306dda28197Spatrick   bool exact_match =
1307dda28197Spatrick       (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
1308061da546Spatrick   if (exact_match) {
1309dda28197Spatrick     full_name.assign(std::string(cmd));
1310061da546Spatrick     return exact_match;
1311061da546Spatrick   } else {
1312061da546Spatrick     StringList matches;
1313061da546Spatrick     size_t num_alias_matches;
1314061da546Spatrick     num_alias_matches =
1315061da546Spatrick         AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1316061da546Spatrick     if (num_alias_matches == 1) {
1317061da546Spatrick       // Make sure this isn't shadowing a command in the regular command space:
1318061da546Spatrick       StringList regular_matches;
1319061da546Spatrick       const bool include_aliases = false;
1320061da546Spatrick       const bool exact = false;
1321061da546Spatrick       CommandObjectSP cmd_obj_sp(
1322061da546Spatrick           GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1323061da546Spatrick       if (cmd_obj_sp || regular_matches.GetSize() > 0)
1324061da546Spatrick         return false;
1325061da546Spatrick       else {
1326061da546Spatrick         full_name.assign(matches.GetStringAtIndex(0));
1327061da546Spatrick         return true;
1328061da546Spatrick       }
1329061da546Spatrick     } else
1330061da546Spatrick       return false;
1331061da546Spatrick   }
1332061da546Spatrick }
1333061da546Spatrick 
AliasExists(llvm::StringRef cmd) const1334061da546Spatrick bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1335dda28197Spatrick   return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
1336061da546Spatrick }
1337061da546Spatrick 
UserCommandExists(llvm::StringRef cmd) const1338061da546Spatrick bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1339dda28197Spatrick   return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
1340061da546Spatrick }
1341061da546Spatrick 
UserMultiwordCommandExists(llvm::StringRef cmd) const1342*f6aab3d8Srobert bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1343*f6aab3d8Srobert   return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
1344*f6aab3d8Srobert }
1345*f6aab3d8Srobert 
1346061da546Spatrick CommandAlias *
AddAlias(llvm::StringRef alias_name,lldb::CommandObjectSP & command_obj_sp,llvm::StringRef args_string)1347061da546Spatrick CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1348061da546Spatrick                              lldb::CommandObjectSP &command_obj_sp,
1349061da546Spatrick                              llvm::StringRef args_string) {
1350061da546Spatrick   if (command_obj_sp.get())
1351061da546Spatrick     lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1352061da546Spatrick                "tried to add a CommandObject from a different interpreter");
1353061da546Spatrick 
1354061da546Spatrick   std::unique_ptr<CommandAlias> command_alias_up(
1355061da546Spatrick       new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1356061da546Spatrick 
1357061da546Spatrick   if (command_alias_up && command_alias_up->IsValid()) {
1358dda28197Spatrick     m_alias_dict[std::string(alias_name)] =
1359dda28197Spatrick         CommandObjectSP(command_alias_up.get());
1360061da546Spatrick     return command_alias_up.release();
1361061da546Spatrick   }
1362061da546Spatrick 
1363061da546Spatrick   return nullptr;
1364061da546Spatrick }
1365061da546Spatrick 
RemoveAlias(llvm::StringRef alias_name)1366061da546Spatrick bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1367dda28197Spatrick   auto pos = m_alias_dict.find(std::string(alias_name));
1368061da546Spatrick   if (pos != m_alias_dict.end()) {
1369061da546Spatrick     m_alias_dict.erase(pos);
1370061da546Spatrick     return true;
1371061da546Spatrick   }
1372061da546Spatrick   return false;
1373061da546Spatrick }
1374061da546Spatrick 
RemoveCommand(llvm::StringRef cmd)1375061da546Spatrick bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd) {
1376dda28197Spatrick   auto pos = m_command_dict.find(std::string(cmd));
1377061da546Spatrick   if (pos != m_command_dict.end()) {
1378061da546Spatrick     if (pos->second->IsRemovable()) {
1379061da546Spatrick       // Only regular expression objects or python commands are removable
1380061da546Spatrick       m_command_dict.erase(pos);
1381061da546Spatrick       return true;
1382061da546Spatrick     }
1383061da546Spatrick   }
1384061da546Spatrick   return false;
1385061da546Spatrick }
1386*f6aab3d8Srobert 
RemoveUser(llvm::StringRef user_name)1387*f6aab3d8Srobert bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1388dda28197Spatrick   CommandObject::CommandMap::iterator pos =
1389*f6aab3d8Srobert       m_user_dict.find(std::string(user_name));
1390061da546Spatrick   if (pos != m_user_dict.end()) {
1391061da546Spatrick     m_user_dict.erase(pos);
1392061da546Spatrick     return true;
1393061da546Spatrick   }
1394061da546Spatrick   return false;
1395061da546Spatrick }
1396061da546Spatrick 
RemoveUserMultiword(llvm::StringRef multi_name)1397*f6aab3d8Srobert bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1398*f6aab3d8Srobert   CommandObject::CommandMap::iterator pos =
1399*f6aab3d8Srobert       m_user_mw_dict.find(std::string(multi_name));
1400*f6aab3d8Srobert   if (pos != m_user_mw_dict.end()) {
1401*f6aab3d8Srobert     m_user_mw_dict.erase(pos);
1402*f6aab3d8Srobert     return true;
1403*f6aab3d8Srobert   }
1404*f6aab3d8Srobert   return false;
1405*f6aab3d8Srobert }
1406*f6aab3d8Srobert 
GetHelp(CommandReturnObject & result,uint32_t cmd_types)1407061da546Spatrick void CommandInterpreter::GetHelp(CommandReturnObject &result,
1408061da546Spatrick                                  uint32_t cmd_types) {
1409061da546Spatrick   llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1410061da546Spatrick   if (!help_prologue.empty()) {
1411061da546Spatrick     OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1412061da546Spatrick                             help_prologue);
1413061da546Spatrick   }
1414061da546Spatrick 
1415061da546Spatrick   CommandObject::CommandMap::const_iterator pos;
1416061da546Spatrick   size_t max_len = FindLongestCommandWord(m_command_dict);
1417061da546Spatrick 
1418061da546Spatrick   if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1419061da546Spatrick     result.AppendMessage("Debugger commands:");
1420061da546Spatrick     result.AppendMessage("");
1421061da546Spatrick 
1422061da546Spatrick     for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1423061da546Spatrick       if (!(cmd_types & eCommandTypesHidden) &&
1424061da546Spatrick           (pos->first.compare(0, 1, "_") == 0))
1425061da546Spatrick         continue;
1426061da546Spatrick 
1427061da546Spatrick       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1428061da546Spatrick                               pos->second->GetHelp(), max_len);
1429061da546Spatrick     }
1430061da546Spatrick     result.AppendMessage("");
1431061da546Spatrick   }
1432061da546Spatrick 
1433061da546Spatrick   if (!m_alias_dict.empty() &&
1434061da546Spatrick       ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1435061da546Spatrick     result.AppendMessageWithFormat(
1436061da546Spatrick         "Current command abbreviations "
1437061da546Spatrick         "(type '%shelp command alias' for more info):\n",
1438061da546Spatrick         GetCommandPrefix());
1439061da546Spatrick     result.AppendMessage("");
1440061da546Spatrick     max_len = FindLongestCommandWord(m_alias_dict);
1441061da546Spatrick 
1442061da546Spatrick     for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1443061da546Spatrick          ++alias_pos) {
1444061da546Spatrick       OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1445061da546Spatrick                               alias_pos->second->GetHelp(), max_len);
1446061da546Spatrick     }
1447061da546Spatrick     result.AppendMessage("");
1448061da546Spatrick   }
1449061da546Spatrick 
1450061da546Spatrick   if (!m_user_dict.empty() &&
1451061da546Spatrick       ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1452061da546Spatrick     result.AppendMessage("Current user-defined commands:");
1453061da546Spatrick     result.AppendMessage("");
1454061da546Spatrick     max_len = FindLongestCommandWord(m_user_dict);
1455061da546Spatrick     for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1456061da546Spatrick       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1457061da546Spatrick                               pos->second->GetHelp(), max_len);
1458061da546Spatrick     }
1459061da546Spatrick     result.AppendMessage("");
1460061da546Spatrick   }
1461061da546Spatrick 
1462*f6aab3d8Srobert   if (!m_user_mw_dict.empty() &&
1463*f6aab3d8Srobert       ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1464*f6aab3d8Srobert     result.AppendMessage("Current user-defined container commands:");
1465*f6aab3d8Srobert     result.AppendMessage("");
1466*f6aab3d8Srobert     max_len = FindLongestCommandWord(m_user_mw_dict);
1467*f6aab3d8Srobert     for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1468*f6aab3d8Srobert       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1469*f6aab3d8Srobert                               pos->second->GetHelp(), max_len);
1470*f6aab3d8Srobert     }
1471*f6aab3d8Srobert     result.AppendMessage("");
1472*f6aab3d8Srobert   }
1473*f6aab3d8Srobert 
1474061da546Spatrick   result.AppendMessageWithFormat(
1475061da546Spatrick       "For more information on any command, type '%shelp <command-name>'.\n",
1476061da546Spatrick       GetCommandPrefix());
1477061da546Spatrick }
1478061da546Spatrick 
GetCommandObjectForCommand(llvm::StringRef & command_string)1479061da546Spatrick CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1480061da546Spatrick     llvm::StringRef &command_string) {
1481061da546Spatrick   // This function finds the final, lowest-level, alias-resolved command object
1482061da546Spatrick   // whose 'Execute' function will eventually be invoked by the given command
1483061da546Spatrick   // line.
1484061da546Spatrick 
1485061da546Spatrick   CommandObject *cmd_obj = nullptr;
1486061da546Spatrick   size_t start = command_string.find_first_not_of(k_white_space);
1487061da546Spatrick   size_t end = 0;
1488061da546Spatrick   bool done = false;
1489061da546Spatrick   while (!done) {
1490061da546Spatrick     if (start != std::string::npos) {
1491061da546Spatrick       // Get the next word from command_string.
1492061da546Spatrick       end = command_string.find_first_of(k_white_space, start);
1493061da546Spatrick       if (end == std::string::npos)
1494061da546Spatrick         end = command_string.size();
1495dda28197Spatrick       std::string cmd_word =
1496dda28197Spatrick           std::string(command_string.substr(start, end - start));
1497061da546Spatrick 
1498061da546Spatrick       if (cmd_obj == nullptr)
1499061da546Spatrick         // Since cmd_obj is NULL we are on our first time through this loop.
1500061da546Spatrick         // Check to see if cmd_word is a valid command or alias.
1501061da546Spatrick         cmd_obj = GetCommandObject(cmd_word);
1502061da546Spatrick       else if (cmd_obj->IsMultiwordObject()) {
1503061da546Spatrick         // Our current object is a multi-word object; see if the cmd_word is a
1504061da546Spatrick         // valid sub-command for our object.
1505061da546Spatrick         CommandObject *sub_cmd_obj =
1506061da546Spatrick             cmd_obj->GetSubcommandObject(cmd_word.c_str());
1507061da546Spatrick         if (sub_cmd_obj)
1508061da546Spatrick           cmd_obj = sub_cmd_obj;
1509061da546Spatrick         else // cmd_word was not a valid sub-command word, so we are done
1510061da546Spatrick           done = true;
1511061da546Spatrick       } else
1512061da546Spatrick         // We have a cmd_obj and it is not a multi-word object, so we are done.
1513061da546Spatrick         done = true;
1514061da546Spatrick 
1515061da546Spatrick       // If we didn't find a valid command object, or our command object is not
1516061da546Spatrick       // a multi-word object, or we are at the end of the command_string, then
1517061da546Spatrick       // we are done.  Otherwise, find the start of the next word.
1518061da546Spatrick 
1519061da546Spatrick       if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1520061da546Spatrick           end >= command_string.size())
1521061da546Spatrick         done = true;
1522061da546Spatrick       else
1523061da546Spatrick         start = command_string.find_first_not_of(k_white_space, end);
1524061da546Spatrick     } else
1525061da546Spatrick       // Unable to find any more words.
1526061da546Spatrick       done = true;
1527061da546Spatrick   }
1528061da546Spatrick 
1529061da546Spatrick   command_string = command_string.substr(end);
1530061da546Spatrick   return cmd_obj;
1531061da546Spatrick }
1532061da546Spatrick 
1533061da546Spatrick static const char *k_valid_command_chars =
1534061da546Spatrick     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
StripLeadingSpaces(std::string & s)1535061da546Spatrick static void StripLeadingSpaces(std::string &s) {
1536061da546Spatrick   if (!s.empty()) {
1537061da546Spatrick     size_t pos = s.find_first_not_of(k_white_space);
1538061da546Spatrick     if (pos == std::string::npos)
1539061da546Spatrick       s.clear();
1540061da546Spatrick     else if (pos == 0)
1541061da546Spatrick       return;
1542061da546Spatrick     s.erase(0, pos);
1543061da546Spatrick   }
1544061da546Spatrick }
1545061da546Spatrick 
FindArgumentTerminator(const std::string & s)1546061da546Spatrick static size_t FindArgumentTerminator(const std::string &s) {
1547061da546Spatrick   const size_t s_len = s.size();
1548061da546Spatrick   size_t offset = 0;
1549061da546Spatrick   while (offset < s_len) {
1550061da546Spatrick     size_t pos = s.find("--", offset);
1551061da546Spatrick     if (pos == std::string::npos)
1552061da546Spatrick       break;
1553061da546Spatrick     if (pos > 0) {
1554dda28197Spatrick       if (llvm::isSpace(s[pos - 1])) {
1555061da546Spatrick         // Check if the string ends "\s--" (where \s is a space character) or
1556061da546Spatrick         // if we have "\s--\s".
1557dda28197Spatrick         if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1558061da546Spatrick           return pos;
1559061da546Spatrick         }
1560061da546Spatrick       }
1561061da546Spatrick     }
1562061da546Spatrick     offset = pos + 2;
1563061da546Spatrick   }
1564061da546Spatrick   return std::string::npos;
1565061da546Spatrick }
1566061da546Spatrick 
ExtractCommand(std::string & command_string,std::string & command,std::string & suffix,char & quote_char)1567061da546Spatrick static bool ExtractCommand(std::string &command_string, std::string &command,
1568061da546Spatrick                            std::string &suffix, char &quote_char) {
1569061da546Spatrick   command.clear();
1570061da546Spatrick   suffix.clear();
1571061da546Spatrick   StripLeadingSpaces(command_string);
1572061da546Spatrick 
1573061da546Spatrick   bool result = false;
1574061da546Spatrick   quote_char = '\0';
1575061da546Spatrick 
1576061da546Spatrick   if (!command_string.empty()) {
1577061da546Spatrick     const char first_char = command_string[0];
1578061da546Spatrick     if (first_char == '\'' || first_char == '"') {
1579061da546Spatrick       quote_char = first_char;
1580061da546Spatrick       const size_t end_quote_pos = command_string.find(quote_char, 1);
1581061da546Spatrick       if (end_quote_pos == std::string::npos) {
1582061da546Spatrick         command.swap(command_string);
1583061da546Spatrick         command_string.erase();
1584061da546Spatrick       } else {
1585061da546Spatrick         command.assign(command_string, 1, end_quote_pos - 1);
1586061da546Spatrick         if (end_quote_pos + 1 < command_string.size())
1587061da546Spatrick           command_string.erase(0, command_string.find_first_not_of(
1588061da546Spatrick                                       k_white_space, end_quote_pos + 1));
1589061da546Spatrick         else
1590061da546Spatrick           command_string.erase();
1591061da546Spatrick       }
1592061da546Spatrick     } else {
1593061da546Spatrick       const size_t first_space_pos =
1594061da546Spatrick           command_string.find_first_of(k_white_space);
1595061da546Spatrick       if (first_space_pos == std::string::npos) {
1596061da546Spatrick         command.swap(command_string);
1597061da546Spatrick         command_string.erase();
1598061da546Spatrick       } else {
1599061da546Spatrick         command.assign(command_string, 0, first_space_pos);
1600061da546Spatrick         command_string.erase(0, command_string.find_first_not_of(
1601061da546Spatrick                                     k_white_space, first_space_pos));
1602061da546Spatrick       }
1603061da546Spatrick     }
1604061da546Spatrick     result = true;
1605061da546Spatrick   }
1606061da546Spatrick 
1607061da546Spatrick   if (!command.empty()) {
1608061da546Spatrick     // actual commands can't start with '-' or '_'
1609061da546Spatrick     if (command[0] != '-' && command[0] != '_') {
1610061da546Spatrick       size_t pos = command.find_first_not_of(k_valid_command_chars);
1611061da546Spatrick       if (pos > 0 && pos != std::string::npos) {
1612061da546Spatrick         suffix.assign(command.begin() + pos, command.end());
1613061da546Spatrick         command.erase(pos);
1614061da546Spatrick       }
1615061da546Spatrick     }
1616061da546Spatrick   }
1617061da546Spatrick 
1618061da546Spatrick   return result;
1619061da546Spatrick }
1620061da546Spatrick 
BuildAliasResult(llvm::StringRef alias_name,std::string & raw_input_string,std::string & alias_result,CommandReturnObject & result)1621061da546Spatrick CommandObject *CommandInterpreter::BuildAliasResult(
1622061da546Spatrick     llvm::StringRef alias_name, std::string &raw_input_string,
1623061da546Spatrick     std::string &alias_result, CommandReturnObject &result) {
1624061da546Spatrick   CommandObject *alias_cmd_obj = nullptr;
1625061da546Spatrick   Args cmd_args(raw_input_string);
1626061da546Spatrick   alias_cmd_obj = GetCommandObject(alias_name);
1627061da546Spatrick   StreamString result_str;
1628061da546Spatrick 
1629061da546Spatrick   if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1630061da546Spatrick     alias_result.clear();
1631061da546Spatrick     return alias_cmd_obj;
1632061da546Spatrick   }
1633061da546Spatrick   std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1634061da546Spatrick       ((CommandAlias *)alias_cmd_obj)->Desugar();
1635061da546Spatrick   OptionArgVectorSP option_arg_vector_sp = desugared.second;
1636061da546Spatrick   alias_cmd_obj = desugared.first.get();
1637dda28197Spatrick   std::string alias_name_str = std::string(alias_name);
1638061da546Spatrick   if ((cmd_args.GetArgumentCount() == 0) ||
1639061da546Spatrick       (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1640061da546Spatrick     cmd_args.Unshift(alias_name_str);
1641061da546Spatrick 
1642061da546Spatrick   result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1643061da546Spatrick 
1644061da546Spatrick   if (!option_arg_vector_sp.get()) {
1645dda28197Spatrick     alias_result = std::string(result_str.GetString());
1646061da546Spatrick     return alias_cmd_obj;
1647061da546Spatrick   }
1648061da546Spatrick   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1649061da546Spatrick 
1650061da546Spatrick   int value_type;
1651061da546Spatrick   std::string option;
1652061da546Spatrick   std::string value;
1653061da546Spatrick   for (const auto &entry : *option_arg_vector) {
1654061da546Spatrick     std::tie(option, value_type, value) = entry;
1655*f6aab3d8Srobert     if (option == g_argument) {
1656061da546Spatrick       result_str.Printf(" %s", value.c_str());
1657061da546Spatrick       continue;
1658061da546Spatrick     }
1659061da546Spatrick 
1660061da546Spatrick     result_str.Printf(" %s", option.c_str());
1661061da546Spatrick     if (value_type == OptionParser::eNoArgument)
1662061da546Spatrick       continue;
1663061da546Spatrick 
1664061da546Spatrick     if (value_type != OptionParser::eOptionalArgument)
1665061da546Spatrick       result_str.Printf(" ");
1666061da546Spatrick     int index = GetOptionArgumentPosition(value.c_str());
1667061da546Spatrick     if (index == 0)
1668061da546Spatrick       result_str.Printf("%s", value.c_str());
1669061da546Spatrick     else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1670061da546Spatrick 
1671061da546Spatrick       result.AppendErrorWithFormat("Not enough arguments provided; you "
1672061da546Spatrick                                    "need at least %d arguments to use "
1673061da546Spatrick                                    "this alias.\n",
1674061da546Spatrick                                    index);
1675061da546Spatrick       return nullptr;
1676061da546Spatrick     } else {
1677*f6aab3d8Srobert       const Args::ArgEntry &entry = cmd_args[index];
1678*f6aab3d8Srobert       size_t strpos = raw_input_string.find(entry.c_str());
1679*f6aab3d8Srobert       const char quote_char = entry.GetQuoteChar();
1680*f6aab3d8Srobert       if (strpos != std::string::npos) {
1681*f6aab3d8Srobert         const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1682*f6aab3d8Srobert         const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1683*f6aab3d8Srobert 
1684*f6aab3d8Srobert         // Make sure we aren't going outside the bounds of the cmd string:
1685*f6aab3d8Srobert         if (strpos < start_fudge) {
1686*f6aab3d8Srobert           result.AppendError("Unmatched quote at command beginning.");
1687*f6aab3d8Srobert           return nullptr;
1688*f6aab3d8Srobert         }
1689*f6aab3d8Srobert         llvm::StringRef arg_text = entry.ref();
1690*f6aab3d8Srobert         if (strpos - start_fudge + arg_text.size() + len_fudge
1691*f6aab3d8Srobert             > raw_input_string.size()) {
1692*f6aab3d8Srobert           result.AppendError("Unmatched quote at command end.");
1693*f6aab3d8Srobert           return nullptr;
1694*f6aab3d8Srobert         }
1695061da546Spatrick         raw_input_string = raw_input_string.erase(
1696*f6aab3d8Srobert             strpos - start_fudge,
1697*f6aab3d8Srobert             strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1698*f6aab3d8Srobert       }
1699*f6aab3d8Srobert       if (quote_char == '\0')
1700061da546Spatrick         result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1701*f6aab3d8Srobert       else
1702*f6aab3d8Srobert         result_str.Printf("%c%s%c", quote_char,
1703*f6aab3d8Srobert                           entry.c_str(), quote_char);
1704061da546Spatrick     }
1705061da546Spatrick   }
1706061da546Spatrick 
1707dda28197Spatrick   alias_result = std::string(result_str.GetString());
1708061da546Spatrick   return alias_cmd_obj;
1709061da546Spatrick }
1710061da546Spatrick 
PreprocessCommand(std::string & command)1711061da546Spatrick Status CommandInterpreter::PreprocessCommand(std::string &command) {
1712061da546Spatrick   // The command preprocessor needs to do things to the command line before any
1713061da546Spatrick   // parsing of arguments or anything else is done. The only current stuff that
1714061da546Spatrick   // gets preprocessed is anything enclosed in backtick ('`') characters is
1715061da546Spatrick   // evaluated as an expression and the result of the expression must be a
1716061da546Spatrick   // scalar that can be substituted into the command. An example would be:
1717061da546Spatrick   // (lldb) memory read `$rsp + 20`
1718061da546Spatrick   Status error; // Status for any expressions that might not evaluate
1719061da546Spatrick   size_t start_backtick;
1720061da546Spatrick   size_t pos = 0;
1721061da546Spatrick   while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1722061da546Spatrick     // Stop if an error was encountered during the previous iteration.
1723061da546Spatrick     if (error.Fail())
1724061da546Spatrick       break;
1725061da546Spatrick 
1726061da546Spatrick     if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1727061da546Spatrick       // The backtick was preceded by a '\' character, remove the slash and
1728061da546Spatrick       // don't treat the backtick as the start of an expression.
1729061da546Spatrick       command.erase(start_backtick - 1, 1);
1730061da546Spatrick       // No need to add one to start_backtick since we just deleted a char.
1731061da546Spatrick       pos = start_backtick;
1732061da546Spatrick       continue;
1733061da546Spatrick     }
1734061da546Spatrick 
1735061da546Spatrick     const size_t expr_content_start = start_backtick + 1;
1736061da546Spatrick     const size_t end_backtick = command.find('`', expr_content_start);
1737061da546Spatrick 
1738061da546Spatrick     if (end_backtick == std::string::npos) {
1739061da546Spatrick       // Stop if there's no end backtick.
1740061da546Spatrick       break;
1741061da546Spatrick     }
1742061da546Spatrick 
1743061da546Spatrick     if (end_backtick == expr_content_start) {
1744061da546Spatrick       // Skip over empty expression. (two backticks in a row)
1745061da546Spatrick       command.erase(start_backtick, 2);
1746061da546Spatrick       continue;
1747061da546Spatrick     }
1748061da546Spatrick 
1749061da546Spatrick     std::string expr_str(command, expr_content_start,
1750061da546Spatrick                          end_backtick - expr_content_start);
1751061da546Spatrick 
1752061da546Spatrick     ExecutionContext exe_ctx(GetExecutionContext());
1753061da546Spatrick 
1754061da546Spatrick     // Get a dummy target to allow for calculator mode while processing
1755061da546Spatrick     // backticks. This also helps break the infinite loop caused when target is
1756061da546Spatrick     // null.
1757be691f3bSpatrick     Target *exe_target = exe_ctx.GetTargetPtr();
1758be691f3bSpatrick     Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1759061da546Spatrick 
1760061da546Spatrick     ValueObjectSP expr_result_valobj_sp;
1761061da546Spatrick 
1762061da546Spatrick     EvaluateExpressionOptions options;
1763061da546Spatrick     options.SetCoerceToId(false);
1764061da546Spatrick     options.SetUnwindOnError(true);
1765061da546Spatrick     options.SetIgnoreBreakpoints(true);
1766061da546Spatrick     options.SetKeepInMemory(false);
1767061da546Spatrick     options.SetTryAllThreads(true);
1768*f6aab3d8Srobert     options.SetTimeout(std::nullopt);
1769061da546Spatrick 
1770061da546Spatrick     ExpressionResults expr_result =
1771be691f3bSpatrick         target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1772061da546Spatrick                                   expr_result_valobj_sp, options);
1773061da546Spatrick 
1774061da546Spatrick     if (expr_result == eExpressionCompleted) {
1775061da546Spatrick       Scalar scalar;
1776061da546Spatrick       if (expr_result_valobj_sp)
1777061da546Spatrick         expr_result_valobj_sp =
1778061da546Spatrick             expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1779061da546Spatrick                 expr_result_valobj_sp->GetDynamicValueType(), true);
1780061da546Spatrick       if (expr_result_valobj_sp->ResolveValue(scalar)) {
1781061da546Spatrick         command.erase(start_backtick, end_backtick - start_backtick + 1);
1782061da546Spatrick         StreamString value_strm;
1783061da546Spatrick         const bool show_type = false;
1784061da546Spatrick         scalar.GetValue(&value_strm, show_type);
1785061da546Spatrick         size_t value_string_size = value_strm.GetSize();
1786061da546Spatrick         if (value_string_size) {
1787dda28197Spatrick           command.insert(start_backtick, std::string(value_strm.GetString()));
1788061da546Spatrick           pos = start_backtick + value_string_size;
1789061da546Spatrick           continue;
1790061da546Spatrick         } else {
1791061da546Spatrick           error.SetErrorStringWithFormat("expression value didn't result "
1792061da546Spatrick                                          "in a scalar value for the "
1793061da546Spatrick                                          "expression '%s'",
1794061da546Spatrick                                          expr_str.c_str());
1795061da546Spatrick           break;
1796061da546Spatrick         }
1797061da546Spatrick       } else {
1798061da546Spatrick         error.SetErrorStringWithFormat("expression value didn't result "
1799061da546Spatrick                                        "in a scalar value for the "
1800061da546Spatrick                                        "expression '%s'",
1801061da546Spatrick                                        expr_str.c_str());
1802061da546Spatrick         break;
1803061da546Spatrick       }
1804061da546Spatrick 
1805061da546Spatrick       continue;
1806061da546Spatrick     }
1807061da546Spatrick 
1808061da546Spatrick     if (expr_result_valobj_sp)
1809061da546Spatrick       error = expr_result_valobj_sp->GetError();
1810061da546Spatrick 
1811061da546Spatrick     if (error.Success()) {
1812061da546Spatrick       switch (expr_result) {
1813061da546Spatrick       case eExpressionSetupError:
1814061da546Spatrick         error.SetErrorStringWithFormat(
1815061da546Spatrick             "expression setup error for the expression '%s'", expr_str.c_str());
1816061da546Spatrick         break;
1817061da546Spatrick       case eExpressionParseError:
1818061da546Spatrick         error.SetErrorStringWithFormat(
1819061da546Spatrick             "expression parse error for the expression '%s'", expr_str.c_str());
1820061da546Spatrick         break;
1821061da546Spatrick       case eExpressionResultUnavailable:
1822061da546Spatrick         error.SetErrorStringWithFormat(
1823061da546Spatrick             "expression error fetching result for the expression '%s'",
1824061da546Spatrick             expr_str.c_str());
1825061da546Spatrick         break;
1826061da546Spatrick       case eExpressionCompleted:
1827061da546Spatrick         break;
1828061da546Spatrick       case eExpressionDiscarded:
1829061da546Spatrick         error.SetErrorStringWithFormat(
1830061da546Spatrick             "expression discarded for the expression '%s'", expr_str.c_str());
1831061da546Spatrick         break;
1832061da546Spatrick       case eExpressionInterrupted:
1833061da546Spatrick         error.SetErrorStringWithFormat(
1834061da546Spatrick             "expression interrupted for the expression '%s'", expr_str.c_str());
1835061da546Spatrick         break;
1836061da546Spatrick       case eExpressionHitBreakpoint:
1837061da546Spatrick         error.SetErrorStringWithFormat(
1838061da546Spatrick             "expression hit breakpoint for the expression '%s'",
1839061da546Spatrick             expr_str.c_str());
1840061da546Spatrick         break;
1841061da546Spatrick       case eExpressionTimedOut:
1842061da546Spatrick         error.SetErrorStringWithFormat(
1843061da546Spatrick             "expression timed out for the expression '%s'", expr_str.c_str());
1844061da546Spatrick         break;
1845061da546Spatrick       case eExpressionStoppedForDebug:
1846061da546Spatrick         error.SetErrorStringWithFormat("expression stop at entry point "
1847061da546Spatrick                                        "for debugging for the "
1848061da546Spatrick                                        "expression '%s'",
1849061da546Spatrick                                        expr_str.c_str());
1850061da546Spatrick         break;
1851dda28197Spatrick       case eExpressionThreadVanished:
1852dda28197Spatrick         error.SetErrorStringWithFormat(
1853dda28197Spatrick             "expression thread vanished for the expression '%s'",
1854dda28197Spatrick             expr_str.c_str());
1855dda28197Spatrick         break;
1856061da546Spatrick       }
1857061da546Spatrick     }
1858061da546Spatrick   }
1859061da546Spatrick   return error;
1860061da546Spatrick }
1861061da546Spatrick 
HandleCommand(const char * command_line,LazyBool lazy_add_to_history,const ExecutionContext & override_context,CommandReturnObject & result)1862061da546Spatrick bool CommandInterpreter::HandleCommand(const char *command_line,
1863061da546Spatrick                                        LazyBool lazy_add_to_history,
1864be691f3bSpatrick                                        const ExecutionContext &override_context,
1865be691f3bSpatrick                                        CommandReturnObject &result) {
1866061da546Spatrick 
1867be691f3bSpatrick   OverrideExecutionContext(override_context);
1868be691f3bSpatrick   bool status = HandleCommand(command_line, lazy_add_to_history, result);
1869be691f3bSpatrick   RestoreExecutionContext();
1870be691f3bSpatrick   return status;
1871be691f3bSpatrick }
1872be691f3bSpatrick 
HandleCommand(const char * command_line,LazyBool lazy_add_to_history,CommandReturnObject & result)1873be691f3bSpatrick bool CommandInterpreter::HandleCommand(const char *command_line,
1874be691f3bSpatrick                                        LazyBool lazy_add_to_history,
1875be691f3bSpatrick                                        CommandReturnObject &result) {
1876061da546Spatrick 
1877061da546Spatrick   std::string command_string(command_line);
1878061da546Spatrick   std::string original_command_string(command_line);
1879061da546Spatrick 
1880*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Commands);
1881061da546Spatrick   llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1882061da546Spatrick                                    command_line);
1883061da546Spatrick 
1884061da546Spatrick   LLDB_LOGF(log, "Processing command: %s", command_line);
1885be691f3bSpatrick   LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1886061da546Spatrick 
1887061da546Spatrick   if (WasInterrupted()) {
1888061da546Spatrick     result.AppendError("interrupted");
1889061da546Spatrick     return false;
1890061da546Spatrick   }
1891061da546Spatrick 
1892061da546Spatrick   bool add_to_history;
1893061da546Spatrick   if (lazy_add_to_history == eLazyBoolCalculate)
1894061da546Spatrick     add_to_history = (m_command_source_depth == 0);
1895061da546Spatrick   else
1896061da546Spatrick     add_to_history = (lazy_add_to_history == eLazyBoolYes);
1897061da546Spatrick 
1898be691f3bSpatrick   m_transcript_stream << "(lldb) " << command_line << '\n';
1899be691f3bSpatrick 
1900061da546Spatrick   bool empty_command = false;
1901061da546Spatrick   bool comment_command = false;
1902061da546Spatrick   if (command_string.empty())
1903061da546Spatrick     empty_command = true;
1904061da546Spatrick   else {
1905061da546Spatrick     const char *k_space_characters = "\t\n\v\f\r ";
1906061da546Spatrick 
1907061da546Spatrick     size_t non_space = command_string.find_first_not_of(k_space_characters);
1908061da546Spatrick     // Check for empty line or comment line (lines whose first non-space
1909061da546Spatrick     // character is the comment character for this interpreter)
1910061da546Spatrick     if (non_space == std::string::npos)
1911061da546Spatrick       empty_command = true;
1912061da546Spatrick     else if (command_string[non_space] == m_comment_char)
1913061da546Spatrick       comment_command = true;
1914061da546Spatrick     else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1915061da546Spatrick       llvm::StringRef search_str(command_string);
1916061da546Spatrick       search_str = search_str.drop_front(non_space);
1917061da546Spatrick       if (auto hist_str = m_command_history.FindString(search_str)) {
1918061da546Spatrick         add_to_history = false;
1919dda28197Spatrick         command_string = std::string(*hist_str);
1920dda28197Spatrick         original_command_string = std::string(*hist_str);
1921061da546Spatrick       } else {
1922061da546Spatrick         result.AppendErrorWithFormat("Could not find entry: %s in history",
1923061da546Spatrick                                      command_string.c_str());
1924061da546Spatrick         return false;
1925061da546Spatrick       }
1926061da546Spatrick     }
1927061da546Spatrick   }
1928061da546Spatrick 
1929061da546Spatrick   if (empty_command) {
1930be691f3bSpatrick     if (!GetRepeatPreviousCommand()) {
1931be691f3bSpatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1932be691f3bSpatrick       return true;
1933be691f3bSpatrick     }
1934be691f3bSpatrick 
1935061da546Spatrick     if (m_command_history.IsEmpty()) {
1936061da546Spatrick       result.AppendError("empty command");
1937061da546Spatrick       return false;
1938be691f3bSpatrick     }
1939be691f3bSpatrick 
1940061da546Spatrick     command_line = m_repeat_command.c_str();
1941061da546Spatrick     command_string = command_line;
1942061da546Spatrick     original_command_string = command_line;
1943061da546Spatrick     if (m_repeat_command.empty()) {
1944be691f3bSpatrick       result.AppendError("No auto repeat.");
1945061da546Spatrick       return false;
1946061da546Spatrick     }
1947be691f3bSpatrick 
1948061da546Spatrick     add_to_history = false;
1949061da546Spatrick   } else if (comment_command) {
1950061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1951061da546Spatrick     return true;
1952061da546Spatrick   }
1953061da546Spatrick 
1954061da546Spatrick   // Phase 1.
1955061da546Spatrick 
1956061da546Spatrick   // Before we do ANY kind of argument processing, we need to figure out what
1957061da546Spatrick   // the real/final command object is for the specified command.  This gets
1958061da546Spatrick   // complicated by the fact that the user could have specified an alias, and,
1959061da546Spatrick   // in translating the alias, there may also be command options and/or even
1960061da546Spatrick   // data (including raw text strings) that need to be found and inserted into
1961061da546Spatrick   // the command line as part of the translation.  So this first step is plain
1962061da546Spatrick   // look-up and replacement, resulting in:
1963061da546Spatrick   //    1. the command object whose Execute method will actually be called
1964061da546Spatrick   //    2. a revised command string, with all substitutions and replacements
1965061da546Spatrick   //       taken care of
1966061da546Spatrick   // From 1 above, we can determine whether the Execute function wants raw
1967061da546Spatrick   // input or not.
1968061da546Spatrick 
1969061da546Spatrick   CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1970061da546Spatrick 
1971*f6aab3d8Srobert   // We have to preprocess the whole command string for Raw commands, since we
1972*f6aab3d8Srobert   // don't know the structure of the command.  For parsed commands, we only
1973*f6aab3d8Srobert   // treat backticks as quote characters specially.
1974*f6aab3d8Srobert   // FIXME: We probably want to have raw commands do their own preprocessing.
1975*f6aab3d8Srobert   // For instance, I don't think people expect substitution in expr expressions.
1976*f6aab3d8Srobert   if (cmd_obj && cmd_obj->WantsRawCommandString()) {
1977*f6aab3d8Srobert     Status error(PreprocessCommand(command_string));
1978*f6aab3d8Srobert 
1979*f6aab3d8Srobert     if (error.Fail()) {
1980*f6aab3d8Srobert       result.AppendError(error.AsCString());
1981*f6aab3d8Srobert       return false;
1982*f6aab3d8Srobert     }
1983*f6aab3d8Srobert   }
1984*f6aab3d8Srobert 
1985061da546Spatrick   // Although the user may have abbreviated the command, the command_string now
1986061da546Spatrick   // has the command expanded to the full name.  For example, if the input was
1987061da546Spatrick   // "br s -n main", command_string is now "breakpoint set -n main".
1988061da546Spatrick   if (log) {
1989061da546Spatrick     llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1990061da546Spatrick     LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
1991061da546Spatrick     LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
1992061da546Spatrick               command_string.c_str());
1993061da546Spatrick     const bool wants_raw_input =
1994061da546Spatrick         (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
1995061da546Spatrick     LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
1996061da546Spatrick               wants_raw_input ? "True" : "False");
1997061da546Spatrick   }
1998061da546Spatrick 
1999061da546Spatrick   // Phase 2.
2000061da546Spatrick   // Take care of things like setting up the history command & calling the
2001061da546Spatrick   // appropriate Execute method on the CommandObject, with the appropriate
2002061da546Spatrick   // arguments.
2003061da546Spatrick 
2004061da546Spatrick   if (cmd_obj != nullptr) {
2005*f6aab3d8Srobert     // If we got here when empty_command was true, then this command is a
2006*f6aab3d8Srobert     // stored "repeat command" which we should give a chance to produce it's
2007*f6aab3d8Srobert     // repeat command, even though we don't add repeat commands to the history.
2008*f6aab3d8Srobert     if (add_to_history || empty_command) {
2009061da546Spatrick       Args command_args(command_string);
2010*f6aab3d8Srobert       std::optional<std::string> repeat_command =
2011*f6aab3d8Srobert           cmd_obj->GetRepeatCommand(command_args, 0);
2012*f6aab3d8Srobert       if (repeat_command)
2013*f6aab3d8Srobert         m_repeat_command.assign(*repeat_command);
2014061da546Spatrick       else
2015061da546Spatrick         m_repeat_command.assign(original_command_string);
2016061da546Spatrick     }
2017061da546Spatrick 
2018*f6aab3d8Srobert     if (add_to_history)
2019*f6aab3d8Srobert       m_command_history.AppendString(original_command_string);
2020*f6aab3d8Srobert 
2021061da546Spatrick     std::string remainder;
2022061da546Spatrick     const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2023061da546Spatrick     if (actual_cmd_name_len < command_string.length())
2024061da546Spatrick       remainder = command_string.substr(actual_cmd_name_len);
2025061da546Spatrick 
2026061da546Spatrick     // Remove any initial spaces
2027061da546Spatrick     size_t pos = remainder.find_first_not_of(k_white_space);
2028061da546Spatrick     if (pos != 0 && pos != std::string::npos)
2029061da546Spatrick       remainder.erase(0, pos);
2030061da546Spatrick 
2031061da546Spatrick     LLDB_LOGF(
2032061da546Spatrick         log, "HandleCommand, command line after removing command name(s): '%s'",
2033061da546Spatrick         remainder.c_str());
2034061da546Spatrick 
2035061da546Spatrick     cmd_obj->Execute(remainder.c_str(), result);
2036061da546Spatrick   }
2037061da546Spatrick 
2038061da546Spatrick   LLDB_LOGF(log, "HandleCommand, command %s",
2039061da546Spatrick             (result.Succeeded() ? "succeeded" : "did not succeed"));
2040061da546Spatrick 
2041be691f3bSpatrick   m_transcript_stream << result.GetOutputData();
2042be691f3bSpatrick   m_transcript_stream << result.GetErrorData();
2043be691f3bSpatrick 
2044061da546Spatrick   return result.Succeeded();
2045061da546Spatrick }
2046061da546Spatrick 
HandleCompletionMatches(CompletionRequest & request)2047061da546Spatrick void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
2048061da546Spatrick   bool look_for_subcommand = false;
2049061da546Spatrick 
2050061da546Spatrick   // For any of the command completions a unique match will be a complete word.
2051061da546Spatrick 
2052061da546Spatrick   if (request.GetParsedLine().GetArgumentCount() == 0) {
2053061da546Spatrick     // We got nothing on the command line, so return the list of commands
2054061da546Spatrick     bool include_aliases = true;
2055061da546Spatrick     StringList new_matches, descriptions;
2056061da546Spatrick     GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2057061da546Spatrick                                          descriptions);
2058061da546Spatrick     request.AddCompletions(new_matches, descriptions);
2059061da546Spatrick   } else if (request.GetCursorIndex() == 0) {
2060061da546Spatrick     // The cursor is in the first argument, so just do a lookup in the
2061061da546Spatrick     // dictionary.
2062061da546Spatrick     StringList new_matches, new_descriptions;
2063061da546Spatrick     CommandObject *cmd_obj =
2064061da546Spatrick         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
2065061da546Spatrick                          &new_matches, &new_descriptions);
2066061da546Spatrick 
2067061da546Spatrick     if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2068061da546Spatrick         new_matches.GetStringAtIndex(0) != nullptr &&
2069061da546Spatrick         strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2070061da546Spatrick                new_matches.GetStringAtIndex(0)) == 0) {
2071061da546Spatrick       if (request.GetParsedLine().GetArgumentCount() != 1) {
2072061da546Spatrick         look_for_subcommand = true;
2073061da546Spatrick         new_matches.DeleteStringAtIndex(0);
2074061da546Spatrick         new_descriptions.DeleteStringAtIndex(0);
2075061da546Spatrick         request.AppendEmptyArgument();
2076061da546Spatrick       }
2077061da546Spatrick     }
2078061da546Spatrick     request.AddCompletions(new_matches, new_descriptions);
2079061da546Spatrick   }
2080061da546Spatrick 
2081061da546Spatrick   if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2082061da546Spatrick     // We are completing further on into a commands arguments, so find the
2083061da546Spatrick     // command and tell it to complete the command. First see if there is a
2084061da546Spatrick     // matching initial command:
2085061da546Spatrick     CommandObject *command_object =
2086061da546Spatrick         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
2087061da546Spatrick     if (command_object) {
2088061da546Spatrick       request.ShiftArguments();
2089061da546Spatrick       command_object->HandleCompletion(request);
2090061da546Spatrick     }
2091061da546Spatrick   }
2092061da546Spatrick }
2093061da546Spatrick 
HandleCompletion(CompletionRequest & request)2094061da546Spatrick void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
2095061da546Spatrick 
2096061da546Spatrick   // Don't complete comments, and if the line we are completing is just the
2097061da546Spatrick   // history repeat character, substitute the appropriate history line.
2098061da546Spatrick   llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2099061da546Spatrick 
2100061da546Spatrick   if (!first_arg.empty()) {
2101061da546Spatrick     if (first_arg.front() == m_comment_char)
2102061da546Spatrick       return;
2103061da546Spatrick     if (first_arg.front() == CommandHistory::g_repeat_char) {
2104061da546Spatrick       if (auto hist_str = m_command_history.FindString(first_arg))
2105061da546Spatrick         request.AddCompletion(*hist_str, "Previous command history event",
2106061da546Spatrick                               CompletionMode::RewriteLine);
2107061da546Spatrick       return;
2108061da546Spatrick     }
2109061da546Spatrick   }
2110061da546Spatrick 
2111061da546Spatrick   HandleCompletionMatches(request);
2112061da546Spatrick }
2113061da546Spatrick 
2114*f6aab3d8Srobert std::optional<std::string>
GetAutoSuggestionForCommand(llvm::StringRef line)2115be691f3bSpatrick CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) {
2116be691f3bSpatrick   if (line.empty())
2117*f6aab3d8Srobert     return std::nullopt;
2118be691f3bSpatrick   const size_t s = m_command_history.GetSize();
2119be691f3bSpatrick   for (int i = s - 1; i >= 0; --i) {
2120be691f3bSpatrick     llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2121be691f3bSpatrick     if (entry.consume_front(line))
2122be691f3bSpatrick       return entry.str();
2123be691f3bSpatrick   }
2124*f6aab3d8Srobert   return std::nullopt;
2125be691f3bSpatrick }
2126061da546Spatrick 
UpdatePrompt(llvm::StringRef new_prompt)2127061da546Spatrick void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2128061da546Spatrick   EventSP prompt_change_event_sp(
2129061da546Spatrick       new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2130061da546Spatrick   ;
2131061da546Spatrick   BroadcastEvent(prompt_change_event_sp);
2132061da546Spatrick   if (m_command_io_handler_sp)
2133061da546Spatrick     m_command_io_handler_sp->SetPrompt(new_prompt);
2134061da546Spatrick }
2135061da546Spatrick 
Confirm(llvm::StringRef message,bool default_answer)2136061da546Spatrick bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2137061da546Spatrick   // Check AutoConfirm first:
2138061da546Spatrick   if (m_debugger.GetAutoConfirm())
2139061da546Spatrick     return default_answer;
2140061da546Spatrick 
2141061da546Spatrick   IOHandlerConfirm *confirm =
2142061da546Spatrick       new IOHandlerConfirm(m_debugger, message, default_answer);
2143061da546Spatrick   IOHandlerSP io_handler_sp(confirm);
2144dda28197Spatrick   m_debugger.RunIOHandlerSync(io_handler_sp);
2145061da546Spatrick   return confirm->GetResponse();
2146061da546Spatrick }
2147061da546Spatrick 
2148061da546Spatrick const CommandAlias *
GetAlias(llvm::StringRef alias_name) const2149061da546Spatrick CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2150061da546Spatrick   OptionArgVectorSP ret_val;
2151061da546Spatrick 
2152dda28197Spatrick   auto pos = m_alias_dict.find(std::string(alias_name));
2153061da546Spatrick   if (pos != m_alias_dict.end())
2154061da546Spatrick     return (CommandAlias *)pos->second.get();
2155061da546Spatrick 
2156061da546Spatrick   return nullptr;
2157061da546Spatrick }
2158061da546Spatrick 
HasCommands() const2159061da546Spatrick bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2160061da546Spatrick 
HasAliases() const2161061da546Spatrick bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2162061da546Spatrick 
HasUserCommands() const2163061da546Spatrick bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2164061da546Spatrick 
HasUserMultiwordCommands() const2165*f6aab3d8Srobert bool CommandInterpreter::HasUserMultiwordCommands() const {
2166*f6aab3d8Srobert   return (!m_user_mw_dict.empty());
2167*f6aab3d8Srobert }
2168*f6aab3d8Srobert 
HasAliasOptions() const2169061da546Spatrick bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
2170061da546Spatrick 
BuildAliasCommandArgs(CommandObject * alias_cmd_obj,const char * alias_name,Args & cmd_args,std::string & raw_input_string,CommandReturnObject & result)2171061da546Spatrick void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
2172061da546Spatrick                                                const char *alias_name,
2173061da546Spatrick                                                Args &cmd_args,
2174061da546Spatrick                                                std::string &raw_input_string,
2175061da546Spatrick                                                CommandReturnObject &result) {
2176061da546Spatrick   OptionArgVectorSP option_arg_vector_sp =
2177061da546Spatrick       GetAlias(alias_name)->GetOptionArguments();
2178061da546Spatrick 
2179061da546Spatrick   bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2180061da546Spatrick 
2181061da546Spatrick   // Make sure that the alias name is the 0th element in cmd_args
2182061da546Spatrick   std::string alias_name_str = alias_name;
2183061da546Spatrick   if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2184061da546Spatrick     cmd_args.Unshift(alias_name_str);
2185061da546Spatrick 
2186061da546Spatrick   Args new_args(alias_cmd_obj->GetCommandName());
2187061da546Spatrick   if (new_args.GetArgumentCount() == 2)
2188061da546Spatrick     new_args.Shift();
2189061da546Spatrick 
2190061da546Spatrick   if (option_arg_vector_sp.get()) {
2191061da546Spatrick     if (wants_raw_input) {
2192061da546Spatrick       // We have a command that both has command options and takes raw input.
2193061da546Spatrick       // Make *sure* it has a " -- " in the right place in the
2194061da546Spatrick       // raw_input_string.
2195061da546Spatrick       size_t pos = raw_input_string.find(" -- ");
2196061da546Spatrick       if (pos == std::string::npos) {
2197061da546Spatrick         // None found; assume it goes at the beginning of the raw input string
2198061da546Spatrick         raw_input_string.insert(0, " -- ");
2199061da546Spatrick       }
2200061da546Spatrick     }
2201061da546Spatrick 
2202061da546Spatrick     OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2203061da546Spatrick     const size_t old_size = cmd_args.GetArgumentCount();
2204061da546Spatrick     std::vector<bool> used(old_size + 1, false);
2205061da546Spatrick 
2206061da546Spatrick     used[0] = true;
2207061da546Spatrick 
2208061da546Spatrick     int value_type;
2209061da546Spatrick     std::string option;
2210061da546Spatrick     std::string value;
2211061da546Spatrick     for (const auto &option_entry : *option_arg_vector) {
2212061da546Spatrick       std::tie(option, value_type, value) = option_entry;
2213*f6aab3d8Srobert       if (option == g_argument) {
2214061da546Spatrick         if (!wants_raw_input || (value != "--")) {
2215061da546Spatrick           // Since we inserted this above, make sure we don't insert it twice
2216061da546Spatrick           new_args.AppendArgument(value);
2217061da546Spatrick         }
2218061da546Spatrick         continue;
2219061da546Spatrick       }
2220061da546Spatrick 
2221061da546Spatrick       if (value_type != OptionParser::eOptionalArgument)
2222061da546Spatrick         new_args.AppendArgument(option);
2223061da546Spatrick 
2224*f6aab3d8Srobert       if (value == g_no_argument)
2225061da546Spatrick         continue;
2226061da546Spatrick 
2227061da546Spatrick       int index = GetOptionArgumentPosition(value.c_str());
2228061da546Spatrick       if (index == 0) {
2229061da546Spatrick         // value was NOT a positional argument; must be a real value
2230061da546Spatrick         if (value_type != OptionParser::eOptionalArgument)
2231061da546Spatrick           new_args.AppendArgument(value);
2232061da546Spatrick         else {
2233be691f3bSpatrick           new_args.AppendArgument(option + value);
2234061da546Spatrick         }
2235061da546Spatrick 
2236061da546Spatrick       } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2237061da546Spatrick         result.AppendErrorWithFormat("Not enough arguments provided; you "
2238061da546Spatrick                                      "need at least %d arguments to use "
2239061da546Spatrick                                      "this alias.\n",
2240061da546Spatrick                                      index);
2241061da546Spatrick         return;
2242061da546Spatrick       } else {
2243061da546Spatrick         // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2244061da546Spatrick         size_t strpos =
2245061da546Spatrick             raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2246061da546Spatrick         if (strpos != std::string::npos) {
2247061da546Spatrick           raw_input_string = raw_input_string.erase(
2248061da546Spatrick               strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2249061da546Spatrick         }
2250061da546Spatrick 
2251061da546Spatrick         if (value_type != OptionParser::eOptionalArgument)
2252061da546Spatrick           new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2253061da546Spatrick         else {
2254be691f3bSpatrick           new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2255061da546Spatrick         }
2256061da546Spatrick         used[index] = true;
2257061da546Spatrick       }
2258061da546Spatrick     }
2259061da546Spatrick 
2260061da546Spatrick     for (auto entry : llvm::enumerate(cmd_args.entries())) {
2261061da546Spatrick       if (!used[entry.index()] && !wants_raw_input)
2262061da546Spatrick         new_args.AppendArgument(entry.value().ref());
2263061da546Spatrick     }
2264061da546Spatrick 
2265061da546Spatrick     cmd_args.Clear();
2266061da546Spatrick     cmd_args.SetArguments(new_args.GetArgumentCount(),
2267061da546Spatrick                           new_args.GetConstArgumentVector());
2268061da546Spatrick   } else {
2269061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2270061da546Spatrick     // This alias was not created with any options; nothing further needs to be
2271061da546Spatrick     // done, unless it is a command that wants raw input, in which case we need
2272061da546Spatrick     // to clear the rest of the data from cmd_args, since its in the raw input
2273061da546Spatrick     // string.
2274061da546Spatrick     if (wants_raw_input) {
2275061da546Spatrick       cmd_args.Clear();
2276061da546Spatrick       cmd_args.SetArguments(new_args.GetArgumentCount(),
2277061da546Spatrick                             new_args.GetConstArgumentVector());
2278061da546Spatrick     }
2279061da546Spatrick     return;
2280061da546Spatrick   }
2281061da546Spatrick 
2282061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2283061da546Spatrick }
2284061da546Spatrick 
GetOptionArgumentPosition(const char * in_string)2285061da546Spatrick int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2286061da546Spatrick   int position = 0; // Any string that isn't an argument position, i.e. '%'
2287061da546Spatrick                     // followed by an integer, gets a position
2288061da546Spatrick                     // of zero.
2289061da546Spatrick 
2290061da546Spatrick   const char *cptr = in_string;
2291061da546Spatrick 
2292061da546Spatrick   // Does it start with '%'
2293061da546Spatrick   if (cptr[0] == '%') {
2294061da546Spatrick     ++cptr;
2295061da546Spatrick 
2296061da546Spatrick     // Is the rest of it entirely digits?
2297061da546Spatrick     if (isdigit(cptr[0])) {
2298061da546Spatrick       const char *start = cptr;
2299061da546Spatrick       while (isdigit(cptr[0]))
2300061da546Spatrick         ++cptr;
2301061da546Spatrick 
2302061da546Spatrick       // We've gotten to the end of the digits; are we at the end of the
2303061da546Spatrick       // string?
2304061da546Spatrick       if (cptr[0] == '\0')
2305061da546Spatrick         position = atoi(start);
2306061da546Spatrick     }
2307061da546Spatrick   }
2308061da546Spatrick 
2309061da546Spatrick   return position;
2310061da546Spatrick }
2311061da546Spatrick 
GetHomeInitFile(llvm::SmallVectorImpl<char> & init_file,llvm::StringRef suffix={})2312061da546Spatrick static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2313061da546Spatrick                             llvm::StringRef suffix = {}) {
2314061da546Spatrick   std::string init_file_name = ".lldbinit";
2315061da546Spatrick   if (!suffix.empty()) {
2316061da546Spatrick     init_file_name.append("-");
2317061da546Spatrick     init_file_name.append(suffix.str());
2318061da546Spatrick   }
2319061da546Spatrick 
2320be691f3bSpatrick   FileSystem::Instance().GetHomeDirectory(init_file);
2321061da546Spatrick   llvm::sys::path::append(init_file, init_file_name);
2322061da546Spatrick 
2323061da546Spatrick   FileSystem::Instance().Resolve(init_file);
2324061da546Spatrick }
2325061da546Spatrick 
GetHomeREPLInitFile(llvm::SmallVectorImpl<char> & init_file,LanguageType language)2326*f6aab3d8Srobert static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
2327*f6aab3d8Srobert                                 LanguageType language) {
2328*f6aab3d8Srobert   if (language == eLanguageTypeUnknown) {
2329be691f3bSpatrick     LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
2330be691f3bSpatrick     if (auto main_repl_language = repl_languages.GetSingularLanguage())
2331be691f3bSpatrick       language = *main_repl_language;
2332be691f3bSpatrick     else
2333be691f3bSpatrick       return;
2334*f6aab3d8Srobert   }
2335be691f3bSpatrick 
2336be691f3bSpatrick   std::string init_file_name =
2337be691f3bSpatrick       (llvm::Twine(".lldbinit-") +
2338be691f3bSpatrick        llvm::Twine(Language::GetNameForLanguageType(language)) +
2339be691f3bSpatrick        llvm::Twine("-repl"))
2340be691f3bSpatrick           .str();
2341be691f3bSpatrick   FileSystem::Instance().GetHomeDirectory(init_file);
2342be691f3bSpatrick   llvm::sys::path::append(init_file, init_file_name);
2343be691f3bSpatrick   FileSystem::Instance().Resolve(init_file);
2344be691f3bSpatrick }
2345be691f3bSpatrick 
GetCwdInitFile(llvm::SmallVectorImpl<char> & init_file)2346061da546Spatrick static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
2347061da546Spatrick   llvm::StringRef s = ".lldbinit";
2348061da546Spatrick   init_file.assign(s.begin(), s.end());
2349061da546Spatrick   FileSystem::Instance().Resolve(init_file);
2350061da546Spatrick }
2351061da546Spatrick 
SourceInitFile(FileSpec file,CommandReturnObject & result)2352061da546Spatrick void CommandInterpreter::SourceInitFile(FileSpec file,
2353061da546Spatrick                                         CommandReturnObject &result) {
2354061da546Spatrick   assert(!m_skip_lldbinit_files);
2355061da546Spatrick 
2356061da546Spatrick   if (!FileSystem::Instance().Exists(file)) {
2357061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2358061da546Spatrick     return;
2359061da546Spatrick   }
2360061da546Spatrick 
2361061da546Spatrick   // Use HandleCommand to 'source' the given file; this will do the actual
2362061da546Spatrick   // broadcasting of the commands back to any appropriate listener (see
2363061da546Spatrick   // CommandObjectSource::Execute for more details).
2364061da546Spatrick   const bool saved_batch = SetBatchCommandMode(true);
2365061da546Spatrick   CommandInterpreterRunOptions options;
2366061da546Spatrick   options.SetSilent(true);
2367061da546Spatrick   options.SetPrintErrors(true);
2368061da546Spatrick   options.SetStopOnError(false);
2369061da546Spatrick   options.SetStopOnContinue(true);
2370be691f3bSpatrick   HandleCommandsFromFile(file, options, result);
2371061da546Spatrick   SetBatchCommandMode(saved_batch);
2372061da546Spatrick }
2373061da546Spatrick 
SourceInitFileCwd(CommandReturnObject & result)2374061da546Spatrick void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
2375061da546Spatrick   if (m_skip_lldbinit_files) {
2376061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2377061da546Spatrick     return;
2378061da546Spatrick   }
2379061da546Spatrick 
2380061da546Spatrick   llvm::SmallString<128> init_file;
2381061da546Spatrick   GetCwdInitFile(init_file);
2382061da546Spatrick   if (!FileSystem::Instance().Exists(init_file)) {
2383061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2384061da546Spatrick     return;
2385061da546Spatrick   }
2386061da546Spatrick 
2387*f6aab3d8Srobert   LoadCWDlldbinitFile should_load =
2388*f6aab3d8Srobert       Target::GetGlobalProperties().GetLoadCWDlldbinitFile();
2389061da546Spatrick 
2390061da546Spatrick   switch (should_load) {
2391061da546Spatrick   case eLoadCWDlldbinitFalse:
2392061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2393061da546Spatrick     break;
2394061da546Spatrick   case eLoadCWDlldbinitTrue:
2395061da546Spatrick     SourceInitFile(FileSpec(init_file.str()), result);
2396061da546Spatrick     break;
2397061da546Spatrick   case eLoadCWDlldbinitWarn: {
2398061da546Spatrick     llvm::SmallString<128> home_init_file;
2399061da546Spatrick     GetHomeInitFile(home_init_file);
2400061da546Spatrick     if (llvm::sys::path::parent_path(init_file) ==
2401061da546Spatrick         llvm::sys::path::parent_path(home_init_file)) {
2402061da546Spatrick       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2403061da546Spatrick     } else {
2404be691f3bSpatrick       result.AppendError(InitFileWarning);
2405061da546Spatrick     }
2406061da546Spatrick   }
2407061da546Spatrick   }
2408061da546Spatrick }
2409061da546Spatrick 
2410061da546Spatrick /// We will first see if there is an application specific ".lldbinit" file
2411061da546Spatrick /// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2412be691f3bSpatrick /// If this file doesn't exist, we fall back to the REPL init file or the
2413be691f3bSpatrick /// default home init file in "~/.lldbinit".
SourceInitFileHome(CommandReturnObject & result,bool is_repl)2414be691f3bSpatrick void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
2415be691f3bSpatrick                                             bool is_repl) {
2416061da546Spatrick   if (m_skip_lldbinit_files) {
2417061da546Spatrick     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2418061da546Spatrick     return;
2419061da546Spatrick   }
2420061da546Spatrick 
2421061da546Spatrick   llvm::SmallString<128> init_file;
2422be691f3bSpatrick 
2423be691f3bSpatrick   if (is_repl)
2424*f6aab3d8Srobert     GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2425be691f3bSpatrick 
2426be691f3bSpatrick   if (init_file.empty())
2427061da546Spatrick     GetHomeInitFile(init_file);
2428061da546Spatrick 
2429061da546Spatrick   if (!m_skip_app_init_files) {
2430061da546Spatrick     llvm::StringRef program_name =
2431061da546Spatrick         HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2432061da546Spatrick     llvm::SmallString<128> program_init_file;
2433061da546Spatrick     GetHomeInitFile(program_init_file, program_name);
2434061da546Spatrick     if (FileSystem::Instance().Exists(program_init_file))
2435061da546Spatrick       init_file = program_init_file;
2436061da546Spatrick   }
2437061da546Spatrick 
2438061da546Spatrick   SourceInitFile(FileSpec(init_file.str()), result);
2439061da546Spatrick }
2440061da546Spatrick 
SourceInitFileGlobal(CommandReturnObject & result)2441*f6aab3d8Srobert void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
2442*f6aab3d8Srobert #ifdef LLDB_GLOBAL_INIT_DIRECTORY
2443*f6aab3d8Srobert   if (!m_skip_lldbinit_files) {
2444*f6aab3d8Srobert     FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2445*f6aab3d8Srobert     if (init_file)
2446*f6aab3d8Srobert       init_file.MakeAbsolute(HostInfo::GetShlibDir());
2447*f6aab3d8Srobert 
2448*f6aab3d8Srobert     init_file.AppendPathComponent("lldbinit");
2449*f6aab3d8Srobert     SourceInitFile(init_file, result);
2450*f6aab3d8Srobert     return;
2451*f6aab3d8Srobert   }
2452*f6aab3d8Srobert #endif
2453*f6aab3d8Srobert   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2454*f6aab3d8Srobert }
2455*f6aab3d8Srobert 
GetCommandPrefix()2456061da546Spatrick const char *CommandInterpreter::GetCommandPrefix() {
2457061da546Spatrick   const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2458061da546Spatrick   return prefix == nullptr ? "" : prefix;
2459061da546Spatrick }
2460061da546Spatrick 
GetPlatform(bool prefer_target_platform)2461061da546Spatrick PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2462061da546Spatrick   PlatformSP platform_sp;
2463061da546Spatrick   if (prefer_target_platform) {
2464061da546Spatrick     ExecutionContext exe_ctx(GetExecutionContext());
2465061da546Spatrick     Target *target = exe_ctx.GetTargetPtr();
2466061da546Spatrick     if (target)
2467061da546Spatrick       platform_sp = target->GetPlatform();
2468061da546Spatrick   }
2469061da546Spatrick 
2470061da546Spatrick   if (!platform_sp)
2471061da546Spatrick     platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2472061da546Spatrick   return platform_sp;
2473061da546Spatrick }
2474061da546Spatrick 
DidProcessStopAbnormally() const2475061da546Spatrick bool CommandInterpreter::DidProcessStopAbnormally() const {
2476be691f3bSpatrick   auto exe_ctx = GetExecutionContext();
2477be691f3bSpatrick   TargetSP target_sp = exe_ctx.GetTargetSP();
2478061da546Spatrick   if (!target_sp)
2479061da546Spatrick     return false;
2480061da546Spatrick 
2481061da546Spatrick   ProcessSP process_sp(target_sp->GetProcessSP());
2482061da546Spatrick   if (!process_sp)
2483061da546Spatrick     return false;
2484061da546Spatrick 
2485061da546Spatrick   if (eStateStopped != process_sp->GetState())
2486061da546Spatrick     return false;
2487061da546Spatrick 
2488061da546Spatrick   for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2489061da546Spatrick     StopInfoSP stop_info = thread_sp->GetStopInfo();
2490*f6aab3d8Srobert     if (!stop_info) {
2491*f6aab3d8Srobert       // If there's no stop_info, keep iterating through the other threads;
2492*f6aab3d8Srobert       // it's enough that any thread has got a stop_info that indicates
2493*f6aab3d8Srobert       // an abnormal stop, to consider the process to be stopped abnormally.
2494*f6aab3d8Srobert       continue;
2495*f6aab3d8Srobert     }
2496061da546Spatrick 
2497061da546Spatrick     const StopReason reason = stop_info->GetStopReason();
2498be691f3bSpatrick     if (reason == eStopReasonException ||
2499be691f3bSpatrick         reason == eStopReasonInstrumentation ||
2500be691f3bSpatrick         reason == eStopReasonProcessorTrace)
2501061da546Spatrick       return true;
2502061da546Spatrick 
2503061da546Spatrick     if (reason == eStopReasonSignal) {
2504061da546Spatrick       const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2505061da546Spatrick       UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2506061da546Spatrick       if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2507061da546Spatrick         // The signal is unknown, treat it as abnormal.
2508061da546Spatrick         return true;
2509061da546Spatrick 
2510061da546Spatrick       const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2511061da546Spatrick       const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2512061da546Spatrick       if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2513061da546Spatrick         // The signal very likely implies a crash.
2514061da546Spatrick         return true;
2515061da546Spatrick     }
2516061da546Spatrick   }
2517061da546Spatrick 
2518061da546Spatrick   return false;
2519061da546Spatrick }
2520061da546Spatrick 
2521be691f3bSpatrick void
HandleCommands(const StringList & commands,const ExecutionContext & override_context,const CommandInterpreterRunOptions & options,CommandReturnObject & result)2522be691f3bSpatrick CommandInterpreter::HandleCommands(const StringList &commands,
2523be691f3bSpatrick                                    const ExecutionContext &override_context,
2524be691f3bSpatrick                                    const CommandInterpreterRunOptions &options,
2525be691f3bSpatrick                                    CommandReturnObject &result) {
2526be691f3bSpatrick 
2527be691f3bSpatrick   OverrideExecutionContext(override_context);
2528be691f3bSpatrick   HandleCommands(commands, options, result);
2529be691f3bSpatrick   RestoreExecutionContext();
2530be691f3bSpatrick }
2531be691f3bSpatrick 
HandleCommands(const StringList & commands,const CommandInterpreterRunOptions & options,CommandReturnObject & result)2532061da546Spatrick void CommandInterpreter::HandleCommands(const StringList &commands,
2533be691f3bSpatrick                                         const CommandInterpreterRunOptions &options,
2534061da546Spatrick                                         CommandReturnObject &result) {
2535061da546Spatrick   size_t num_lines = commands.GetSize();
2536061da546Spatrick 
2537061da546Spatrick   // If we are going to continue past a "continue" then we need to run the
2538061da546Spatrick   // commands synchronously. Make sure you reset this value anywhere you return
2539061da546Spatrick   // from the function.
2540061da546Spatrick 
2541061da546Spatrick   bool old_async_execution = m_debugger.GetAsyncExecution();
2542061da546Spatrick 
2543061da546Spatrick   if (!options.GetStopOnContinue()) {
2544061da546Spatrick     m_debugger.SetAsyncExecution(false);
2545061da546Spatrick   }
2546061da546Spatrick 
2547061da546Spatrick   for (size_t idx = 0; idx < num_lines && !WasInterrupted(); idx++) {
2548061da546Spatrick     const char *cmd = commands.GetStringAtIndex(idx);
2549061da546Spatrick     if (cmd[0] == '\0')
2550061da546Spatrick       continue;
2551061da546Spatrick 
2552061da546Spatrick     if (options.GetEchoCommands()) {
2553061da546Spatrick       // TODO: Add Stream support.
2554061da546Spatrick       result.AppendMessageWithFormat("%s %s\n",
2555061da546Spatrick                                      m_debugger.GetPrompt().str().c_str(), cmd);
2556061da546Spatrick     }
2557061da546Spatrick 
2558dda28197Spatrick     CommandReturnObject tmp_result(m_debugger.GetUseColor());
2559be691f3bSpatrick     tmp_result.SetInteractive(result.GetInteractive());
2560be691f3bSpatrick     tmp_result.SetSuppressImmediateOutput(true);
2561061da546Spatrick 
2562061da546Spatrick     // We might call into a regex or alias command, in which case the
2563061da546Spatrick     // add_to_history will get lost.  This m_command_source_depth dingus is the
2564061da546Spatrick     // way we turn off adding to the history in that case, so set it up here.
2565061da546Spatrick     if (!options.GetAddToHistory())
2566061da546Spatrick       m_command_source_depth++;
2567be691f3bSpatrick     bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2568061da546Spatrick     if (!options.GetAddToHistory())
2569061da546Spatrick       m_command_source_depth--;
2570061da546Spatrick 
2571061da546Spatrick     if (options.GetPrintResults()) {
2572061da546Spatrick       if (tmp_result.Succeeded())
2573061da546Spatrick         result.AppendMessage(tmp_result.GetOutputData());
2574061da546Spatrick     }
2575061da546Spatrick 
2576061da546Spatrick     if (!success || !tmp_result.Succeeded()) {
2577061da546Spatrick       llvm::StringRef error_msg = tmp_result.GetErrorData();
2578061da546Spatrick       if (error_msg.empty())
2579061da546Spatrick         error_msg = "<unknown error>.\n";
2580061da546Spatrick       if (options.GetStopOnError()) {
2581061da546Spatrick         result.AppendErrorWithFormat(
2582061da546Spatrick             "Aborting reading of commands after command #%" PRIu64
2583061da546Spatrick             ": '%s' failed with %s",
2584061da546Spatrick             (uint64_t)idx, cmd, error_msg.str().c_str());
2585061da546Spatrick         m_debugger.SetAsyncExecution(old_async_execution);
2586061da546Spatrick         return;
2587061da546Spatrick       } else if (options.GetPrintResults()) {
2588061da546Spatrick         result.AppendMessageWithFormat(
2589061da546Spatrick             "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2590061da546Spatrick             error_msg.str().c_str());
2591061da546Spatrick       }
2592061da546Spatrick     }
2593061da546Spatrick 
2594061da546Spatrick     if (result.GetImmediateOutputStream())
2595061da546Spatrick       result.GetImmediateOutputStream()->Flush();
2596061da546Spatrick 
2597061da546Spatrick     if (result.GetImmediateErrorStream())
2598061da546Spatrick       result.GetImmediateErrorStream()->Flush();
2599061da546Spatrick 
2600061da546Spatrick     // N.B. Can't depend on DidChangeProcessState, because the state coming
2601061da546Spatrick     // into the command execution could be running (for instance in Breakpoint
2602061da546Spatrick     // Commands. So we check the return value to see if it is has running in
2603061da546Spatrick     // it.
2604061da546Spatrick     if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2605061da546Spatrick         (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2606061da546Spatrick       if (options.GetStopOnContinue()) {
2607061da546Spatrick         // If we caused the target to proceed, and we're going to stop in that
2608061da546Spatrick         // case, set the status in our real result before returning.  This is
2609061da546Spatrick         // an error if the continue was not the last command in the set of
2610061da546Spatrick         // commands to be run.
2611061da546Spatrick         if (idx != num_lines - 1)
2612061da546Spatrick           result.AppendErrorWithFormat(
2613061da546Spatrick               "Aborting reading of commands after command #%" PRIu64
2614061da546Spatrick               ": '%s' continued the target.\n",
2615061da546Spatrick               (uint64_t)idx + 1, cmd);
2616061da546Spatrick         else
2617061da546Spatrick           result.AppendMessageWithFormat("Command #%" PRIu64
2618061da546Spatrick                                          " '%s' continued the target.\n",
2619061da546Spatrick                                          (uint64_t)idx + 1, cmd);
2620061da546Spatrick 
2621061da546Spatrick         result.SetStatus(tmp_result.GetStatus());
2622061da546Spatrick         m_debugger.SetAsyncExecution(old_async_execution);
2623061da546Spatrick 
2624061da546Spatrick         return;
2625061da546Spatrick       }
2626061da546Spatrick     }
2627061da546Spatrick 
2628061da546Spatrick     // Also check for "stop on crash here:
2629061da546Spatrick     if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2630061da546Spatrick         DidProcessStopAbnormally()) {
2631061da546Spatrick       if (idx != num_lines - 1)
2632061da546Spatrick         result.AppendErrorWithFormat(
2633061da546Spatrick             "Aborting reading of commands after command #%" PRIu64
2634061da546Spatrick             ": '%s' stopped with a signal or exception.\n",
2635061da546Spatrick             (uint64_t)idx + 1, cmd);
2636061da546Spatrick       else
2637061da546Spatrick         result.AppendMessageWithFormat(
2638061da546Spatrick             "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2639061da546Spatrick             (uint64_t)idx + 1, cmd);
2640061da546Spatrick 
2641061da546Spatrick       result.SetStatus(tmp_result.GetStatus());
2642061da546Spatrick       m_debugger.SetAsyncExecution(old_async_execution);
2643061da546Spatrick 
2644061da546Spatrick       return;
2645061da546Spatrick     }
2646061da546Spatrick   }
2647061da546Spatrick 
2648061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishResult);
2649061da546Spatrick   m_debugger.SetAsyncExecution(old_async_execution);
2650061da546Spatrick }
2651061da546Spatrick 
2652061da546Spatrick // Make flags that we can pass into the IOHandler so our delegates can do the
2653061da546Spatrick // right thing
2654061da546Spatrick enum {
2655061da546Spatrick   eHandleCommandFlagStopOnContinue = (1u << 0),
2656061da546Spatrick   eHandleCommandFlagStopOnError = (1u << 1),
2657061da546Spatrick   eHandleCommandFlagEchoCommand = (1u << 2),
2658061da546Spatrick   eHandleCommandFlagEchoCommentCommand = (1u << 3),
2659061da546Spatrick   eHandleCommandFlagPrintResult = (1u << 4),
2660061da546Spatrick   eHandleCommandFlagPrintErrors = (1u << 5),
2661061da546Spatrick   eHandleCommandFlagStopOnCrash = (1u << 6)
2662061da546Spatrick };
2663061da546Spatrick 
HandleCommandsFromFile(FileSpec & cmd_file,const ExecutionContext & context,const CommandInterpreterRunOptions & options,CommandReturnObject & result)2664061da546Spatrick void CommandInterpreter::HandleCommandsFromFile(
2665be691f3bSpatrick     FileSpec &cmd_file, const ExecutionContext &context,
2666be691f3bSpatrick     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2667be691f3bSpatrick   OverrideExecutionContext(context);
2668be691f3bSpatrick   HandleCommandsFromFile(cmd_file, options, result);
2669be691f3bSpatrick   RestoreExecutionContext();
2670be691f3bSpatrick }
2671be691f3bSpatrick 
HandleCommandsFromFile(FileSpec & cmd_file,const CommandInterpreterRunOptions & options,CommandReturnObject & result)2672be691f3bSpatrick void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
2673be691f3bSpatrick     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2674061da546Spatrick   if (!FileSystem::Instance().Exists(cmd_file)) {
2675061da546Spatrick     result.AppendErrorWithFormat(
2676061da546Spatrick         "Error reading commands from file %s - file not found.\n",
2677061da546Spatrick         cmd_file.GetFilename().AsCString("<Unknown>"));
2678061da546Spatrick     return;
2679061da546Spatrick   }
2680061da546Spatrick 
2681061da546Spatrick   std::string cmd_file_path = cmd_file.GetPath();
2682061da546Spatrick   auto input_file_up =
2683*f6aab3d8Srobert       FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly);
2684061da546Spatrick   if (!input_file_up) {
2685061da546Spatrick     std::string error = llvm::toString(input_file_up.takeError());
2686061da546Spatrick     result.AppendErrorWithFormatv(
2687061da546Spatrick         "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2688061da546Spatrick         llvm::fmt_consume(input_file_up.takeError()));
2689061da546Spatrick     return;
2690061da546Spatrick   }
2691061da546Spatrick   FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2692061da546Spatrick 
2693061da546Spatrick   Debugger &debugger = GetDebugger();
2694061da546Spatrick 
2695061da546Spatrick   uint32_t flags = 0;
2696061da546Spatrick 
2697061da546Spatrick   if (options.m_stop_on_continue == eLazyBoolCalculate) {
2698061da546Spatrick     if (m_command_source_flags.empty()) {
2699061da546Spatrick       // Stop on continue by default
2700061da546Spatrick       flags |= eHandleCommandFlagStopOnContinue;
2701061da546Spatrick     } else if (m_command_source_flags.back() &
2702061da546Spatrick                eHandleCommandFlagStopOnContinue) {
2703061da546Spatrick       flags |= eHandleCommandFlagStopOnContinue;
2704061da546Spatrick     }
2705061da546Spatrick   } else if (options.m_stop_on_continue == eLazyBoolYes) {
2706061da546Spatrick     flags |= eHandleCommandFlagStopOnContinue;
2707061da546Spatrick   }
2708061da546Spatrick 
2709061da546Spatrick   if (options.m_stop_on_error == eLazyBoolCalculate) {
2710061da546Spatrick     if (m_command_source_flags.empty()) {
2711061da546Spatrick       if (GetStopCmdSourceOnError())
2712061da546Spatrick         flags |= eHandleCommandFlagStopOnError;
2713061da546Spatrick     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2714061da546Spatrick       flags |= eHandleCommandFlagStopOnError;
2715061da546Spatrick     }
2716061da546Spatrick   } else if (options.m_stop_on_error == eLazyBoolYes) {
2717061da546Spatrick     flags |= eHandleCommandFlagStopOnError;
2718061da546Spatrick   }
2719061da546Spatrick 
2720061da546Spatrick   // stop-on-crash can only be set, if it is present in all levels of
2721061da546Spatrick   // pushed flag sets.
2722061da546Spatrick   if (options.GetStopOnCrash()) {
2723061da546Spatrick     if (m_command_source_flags.empty()) {
2724061da546Spatrick       flags |= eHandleCommandFlagStopOnCrash;
2725061da546Spatrick     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2726061da546Spatrick       flags |= eHandleCommandFlagStopOnCrash;
2727061da546Spatrick     }
2728061da546Spatrick   }
2729061da546Spatrick 
2730061da546Spatrick   if (options.m_echo_commands == eLazyBoolCalculate) {
2731061da546Spatrick     if (m_command_source_flags.empty()) {
2732061da546Spatrick       // Echo command by default
2733061da546Spatrick       flags |= eHandleCommandFlagEchoCommand;
2734061da546Spatrick     } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2735061da546Spatrick       flags |= eHandleCommandFlagEchoCommand;
2736061da546Spatrick     }
2737061da546Spatrick   } else if (options.m_echo_commands == eLazyBoolYes) {
2738061da546Spatrick     flags |= eHandleCommandFlagEchoCommand;
2739061da546Spatrick   }
2740061da546Spatrick 
2741061da546Spatrick   // We will only ever ask for this flag, if we echo commands in general.
2742061da546Spatrick   if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2743061da546Spatrick     if (m_command_source_flags.empty()) {
2744061da546Spatrick       // Echo comments by default
2745061da546Spatrick       flags |= eHandleCommandFlagEchoCommentCommand;
2746061da546Spatrick     } else if (m_command_source_flags.back() &
2747061da546Spatrick                eHandleCommandFlagEchoCommentCommand) {
2748061da546Spatrick       flags |= eHandleCommandFlagEchoCommentCommand;
2749061da546Spatrick     }
2750061da546Spatrick   } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2751061da546Spatrick     flags |= eHandleCommandFlagEchoCommentCommand;
2752061da546Spatrick   }
2753061da546Spatrick 
2754061da546Spatrick   if (options.m_print_results == eLazyBoolCalculate) {
2755061da546Spatrick     if (m_command_source_flags.empty()) {
2756061da546Spatrick       // Print output by default
2757061da546Spatrick       flags |= eHandleCommandFlagPrintResult;
2758061da546Spatrick     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2759061da546Spatrick       flags |= eHandleCommandFlagPrintResult;
2760061da546Spatrick     }
2761061da546Spatrick   } else if (options.m_print_results == eLazyBoolYes) {
2762061da546Spatrick     flags |= eHandleCommandFlagPrintResult;
2763061da546Spatrick   }
2764061da546Spatrick 
2765061da546Spatrick   if (options.m_print_errors == eLazyBoolCalculate) {
2766061da546Spatrick     if (m_command_source_flags.empty()) {
2767061da546Spatrick       // Print output by default
2768061da546Spatrick       flags |= eHandleCommandFlagPrintErrors;
2769061da546Spatrick     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2770061da546Spatrick       flags |= eHandleCommandFlagPrintErrors;
2771061da546Spatrick     }
2772061da546Spatrick   } else if (options.m_print_errors == eLazyBoolYes) {
2773061da546Spatrick     flags |= eHandleCommandFlagPrintErrors;
2774061da546Spatrick   }
2775061da546Spatrick 
2776061da546Spatrick   if (flags & eHandleCommandFlagPrintResult) {
2777061da546Spatrick     debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2778061da546Spatrick                                     cmd_file_path.c_str());
2779061da546Spatrick   }
2780061da546Spatrick 
2781061da546Spatrick   // Used for inheriting the right settings when "command source" might
2782061da546Spatrick   // have nested "command source" commands
2783061da546Spatrick   lldb::StreamFileSP empty_stream_sp;
2784061da546Spatrick   m_command_source_flags.push_back(flags);
2785061da546Spatrick   IOHandlerSP io_handler_sp(new IOHandlerEditline(
2786061da546Spatrick       debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2787061da546Spatrick       empty_stream_sp, // Pass in an empty stream so we inherit the top
2788061da546Spatrick                        // input reader output stream
2789061da546Spatrick       empty_stream_sp, // Pass in an empty stream so we inherit the top
2790061da546Spatrick                        // input reader error stream
2791061da546Spatrick       flags,
2792061da546Spatrick       nullptr, // Pass in NULL for "editline_name" so no history is saved,
2793061da546Spatrick                // or written
2794061da546Spatrick       debugger.GetPrompt(), llvm::StringRef(),
2795061da546Spatrick       false, // Not multi-line
2796*f6aab3d8Srobert       debugger.GetUseColor(), 0, *this));
2797061da546Spatrick   const bool old_async_execution = debugger.GetAsyncExecution();
2798061da546Spatrick 
2799061da546Spatrick   // Set synchronous execution if we are not stopping on continue
2800061da546Spatrick   if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2801061da546Spatrick     debugger.SetAsyncExecution(false);
2802061da546Spatrick 
2803061da546Spatrick   m_command_source_depth++;
2804be691f3bSpatrick   m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent());
2805061da546Spatrick 
2806dda28197Spatrick   debugger.RunIOHandlerSync(io_handler_sp);
2807061da546Spatrick   if (!m_command_source_flags.empty())
2808061da546Spatrick     m_command_source_flags.pop_back();
2809be691f3bSpatrick 
2810be691f3bSpatrick   m_command_source_dirs.pop_back();
2811061da546Spatrick   m_command_source_depth--;
2812be691f3bSpatrick 
2813061da546Spatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2814061da546Spatrick   debugger.SetAsyncExecution(old_async_execution);
2815061da546Spatrick }
2816061da546Spatrick 
GetSynchronous()2817061da546Spatrick bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2818061da546Spatrick 
SetSynchronous(bool value)2819061da546Spatrick void CommandInterpreter::SetSynchronous(bool value) {
2820061da546Spatrick   m_synchronous_execution = value;
2821061da546Spatrick }
2822061da546Spatrick 
OutputFormattedHelpText(Stream & strm,llvm::StringRef prefix,llvm::StringRef help_text)2823061da546Spatrick void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2824061da546Spatrick                                                  llvm::StringRef prefix,
2825061da546Spatrick                                                  llvm::StringRef help_text) {
2826061da546Spatrick   const uint32_t max_columns = m_debugger.GetTerminalWidth();
2827061da546Spatrick 
2828061da546Spatrick   size_t line_width_max = max_columns - prefix.size();
2829061da546Spatrick   if (line_width_max < 16)
2830061da546Spatrick     line_width_max = help_text.size() + prefix.size();
2831061da546Spatrick 
2832061da546Spatrick   strm.IndentMore(prefix.size());
2833061da546Spatrick   bool prefixed_yet = false;
2834*f6aab3d8Srobert   // Even if we have no help text we still want to emit the command name.
2835*f6aab3d8Srobert   if (help_text.empty())
2836*f6aab3d8Srobert     help_text = "No help text";
2837061da546Spatrick   while (!help_text.empty()) {
2838061da546Spatrick     // Prefix the first line, indent subsequent lines to line up
2839061da546Spatrick     if (!prefixed_yet) {
2840061da546Spatrick       strm << prefix;
2841061da546Spatrick       prefixed_yet = true;
2842061da546Spatrick     } else
2843061da546Spatrick       strm.Indent();
2844061da546Spatrick 
2845061da546Spatrick     // Never print more than the maximum on one line.
2846061da546Spatrick     llvm::StringRef this_line = help_text.substr(0, line_width_max);
2847061da546Spatrick 
2848061da546Spatrick     // Always break on an explicit newline.
2849061da546Spatrick     std::size_t first_newline = this_line.find_first_of("\n");
2850061da546Spatrick 
2851061da546Spatrick     // Don't break on space/tab unless the text is too long to fit on one line.
2852061da546Spatrick     std::size_t last_space = llvm::StringRef::npos;
2853061da546Spatrick     if (this_line.size() != help_text.size())
2854061da546Spatrick       last_space = this_line.find_last_of(" \t");
2855061da546Spatrick 
2856061da546Spatrick     // Break at whichever condition triggered first.
2857061da546Spatrick     this_line = this_line.substr(0, std::min(first_newline, last_space));
2858061da546Spatrick     strm.PutCString(this_line);
2859061da546Spatrick     strm.EOL();
2860061da546Spatrick 
2861061da546Spatrick     // Remove whitespace / newlines after breaking.
2862061da546Spatrick     help_text = help_text.drop_front(this_line.size()).ltrim();
2863061da546Spatrick   }
2864061da546Spatrick   strm.IndentLess(prefix.size());
2865061da546Spatrick }
2866061da546Spatrick 
OutputFormattedHelpText(Stream & strm,llvm::StringRef word_text,llvm::StringRef separator,llvm::StringRef help_text,size_t max_word_len)2867061da546Spatrick void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2868061da546Spatrick                                                  llvm::StringRef word_text,
2869061da546Spatrick                                                  llvm::StringRef separator,
2870061da546Spatrick                                                  llvm::StringRef help_text,
2871061da546Spatrick                                                  size_t max_word_len) {
2872061da546Spatrick   StreamString prefix_stream;
2873061da546Spatrick   prefix_stream.Printf("  %-*s %*s ", (int)max_word_len, word_text.data(),
2874061da546Spatrick                        (int)separator.size(), separator.data());
2875061da546Spatrick   OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2876061da546Spatrick }
2877061da546Spatrick 
OutputHelpText(Stream & strm,llvm::StringRef word_text,llvm::StringRef separator,llvm::StringRef help_text,uint32_t max_word_len)2878061da546Spatrick void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2879061da546Spatrick                                         llvm::StringRef separator,
2880061da546Spatrick                                         llvm::StringRef help_text,
2881061da546Spatrick                                         uint32_t max_word_len) {
2882061da546Spatrick   int indent_size = max_word_len + separator.size() + 2;
2883061da546Spatrick 
2884061da546Spatrick   strm.IndentMore(indent_size);
2885061da546Spatrick 
2886061da546Spatrick   StreamString text_strm;
2887061da546Spatrick   text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2888061da546Spatrick   text_strm << separator << " " << help_text;
2889061da546Spatrick 
2890061da546Spatrick   const uint32_t max_columns = m_debugger.GetTerminalWidth();
2891061da546Spatrick 
2892061da546Spatrick   llvm::StringRef text = text_strm.GetString();
2893061da546Spatrick 
2894061da546Spatrick   uint32_t chars_left = max_columns;
2895061da546Spatrick 
2896061da546Spatrick   auto nextWordLength = [](llvm::StringRef S) {
2897061da546Spatrick     size_t pos = S.find(' ');
2898061da546Spatrick     return pos == llvm::StringRef::npos ? S.size() : pos;
2899061da546Spatrick   };
2900061da546Spatrick 
2901061da546Spatrick   while (!text.empty()) {
2902061da546Spatrick     if (text.front() == '\n' ||
2903061da546Spatrick         (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2904061da546Spatrick       strm.EOL();
2905061da546Spatrick       strm.Indent();
2906061da546Spatrick       chars_left = max_columns - indent_size;
2907061da546Spatrick       if (text.front() == '\n')
2908061da546Spatrick         text = text.drop_front();
2909061da546Spatrick       else
2910061da546Spatrick         text = text.ltrim(' ');
2911061da546Spatrick     } else {
2912061da546Spatrick       strm.PutChar(text.front());
2913061da546Spatrick       --chars_left;
2914061da546Spatrick       text = text.drop_front();
2915061da546Spatrick     }
2916061da546Spatrick   }
2917061da546Spatrick 
2918061da546Spatrick   strm.EOL();
2919061da546Spatrick   strm.IndentLess(indent_size);
2920061da546Spatrick }
2921061da546Spatrick 
FindCommandsForApropos(llvm::StringRef search_word,StringList & commands_found,StringList & commands_help,const CommandObject::CommandMap & command_map)2922061da546Spatrick void CommandInterpreter::FindCommandsForApropos(
2923061da546Spatrick     llvm::StringRef search_word, StringList &commands_found,
2924*f6aab3d8Srobert     StringList &commands_help, const CommandObject::CommandMap &command_map) {
2925*f6aab3d8Srobert   for (const auto &pair : command_map) {
2926*f6aab3d8Srobert     llvm::StringRef command_name = pair.first;
2927*f6aab3d8Srobert     CommandObject *cmd_obj = pair.second.get();
2928061da546Spatrick 
2929061da546Spatrick     const bool search_short_help = true;
2930061da546Spatrick     const bool search_long_help = false;
2931061da546Spatrick     const bool search_syntax = false;
2932061da546Spatrick     const bool search_options = false;
2933be691f3bSpatrick     if (command_name.contains_insensitive(search_word) ||
2934061da546Spatrick         cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2935061da546Spatrick                                       search_long_help, search_syntax,
2936061da546Spatrick                                       search_options)) {
2937*f6aab3d8Srobert       commands_found.AppendString(command_name);
2938061da546Spatrick       commands_help.AppendString(cmd_obj->GetHelp());
2939061da546Spatrick     }
2940061da546Spatrick 
2941*f6aab3d8Srobert     if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
2942*f6aab3d8Srobert       StringList subcommands_found;
2943*f6aab3d8Srobert       FindCommandsForApropos(search_word, subcommands_found, commands_help,
2944*f6aab3d8Srobert                              multiword_cmd->GetSubcommandDictionary());
2945*f6aab3d8Srobert       for (const auto &subcommand_name : subcommands_found) {
2946*f6aab3d8Srobert         std::string qualified_name =
2947*f6aab3d8Srobert             (command_name + " " + subcommand_name).str();
2948*f6aab3d8Srobert         commands_found.AppendString(qualified_name);
2949*f6aab3d8Srobert       }
2950061da546Spatrick     }
2951061da546Spatrick   }
2952061da546Spatrick }
2953061da546Spatrick 
FindCommandsForApropos(llvm::StringRef search_word,StringList & commands_found,StringList & commands_help,bool search_builtin_commands,bool search_user_commands,bool search_alias_commands,bool search_user_mw_commands)2954061da546Spatrick void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
2955061da546Spatrick                                                 StringList &commands_found,
2956061da546Spatrick                                                 StringList &commands_help,
2957061da546Spatrick                                                 bool search_builtin_commands,
2958061da546Spatrick                                                 bool search_user_commands,
2959*f6aab3d8Srobert                                                 bool search_alias_commands,
2960*f6aab3d8Srobert                                                 bool search_user_mw_commands) {
2961061da546Spatrick   CommandObject::CommandMap::const_iterator pos;
2962061da546Spatrick 
2963061da546Spatrick   if (search_builtin_commands)
2964061da546Spatrick     FindCommandsForApropos(search_word, commands_found, commands_help,
2965061da546Spatrick                            m_command_dict);
2966061da546Spatrick 
2967061da546Spatrick   if (search_user_commands)
2968061da546Spatrick     FindCommandsForApropos(search_word, commands_found, commands_help,
2969061da546Spatrick                            m_user_dict);
2970061da546Spatrick 
2971*f6aab3d8Srobert   if (search_user_mw_commands)
2972*f6aab3d8Srobert     FindCommandsForApropos(search_word, commands_found, commands_help,
2973*f6aab3d8Srobert                            m_user_mw_dict);
2974*f6aab3d8Srobert 
2975061da546Spatrick   if (search_alias_commands)
2976061da546Spatrick     FindCommandsForApropos(search_word, commands_found, commands_help,
2977061da546Spatrick                            m_alias_dict);
2978061da546Spatrick }
2979061da546Spatrick 
GetExecutionContext() const2980be691f3bSpatrick ExecutionContext CommandInterpreter::GetExecutionContext() const {
2981be691f3bSpatrick   return !m_overriden_exe_contexts.empty()
2982be691f3bSpatrick              ? m_overriden_exe_contexts.top()
2983be691f3bSpatrick              : m_debugger.GetSelectedExecutionContext();
2984061da546Spatrick }
2985be691f3bSpatrick 
OverrideExecutionContext(const ExecutionContext & override_context)2986be691f3bSpatrick void CommandInterpreter::OverrideExecutionContext(
2987be691f3bSpatrick     const ExecutionContext &override_context) {
2988be691f3bSpatrick   m_overriden_exe_contexts.push(override_context);
2989be691f3bSpatrick }
2990be691f3bSpatrick 
RestoreExecutionContext()2991be691f3bSpatrick void CommandInterpreter::RestoreExecutionContext() {
2992be691f3bSpatrick   if (!m_overriden_exe_contexts.empty())
2993be691f3bSpatrick     m_overriden_exe_contexts.pop();
2994061da546Spatrick }
2995061da546Spatrick 
GetProcessOutput()2996061da546Spatrick void CommandInterpreter::GetProcessOutput() {
2997be691f3bSpatrick   if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
2998061da546Spatrick     m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
2999061da546Spatrick                                   /*flush_stderr*/ true);
3000061da546Spatrick }
3001061da546Spatrick 
StartHandlingCommand()3002061da546Spatrick void CommandInterpreter::StartHandlingCommand() {
3003061da546Spatrick   auto idle_state = CommandHandlingState::eIdle;
3004061da546Spatrick   if (m_command_state.compare_exchange_strong(
3005061da546Spatrick           idle_state, CommandHandlingState::eInProgress))
3006061da546Spatrick     lldbassert(m_iohandler_nesting_level == 0);
3007061da546Spatrick   else
3008061da546Spatrick     lldbassert(m_iohandler_nesting_level > 0);
3009061da546Spatrick   ++m_iohandler_nesting_level;
3010061da546Spatrick }
3011061da546Spatrick 
FinishHandlingCommand()3012061da546Spatrick void CommandInterpreter::FinishHandlingCommand() {
3013061da546Spatrick   lldbassert(m_iohandler_nesting_level > 0);
3014061da546Spatrick   if (--m_iohandler_nesting_level == 0) {
3015061da546Spatrick     auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3016061da546Spatrick     lldbassert(prev_state != CommandHandlingState::eIdle);
3017061da546Spatrick   }
3018061da546Spatrick }
3019061da546Spatrick 
InterruptCommand()3020061da546Spatrick bool CommandInterpreter::InterruptCommand() {
3021061da546Spatrick   auto in_progress = CommandHandlingState::eInProgress;
3022061da546Spatrick   return m_command_state.compare_exchange_strong(
3023061da546Spatrick       in_progress, CommandHandlingState::eInterrupted);
3024061da546Spatrick }
3025061da546Spatrick 
WasInterrupted() const3026061da546Spatrick bool CommandInterpreter::WasInterrupted() const {
3027061da546Spatrick   bool was_interrupted =
3028061da546Spatrick       (m_command_state == CommandHandlingState::eInterrupted);
3029061da546Spatrick   lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3030061da546Spatrick   return was_interrupted;
3031061da546Spatrick }
3032061da546Spatrick 
PrintCommandOutput(IOHandler & io_handler,llvm::StringRef str,bool is_stdout)3033*f6aab3d8Srobert void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
3034*f6aab3d8Srobert                                             llvm::StringRef str,
3035*f6aab3d8Srobert                                             bool is_stdout) {
3036*f6aab3d8Srobert 
3037*f6aab3d8Srobert   lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3038*f6aab3d8Srobert                                         : io_handler.GetErrorStreamFileSP();
3039061da546Spatrick   // Split the output into lines and poll for interrupt requests
3040*f6aab3d8Srobert   while (!str.empty() && !WasInterrupted()) {
3041*f6aab3d8Srobert     llvm::StringRef line;
3042*f6aab3d8Srobert     std::tie(line, str) = str.split('\n');
3043*f6aab3d8Srobert     {
3044*f6aab3d8Srobert       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3045*f6aab3d8Srobert       stream->Write(line.data(), line.size());
3046*f6aab3d8Srobert       stream->Write("\n", 1);
3047061da546Spatrick     }
3048061da546Spatrick   }
3049*f6aab3d8Srobert 
3050*f6aab3d8Srobert   std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3051*f6aab3d8Srobert   if (!str.empty())
3052*f6aab3d8Srobert     stream->Printf("\n... Interrupted.\n");
3053*f6aab3d8Srobert   stream->Flush();
3054061da546Spatrick }
3055061da546Spatrick 
EchoCommandNonInteractive(llvm::StringRef line,const Flags & io_handler_flags) const3056061da546Spatrick bool CommandInterpreter::EchoCommandNonInteractive(
3057061da546Spatrick     llvm::StringRef line, const Flags &io_handler_flags) const {
3058061da546Spatrick   if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3059061da546Spatrick     return false;
3060061da546Spatrick 
3061061da546Spatrick   llvm::StringRef command = line.trim();
3062061da546Spatrick   if (command.empty())
3063061da546Spatrick     return true;
3064061da546Spatrick 
3065061da546Spatrick   if (command.front() == m_comment_char)
3066061da546Spatrick     return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3067061da546Spatrick 
3068061da546Spatrick   return true;
3069061da546Spatrick }
3070061da546Spatrick 
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)3071061da546Spatrick void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
3072061da546Spatrick                                                 std::string &line) {
3073061da546Spatrick     // If we were interrupted, bail out...
3074061da546Spatrick     if (WasInterrupted())
3075061da546Spatrick       return;
3076061da546Spatrick 
3077061da546Spatrick   const bool is_interactive = io_handler.GetIsInteractive();
3078061da546Spatrick   if (!is_interactive) {
3079061da546Spatrick     // When we are not interactive, don't execute blank lines. This will happen
3080061da546Spatrick     // sourcing a commands file. We don't want blank lines to repeat the
3081061da546Spatrick     // previous command and cause any errors to occur (like redefining an
3082061da546Spatrick     // alias, get an error and stop parsing the commands file).
3083061da546Spatrick     if (line.empty())
3084061da546Spatrick       return;
3085061da546Spatrick 
3086061da546Spatrick     // When using a non-interactive file handle (like when sourcing commands
3087061da546Spatrick     // from a file) we need to echo the command out so we don't just see the
3088061da546Spatrick     // command output and no command...
3089*f6aab3d8Srobert     if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3090*f6aab3d8Srobert       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3091061da546Spatrick       io_handler.GetOutputStreamFileSP()->Printf(
3092061da546Spatrick           "%s%s\n", io_handler.GetPrompt(), line.c_str());
3093061da546Spatrick     }
3094*f6aab3d8Srobert   }
3095061da546Spatrick 
3096061da546Spatrick   StartHandlingCommand();
3097061da546Spatrick 
3098*f6aab3d8Srobert   ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
3099*f6aab3d8Srobert   bool pushed_exe_ctx = false;
3100*f6aab3d8Srobert   if (exe_ctx.HasTargetScope()) {
3101*f6aab3d8Srobert     OverrideExecutionContext(exe_ctx);
3102*f6aab3d8Srobert     pushed_exe_ctx = true;
3103*f6aab3d8Srobert   }
3104*f6aab3d8Srobert   auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3105*f6aab3d8Srobert     if (pushed_exe_ctx)
3106be691f3bSpatrick       RestoreExecutionContext();
3107be691f3bSpatrick   });
3108be691f3bSpatrick 
3109dda28197Spatrick   lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
3110061da546Spatrick   HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3111061da546Spatrick 
3112061da546Spatrick   // Now emit the command output text from the command we just executed
3113061da546Spatrick   if ((result.Succeeded() &&
3114061da546Spatrick        io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
3115061da546Spatrick       io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
3116061da546Spatrick     // Display any STDOUT/STDERR _prior_ to emitting the command result text
3117061da546Spatrick     GetProcessOutput();
3118061da546Spatrick 
3119061da546Spatrick     if (!result.GetImmediateOutputStream()) {
3120061da546Spatrick       llvm::StringRef output = result.GetOutputData();
3121*f6aab3d8Srobert       PrintCommandOutput(io_handler, output, true);
3122061da546Spatrick     }
3123061da546Spatrick 
3124061da546Spatrick     // Now emit the command error text from the command we just executed
3125061da546Spatrick     if (!result.GetImmediateErrorStream()) {
3126061da546Spatrick       llvm::StringRef error = result.GetErrorData();
3127*f6aab3d8Srobert       PrintCommandOutput(io_handler, error, false);
3128061da546Spatrick     }
3129061da546Spatrick   }
3130061da546Spatrick 
3131061da546Spatrick   FinishHandlingCommand();
3132061da546Spatrick 
3133061da546Spatrick   switch (result.GetStatus()) {
3134061da546Spatrick   case eReturnStatusInvalid:
3135061da546Spatrick   case eReturnStatusSuccessFinishNoResult:
3136061da546Spatrick   case eReturnStatusSuccessFinishResult:
3137061da546Spatrick   case eReturnStatusStarted:
3138061da546Spatrick     break;
3139061da546Spatrick 
3140061da546Spatrick   case eReturnStatusSuccessContinuingNoResult:
3141061da546Spatrick   case eReturnStatusSuccessContinuingResult:
3142061da546Spatrick     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
3143061da546Spatrick       io_handler.SetIsDone(true);
3144061da546Spatrick     break;
3145061da546Spatrick 
3146061da546Spatrick   case eReturnStatusFailed:
3147dda28197Spatrick     m_result.IncrementNumberOfErrors();
3148dda28197Spatrick     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3149dda28197Spatrick       m_result.SetResult(lldb::eCommandInterpreterResultCommandError);
3150061da546Spatrick       io_handler.SetIsDone(true);
3151dda28197Spatrick     }
3152061da546Spatrick     break;
3153061da546Spatrick 
3154061da546Spatrick   case eReturnStatusQuit:
3155dda28197Spatrick     m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested);
3156061da546Spatrick     io_handler.SetIsDone(true);
3157061da546Spatrick     break;
3158061da546Spatrick   }
3159061da546Spatrick 
3160061da546Spatrick   // Finally, if we're going to stop on crash, check that here:
3161dda28197Spatrick   if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) &&
3162dda28197Spatrick       result.GetDidChangeProcessState() &&
3163061da546Spatrick       io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
3164061da546Spatrick       DidProcessStopAbnormally()) {
3165061da546Spatrick     io_handler.SetIsDone(true);
3166dda28197Spatrick     m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash);
3167061da546Spatrick   }
3168061da546Spatrick }
3169061da546Spatrick 
IOHandlerInterrupt(IOHandler & io_handler)3170061da546Spatrick bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
3171061da546Spatrick   ExecutionContext exe_ctx(GetExecutionContext());
3172061da546Spatrick   Process *process = exe_ctx.GetProcessPtr();
3173061da546Spatrick 
3174061da546Spatrick   if (InterruptCommand())
3175061da546Spatrick     return true;
3176061da546Spatrick 
3177061da546Spatrick   if (process) {
3178061da546Spatrick     StateType state = process->GetState();
3179061da546Spatrick     if (StateIsRunningState(state)) {
3180061da546Spatrick       process->Halt();
3181061da546Spatrick       return true; // Don't do any updating when we are running
3182061da546Spatrick     }
3183061da546Spatrick   }
3184061da546Spatrick 
3185061da546Spatrick   ScriptInterpreter *script_interpreter =
3186061da546Spatrick       m_debugger.GetScriptInterpreter(false);
3187061da546Spatrick   if (script_interpreter) {
3188061da546Spatrick     if (script_interpreter->Interrupt())
3189061da546Spatrick       return true;
3190061da546Spatrick   }
3191061da546Spatrick   return false;
3192061da546Spatrick }
3193061da546Spatrick 
SaveTranscript(CommandReturnObject & result,std::optional<std::string> output_file)3194be691f3bSpatrick bool CommandInterpreter::SaveTranscript(
3195*f6aab3d8Srobert     CommandReturnObject &result, std::optional<std::string> output_file) {
3196*f6aab3d8Srobert   if (output_file == std::nullopt || output_file->empty()) {
3197be691f3bSpatrick     std::string now = llvm::to_string(std::chrono::system_clock::now());
3198be691f3bSpatrick     std::replace(now.begin(), now.end(), ' ', '_');
3199be691f3bSpatrick     const std::string file_name = "lldb_session_" + now + ".log";
3200be691f3bSpatrick 
3201be691f3bSpatrick     FileSpec save_location = GetSaveSessionDirectory();
3202be691f3bSpatrick 
3203be691f3bSpatrick     if (!save_location)
3204be691f3bSpatrick       save_location = HostInfo::GetGlobalTempDir();
3205be691f3bSpatrick 
3206be691f3bSpatrick     FileSystem::Instance().Resolve(save_location);
3207be691f3bSpatrick     save_location.AppendPathComponent(file_name);
3208be691f3bSpatrick     output_file = save_location.GetPath();
3209be691f3bSpatrick   }
3210be691f3bSpatrick 
3211be691f3bSpatrick   auto error_out = [&](llvm::StringRef error_message, std::string description) {
3212*f6aab3d8Srobert     LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3213*f6aab3d8Srobert              output_file, description);
3214be691f3bSpatrick     result.AppendErrorWithFormatv(
3215be691f3bSpatrick         "Failed to save session's transcripts to {0}!", *output_file);
3216be691f3bSpatrick     return false;
3217be691f3bSpatrick   };
3218be691f3bSpatrick 
3219*f6aab3d8Srobert   File::OpenOptions flags = File::eOpenOptionWriteOnly |
3220be691f3bSpatrick                             File::eOpenOptionCanCreate |
3221be691f3bSpatrick                             File::eOpenOptionTruncate;
3222be691f3bSpatrick 
3223be691f3bSpatrick   auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3224be691f3bSpatrick 
3225be691f3bSpatrick   if (!opened_file)
3226be691f3bSpatrick     return error_out("Unable to create file",
3227be691f3bSpatrick                      llvm::toString(opened_file.takeError()));
3228be691f3bSpatrick 
3229be691f3bSpatrick   FileUP file = std::move(opened_file.get());
3230be691f3bSpatrick 
3231be691f3bSpatrick   size_t byte_size = m_transcript_stream.GetSize();
3232be691f3bSpatrick 
3233be691f3bSpatrick   Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3234be691f3bSpatrick 
3235be691f3bSpatrick   if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3236be691f3bSpatrick     return error_out("Unable to write to destination file",
3237be691f3bSpatrick                      "Bytes written do not match transcript size.");
3238be691f3bSpatrick 
3239be691f3bSpatrick   result.SetStatus(eReturnStatusSuccessFinishNoResult);
3240be691f3bSpatrick   result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3241be691f3bSpatrick                                  output_file->c_str());
3242be691f3bSpatrick 
3243*f6aab3d8Srobert   if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) {
3244*f6aab3d8Srobert     const FileSpec file_spec;
3245*f6aab3d8Srobert     error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3246*f6aab3d8Srobert     if (error.Success())
3247*f6aab3d8Srobert       Host::OpenFileInExternalEditor(file_spec, 1);
3248*f6aab3d8Srobert   }
3249*f6aab3d8Srobert 
3250be691f3bSpatrick   return true;
3251be691f3bSpatrick }
3252be691f3bSpatrick 
IsInteractive()3253*f6aab3d8Srobert bool CommandInterpreter::IsInteractive() {
3254*f6aab3d8Srobert   return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3255*f6aab3d8Srobert }
3256*f6aab3d8Srobert 
GetCurrentSourceDir()3257be691f3bSpatrick FileSpec CommandInterpreter::GetCurrentSourceDir() {
3258be691f3bSpatrick   if (m_command_source_dirs.empty())
3259be691f3bSpatrick     return {};
3260be691f3bSpatrick   return m_command_source_dirs.back();
3261be691f3bSpatrick }
3262be691f3bSpatrick 
GetLLDBCommandsFromIOHandler(const char * prompt,IOHandlerDelegate & delegate,void * baton)3263061da546Spatrick void CommandInterpreter::GetLLDBCommandsFromIOHandler(
3264061da546Spatrick     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3265061da546Spatrick   Debugger &debugger = GetDebugger();
3266061da546Spatrick   IOHandlerSP io_handler_sp(
3267061da546Spatrick       new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
3268061da546Spatrick                             "lldb", // Name of input reader for history
3269be691f3bSpatrick                             llvm::StringRef(prompt), // Prompt
3270061da546Spatrick                             llvm::StringRef(),       // Continuation prompt
3271061da546Spatrick                             true,                    // Get multiple lines
3272061da546Spatrick                             debugger.GetUseColor(),
3273061da546Spatrick                             0,          // Don't show line numbers
3274*f6aab3d8Srobert                             delegate)); // IOHandlerDelegate
3275061da546Spatrick 
3276061da546Spatrick   if (io_handler_sp) {
3277061da546Spatrick     io_handler_sp->SetUserData(baton);
3278dda28197Spatrick     debugger.RunIOHandlerAsync(io_handler_sp);
3279061da546Spatrick   }
3280061da546Spatrick }
3281061da546Spatrick 
GetPythonCommandsFromIOHandler(const char * prompt,IOHandlerDelegate & delegate,void * baton)3282061da546Spatrick void CommandInterpreter::GetPythonCommandsFromIOHandler(
3283061da546Spatrick     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3284061da546Spatrick   Debugger &debugger = GetDebugger();
3285061da546Spatrick   IOHandlerSP io_handler_sp(
3286061da546Spatrick       new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
3287061da546Spatrick                             "lldb-python", // Name of input reader for history
3288be691f3bSpatrick                             llvm::StringRef(prompt), // Prompt
3289061da546Spatrick                             llvm::StringRef(),       // Continuation prompt
3290061da546Spatrick                             true,                    // Get multiple lines
3291061da546Spatrick                             debugger.GetUseColor(),
3292061da546Spatrick                             0,          // Don't show line numbers
3293*f6aab3d8Srobert                             delegate)); // IOHandlerDelegate
3294061da546Spatrick 
3295061da546Spatrick   if (io_handler_sp) {
3296061da546Spatrick     io_handler_sp->SetUserData(baton);
3297dda28197Spatrick     debugger.RunIOHandlerAsync(io_handler_sp);
3298061da546Spatrick   }
3299061da546Spatrick }
3300061da546Spatrick 
IsActive()3301061da546Spatrick bool CommandInterpreter::IsActive() {
3302061da546Spatrick   return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
3303061da546Spatrick }
3304061da546Spatrick 
3305061da546Spatrick lldb::IOHandlerSP
GetIOHandler(bool force_create,CommandInterpreterRunOptions * options)3306061da546Spatrick CommandInterpreter::GetIOHandler(bool force_create,
3307061da546Spatrick                                  CommandInterpreterRunOptions *options) {
3308061da546Spatrick   // Always re-create the IOHandlerEditline in case the input changed. The old
3309061da546Spatrick   // instance might have had a non-interactive input and now it does or vice
3310061da546Spatrick   // versa.
3311061da546Spatrick   if (force_create || !m_command_io_handler_sp) {
3312061da546Spatrick     // Always re-create the IOHandlerEditline in case the input changed. The
3313061da546Spatrick     // old instance might have had a non-interactive input and now it does or
3314061da546Spatrick     // vice versa.
3315061da546Spatrick     uint32_t flags = 0;
3316061da546Spatrick 
3317061da546Spatrick     if (options) {
3318061da546Spatrick       if (options->m_stop_on_continue == eLazyBoolYes)
3319061da546Spatrick         flags |= eHandleCommandFlagStopOnContinue;
3320061da546Spatrick       if (options->m_stop_on_error == eLazyBoolYes)
3321061da546Spatrick         flags |= eHandleCommandFlagStopOnError;
3322061da546Spatrick       if (options->m_stop_on_crash == eLazyBoolYes)
3323061da546Spatrick         flags |= eHandleCommandFlagStopOnCrash;
3324061da546Spatrick       if (options->m_echo_commands != eLazyBoolNo)
3325061da546Spatrick         flags |= eHandleCommandFlagEchoCommand;
3326061da546Spatrick       if (options->m_echo_comment_commands != eLazyBoolNo)
3327061da546Spatrick         flags |= eHandleCommandFlagEchoCommentCommand;
3328061da546Spatrick       if (options->m_print_results != eLazyBoolNo)
3329061da546Spatrick         flags |= eHandleCommandFlagPrintResult;
3330061da546Spatrick       if (options->m_print_errors != eLazyBoolNo)
3331061da546Spatrick         flags |= eHandleCommandFlagPrintErrors;
3332061da546Spatrick     } else {
3333061da546Spatrick       flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
3334061da546Spatrick               eHandleCommandFlagPrintErrors;
3335061da546Spatrick     }
3336061da546Spatrick 
3337061da546Spatrick     m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3338061da546Spatrick         m_debugger, IOHandler::Type::CommandInterpreter,
3339061da546Spatrick         m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(),
3340061da546Spatrick         m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3341061da546Spatrick         llvm::StringRef(), // Continuation prompt
3342061da546Spatrick         false, // Don't enable multiple line input, just single line commands
3343061da546Spatrick         m_debugger.GetUseColor(),
3344061da546Spatrick         0,      // Don't show line numbers
3345*f6aab3d8Srobert         *this); // IOHandlerDelegate
3346061da546Spatrick   }
3347061da546Spatrick   return m_command_io_handler_sp;
3348061da546Spatrick }
3349061da546Spatrick 
RunCommandInterpreter(CommandInterpreterRunOptions & options)3350dda28197Spatrick CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter(
3351061da546Spatrick     CommandInterpreterRunOptions &options) {
3352061da546Spatrick   // Always re-create the command interpreter when we run it in case any file
3353061da546Spatrick   // handles have changed.
3354061da546Spatrick   bool force_create = true;
3355dda28197Spatrick   m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3356dda28197Spatrick   m_result = CommandInterpreterRunResult();
3357061da546Spatrick 
3358dda28197Spatrick   if (options.GetAutoHandleEvents())
3359061da546Spatrick     m_debugger.StartEventHandlerThread();
3360061da546Spatrick 
3361dda28197Spatrick   if (options.GetSpawnThread()) {
3362061da546Spatrick     m_debugger.StartIOHandlerThread();
3363061da546Spatrick   } else {
3364dda28197Spatrick     m_debugger.RunIOHandlers();
3365061da546Spatrick 
3366dda28197Spatrick     if (options.GetAutoHandleEvents())
3367061da546Spatrick       m_debugger.StopEventHandlerThread();
3368061da546Spatrick   }
3369dda28197Spatrick 
3370dda28197Spatrick   return m_result;
3371061da546Spatrick }
3372061da546Spatrick 
3373061da546Spatrick CommandObject *
ResolveCommandImpl(std::string & command_line,CommandReturnObject & result)3374061da546Spatrick CommandInterpreter::ResolveCommandImpl(std::string &command_line,
3375061da546Spatrick                                        CommandReturnObject &result) {
3376061da546Spatrick   std::string scratch_command(command_line); // working copy so we don't modify
3377061da546Spatrick                                              // command_line unless we succeed
3378061da546Spatrick   CommandObject *cmd_obj = nullptr;
3379061da546Spatrick   StreamString revised_command_line;
3380061da546Spatrick   bool wants_raw_input = false;
3381061da546Spatrick   std::string next_word;
3382061da546Spatrick   StringList matches;
3383061da546Spatrick   bool done = false;
3384061da546Spatrick   while (!done) {
3385061da546Spatrick     char quote_char = '\0';
3386061da546Spatrick     std::string suffix;
3387061da546Spatrick     ExtractCommand(scratch_command, next_word, suffix, quote_char);
3388061da546Spatrick     if (cmd_obj == nullptr) {
3389061da546Spatrick       std::string full_name;
3390061da546Spatrick       bool is_alias = GetAliasFullName(next_word, full_name);
3391061da546Spatrick       cmd_obj = GetCommandObject(next_word, &matches);
3392061da546Spatrick       bool is_real_command =
3393061da546Spatrick           (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3394061da546Spatrick       if (!is_real_command) {
3395061da546Spatrick         matches.Clear();
3396061da546Spatrick         std::string alias_result;
3397061da546Spatrick         cmd_obj =
3398061da546Spatrick             BuildAliasResult(full_name, scratch_command, alias_result, result);
3399061da546Spatrick         revised_command_line.Printf("%s", alias_result.c_str());
3400061da546Spatrick         if (cmd_obj) {
3401061da546Spatrick           wants_raw_input = cmd_obj->WantsRawCommandString();
3402061da546Spatrick         }
3403061da546Spatrick       } else {
3404061da546Spatrick         if (cmd_obj) {
3405061da546Spatrick           llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3406061da546Spatrick           revised_command_line.Printf("%s", cmd_name.str().c_str());
3407061da546Spatrick           wants_raw_input = cmd_obj->WantsRawCommandString();
3408061da546Spatrick         } else {
3409061da546Spatrick           revised_command_line.Printf("%s", next_word.c_str());
3410061da546Spatrick         }
3411061da546Spatrick       }
3412061da546Spatrick     } else {
3413061da546Spatrick       if (cmd_obj->IsMultiwordObject()) {
3414061da546Spatrick         CommandObject *sub_cmd_obj =
3415061da546Spatrick             cmd_obj->GetSubcommandObject(next_word.c_str());
3416061da546Spatrick         if (sub_cmd_obj) {
3417061da546Spatrick           // The subcommand's name includes the parent command's name, so
3418061da546Spatrick           // restart rather than append to the revised_command_line.
3419061da546Spatrick           llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3420061da546Spatrick           revised_command_line.Clear();
3421061da546Spatrick           revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3422061da546Spatrick           cmd_obj = sub_cmd_obj;
3423061da546Spatrick           wants_raw_input = cmd_obj->WantsRawCommandString();
3424061da546Spatrick         } else {
3425061da546Spatrick           if (quote_char)
3426061da546Spatrick             revised_command_line.Printf(" %c%s%s%c", quote_char,
3427061da546Spatrick                                         next_word.c_str(), suffix.c_str(),
3428061da546Spatrick                                         quote_char);
3429061da546Spatrick           else
3430061da546Spatrick             revised_command_line.Printf(" %s%s", next_word.c_str(),
3431061da546Spatrick                                         suffix.c_str());
3432061da546Spatrick           done = true;
3433061da546Spatrick         }
3434061da546Spatrick       } else {
3435061da546Spatrick         if (quote_char)
3436061da546Spatrick           revised_command_line.Printf(" %c%s%s%c", quote_char,
3437061da546Spatrick                                       next_word.c_str(), suffix.c_str(),
3438061da546Spatrick                                       quote_char);
3439061da546Spatrick         else
3440061da546Spatrick           revised_command_line.Printf(" %s%s", next_word.c_str(),
3441061da546Spatrick                                       suffix.c_str());
3442061da546Spatrick         done = true;
3443061da546Spatrick       }
3444061da546Spatrick     }
3445061da546Spatrick 
3446061da546Spatrick     if (cmd_obj == nullptr) {
3447061da546Spatrick       const size_t num_matches = matches.GetSize();
3448061da546Spatrick       if (matches.GetSize() > 1) {
3449061da546Spatrick         StreamString error_msg;
3450061da546Spatrick         error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3451061da546Spatrick                          next_word.c_str());
3452061da546Spatrick 
3453061da546Spatrick         for (uint32_t i = 0; i < num_matches; ++i) {
3454061da546Spatrick           error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3455061da546Spatrick         }
3456061da546Spatrick         result.AppendRawError(error_msg.GetString());
3457061da546Spatrick       } else {
3458061da546Spatrick         // We didn't have only one match, otherwise we wouldn't get here.
3459061da546Spatrick         lldbassert(num_matches == 0);
3460061da546Spatrick         result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3461061da546Spatrick                                      next_word.c_str());
3462061da546Spatrick       }
3463061da546Spatrick       return nullptr;
3464061da546Spatrick     }
3465061da546Spatrick 
3466061da546Spatrick     if (cmd_obj->IsMultiwordObject()) {
3467061da546Spatrick       if (!suffix.empty()) {
3468061da546Spatrick         result.AppendErrorWithFormat(
3469061da546Spatrick             "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3470061da546Spatrick             "might be invalid).\n",
3471061da546Spatrick             cmd_obj->GetCommandName().str().c_str(),
3472061da546Spatrick             next_word.empty() ? "" : next_word.c_str(),
3473061da546Spatrick             next_word.empty() ? " -- " : " ", suffix.c_str());
3474061da546Spatrick         return nullptr;
3475061da546Spatrick       }
3476061da546Spatrick     } else {
3477061da546Spatrick       // If we found a normal command, we are done
3478061da546Spatrick       done = true;
3479061da546Spatrick       if (!suffix.empty()) {
3480061da546Spatrick         switch (suffix[0]) {
3481061da546Spatrick         case '/':
3482061da546Spatrick           // GDB format suffixes
3483061da546Spatrick           {
3484061da546Spatrick             Options *command_options = cmd_obj->GetOptions();
3485061da546Spatrick             if (command_options &&
3486061da546Spatrick                 command_options->SupportsLongOption("gdb-format")) {
3487061da546Spatrick               std::string gdb_format_option("--gdb-format=");
3488061da546Spatrick               gdb_format_option += (suffix.c_str() + 1);
3489061da546Spatrick 
3490dda28197Spatrick               std::string cmd = std::string(revised_command_line.GetString());
3491061da546Spatrick               size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3492061da546Spatrick               if (arg_terminator_idx != std::string::npos) {
3493061da546Spatrick                 // Insert the gdb format option before the "--" that terminates
3494061da546Spatrick                 // options
3495061da546Spatrick                 gdb_format_option.append(1, ' ');
3496061da546Spatrick                 cmd.insert(arg_terminator_idx, gdb_format_option);
3497061da546Spatrick                 revised_command_line.Clear();
3498061da546Spatrick                 revised_command_line.PutCString(cmd);
3499061da546Spatrick               } else
3500061da546Spatrick                 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3501061da546Spatrick 
3502061da546Spatrick               if (wants_raw_input &&
3503061da546Spatrick                   FindArgumentTerminator(cmd) == std::string::npos)
3504061da546Spatrick                 revised_command_line.PutCString(" --");
3505061da546Spatrick             } else {
3506061da546Spatrick               result.AppendErrorWithFormat(
3507061da546Spatrick                   "the '%s' command doesn't support the --gdb-format option\n",
3508061da546Spatrick                   cmd_obj->GetCommandName().str().c_str());
3509061da546Spatrick               return nullptr;
3510061da546Spatrick             }
3511061da546Spatrick           }
3512061da546Spatrick           break;
3513061da546Spatrick 
3514061da546Spatrick         default:
3515061da546Spatrick           result.AppendErrorWithFormat(
3516061da546Spatrick               "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3517061da546Spatrick           return nullptr;
3518061da546Spatrick         }
3519061da546Spatrick       }
3520061da546Spatrick     }
3521061da546Spatrick     if (scratch_command.empty())
3522061da546Spatrick       done = true;
3523061da546Spatrick   }
3524061da546Spatrick 
3525061da546Spatrick   if (!scratch_command.empty())
3526061da546Spatrick     revised_command_line.Printf(" %s", scratch_command.c_str());
3527061da546Spatrick 
3528061da546Spatrick   if (cmd_obj != nullptr)
3529dda28197Spatrick     command_line = std::string(revised_command_line.GetString());
3530061da546Spatrick 
3531061da546Spatrick   return cmd_obj;
3532061da546Spatrick }
3533