xref: /llvm-project/lldb/source/Interpreter/CommandInterpreter.cpp (revision ebcdc700d68582a44dd059c40f382583126f29a6)
1 //===-- CommandInterpreter.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include <chrono>
10 #include <cstdlib>
11 #include <limits>
12 #include <memory>
13 #include <optional>
14 #include <string>
15 #include <vector>
16 
17 #include "Commands/CommandObjectApropos.h"
18 #include "Commands/CommandObjectBreakpoint.h"
19 #include "Commands/CommandObjectCommands.h"
20 #include "Commands/CommandObjectDWIMPrint.h"
21 #include "Commands/CommandObjectDiagnostics.h"
22 #include "Commands/CommandObjectDisassemble.h"
23 #include "Commands/CommandObjectExpression.h"
24 #include "Commands/CommandObjectFrame.h"
25 #include "Commands/CommandObjectGUI.h"
26 #include "Commands/CommandObjectHelp.h"
27 #include "Commands/CommandObjectLanguage.h"
28 #include "Commands/CommandObjectLog.h"
29 #include "Commands/CommandObjectMemory.h"
30 #include "Commands/CommandObjectPlatform.h"
31 #include "Commands/CommandObjectPlugin.h"
32 #include "Commands/CommandObjectProcess.h"
33 #include "Commands/CommandObjectQuit.h"
34 #include "Commands/CommandObjectRegexCommand.h"
35 #include "Commands/CommandObjectRegister.h"
36 #include "Commands/CommandObjectScripting.h"
37 #include "Commands/CommandObjectSession.h"
38 #include "Commands/CommandObjectSettings.h"
39 #include "Commands/CommandObjectSource.h"
40 #include "Commands/CommandObjectStats.h"
41 #include "Commands/CommandObjectTarget.h"
42 #include "Commands/CommandObjectThread.h"
43 #include "Commands/CommandObjectTrace.h"
44 #include "Commands/CommandObjectType.h"
45 #include "Commands/CommandObjectVersion.h"
46 #include "Commands/CommandObjectWatchpoint.h"
47 
48 #include "lldb/Core/Debugger.h"
49 #include "lldb/Core/PluginManager.h"
50 #include "lldb/Host/StreamFile.h"
51 #include "lldb/Utility/ErrorMessages.h"
52 #include "lldb/Utility/LLDBLog.h"
53 #include "lldb/Utility/Log.h"
54 #include "lldb/Utility/State.h"
55 #include "lldb/Utility/Stream.h"
56 #include "lldb/Utility/StructuredData.h"
57 #include "lldb/Utility/Timer.h"
58 
59 #include "lldb/Host/Config.h"
60 #if LLDB_ENABLE_LIBEDIT
61 #include "lldb/Host/Editline.h"
62 #endif
63 #include "lldb/Host/File.h"
64 #include "lldb/Host/FileCache.h"
65 #include "lldb/Host/Host.h"
66 #include "lldb/Host/HostInfo.h"
67 
68 #include "lldb/Interpreter/CommandCompletions.h"
69 #include "lldb/Interpreter/CommandInterpreter.h"
70 #include "lldb/Interpreter/CommandReturnObject.h"
71 #include "lldb/Interpreter/OptionValueProperties.h"
72 #include "lldb/Interpreter/Options.h"
73 #include "lldb/Interpreter/Property.h"
74 #include "lldb/Utility/Args.h"
75 
76 #include "lldb/Target/Language.h"
77 #include "lldb/Target/Process.h"
78 #include "lldb/Target/StopInfo.h"
79 #include "lldb/Target/TargetList.h"
80 #include "lldb/Target/Thread.h"
81 #include "lldb/Target/UnixSignals.h"
82 
83 #include "llvm/ADT/STLExtras.h"
84 #include "llvm/ADT/ScopeExit.h"
85 #include "llvm/ADT/SmallString.h"
86 #include "llvm/Support/FormatAdapters.h"
87 #include "llvm/Support/Path.h"
88 #include "llvm/Support/PrettyStackTrace.h"
89 #include "llvm/Support/ScopedPrinter.h"
90 
91 #if defined(__APPLE__)
92 #include <TargetConditionals.h>
93 #endif
94 
95 using namespace lldb;
96 using namespace lldb_private;
97 
98 static const char *k_white_space = " \t\v";
99 
100 static constexpr const char *InitFileWarning =
101     "There is a .lldbinit file in the current directory which is not being "
102     "read.\n"
103     "To silence this warning without sourcing in the local .lldbinit,\n"
104     "add the following to the lldbinit file in your home directory:\n"
105     "    settings set target.load-cwd-lldbinit false\n"
106     "To allow lldb to source .lldbinit files in the current working "
107     "directory,\n"
108     "set the value of this variable to true.  Only do so if you understand "
109     "and\n"
110     "accept the security risk.";
111 
112 const char *CommandInterpreter::g_no_argument = "<no-argument>";
113 const char *CommandInterpreter::g_need_argument = "<need-argument>";
114 const char *CommandInterpreter::g_argument = "<argument>";
115 
116 
117 #define LLDB_PROPERTIES_interpreter
118 #include "InterpreterProperties.inc"
119 
120 enum {
121 #define LLDB_PROPERTIES_interpreter
122 #include "InterpreterPropertiesEnum.inc"
123 };
124 
125 llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() {
126   static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter");
127   return class_name;
128 }
129 
130 CommandInterpreter::CommandInterpreter(Debugger &debugger,
131                                        bool synchronous_execution)
132     : Broadcaster(debugger.GetBroadcasterManager(),
133                   CommandInterpreter::GetStaticBroadcasterClass().str()),
134       Properties(
135           OptionValuePropertiesSP(new OptionValueProperties("interpreter"))),
136       IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
137       m_debugger(debugger), m_synchronous_execution(true),
138       m_skip_lldbinit_files(false), m_skip_app_init_files(false),
139       m_comment_char('#'), m_batch_command_mode(false),
140       m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
141       m_command_source_depth(0) {
142   SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
143   SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
144   SetEventName(eBroadcastBitQuitCommandReceived, "quit");
145   SetSynchronous(synchronous_execution);
146   CheckInWithManager();
147   m_collection_sp->Initialize(g_interpreter_properties);
148 }
149 
150 bool CommandInterpreter::GetExpandRegexAliases() const {
151   const uint32_t idx = ePropertyExpandRegexAliases;
152   return GetPropertyAtIndexAs<bool>(
153       idx, g_interpreter_properties[idx].default_uint_value != 0);
154 }
155 
156 bool CommandInterpreter::GetPromptOnQuit() const {
157   const uint32_t idx = ePropertyPromptOnQuit;
158   return GetPropertyAtIndexAs<bool>(
159       idx, g_interpreter_properties[idx].default_uint_value != 0);
160 }
161 
162 void CommandInterpreter::SetPromptOnQuit(bool enable) {
163   const uint32_t idx = ePropertyPromptOnQuit;
164   SetPropertyAtIndex(idx, enable);
165 }
166 
167 bool CommandInterpreter::GetSaveTranscript() const {
168   const uint32_t idx = ePropertySaveTranscript;
169   return GetPropertyAtIndexAs<bool>(
170       idx, g_interpreter_properties[idx].default_uint_value != 0);
171 }
172 
173 void CommandInterpreter::SetSaveTranscript(bool enable) {
174   const uint32_t idx = ePropertySaveTranscript;
175   SetPropertyAtIndex(idx, enable);
176 }
177 
178 bool CommandInterpreter::GetSaveSessionOnQuit() const {
179   const uint32_t idx = ePropertySaveSessionOnQuit;
180   return GetPropertyAtIndexAs<bool>(
181       idx, g_interpreter_properties[idx].default_uint_value != 0);
182 }
183 
184 void CommandInterpreter::SetSaveSessionOnQuit(bool enable) {
185   const uint32_t idx = ePropertySaveSessionOnQuit;
186   SetPropertyAtIndex(idx, enable);
187 }
188 
189 bool CommandInterpreter::GetOpenTranscriptInEditor() const {
190   const uint32_t idx = ePropertyOpenTranscriptInEditor;
191   return GetPropertyAtIndexAs<bool>(
192       idx, g_interpreter_properties[idx].default_uint_value != 0);
193 }
194 
195 void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) {
196   const uint32_t idx = ePropertyOpenTranscriptInEditor;
197   SetPropertyAtIndex(idx, enable);
198 }
199 
200 FileSpec CommandInterpreter::GetSaveSessionDirectory() const {
201   const uint32_t idx = ePropertySaveSessionDirectory;
202   return GetPropertyAtIndexAs<FileSpec>(idx, {});
203 }
204 
205 void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) {
206   const uint32_t idx = ePropertySaveSessionDirectory;
207   SetPropertyAtIndex(idx, path);
208 }
209 
210 bool CommandInterpreter::GetEchoCommands() const {
211   const uint32_t idx = ePropertyEchoCommands;
212   return GetPropertyAtIndexAs<bool>(
213       idx, g_interpreter_properties[idx].default_uint_value != 0);
214 }
215 
216 void CommandInterpreter::SetEchoCommands(bool enable) {
217   const uint32_t idx = ePropertyEchoCommands;
218   SetPropertyAtIndex(idx, enable);
219 }
220 
221 bool CommandInterpreter::GetEchoCommentCommands() const {
222   const uint32_t idx = ePropertyEchoCommentCommands;
223   return GetPropertyAtIndexAs<bool>(
224       idx, g_interpreter_properties[idx].default_uint_value != 0);
225 }
226 
227 void CommandInterpreter::SetEchoCommentCommands(bool enable) {
228   const uint32_t idx = ePropertyEchoCommentCommands;
229   SetPropertyAtIndex(idx, enable);
230 }
231 
232 void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
233   m_allow_exit_code = allow;
234   if (!allow)
235     m_quit_exit_code.reset();
236 }
237 
238 bool CommandInterpreter::SetQuitExitCode(int exit_code) {
239   if (!m_allow_exit_code)
240     return false;
241   m_quit_exit_code = exit_code;
242   return true;
243 }
244 
245 int CommandInterpreter::GetQuitExitCode(bool &exited) const {
246   exited = m_quit_exit_code.has_value();
247   if (exited)
248     return *m_quit_exit_code;
249   return 0;
250 }
251 
252 void CommandInterpreter::ResolveCommand(const char *command_line,
253                                         CommandReturnObject &result) {
254   std::string command = command_line;
255   if (ResolveCommandImpl(command, result) != nullptr) {
256     result.AppendMessageWithFormat("%s", command.c_str());
257     result.SetStatus(eReturnStatusSuccessFinishResult);
258   }
259 }
260 
261 bool CommandInterpreter::GetStopCmdSourceOnError() const {
262   const uint32_t idx = ePropertyStopCmdSourceOnError;
263   return GetPropertyAtIndexAs<bool>(
264       idx, g_interpreter_properties[idx].default_uint_value != 0);
265 }
266 
267 bool CommandInterpreter::GetSpaceReplPrompts() const {
268   const uint32_t idx = ePropertySpaceReplPrompts;
269   return GetPropertyAtIndexAs<bool>(
270       idx, g_interpreter_properties[idx].default_uint_value != 0);
271 }
272 
273 bool CommandInterpreter::GetRepeatPreviousCommand() const {
274   const uint32_t idx = ePropertyRepeatPreviousCommand;
275   return GetPropertyAtIndexAs<bool>(
276       idx, g_interpreter_properties[idx].default_uint_value != 0);
277 }
278 
279 bool CommandInterpreter::GetRequireCommandOverwrite() const {
280   const uint32_t idx = ePropertyRequireCommandOverwrite;
281   return GetPropertyAtIndexAs<bool>(
282       idx, g_interpreter_properties[idx].default_uint_value != 0);
283 }
284 
285 void CommandInterpreter::Initialize() {
286   LLDB_SCOPED_TIMER();
287 
288   CommandReturnObject result(m_debugger.GetUseColor());
289 
290   LoadCommandDictionary();
291 
292   // An alias arguments vector to reuse - reset it before use...
293   OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
294 
295   // Set up some initial aliases.
296   CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit");
297   if (cmd_obj_sp) {
298     AddAlias("q", cmd_obj_sp);
299     AddAlias("exit", cmd_obj_sp);
300   }
301 
302   cmd_obj_sp = GetCommandSPExact("_regexp-attach");
303   if (cmd_obj_sp)
304     AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
305 
306   cmd_obj_sp = GetCommandSPExact("process detach");
307   if (cmd_obj_sp) {
308     AddAlias("detach", cmd_obj_sp);
309   }
310 
311   cmd_obj_sp = GetCommandSPExact("process continue");
312   if (cmd_obj_sp) {
313     AddAlias("c", cmd_obj_sp);
314     AddAlias("continue", cmd_obj_sp);
315   }
316 
317   cmd_obj_sp = GetCommandSPExact("_regexp-break");
318   if (cmd_obj_sp)
319     AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
320 
321   cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
322   if (cmd_obj_sp)
323     AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
324 
325   cmd_obj_sp = GetCommandSPExact("thread step-inst");
326   if (cmd_obj_sp) {
327     AddAlias("stepi", cmd_obj_sp);
328     AddAlias("si", cmd_obj_sp);
329   }
330 
331   cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
332   if (cmd_obj_sp) {
333     AddAlias("nexti", cmd_obj_sp);
334     AddAlias("ni", cmd_obj_sp);
335   }
336 
337   cmd_obj_sp = GetCommandSPExact("thread step-in");
338   if (cmd_obj_sp) {
339     AddAlias("s", cmd_obj_sp);
340     AddAlias("step", cmd_obj_sp);
341     CommandAlias *sif_alias = AddAlias(
342         "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
343     if (sif_alias) {
344       sif_alias->SetHelp("Step through the current block, stopping if you step "
345                          "directly into a function whose name matches the "
346                          "TargetFunctionName.");
347       sif_alias->SetSyntax("sif <TargetFunctionName>");
348     }
349   }
350 
351   cmd_obj_sp = GetCommandSPExact("thread step-over");
352   if (cmd_obj_sp) {
353     AddAlias("n", cmd_obj_sp);
354     AddAlias("next", cmd_obj_sp);
355   }
356 
357   cmd_obj_sp = GetCommandSPExact("thread step-out");
358   if (cmd_obj_sp) {
359     AddAlias("finish", cmd_obj_sp);
360   }
361 
362   cmd_obj_sp = GetCommandSPExact("frame select");
363   if (cmd_obj_sp) {
364     AddAlias("f", cmd_obj_sp);
365   }
366 
367   cmd_obj_sp = GetCommandSPExact("thread select");
368   if (cmd_obj_sp) {
369     AddAlias("t", cmd_obj_sp);
370   }
371 
372   cmd_obj_sp = GetCommandSPExact("_regexp-jump");
373   if (cmd_obj_sp) {
374     AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
375     AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
376   }
377 
378   cmd_obj_sp = GetCommandSPExact("_regexp-list");
379   if (cmd_obj_sp) {
380     AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
381     AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
382   }
383 
384   cmd_obj_sp = GetCommandSPExact("_regexp-env");
385   if (cmd_obj_sp)
386     AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
387 
388   cmd_obj_sp = GetCommandSPExact("memory read");
389   if (cmd_obj_sp)
390     AddAlias("x", cmd_obj_sp);
391 
392   cmd_obj_sp = GetCommandSPExact("_regexp-up");
393   if (cmd_obj_sp)
394     AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
395 
396   cmd_obj_sp = GetCommandSPExact("_regexp-down");
397   if (cmd_obj_sp)
398     AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
399 
400   cmd_obj_sp = GetCommandSPExact("_regexp-display");
401   if (cmd_obj_sp)
402     AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
403 
404   cmd_obj_sp = GetCommandSPExact("disassemble");
405   if (cmd_obj_sp)
406     AddAlias("dis", cmd_obj_sp);
407 
408   cmd_obj_sp = GetCommandSPExact("disassemble");
409   if (cmd_obj_sp)
410     AddAlias("di", cmd_obj_sp);
411 
412   cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
413   if (cmd_obj_sp)
414     AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
415 
416   cmd_obj_sp = GetCommandSPExact("_regexp-bt");
417   if (cmd_obj_sp)
418     AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
419 
420   cmd_obj_sp = GetCommandSPExact("target create");
421   if (cmd_obj_sp)
422     AddAlias("file", cmd_obj_sp);
423 
424   cmd_obj_sp = GetCommandSPExact("target modules");
425   if (cmd_obj_sp)
426     AddAlias("image", cmd_obj_sp);
427 
428   alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
429 
430   cmd_obj_sp = GetCommandSPExact("dwim-print");
431   if (cmd_obj_sp) {
432     AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
433     AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
434     if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) {
435       po->SetHelp("Evaluate an expression on the current thread.  Displays any "
436                   "returned value with formatting "
437                   "controlled by the type's author.");
438       po->SetHelpLong("");
439     }
440   }
441 
442   cmd_obj_sp = GetCommandSPExact("expression");
443   if (cmd_obj_sp) {
444     // Ensure `e` runs `expression`.
445     AddAlias("e", cmd_obj_sp);
446     AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
447     CommandAlias *parray_alias =
448         AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
449     if (parray_alias) {
450         parray_alias->SetHelp
451           ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
452            "to get a typed-pointer-to-an-array in memory, and will display "
453            "COUNT elements of that type from the array.");
454         parray_alias->SetHelpLong("");
455     }
456     CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
457              "--object-description --element-count %1 --");
458     if (poarray_alias) {
459       poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
460           "evaluate EXPRESSION to get the address of an array of COUNT "
461           "objects in memory, and will call po on them.");
462       poarray_alias->SetHelpLong("");
463     }
464   }
465 
466   cmd_obj_sp = GetCommandSPExact("platform shell");
467   if (cmd_obj_sp) {
468     CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
469     if (shell_alias) {
470       shell_alias->SetHelp("Run a shell command on the host.");
471       shell_alias->SetHelpLong("");
472       shell_alias->SetSyntax("shell <shell-command>");
473     }
474   }
475 
476   cmd_obj_sp = GetCommandSPExact("process kill");
477   if (cmd_obj_sp) {
478     AddAlias("kill", cmd_obj_sp);
479   }
480 
481   cmd_obj_sp = GetCommandSPExact("process launch");
482   if (cmd_obj_sp) {
483     alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
484 #if defined(__APPLE__)
485 #if TARGET_OS_IPHONE
486     AddAlias("r", cmd_obj_sp, "--");
487     AddAlias("run", cmd_obj_sp, "--");
488 #else
489     AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
490     AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
491 #endif
492 #else
493     StreamString defaultshell;
494     defaultshell.Printf("--shell=%s --",
495                         HostInfo::GetDefaultShell().GetPath().c_str());
496     AddAlias("r", cmd_obj_sp, defaultshell.GetString());
497     AddAlias("run", cmd_obj_sp, defaultshell.GetString());
498 #endif
499   }
500 
501   cmd_obj_sp = GetCommandSPExact("target symbols add");
502   if (cmd_obj_sp) {
503     AddAlias("add-dsym", cmd_obj_sp);
504   }
505 
506   cmd_obj_sp = GetCommandSPExact("breakpoint set");
507   if (cmd_obj_sp) {
508     AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
509   }
510 
511   cmd_obj_sp = GetCommandSPExact("frame variable");
512   if (cmd_obj_sp) {
513     AddAlias("v", cmd_obj_sp);
514     AddAlias("var", cmd_obj_sp);
515     AddAlias("vo", cmd_obj_sp, "--object-description");
516   }
517 
518   cmd_obj_sp = GetCommandSPExact("register");
519   if (cmd_obj_sp) {
520     AddAlias("re", cmd_obj_sp);
521   }
522 
523   cmd_obj_sp = GetCommandSPExact("scripting run");
524   if (cmd_obj_sp) {
525     AddAlias("script", cmd_obj_sp);
526   }
527 
528   cmd_obj_sp = GetCommandSPExact("session history");
529   if (cmd_obj_sp) {
530     AddAlias("history", cmd_obj_sp);
531   }
532 
533   cmd_obj_sp = GetCommandSPExact("help");
534   if (cmd_obj_sp) {
535     AddAlias("h", cmd_obj_sp);
536   }
537 }
538 
539 void CommandInterpreter::Clear() {
540   m_command_io_handler_sp.reset();
541 }
542 
543 const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
544   // This function has not yet been implemented.
545 
546   // Look for any embedded script command
547   // If found,
548   //    get interpreter object from the command dictionary,
549   //    call execute_one_command on it,
550   //    get the results as a string,
551   //    substitute that string for current stuff.
552 
553   return arg;
554 }
555 
556 #define REGISTER_COMMAND_OBJECT(NAME, CLASS)                                   \
557   m_command_dict[NAME] = std::make_shared<CLASS>(*this);
558 
559 void CommandInterpreter::LoadCommandDictionary() {
560   LLDB_SCOPED_TIMER();
561 
562   REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
563   REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
564   REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
565   REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
566   REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
567   REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
568   REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
569   REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
570   REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
571   REGISTER_COMMAND_OBJECT("help", CommandObjectHelp);
572   REGISTER_COMMAND_OBJECT("log", CommandObjectLog);
573   REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory);
574   REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform);
575   REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin);
576   REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
577   REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
578   REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
579   REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting);
580   REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
581   REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
582   REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
583   REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats);
584   REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget);
585   REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread);
586   REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace);
587   REGISTER_COMMAND_OBJECT("type", CommandObjectType);
588   REGISTER_COMMAND_OBJECT("version", CommandObjectVersion);
589   REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint);
590   REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage);
591 
592   // clang-format off
593   const char *break_regexes[][2] = {
594       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
595        "breakpoint set --file '%1' --line %2 --column %3"},
596       {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
597        "breakpoint set --file '%1' --line %2"},
598       {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
599       {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
600       {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
601       {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
602        "breakpoint set --name '%1'"},
603       {"^(-.*)$", "breakpoint set %1"},
604       {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
605        "breakpoint set --name '%2' --shlib '%1'"},
606       {"^\\&(.*[^[:space:]])[[:space:]]*$",
607        "breakpoint set --name '%1' --skip-prologue=0"},
608       {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
609        "breakpoint set --name '%1'"}};
610   // clang-format on
611 
612   size_t num_regexes = std::size(break_regexes);
613 
614   std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
615       new CommandObjectRegexCommand(
616           *this, "_regexp-break",
617           "Set a breakpoint using one of several shorthand formats.",
618           "\n"
619           "_regexp-break <filename>:<linenum>:<colnum>\n"
620           "              main.c:12:21          // Break at line 12 and column "
621           "21 of main.c\n\n"
622           "_regexp-break <filename>:<linenum>\n"
623           "              main.c:12             // Break at line 12 of "
624           "main.c\n\n"
625           "_regexp-break <linenum>\n"
626           "              12                    // Break at line 12 of current "
627           "file\n\n"
628           "_regexp-break 0x<address>\n"
629           "              0x1234000             // Break at address "
630           "0x1234000\n\n"
631           "_regexp-break <name>\n"
632           "              main                  // Break in 'main' after the "
633           "prologue\n\n"
634           "_regexp-break &<name>\n"
635           "              &main                 // Break at first instruction "
636           "in 'main'\n\n"
637           "_regexp-break <module>`<name>\n"
638           "              libc.so`malloc        // Break in 'malloc' from "
639           "'libc.so'\n\n"
640           "_regexp-break /<source-regex>/\n"
641           "              /break here/          // Break on source lines in "
642           "current file\n"
643           "                                    // containing text 'break "
644           "here'.\n",
645           lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
646 
647   if (break_regex_cmd_up) {
648     bool success = true;
649     for (size_t i = 0; i < num_regexes; i++) {
650       success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
651                                                     break_regexes[i][1]);
652       if (!success)
653         break;
654     }
655     success =
656         break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
657 
658     if (success) {
659       CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
660       m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
661           break_regex_cmd_sp;
662     }
663   }
664 
665   std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
666       new CommandObjectRegexCommand(
667           *this, "_regexp-tbreak",
668           "Set a one-shot breakpoint using one of several shorthand formats.",
669           "\n"
670           "_regexp-break <filename>:<linenum>:<colnum>\n"
671           "              main.c:12:21          // Break at line 12 and column "
672           "21 of main.c\n\n"
673           "_regexp-break <filename>:<linenum>\n"
674           "              main.c:12             // Break at line 12 of "
675           "main.c\n\n"
676           "_regexp-break <linenum>\n"
677           "              12                    // Break at line 12 of current "
678           "file\n\n"
679           "_regexp-break 0x<address>\n"
680           "              0x1234000             // Break at address "
681           "0x1234000\n\n"
682           "_regexp-break <name>\n"
683           "              main                  // Break in 'main' after the "
684           "prologue\n\n"
685           "_regexp-break &<name>\n"
686           "              &main                 // Break at first instruction "
687           "in 'main'\n\n"
688           "_regexp-break <module>`<name>\n"
689           "              libc.so`malloc        // Break in 'malloc' from "
690           "'libc.so'\n\n"
691           "_regexp-break /<source-regex>/\n"
692           "              /break here/          // Break on source lines in "
693           "current file\n"
694           "                                    // containing text 'break "
695           "here'.\n",
696           lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
697 
698   if (tbreak_regex_cmd_up) {
699     bool success = true;
700     for (size_t i = 0; i < num_regexes; i++) {
701       std::string command = break_regexes[i][1];
702       command += " -o 1";
703       success =
704           tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
705       if (!success)
706         break;
707     }
708     success =
709         tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
710 
711     if (success) {
712       CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
713       m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
714           tbreak_regex_cmd_sp;
715     }
716   }
717 
718   std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
719       new CommandObjectRegexCommand(
720           *this, "_regexp-attach", "Attach to process by ID or name.",
721           "_regexp-attach <pid> | <process-name>", 0, false));
722   if (attach_regex_cmd_up) {
723     if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
724                                              "process attach --pid %1") &&
725         attach_regex_cmd_up->AddRegexCommand(
726             "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
727                                                       // specified get passed to
728                                                       // 'process attach'
729         attach_regex_cmd_up->AddRegexCommand("^(.+)$",
730                                              "process attach --name '%1'") &&
731         attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
732       CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
733       m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
734           attach_regex_cmd_sp;
735     }
736   }
737 
738   std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
739       new CommandObjectRegexCommand(*this, "_regexp-down",
740                                     "Select a newer stack frame.  Defaults to "
741                                     "moving one frame, a numeric argument can "
742                                     "specify an arbitrary number.",
743                                     "_regexp-down [<count>]", 0, false));
744   if (down_regex_cmd_up) {
745     if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
746         down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
747                                            "frame select -r -%1")) {
748       CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
749       m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
750           down_regex_cmd_sp;
751     }
752   }
753 
754   std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
755       new CommandObjectRegexCommand(
756           *this, "_regexp-up",
757           "Select an older stack frame.  Defaults to moving one "
758           "frame, a numeric argument can specify an arbitrary number.",
759           "_regexp-up [<count>]", 0, false));
760   if (up_regex_cmd_up) {
761     if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
762         up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
763       CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
764       m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
765           up_regex_cmd_sp;
766     }
767   }
768 
769   std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
770       new CommandObjectRegexCommand(
771           *this, "_regexp-display",
772           "Evaluate an expression at every stop (see 'help target stop-hook'.)",
773           "_regexp-display expression", 0, false));
774   if (display_regex_cmd_up) {
775     if (display_regex_cmd_up->AddRegexCommand(
776             "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
777       CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
778       m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
779           display_regex_cmd_sp;
780     }
781   }
782 
783   std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
784       new CommandObjectRegexCommand(*this, "_regexp-undisplay",
785                                     "Stop displaying expression at every "
786                                     "stop (specified by stop-hook index.)",
787                                     "_regexp-undisplay stop-hook-number", 0,
788                                     false));
789   if (undisplay_regex_cmd_up) {
790     if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
791                                                 "target stop-hook delete %1")) {
792       CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
793       m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
794           undisplay_regex_cmd_sp;
795     }
796   }
797 
798   std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
799       new CommandObjectRegexCommand(
800           *this, "gdb-remote",
801           "Connect to a process via remote GDB server.\n"
802           "If no host is specified, localhost is assumed.\n"
803           "gdb-remote is an abbreviation for 'process connect --plugin "
804           "gdb-remote connect://<hostname>:<port>'\n",
805           "gdb-remote [<hostname>:]<portnum>", 0, false));
806   if (connect_gdb_remote_cmd_up) {
807     if (connect_gdb_remote_cmd_up->AddRegexCommand(
808             "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
809             "process connect --plugin gdb-remote connect://%1:%2") &&
810         connect_gdb_remote_cmd_up->AddRegexCommand(
811             "^([[:digit:]]+)$",
812             "process connect --plugin gdb-remote connect://localhost:%1")) {
813       CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
814       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
815     }
816   }
817 
818   std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
819       new CommandObjectRegexCommand(
820           *this, "kdp-remote",
821           "Connect to a process via remote KDP server.\n"
822           "If no UDP port is specified, port 41139 is assumed.\n"
823           "kdp-remote is an abbreviation for 'process connect --plugin "
824           "kdp-remote udp://<hostname>:<port>'\n",
825           "kdp-remote <hostname>[:<portnum>]", 0, false));
826   if (connect_kdp_remote_cmd_up) {
827     if (connect_kdp_remote_cmd_up->AddRegexCommand(
828             "^([^:]+:[[:digit:]]+)$",
829             "process connect --plugin kdp-remote udp://%1") &&
830         connect_kdp_remote_cmd_up->AddRegexCommand(
831             "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
832       CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
833       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
834     }
835   }
836 
837   std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
838       new CommandObjectRegexCommand(
839           *this, "_regexp-bt",
840           "Show backtrace of the current thread's call stack. Any numeric "
841           "argument displays at most that many frames. The argument 'all' "
842           "displays all threads. Use 'settings set frame-format' to customize "
843           "the printing of individual frames and 'settings set thread-format' "
844           "to customize the thread header. Frame recognizers may filter the "
845           "list. Use 'thread backtrace -u (--unfiltered)' to see them all.",
846           "bt [<digit> | all]", 0, false));
847   if (bt_regex_cmd_up) {
848     // accept but don't document "bt -c <number>" -- before bt was a regex
849     // command if you wanted to backtrace three frames you would do "bt -c 3"
850     // but the intention is to have this emulate the gdb "bt" command and so
851     // now "bt 3" is the preferred form, in line with gdb.
852     if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
853                                          "thread backtrace -c %1") &&
854         bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
855                                          "thread backtrace -c %1") &&
856         bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
857         bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
858       CommandObjectSP command_sp(bt_regex_cmd_up.release());
859       m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
860     }
861   }
862 
863   std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
864       new CommandObjectRegexCommand(
865           *this, "_regexp-list",
866           "List relevant source code using one of several shorthand formats.",
867           "\n"
868           "_regexp-list <file>:<line>   // List around specific file/line\n"
869           "_regexp-list <line>          // List current file around specified "
870           "line\n"
871           "_regexp-list <function-name> // List specified function\n"
872           "_regexp-list 0x<address>     // List around specified address\n"
873           "_regexp-list -[<count>]      // List previous <count> lines\n"
874           "_regexp-list                 // List subsequent lines",
875           lldb::eSourceFileCompletion, false));
876   if (list_regex_cmd_up) {
877     if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
878                                            "source list --line %1") &&
879         list_regex_cmd_up->AddRegexCommand(
880             "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
881             "]*$",
882             "source list --file '%1' --line %2") &&
883         list_regex_cmd_up->AddRegexCommand(
884             "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
885             "source list --address %1") &&
886         list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
887                                            "source list --reverse") &&
888         list_regex_cmd_up->AddRegexCommand(
889             "^-([[:digit:]]+)[[:space:]]*$",
890             "source list --reverse --count %1") &&
891         list_regex_cmd_up->AddRegexCommand("^(.+)$",
892                                            "source list --name \"%1\"") &&
893         list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
894       CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
895       m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
896           list_regex_cmd_sp;
897     }
898   }
899 
900   std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
901       new CommandObjectRegexCommand(
902           *this, "_regexp-env",
903           "Shorthand for viewing and setting environment variables.",
904           "\n"
905           "_regexp-env                  // Show environment\n"
906           "_regexp-env <name>=<value>   // Set an environment variable",
907           0, false));
908   if (env_regex_cmd_up) {
909     if (env_regex_cmd_up->AddRegexCommand("^$",
910                                           "settings show target.env-vars") &&
911         env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
912                                           "settings set target.env-vars %1")) {
913       CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
914       m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
915           env_regex_cmd_sp;
916     }
917   }
918 
919   std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
920       new CommandObjectRegexCommand(
921           *this, "_regexp-jump", "Set the program counter to a new address.",
922           "\n"
923           "_regexp-jump <line>\n"
924           "_regexp-jump +<line-offset> | -<line-offset>\n"
925           "_regexp-jump <file>:<line>\n"
926           "_regexp-jump *<addr>\n",
927           0, false));
928   if (jump_regex_cmd_up) {
929     if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
930                                            "thread jump --addr %1") &&
931         jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
932                                            "thread jump --line %1") &&
933         jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
934                                            "thread jump --file %1 --line %2") &&
935         jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
936                                            "thread jump --by %1")) {
937       CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
938       m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
939           jump_regex_cmd_sp;
940     }
941   }
942 }
943 
944 int CommandInterpreter::GetCommandNamesMatchingPartialString(
945     const char *cmd_str, bool include_aliases, StringList &matches,
946     StringList &descriptions) {
947   AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
948                                 &descriptions);
949 
950   if (include_aliases) {
951     AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
952                                   &descriptions);
953   }
954 
955   return matches.GetSize();
956 }
957 
958 CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath(
959     Args &path, bool leaf_is_command, Status &result) {
960   result.Clear();
961 
962   auto get_multi_or_report_error =
963       [&result](CommandObjectSP cmd_sp,
964                            const char *name) -> CommandObjectMultiword * {
965     if (!cmd_sp) {
966       result = Status::FromErrorStringWithFormat(
967           "Path component: '%s' not found", name);
968       return nullptr;
969     }
970     if (!cmd_sp->IsUserCommand()) {
971       result = Status::FromErrorStringWithFormat(
972           "Path component: '%s' is not a user "
973           "command",
974           name);
975       return nullptr;
976     }
977     CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
978     if (!cmd_as_multi) {
979       result = Status::FromErrorStringWithFormat(
980           "Path component: '%s' is not a container "
981           "command",
982           name);
983       return nullptr;
984     }
985     return cmd_as_multi;
986   };
987 
988   size_t num_args = path.GetArgumentCount();
989   if (num_args == 0) {
990     result = Status::FromErrorString("empty command path");
991     return nullptr;
992   }
993 
994   if (num_args == 1 && leaf_is_command) {
995     // We just got a leaf command to be added to the root.  That's not an error,
996     // just return null for the container.
997     return nullptr;
998   }
999 
1000   // Start by getting the root command from the interpreter.
1001   const char *cur_name = path.GetArgumentAtIndex(0);
1002   CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
1003   CommandObjectMultiword *cur_as_multi =
1004       get_multi_or_report_error(cur_cmd_sp, cur_name);
1005   if (cur_as_multi == nullptr)
1006     return nullptr;
1007 
1008   size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
1009   for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
1010        cursor++) {
1011     cur_name = path.GetArgumentAtIndex(cursor);
1012     cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
1013     cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
1014   }
1015   return cur_as_multi;
1016 }
1017 
1018 CommandObjectSP
1019 CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
1020                                  bool exact, StringList *matches,
1021                                  StringList *descriptions) const {
1022   CommandObjectSP command_sp;
1023 
1024   std::string cmd = std::string(cmd_str);
1025 
1026   if (HasCommands()) {
1027     auto pos = m_command_dict.find(cmd);
1028     if (pos != m_command_dict.end())
1029       command_sp = pos->second;
1030   }
1031 
1032   if (include_aliases && HasAliases()) {
1033     auto alias_pos = m_alias_dict.find(cmd);
1034     if (alias_pos != m_alias_dict.end())
1035       command_sp = alias_pos->second;
1036   }
1037 
1038   if (HasUserCommands()) {
1039     auto pos = m_user_dict.find(cmd);
1040     if (pos != m_user_dict.end())
1041       command_sp = pos->second;
1042   }
1043 
1044   if (HasUserMultiwordCommands()) {
1045     auto pos = m_user_mw_dict.find(cmd);
1046     if (pos != m_user_mw_dict.end())
1047       command_sp = pos->second;
1048   }
1049 
1050   if (!exact && !command_sp) {
1051     // We will only get into here if we didn't find any exact matches.
1052 
1053     CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1054         real_match_sp;
1055 
1056     StringList local_matches;
1057     if (matches == nullptr)
1058       matches = &local_matches;
1059 
1060     unsigned int num_cmd_matches = 0;
1061     unsigned int num_alias_matches = 0;
1062     unsigned int num_user_matches = 0;
1063     unsigned int num_user_mw_matches = 0;
1064 
1065     // Look through the command dictionaries one by one, and if we get only one
1066     // match from any of them in toto, then return that, otherwise return an
1067     // empty CommandObjectSP and the list of matches.
1068 
1069     if (HasCommands()) {
1070       num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
1071                                                       *matches, descriptions);
1072     }
1073 
1074     if (num_cmd_matches == 1) {
1075       cmd.assign(matches->GetStringAtIndex(0));
1076       auto pos = m_command_dict.find(cmd);
1077       if (pos != m_command_dict.end())
1078         real_match_sp = pos->second;
1079     }
1080 
1081     if (include_aliases && HasAliases()) {
1082       num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
1083                                                         *matches, descriptions);
1084     }
1085 
1086     if (num_alias_matches == 1) {
1087       cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
1088       auto alias_pos = m_alias_dict.find(cmd);
1089       if (alias_pos != m_alias_dict.end())
1090         alias_match_sp = alias_pos->second;
1091     }
1092 
1093     if (HasUserCommands()) {
1094       num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
1095                                                        *matches, descriptions);
1096     }
1097 
1098     if (num_user_matches == 1) {
1099       cmd.assign(
1100           matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
1101 
1102       auto pos = m_user_dict.find(cmd);
1103       if (pos != m_user_dict.end())
1104         user_match_sp = pos->second;
1105     }
1106 
1107     if (HasUserMultiwordCommands()) {
1108       num_user_mw_matches = AddNamesMatchingPartialString(
1109           m_user_mw_dict, cmd_str, *matches, descriptions);
1110     }
1111 
1112     if (num_user_mw_matches == 1) {
1113       cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1114                                            num_user_matches));
1115 
1116       auto pos = m_user_mw_dict.find(cmd);
1117       if (pos != m_user_mw_dict.end())
1118         user_mw_match_sp = pos->second;
1119     }
1120 
1121     // If we got exactly one match, return that, otherwise return the match
1122     // list.
1123 
1124     if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1125             num_alias_matches ==
1126         1) {
1127       if (num_cmd_matches)
1128         return real_match_sp;
1129       else if (num_alias_matches)
1130         return alias_match_sp;
1131       else if (num_user_mw_matches)
1132         return user_mw_match_sp;
1133       else
1134         return user_match_sp;
1135     }
1136   } else if (matches && command_sp) {
1137     matches->AppendString(cmd_str);
1138     if (descriptions)
1139       descriptions->AppendString(command_sp->GetHelp());
1140   }
1141 
1142   return command_sp;
1143 }
1144 
1145 bool CommandInterpreter::AddCommand(llvm::StringRef name,
1146                                     const lldb::CommandObjectSP &cmd_sp,
1147                                     bool can_replace) {
1148   if (cmd_sp.get())
1149     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1150                "tried to add a CommandObject from a different interpreter");
1151 
1152   if (name.empty())
1153     return false;
1154 
1155   cmd_sp->SetIsUserCommand(false);
1156 
1157   std::string name_sstr(name);
1158   auto name_iter = m_command_dict.find(name_sstr);
1159   if (name_iter != m_command_dict.end()) {
1160     if (!can_replace || !name_iter->second->IsRemovable())
1161       return false;
1162     name_iter->second = cmd_sp;
1163   } else {
1164     m_command_dict[name_sstr] = cmd_sp;
1165   }
1166   return true;
1167 }
1168 
1169 Status CommandInterpreter::AddUserCommand(llvm::StringRef name,
1170                                           const lldb::CommandObjectSP &cmd_sp,
1171                                           bool can_replace) {
1172   Status result;
1173   if (cmd_sp.get())
1174     lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1175                "tried to add a CommandObject from a different interpreter");
1176   if (name.empty()) {
1177     result = Status::FromErrorString(
1178         "can't use the empty string for a command name");
1179     return result;
1180   }
1181   // do not allow replacement of internal commands
1182   if (CommandExists(name)) {
1183     result = Status::FromErrorString("can't replace builtin command");
1184     return result;
1185   }
1186 
1187   if (UserCommandExists(name)) {
1188     if (!can_replace) {
1189       result = Status::FromErrorStringWithFormatv(
1190           "user command \"{0}\" already exists and force replace was not set "
1191           "by --overwrite or 'settings set interpreter.require-overwrite "
1192           "false'",
1193           name);
1194       return result;
1195     }
1196     if (cmd_sp->IsMultiwordObject()) {
1197       if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1198         result = Status::FromErrorString(
1199             "can't replace explicitly non-removable multi-word command");
1200         return result;
1201       }
1202     } else {
1203       if (!m_user_dict[std::string(name)]->IsRemovable()) {
1204         result = Status::FromErrorString(
1205             "can't replace explicitly non-removable command");
1206         return result;
1207       }
1208     }
1209   }
1210 
1211   cmd_sp->SetIsUserCommand(true);
1212 
1213   if (cmd_sp->IsMultiwordObject())
1214     m_user_mw_dict[std::string(name)] = cmd_sp;
1215   else
1216     m_user_dict[std::string(name)] = cmd_sp;
1217   return result;
1218 }
1219 
1220 CommandObjectSP
1221 CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1222                                       bool include_aliases) const {
1223   // Break up the command string into words, in case it's a multi-word command.
1224   Args cmd_words(cmd_str);
1225 
1226   if (cmd_str.empty())
1227     return {};
1228 
1229   if (cmd_words.GetArgumentCount() == 1)
1230     return GetCommandSP(cmd_str, include_aliases, true);
1231 
1232   // We have a multi-word command (seemingly), so we need to do more work.
1233   // First, get the cmd_obj_sp for the first word in the command.
1234   CommandObjectSP cmd_obj_sp =
1235       GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1236   if (!cmd_obj_sp)
1237     return {};
1238 
1239   // Loop through the rest of the words in the command (everything passed in
1240   // was supposed to be part of a command name), and find the appropriate
1241   // sub-command SP for each command word....
1242   size_t end = cmd_words.GetArgumentCount();
1243   for (size_t i = 1; i < end; ++i) {
1244     if (!cmd_obj_sp->IsMultiwordObject()) {
1245       // We have more words in the command name, but we don't have a
1246       // multiword object. Fail and return.
1247       return {};
1248     }
1249 
1250     cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1251     if (!cmd_obj_sp) {
1252       // The sub-command name was invalid.  Fail and return.
1253       return {};
1254     }
1255   }
1256 
1257   // We successfully looped through all the command words and got valid
1258   // command objects for them.
1259   return cmd_obj_sp;
1260 }
1261 
1262 CommandObject *
1263 CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1264                                      StringList *matches,
1265                                      StringList *descriptions) const {
1266   // Try to find a match among commands and aliases. Allowing inexact matches,
1267   // but perferring exact matches.
1268   return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
1269                              matches, descriptions)
1270                     .get();
1271 }
1272 
1273 CommandObject *CommandInterpreter::GetUserCommandObject(
1274     llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1275   std::string cmd_str(cmd);
1276   auto find_exact = [&](const CommandObject::CommandMap &map) {
1277     auto found_elem = map.find(cmd);
1278     if (found_elem == map.end())
1279       return (CommandObject *)nullptr;
1280     CommandObject *exact_cmd = found_elem->second.get();
1281     if (exact_cmd) {
1282       if (matches)
1283         matches->AppendString(exact_cmd->GetCommandName());
1284       if (descriptions)
1285         descriptions->AppendString(exact_cmd->GetHelp());
1286       return exact_cmd;
1287     }
1288     return (CommandObject *)nullptr;
1289   };
1290 
1291   CommandObject *exact_cmd = find_exact(GetUserCommands());
1292   if (exact_cmd)
1293     return exact_cmd;
1294 
1295   exact_cmd = find_exact(GetUserMultiwordCommands());
1296   if (exact_cmd)
1297     return exact_cmd;
1298 
1299   // We didn't have an exact command, so now look for partial matches.
1300   StringList tmp_list;
1301   StringList *matches_ptr = matches ? matches : &tmp_list;
1302   AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1303   AddNamesMatchingPartialString(GetUserMultiwordCommands(),
1304                                 cmd_str, *matches_ptr);
1305 
1306   return {};
1307 }
1308 
1309 CommandObject *CommandInterpreter::GetAliasCommandObject(
1310     llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1311   auto find_exact =
1312       [&](const CommandObject::CommandMap &map) -> CommandObject * {
1313     auto found_elem = map.find(cmd);
1314     if (found_elem == map.end())
1315       return (CommandObject *)nullptr;
1316     CommandObject *exact_cmd = found_elem->second.get();
1317     if (!exact_cmd)
1318       return nullptr;
1319 
1320     if (matches)
1321       matches->AppendString(exact_cmd->GetCommandName());
1322 
1323     if (descriptions)
1324       descriptions->AppendString(exact_cmd->GetHelp());
1325 
1326     return exact_cmd;
1327     return nullptr;
1328   };
1329 
1330   CommandObject *exact_cmd = find_exact(GetAliases());
1331   if (exact_cmd)
1332     return exact_cmd;
1333 
1334   // We didn't have an exact command, so now look for partial matches.
1335   StringList tmp_list;
1336   StringList *matches_ptr = matches ? matches : &tmp_list;
1337   AddNamesMatchingPartialString(GetAliases(), cmd, *matches_ptr);
1338 
1339   return {};
1340 }
1341 
1342 bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1343   return m_command_dict.find(cmd) != m_command_dict.end();
1344 }
1345 
1346 bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1347                                           std::string &full_name) const {
1348   bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
1349   if (exact_match) {
1350     full_name.assign(std::string(cmd));
1351     return exact_match;
1352   } else {
1353     StringList matches;
1354     size_t num_alias_matches;
1355     num_alias_matches =
1356         AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1357     if (num_alias_matches == 1) {
1358       // Make sure this isn't shadowing a command in the regular command space:
1359       StringList regular_matches;
1360       const bool include_aliases = false;
1361       const bool exact = false;
1362       CommandObjectSP cmd_obj_sp(
1363           GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1364       if (cmd_obj_sp || regular_matches.GetSize() > 0)
1365         return false;
1366       else {
1367         full_name.assign(matches.GetStringAtIndex(0));
1368         return true;
1369       }
1370     } else
1371       return false;
1372   }
1373 }
1374 
1375 bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1376   return m_alias_dict.find(cmd) != m_alias_dict.end();
1377 }
1378 
1379 bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1380   return m_user_dict.find(cmd) != m_user_dict.end();
1381 }
1382 
1383 bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1384   return m_user_mw_dict.find(cmd) != m_user_mw_dict.end();
1385 }
1386 
1387 CommandAlias *
1388 CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1389                              lldb::CommandObjectSP &command_obj_sp,
1390                              llvm::StringRef args_string) {
1391   if (command_obj_sp.get())
1392     lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1393                "tried to add a CommandObject from a different interpreter");
1394 
1395   std::unique_ptr<CommandAlias> command_alias_up(
1396       new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1397 
1398   if (command_alias_up && command_alias_up->IsValid()) {
1399     m_alias_dict[std::string(alias_name)] =
1400         CommandObjectSP(command_alias_up.get());
1401     return command_alias_up.release();
1402   }
1403 
1404   return nullptr;
1405 }
1406 
1407 bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1408   auto pos = m_alias_dict.find(alias_name);
1409   if (pos != m_alias_dict.end()) {
1410     m_alias_dict.erase(pos);
1411     return true;
1412   }
1413   return false;
1414 }
1415 
1416 bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
1417   auto pos = m_command_dict.find(cmd);
1418   if (pos != m_command_dict.end()) {
1419     if (force || pos->second->IsRemovable()) {
1420       // Only regular expression objects or python commands are removable under
1421       // normal circumstances.
1422       m_command_dict.erase(pos);
1423       return true;
1424     }
1425   }
1426   return false;
1427 }
1428 
1429 bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1430   CommandObject::CommandMap::iterator pos = m_user_dict.find(user_name);
1431   if (pos != m_user_dict.end()) {
1432     m_user_dict.erase(pos);
1433     return true;
1434   }
1435   return false;
1436 }
1437 
1438 bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1439   CommandObject::CommandMap::iterator pos = m_user_mw_dict.find(multi_name);
1440   if (pos != m_user_mw_dict.end()) {
1441     m_user_mw_dict.erase(pos);
1442     return true;
1443   }
1444   return false;
1445 }
1446 
1447 void CommandInterpreter::GetHelp(CommandReturnObject &result,
1448                                  uint32_t cmd_types) {
1449   llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1450   if (!help_prologue.empty()) {
1451     OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1452                             help_prologue);
1453   }
1454 
1455   CommandObject::CommandMap::const_iterator pos;
1456   size_t max_len = FindLongestCommandWord(m_command_dict);
1457 
1458   if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1459     result.AppendMessage("Debugger commands:");
1460     result.AppendMessage("");
1461 
1462     for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1463       if (!(cmd_types & eCommandTypesHidden) &&
1464           (pos->first.compare(0, 1, "_") == 0))
1465         continue;
1466 
1467       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1468                               pos->second->GetHelp(), max_len);
1469     }
1470     result.AppendMessage("");
1471   }
1472 
1473   if (!m_alias_dict.empty() &&
1474       ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1475     result.AppendMessageWithFormat(
1476         "Current command abbreviations "
1477         "(type '%shelp command alias' for more info):\n",
1478         GetCommandPrefix());
1479     result.AppendMessage("");
1480     max_len = FindLongestCommandWord(m_alias_dict);
1481 
1482     for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1483          ++alias_pos) {
1484       OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1485                               alias_pos->second->GetHelp(), max_len);
1486     }
1487     result.AppendMessage("");
1488   }
1489 
1490   if (!m_user_dict.empty() &&
1491       ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1492     result.AppendMessage("Current user-defined commands:");
1493     result.AppendMessage("");
1494     max_len = FindLongestCommandWord(m_user_dict);
1495     for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1496       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1497                               pos->second->GetHelp(), max_len);
1498     }
1499     result.AppendMessage("");
1500   }
1501 
1502   if (!m_user_mw_dict.empty() &&
1503       ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1504     result.AppendMessage("Current user-defined container commands:");
1505     result.AppendMessage("");
1506     max_len = FindLongestCommandWord(m_user_mw_dict);
1507     for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1508       OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1509                               pos->second->GetHelp(), max_len);
1510     }
1511     result.AppendMessage("");
1512   }
1513 
1514   result.AppendMessageWithFormat(
1515       "For more information on any command, type '%shelp <command-name>'.\n",
1516       GetCommandPrefix());
1517 }
1518 
1519 CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1520     llvm::StringRef &command_string) {
1521   // This function finds the final, lowest-level, alias-resolved command object
1522   // whose 'Execute' function will eventually be invoked by the given command
1523   // line.
1524 
1525   CommandObject *cmd_obj = nullptr;
1526   size_t start = command_string.find_first_not_of(k_white_space);
1527   size_t end = 0;
1528   bool done = false;
1529   while (!done) {
1530     if (start != std::string::npos) {
1531       // Get the next word from command_string.
1532       end = command_string.find_first_of(k_white_space, start);
1533       if (end == std::string::npos)
1534         end = command_string.size();
1535       std::string cmd_word =
1536           std::string(command_string.substr(start, end - start));
1537 
1538       if (cmd_obj == nullptr)
1539         // Since cmd_obj is NULL we are on our first time through this loop.
1540         // Check to see if cmd_word is a valid command or alias.
1541         cmd_obj = GetCommandObject(cmd_word);
1542       else if (cmd_obj->IsMultiwordObject()) {
1543         // Our current object is a multi-word object; see if the cmd_word is a
1544         // valid sub-command for our object.
1545         CommandObject *sub_cmd_obj =
1546             cmd_obj->GetSubcommandObject(cmd_word.c_str());
1547         if (sub_cmd_obj)
1548           cmd_obj = sub_cmd_obj;
1549         else // cmd_word was not a valid sub-command word, so we are done
1550           done = true;
1551       } else
1552         // We have a cmd_obj and it is not a multi-word object, so we are done.
1553         done = true;
1554 
1555       // If we didn't find a valid command object, or our command object is not
1556       // a multi-word object, or we are at the end of the command_string, then
1557       // we are done.  Otherwise, find the start of the next word.
1558 
1559       if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1560           end >= command_string.size())
1561         done = true;
1562       else
1563         start = command_string.find_first_not_of(k_white_space, end);
1564     } else
1565       // Unable to find any more words.
1566       done = true;
1567   }
1568 
1569   command_string = command_string.substr(end);
1570   return cmd_obj;
1571 }
1572 
1573 static const char *k_valid_command_chars =
1574     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1575 static void StripLeadingSpaces(std::string &s) {
1576   if (!s.empty()) {
1577     size_t pos = s.find_first_not_of(k_white_space);
1578     if (pos == std::string::npos)
1579       s.clear();
1580     else if (pos == 0)
1581       return;
1582     s.erase(0, pos);
1583   }
1584 }
1585 
1586 static size_t FindArgumentTerminator(const std::string &s) {
1587   const size_t s_len = s.size();
1588   size_t offset = 0;
1589   while (offset < s_len) {
1590     size_t pos = s.find("--", offset);
1591     if (pos == std::string::npos)
1592       break;
1593     if (pos > 0) {
1594       if (llvm::isSpace(s[pos - 1])) {
1595         // Check if the string ends "\s--" (where \s is a space character) or
1596         // if we have "\s--\s".
1597         if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1598           return pos;
1599         }
1600       }
1601     }
1602     offset = pos + 2;
1603   }
1604   return std::string::npos;
1605 }
1606 
1607 static bool ExtractCommand(std::string &command_string, std::string &command,
1608                            std::string &suffix, char &quote_char) {
1609   command.clear();
1610   suffix.clear();
1611   StripLeadingSpaces(command_string);
1612 
1613   bool result = false;
1614   quote_char = '\0';
1615 
1616   if (!command_string.empty()) {
1617     const char first_char = command_string[0];
1618     if (first_char == '\'' || first_char == '"') {
1619       quote_char = first_char;
1620       const size_t end_quote_pos = command_string.find(quote_char, 1);
1621       if (end_quote_pos == std::string::npos) {
1622         command.swap(command_string);
1623         command_string.erase();
1624       } else {
1625         command.assign(command_string, 1, end_quote_pos - 1);
1626         if (end_quote_pos + 1 < command_string.size())
1627           command_string.erase(0, command_string.find_first_not_of(
1628                                       k_white_space, end_quote_pos + 1));
1629         else
1630           command_string.erase();
1631       }
1632     } else {
1633       const size_t first_space_pos =
1634           command_string.find_first_of(k_white_space);
1635       if (first_space_pos == std::string::npos) {
1636         command.swap(command_string);
1637         command_string.erase();
1638       } else {
1639         command.assign(command_string, 0, first_space_pos);
1640         command_string.erase(0, command_string.find_first_not_of(
1641                                     k_white_space, first_space_pos));
1642       }
1643     }
1644     result = true;
1645   }
1646 
1647   if (!command.empty()) {
1648     // actual commands can't start with '-' or '_'
1649     if (command[0] != '-' && command[0] != '_') {
1650       size_t pos = command.find_first_not_of(k_valid_command_chars);
1651       if (pos > 0 && pos != std::string::npos) {
1652         suffix.assign(command.begin() + pos, command.end());
1653         command.erase(pos);
1654       }
1655     }
1656   }
1657 
1658   return result;
1659 }
1660 
1661 CommandObject *CommandInterpreter::BuildAliasResult(
1662     llvm::StringRef alias_name, std::string &raw_input_string,
1663     std::string &alias_result, CommandReturnObject &result) {
1664   CommandObject *alias_cmd_obj = nullptr;
1665   Args cmd_args(raw_input_string);
1666   alias_cmd_obj = GetCommandObject(alias_name);
1667   StreamString result_str;
1668 
1669   if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1670     alias_result.clear();
1671     return alias_cmd_obj;
1672   }
1673   std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1674       ((CommandAlias *)alias_cmd_obj)->Desugar();
1675   OptionArgVectorSP option_arg_vector_sp = desugared.second;
1676   alias_cmd_obj = desugared.first.get();
1677   std::string alias_name_str = std::string(alias_name);
1678   if ((cmd_args.GetArgumentCount() == 0) ||
1679       (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1680     cmd_args.Unshift(alias_name_str);
1681 
1682   result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1683 
1684   if (!option_arg_vector_sp.get()) {
1685     alias_result = std::string(result_str.GetString());
1686     return alias_cmd_obj;
1687   }
1688   OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1689 
1690   int value_type;
1691   std::string option;
1692   std::string value;
1693   for (const auto &entry : *option_arg_vector) {
1694     std::tie(option, value_type, value) = entry;
1695     if (option == g_argument) {
1696       result_str.Printf(" %s", value.c_str());
1697       continue;
1698     }
1699 
1700     result_str.Printf(" %s", option.c_str());
1701     if (value_type == OptionParser::eNoArgument)
1702       continue;
1703 
1704     if (value_type != OptionParser::eOptionalArgument)
1705       result_str.Printf(" ");
1706     int index = GetOptionArgumentPosition(value.c_str());
1707     if (index == 0)
1708       result_str.Printf("%s", value.c_str());
1709     else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1710 
1711       result.AppendErrorWithFormat("Not enough arguments provided; you "
1712                                    "need at least %d arguments to use "
1713                                    "this alias.\n",
1714                                    index);
1715       return nullptr;
1716     } else {
1717       const Args::ArgEntry &entry = cmd_args[index];
1718       size_t strpos = raw_input_string.find(entry.c_str());
1719       const char quote_char = entry.GetQuoteChar();
1720       if (strpos != std::string::npos) {
1721         const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1722         const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1723 
1724         // Make sure we aren't going outside the bounds of the cmd string:
1725         if (strpos < start_fudge) {
1726           result.AppendError("Unmatched quote at command beginning.");
1727           return nullptr;
1728         }
1729         llvm::StringRef arg_text = entry.ref();
1730         if (strpos - start_fudge + arg_text.size() + len_fudge >
1731             raw_input_string.size()) {
1732           result.AppendError("Unmatched quote at command end.");
1733           return nullptr;
1734         }
1735         raw_input_string = raw_input_string.erase(
1736             strpos - start_fudge,
1737             strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1738       }
1739       if (quote_char == '\0')
1740         result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1741       else
1742         result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
1743     }
1744   }
1745 
1746   alias_result = std::string(result_str.GetString());
1747   return alias_cmd_obj;
1748 }
1749 
1750 Status CommandInterpreter::PreprocessCommand(std::string &command) {
1751   // The command preprocessor needs to do things to the command line before any
1752   // parsing of arguments or anything else is done. The only current stuff that
1753   // gets preprocessed is anything enclosed in backtick ('`') characters is
1754   // evaluated as an expression and the result of the expression must be a
1755   // scalar that can be substituted into the command. An example would be:
1756   // (lldb) memory read `$rsp + 20`
1757   Status error; // Status for any expressions that might not evaluate
1758   size_t start_backtick;
1759   size_t pos = 0;
1760   while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1761     // Stop if an error was encountered during the previous iteration.
1762     if (error.Fail())
1763       break;
1764 
1765     if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1766       // The backtick was preceded by a '\' character, remove the slash and
1767       // don't treat the backtick as the start of an expression.
1768       command.erase(start_backtick - 1, 1);
1769       // No need to add one to start_backtick since we just deleted a char.
1770       pos = start_backtick;
1771       continue;
1772     }
1773 
1774     const size_t expr_content_start = start_backtick + 1;
1775     const size_t end_backtick = command.find('`', expr_content_start);
1776 
1777     if (end_backtick == std::string::npos) {
1778       // Stop if there's no end backtick.
1779       break;
1780     }
1781 
1782     if (end_backtick == expr_content_start) {
1783       // Skip over empty expression. (two backticks in a row)
1784       command.erase(start_backtick, 2);
1785       continue;
1786     }
1787 
1788     std::string expr_str(command, expr_content_start,
1789                          end_backtick - expr_content_start);
1790     error = PreprocessToken(expr_str);
1791     // We always stop at the first error:
1792     if (error.Fail())
1793       break;
1794 
1795     command.erase(start_backtick, end_backtick - start_backtick + 1);
1796     command.insert(start_backtick, std::string(expr_str));
1797     pos = start_backtick + expr_str.size();
1798   }
1799   return error;
1800 }
1801 
1802 Status
1803 CommandInterpreter::PreprocessToken(std::string &expr_str) {
1804   Status error;
1805   ExecutionContext exe_ctx(GetExecutionContext());
1806 
1807   // Get a dummy target to allow for calculator mode while processing
1808   // backticks. This also helps break the infinite loop caused when target is
1809   // null.
1810   Target *exe_target = exe_ctx.GetTargetPtr();
1811   Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1812 
1813   ValueObjectSP expr_result_valobj_sp;
1814 
1815   EvaluateExpressionOptions options;
1816   options.SetCoerceToId(false);
1817   options.SetUnwindOnError(true);
1818   options.SetIgnoreBreakpoints(true);
1819   options.SetKeepInMemory(false);
1820   options.SetTryAllThreads(true);
1821   options.SetTimeout(std::nullopt);
1822 
1823   ExpressionResults expr_result =
1824       target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1825                                 expr_result_valobj_sp, options);
1826 
1827   if (expr_result == eExpressionCompleted) {
1828     Scalar scalar;
1829     if (expr_result_valobj_sp)
1830       expr_result_valobj_sp =
1831           expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1832               expr_result_valobj_sp->GetDynamicValueType(), true);
1833     if (expr_result_valobj_sp->ResolveValue(scalar)) {
1834 
1835       StreamString value_strm;
1836       const bool show_type = false;
1837       scalar.GetValue(value_strm, show_type);
1838       size_t value_string_size = value_strm.GetSize();
1839       if (value_string_size) {
1840         expr_str = value_strm.GetData();
1841       } else {
1842         error =
1843             Status::FromErrorStringWithFormat("expression value didn't result "
1844                                               "in a scalar value for the "
1845                                               "expression '%s'",
1846                                               expr_str.c_str());
1847       }
1848     } else {
1849       error =
1850           Status::FromErrorStringWithFormat("expression value didn't result "
1851                                             "in a scalar value for the "
1852                                             "expression '%s'",
1853                                             expr_str.c_str());
1854     }
1855     return error;
1856   }
1857 
1858   // If we have an error from the expression evaluation it will be in the
1859   // ValueObject error, which won't be success and we will just report it.
1860   // But if for some reason we didn't get a value object at all, then we will
1861   // make up some helpful errors from the expression result.
1862   if (expr_result_valobj_sp)
1863     error = expr_result_valobj_sp->GetError().Clone();
1864 
1865   if (error.Success()) {
1866     std::string result = lldb_private::toString(expr_result) +
1867                          "for the expression '" + expr_str + "'";
1868     error = Status(result);
1869   }
1870   return error;
1871 }
1872 
1873 bool CommandInterpreter::HandleCommand(const char *command_line,
1874                                        LazyBool lazy_add_to_history,
1875                                        const ExecutionContext &override_context,
1876                                        CommandReturnObject &result) {
1877 
1878   OverrideExecutionContext(override_context);
1879   bool status = HandleCommand(command_line, lazy_add_to_history, result);
1880   RestoreExecutionContext();
1881   return status;
1882 }
1883 
1884 bool CommandInterpreter::HandleCommand(const char *command_line,
1885                                        LazyBool lazy_add_to_history,
1886                                        CommandReturnObject &result,
1887                                        bool force_repeat_command) {
1888   std::string command_string(command_line);
1889   std::string original_command_string(command_string);
1890   std::string real_original_command_string(command_string);
1891 
1892   Log *log = GetLog(LLDBLog::Commands);
1893   llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1894                                    command_line);
1895 
1896   LLDB_LOGF(log, "Processing command: %s", command_line);
1897   LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1898 
1899   if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
1900     result.AppendError("... Interrupted");
1901     return false;
1902   }
1903 
1904   bool add_to_history;
1905   if (lazy_add_to_history == eLazyBoolCalculate)
1906     add_to_history = (m_command_source_depth == 0);
1907   else
1908     add_to_history = (lazy_add_to_history == eLazyBoolYes);
1909 
1910   // The same `transcript_item` will be used below to add output and error of
1911   // the command.
1912   StructuredData::DictionarySP transcript_item;
1913   if (GetSaveTranscript()) {
1914     m_transcript_stream << "(lldb) " << command_line << '\n';
1915 
1916     transcript_item = std::make_shared<StructuredData::Dictionary>();
1917     transcript_item->AddStringItem("command", command_line);
1918     transcript_item->AddIntegerItem(
1919         "timestampInEpochSeconds",
1920         std::chrono::duration_cast<std::chrono::seconds>(
1921             std::chrono::system_clock::now().time_since_epoch())
1922             .count());
1923     m_transcript.AddItem(transcript_item);
1924   }
1925 
1926   bool empty_command = false;
1927   bool comment_command = false;
1928   if (command_string.empty())
1929     empty_command = true;
1930   else {
1931     const char *k_space_characters = "\t\n\v\f\r ";
1932 
1933     size_t non_space = command_string.find_first_not_of(k_space_characters);
1934     // Check for empty line or comment line (lines whose first non-space
1935     // character is the comment character for this interpreter)
1936     if (non_space == std::string::npos)
1937       empty_command = true;
1938     else if (command_string[non_space] == m_comment_char)
1939       comment_command = true;
1940     else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1941       llvm::StringRef search_str(command_string);
1942       search_str = search_str.drop_front(non_space);
1943       if (auto hist_str = m_command_history.FindString(search_str)) {
1944         add_to_history = false;
1945         command_string = std::string(*hist_str);
1946         original_command_string = std::string(*hist_str);
1947       } else {
1948         result.AppendErrorWithFormat("Could not find entry: %s in history",
1949                                      command_string.c_str());
1950         return false;
1951       }
1952     }
1953   }
1954 
1955   if (empty_command) {
1956     if (!GetRepeatPreviousCommand()) {
1957       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1958       return true;
1959     }
1960 
1961     if (m_command_history.IsEmpty()) {
1962       result.AppendError("empty command");
1963       return false;
1964     }
1965 
1966     command_line = m_repeat_command.c_str();
1967     command_string = command_line;
1968     original_command_string = command_line;
1969     if (m_repeat_command.empty()) {
1970       result.AppendError("No auto repeat.");
1971       return false;
1972     }
1973 
1974     add_to_history = false;
1975   } else if (comment_command) {
1976     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1977     return true;
1978   }
1979 
1980   // Phase 1.
1981 
1982   // Before we do ANY kind of argument processing, we need to figure out what
1983   // the real/final command object is for the specified command.  This gets
1984   // complicated by the fact that the user could have specified an alias, and,
1985   // in translating the alias, there may also be command options and/or even
1986   // data (including raw text strings) that need to be found and inserted into
1987   // the command line as part of the translation.  So this first step is plain
1988   // look-up and replacement, resulting in:
1989   //    1. the command object whose Execute method will actually be called
1990   //    2. a revised command string, with all substitutions and replacements
1991   //       taken care of
1992   // From 1 above, we can determine whether the Execute function wants raw
1993   // input or not.
1994 
1995   CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1996 
1997   // We have to preprocess the whole command string for Raw commands, since we
1998   // don't know the structure of the command.  For parsed commands, we only
1999   // treat backticks as quote characters specially.
2000   // FIXME: We probably want to have raw commands do their own preprocessing.
2001   // For instance, I don't think people expect substitution in expr expressions.
2002   if (cmd_obj && cmd_obj->WantsRawCommandString()) {
2003     Status error(PreprocessCommand(command_string));
2004 
2005     if (error.Fail()) {
2006       result.AppendError(error.AsCString());
2007       return false;
2008     }
2009   }
2010 
2011   // Although the user may have abbreviated the command, the command_string now
2012   // has the command expanded to the full name.  For example, if the input was
2013   // "br s -n main", command_string is now "breakpoint set -n main".
2014   if (log) {
2015     llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
2016     LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
2017     LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
2018               command_string.c_str());
2019     const bool wants_raw_input =
2020         (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
2021     LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
2022               wants_raw_input ? "True" : "False");
2023   }
2024 
2025   // Phase 2.
2026   // Take care of things like setting up the history command & calling the
2027   // appropriate Execute method on the CommandObject, with the appropriate
2028   // arguments.
2029   StatsDuration execute_time;
2030   if (cmd_obj != nullptr) {
2031     bool generate_repeat_command = add_to_history;
2032     // If we got here when empty_command was true, then this command is a
2033     // stored "repeat command" which we should give a chance to produce it's
2034     // repeat command, even though we don't add repeat commands to the history.
2035     generate_repeat_command |= empty_command;
2036     // For `command regex`, the regex command (ex `bt`) is added to history, but
2037     // the resolved command (ex `thread backtrace`) is _not_ added to history.
2038     // However, the resolved command must be given the opportunity to provide a
2039     // repeat command. `force_repeat_command` supports this case.
2040     generate_repeat_command |= force_repeat_command;
2041     if (generate_repeat_command) {
2042       Args command_args(command_string);
2043       std::optional<std::string> repeat_command =
2044           cmd_obj->GetRepeatCommand(command_args, 0);
2045       if (repeat_command) {
2046         LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
2047         m_repeat_command.assign(*repeat_command);
2048       } else {
2049         m_repeat_command.assign(original_command_string);
2050       }
2051     }
2052 
2053     if (add_to_history)
2054       m_command_history.AppendString(original_command_string);
2055 
2056     std::string remainder;
2057     const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2058     if (actual_cmd_name_len < command_string.length())
2059       remainder = command_string.substr(actual_cmd_name_len);
2060 
2061     // Remove any initial spaces
2062     size_t pos = remainder.find_first_not_of(k_white_space);
2063     if (pos != 0 && pos != std::string::npos)
2064       remainder.erase(0, pos);
2065 
2066     LLDB_LOGF(
2067         log, "HandleCommand, command line after removing command name(s): '%s'",
2068         remainder.c_str());
2069 
2070     // To test whether or not transcript should be saved, `transcript_item` is
2071     // used instead of `GetSaveTranscript()`. This is because the latter will
2072     // fail when the command is "settings set interpreter.save-transcript true".
2073     if (transcript_item) {
2074       transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName());
2075       transcript_item->AddStringItem("commandArguments", remainder);
2076     }
2077 
2078     ElapsedTime elapsed(execute_time);
2079     cmd_obj->SetOriginalCommandString(real_original_command_string);
2080     // Set the indent to the position of the command in the command line.
2081     pos = real_original_command_string.rfind(remainder);
2082     std::optional<uint16_t> indent;
2083     if (pos != std::string::npos)
2084       indent = pos;
2085     result.SetDiagnosticIndent(indent);
2086     cmd_obj->Execute(remainder.c_str(), result);
2087   }
2088 
2089   LLDB_LOGF(log, "HandleCommand, command %s",
2090             (result.Succeeded() ? "succeeded" : "did not succeed"));
2091 
2092   // To test whether or not transcript should be saved, `transcript_item` is
2093   // used instead of `GetSaveTrasncript()`. This is because the latter will
2094   // fail when the command is "settings set interpreter.save-transcript true".
2095   if (transcript_item) {
2096     m_transcript_stream << result.GetOutputString();
2097     m_transcript_stream << result.GetErrorString();
2098 
2099     transcript_item->AddStringItem("output", result.GetOutputString());
2100     transcript_item->AddStringItem("error", result.GetErrorString());
2101     transcript_item->AddFloatItem("durationInSeconds",
2102                                   execute_time.get().count());
2103   }
2104 
2105   return result.Succeeded();
2106 }
2107 
2108 void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
2109   bool look_for_subcommand = false;
2110 
2111   // For any of the command completions a unique match will be a complete word.
2112 
2113   if (request.GetParsedLine().GetArgumentCount() == 0) {
2114     // We got nothing on the command line, so return the list of commands
2115     bool include_aliases = true;
2116     StringList new_matches, descriptions;
2117     GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2118                                          descriptions);
2119     request.AddCompletions(new_matches, descriptions);
2120   } else if (request.GetCursorIndex() == 0) {
2121     // The cursor is in the first argument, so just do a lookup in the
2122     // dictionary.
2123     StringList new_matches, new_descriptions;
2124     CommandObject *cmd_obj =
2125         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
2126                          &new_matches, &new_descriptions);
2127 
2128     if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2129         new_matches.GetStringAtIndex(0) != nullptr &&
2130         strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2131                new_matches.GetStringAtIndex(0)) == 0) {
2132       if (request.GetParsedLine().GetArgumentCount() != 1) {
2133         look_for_subcommand = true;
2134         new_matches.DeleteStringAtIndex(0);
2135         new_descriptions.DeleteStringAtIndex(0);
2136         request.AppendEmptyArgument();
2137       }
2138     }
2139     request.AddCompletions(new_matches, new_descriptions);
2140   }
2141 
2142   if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2143     // We are completing further on into a commands arguments, so find the
2144     // command and tell it to complete the command. First see if there is a
2145     // matching initial command:
2146     CommandObject *command_object =
2147         GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
2148     if (command_object) {
2149       request.ShiftArguments();
2150       command_object->HandleCompletion(request);
2151     }
2152   }
2153 }
2154 
2155 void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
2156 
2157   // Don't complete comments, and if the line we are completing is just the
2158   // history repeat character, substitute the appropriate history line.
2159   llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2160 
2161   if (!first_arg.empty()) {
2162     if (first_arg.front() == m_comment_char)
2163       return;
2164     if (first_arg.front() == CommandHistory::g_repeat_char) {
2165       if (auto hist_str = m_command_history.FindString(first_arg))
2166         request.AddCompletion(*hist_str, "Previous command history event",
2167                               CompletionMode::RewriteLine);
2168       return;
2169     }
2170   }
2171 
2172   HandleCompletionMatches(request);
2173 }
2174 
2175 std::optional<std::string>
2176 CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) {
2177   if (line.empty())
2178     return std::nullopt;
2179   const size_t s = m_command_history.GetSize();
2180   for (int i = s - 1; i >= 0; --i) {
2181     llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2182     if (entry.consume_front(line))
2183       return entry.str();
2184   }
2185   return std::nullopt;
2186 }
2187 
2188 void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2189   EventSP prompt_change_event_sp(
2190       new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2191   ;
2192   BroadcastEvent(prompt_change_event_sp);
2193   if (m_command_io_handler_sp)
2194     m_command_io_handler_sp->SetPrompt(new_prompt);
2195 }
2196 
2197 bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2198   // Check AutoConfirm first:
2199   if (m_debugger.GetAutoConfirm())
2200     return default_answer;
2201 
2202   IOHandlerConfirm *confirm =
2203       new IOHandlerConfirm(m_debugger, message, default_answer);
2204   IOHandlerSP io_handler_sp(confirm);
2205   m_debugger.RunIOHandlerSync(io_handler_sp);
2206   return confirm->GetResponse();
2207 }
2208 
2209 const CommandAlias *
2210 CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2211   OptionArgVectorSP ret_val;
2212 
2213   auto pos = m_alias_dict.find(alias_name);
2214   if (pos != m_alias_dict.end())
2215     return (CommandAlias *)pos->second.get();
2216 
2217   return nullptr;
2218 }
2219 
2220 bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2221 
2222 bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2223 
2224 bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2225 
2226 bool CommandInterpreter::HasUserMultiwordCommands() const {
2227   return (!m_user_mw_dict.empty());
2228 }
2229 
2230 bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
2231 
2232 void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
2233                                                const char *alias_name,
2234                                                Args &cmd_args,
2235                                                std::string &raw_input_string,
2236                                                CommandReturnObject &result) {
2237   OptionArgVectorSP option_arg_vector_sp =
2238       GetAlias(alias_name)->GetOptionArguments();
2239 
2240   bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2241 
2242   // Make sure that the alias name is the 0th element in cmd_args
2243   std::string alias_name_str = alias_name;
2244   if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2245     cmd_args.Unshift(alias_name_str);
2246 
2247   Args new_args(alias_cmd_obj->GetCommandName());
2248   if (new_args.GetArgumentCount() == 2)
2249     new_args.Shift();
2250 
2251   if (option_arg_vector_sp.get()) {
2252     if (wants_raw_input) {
2253       // We have a command that both has command options and takes raw input.
2254       // Make *sure* it has a " -- " in the right place in the
2255       // raw_input_string.
2256       size_t pos = raw_input_string.find(" -- ");
2257       if (pos == std::string::npos) {
2258         // None found; assume it goes at the beginning of the raw input string
2259         raw_input_string.insert(0, " -- ");
2260       }
2261     }
2262 
2263     OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2264     const size_t old_size = cmd_args.GetArgumentCount();
2265     std::vector<bool> used(old_size + 1, false);
2266 
2267     used[0] = true;
2268 
2269     int value_type;
2270     std::string option;
2271     std::string value;
2272     for (const auto &option_entry : *option_arg_vector) {
2273       std::tie(option, value_type, value) = option_entry;
2274       if (option == g_argument) {
2275         if (!wants_raw_input || (value != "--")) {
2276           // Since we inserted this above, make sure we don't insert it twice
2277           new_args.AppendArgument(value);
2278         }
2279         continue;
2280       }
2281 
2282       if (value_type != OptionParser::eOptionalArgument)
2283         new_args.AppendArgument(option);
2284 
2285       if (value == g_no_argument)
2286         continue;
2287 
2288       int index = GetOptionArgumentPosition(value.c_str());
2289       if (index == 0) {
2290         // value was NOT a positional argument; must be a real value
2291         if (value_type != OptionParser::eOptionalArgument)
2292           new_args.AppendArgument(value);
2293         else {
2294           new_args.AppendArgument(option + value);
2295         }
2296 
2297       } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2298         result.AppendErrorWithFormat("Not enough arguments provided; you "
2299                                      "need at least %d arguments to use "
2300                                      "this alias.\n",
2301                                      index);
2302         return;
2303       } else {
2304         // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2305         size_t strpos =
2306             raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2307         if (strpos != std::string::npos) {
2308           raw_input_string = raw_input_string.erase(
2309               strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2310         }
2311 
2312         if (value_type != OptionParser::eOptionalArgument)
2313           new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2314         else {
2315           new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2316         }
2317         used[index] = true;
2318       }
2319     }
2320 
2321     for (auto entry : llvm::enumerate(cmd_args.entries())) {
2322       if (!used[entry.index()] && !wants_raw_input)
2323         new_args.AppendArgument(entry.value().ref());
2324     }
2325 
2326     cmd_args.Clear();
2327     cmd_args.SetArguments(new_args.GetArgumentCount(),
2328                           new_args.GetConstArgumentVector());
2329   } else {
2330     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2331     // This alias was not created with any options; nothing further needs to be
2332     // done, unless it is a command that wants raw input, in which case we need
2333     // to clear the rest of the data from cmd_args, since its in the raw input
2334     // string.
2335     if (wants_raw_input) {
2336       cmd_args.Clear();
2337       cmd_args.SetArguments(new_args.GetArgumentCount(),
2338                             new_args.GetConstArgumentVector());
2339     }
2340     return;
2341   }
2342 
2343   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2344 }
2345 
2346 int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2347   int position = 0; // Any string that isn't an argument position, i.e. '%'
2348                     // followed by an integer, gets a position
2349                     // of zero.
2350 
2351   const char *cptr = in_string;
2352 
2353   // Does it start with '%'
2354   if (cptr[0] == '%') {
2355     ++cptr;
2356 
2357     // Is the rest of it entirely digits?
2358     if (isdigit(cptr[0])) {
2359       const char *start = cptr;
2360       while (isdigit(cptr[0]))
2361         ++cptr;
2362 
2363       // We've gotten to the end of the digits; are we at the end of the
2364       // string?
2365       if (cptr[0] == '\0')
2366         position = atoi(start);
2367     }
2368   }
2369 
2370   return position;
2371 }
2372 
2373 static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2374                             llvm::StringRef suffix = {}) {
2375   std::string init_file_name = ".lldbinit";
2376   if (!suffix.empty()) {
2377     init_file_name.append("-");
2378     init_file_name.append(suffix.str());
2379   }
2380 
2381   FileSystem::Instance().GetHomeDirectory(init_file);
2382   llvm::sys::path::append(init_file, init_file_name);
2383 
2384   FileSystem::Instance().Resolve(init_file);
2385 }
2386 
2387 static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
2388                                 LanguageType language) {
2389   if (language == eLanguageTypeUnknown) {
2390     LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
2391     if (auto main_repl_language = repl_languages.GetSingularLanguage())
2392       language = *main_repl_language;
2393     else
2394       return;
2395   }
2396 
2397   std::string init_file_name =
2398       (llvm::Twine(".lldbinit-") +
2399        llvm::Twine(Language::GetNameForLanguageType(language)) +
2400        llvm::Twine("-repl"))
2401           .str();
2402   FileSystem::Instance().GetHomeDirectory(init_file);
2403   llvm::sys::path::append(init_file, init_file_name);
2404   FileSystem::Instance().Resolve(init_file);
2405 }
2406 
2407 static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
2408   llvm::StringRef s = ".lldbinit";
2409   init_file.assign(s.begin(), s.end());
2410   FileSystem::Instance().Resolve(init_file);
2411 }
2412 
2413 void CommandInterpreter::SourceInitFile(FileSpec file,
2414                                         CommandReturnObject &result) {
2415   assert(!m_skip_lldbinit_files);
2416 
2417   if (!FileSystem::Instance().Exists(file)) {
2418     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2419     return;
2420   }
2421 
2422   // Use HandleCommand to 'source' the given file; this will do the actual
2423   // broadcasting of the commands back to any appropriate listener (see
2424   // CommandObjectSource::Execute for more details).
2425   const bool saved_batch = SetBatchCommandMode(true);
2426   CommandInterpreterRunOptions options;
2427   options.SetSilent(true);
2428   options.SetPrintErrors(true);
2429   options.SetStopOnError(false);
2430   options.SetStopOnContinue(true);
2431   HandleCommandsFromFile(file, options, result);
2432   SetBatchCommandMode(saved_batch);
2433 }
2434 
2435 void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
2436   if (m_skip_lldbinit_files) {
2437     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2438     return;
2439   }
2440 
2441   llvm::SmallString<128> init_file;
2442   GetCwdInitFile(init_file);
2443   if (!FileSystem::Instance().Exists(init_file)) {
2444     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2445     return;
2446   }
2447 
2448   LoadCWDlldbinitFile should_load =
2449       Target::GetGlobalProperties().GetLoadCWDlldbinitFile();
2450 
2451   switch (should_load) {
2452   case eLoadCWDlldbinitFalse:
2453     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2454     break;
2455   case eLoadCWDlldbinitTrue:
2456     SourceInitFile(FileSpec(init_file.str()), result);
2457     break;
2458   case eLoadCWDlldbinitWarn: {
2459     llvm::SmallString<128> home_init_file;
2460     GetHomeInitFile(home_init_file);
2461     if (llvm::sys::path::parent_path(init_file) ==
2462         llvm::sys::path::parent_path(home_init_file)) {
2463       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2464     } else {
2465       result.AppendError(InitFileWarning);
2466     }
2467   }
2468   }
2469 }
2470 
2471 /// We will first see if there is an application specific ".lldbinit" file
2472 /// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2473 /// If this file doesn't exist, we fall back to the REPL init file or the
2474 /// default home init file in "~/.lldbinit".
2475 void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
2476                                             bool is_repl) {
2477   if (m_skip_lldbinit_files) {
2478     result.SetStatus(eReturnStatusSuccessFinishNoResult);
2479     return;
2480   }
2481 
2482   llvm::SmallString<128> init_file;
2483 
2484   if (is_repl)
2485     GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2486 
2487   if (init_file.empty())
2488     GetHomeInitFile(init_file);
2489 
2490   if (!m_skip_app_init_files) {
2491     llvm::StringRef program_name =
2492         HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2493     llvm::SmallString<128> program_init_file;
2494     GetHomeInitFile(program_init_file, program_name);
2495     if (FileSystem::Instance().Exists(program_init_file))
2496       init_file = program_init_file;
2497   }
2498 
2499   SourceInitFile(FileSpec(init_file.str()), result);
2500 }
2501 
2502 void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
2503 #ifdef LLDB_GLOBAL_INIT_DIRECTORY
2504   if (!m_skip_lldbinit_files) {
2505     FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2506     if (init_file)
2507       init_file.MakeAbsolute(HostInfo::GetShlibDir());
2508 
2509     init_file.AppendPathComponent("lldbinit");
2510     SourceInitFile(init_file, result);
2511     return;
2512   }
2513 #endif
2514   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2515 }
2516 
2517 const char *CommandInterpreter::GetCommandPrefix() {
2518   const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2519   return prefix == nullptr ? "" : prefix;
2520 }
2521 
2522 PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2523   PlatformSP platform_sp;
2524   if (prefer_target_platform) {
2525     ExecutionContext exe_ctx(GetExecutionContext());
2526     Target *target = exe_ctx.GetTargetPtr();
2527     if (target)
2528       platform_sp = target->GetPlatform();
2529   }
2530 
2531   if (!platform_sp)
2532     platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2533   return platform_sp;
2534 }
2535 
2536 bool CommandInterpreter::DidProcessStopAbnormally() const {
2537   auto exe_ctx = GetExecutionContext();
2538   TargetSP target_sp = exe_ctx.GetTargetSP();
2539   if (!target_sp)
2540     return false;
2541 
2542   ProcessSP process_sp(target_sp->GetProcessSP());
2543   if (!process_sp)
2544     return false;
2545 
2546   if (eStateStopped != process_sp->GetState())
2547     return false;
2548 
2549   for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2550     StopInfoSP stop_info = thread_sp->GetStopInfo();
2551     if (!stop_info) {
2552       // If there's no stop_info, keep iterating through the other threads;
2553       // it's enough that any thread has got a stop_info that indicates
2554       // an abnormal stop, to consider the process to be stopped abnormally.
2555       continue;
2556     }
2557 
2558     const StopReason reason = stop_info->GetStopReason();
2559     if (reason == eStopReasonException ||
2560         reason == eStopReasonInstrumentation ||
2561         reason == eStopReasonProcessorTrace || reason == eStopReasonInterrupt)
2562       return true;
2563 
2564     if (reason == eStopReasonSignal) {
2565       const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2566       UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2567       if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2568         // The signal is unknown, treat it as abnormal.
2569         return true;
2570 
2571       const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2572       const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2573       if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2574         // The signal very likely implies a crash.
2575         return true;
2576     }
2577   }
2578 
2579   return false;
2580 }
2581 
2582 void
2583 CommandInterpreter::HandleCommands(const StringList &commands,
2584                                    const ExecutionContext &override_context,
2585                                    const CommandInterpreterRunOptions &options,
2586                                    CommandReturnObject &result) {
2587 
2588   OverrideExecutionContext(override_context);
2589   HandleCommands(commands, options, result);
2590   RestoreExecutionContext();
2591 }
2592 
2593 void CommandInterpreter::HandleCommands(const StringList &commands,
2594                                         const CommandInterpreterRunOptions &options,
2595                                         CommandReturnObject &result) {
2596   size_t num_lines = commands.GetSize();
2597 
2598   // If we are going to continue past a "continue" then we need to run the
2599   // commands synchronously. Make sure you reset this value anywhere you return
2600   // from the function.
2601 
2602   bool old_async_execution = m_debugger.GetAsyncExecution();
2603 
2604   if (!options.GetStopOnContinue()) {
2605     m_debugger.SetAsyncExecution(false);
2606   }
2607 
2608   for (size_t idx = 0; idx < num_lines; idx++) {
2609     const char *cmd = commands.GetStringAtIndex(idx);
2610     if (cmd[0] == '\0')
2611       continue;
2612 
2613     if (options.GetEchoCommands()) {
2614       // TODO: Add Stream support.
2615       result.AppendMessageWithFormat("%s %s\n",
2616                                      m_debugger.GetPrompt().str().c_str(), cmd);
2617     }
2618 
2619     CommandReturnObject tmp_result(m_debugger.GetUseColor());
2620     tmp_result.SetInteractive(result.GetInteractive());
2621     tmp_result.SetSuppressImmediateOutput(true);
2622 
2623     // We might call into a regex or alias command, in which case the
2624     // add_to_history will get lost.  This m_command_source_depth dingus is the
2625     // way we turn off adding to the history in that case, so set it up here.
2626     if (!options.GetAddToHistory())
2627       m_command_source_depth++;
2628     bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2629     if (!options.GetAddToHistory())
2630       m_command_source_depth--;
2631 
2632     if (options.GetPrintResults()) {
2633       if (tmp_result.Succeeded())
2634         result.AppendMessage(tmp_result.GetOutputString());
2635     }
2636 
2637     if (!success || !tmp_result.Succeeded()) {
2638       std::string error_msg = tmp_result.GetErrorString();
2639       if (error_msg.empty())
2640         error_msg = "<unknown error>.\n";
2641       if (options.GetStopOnError()) {
2642         result.AppendErrorWithFormatv("Aborting reading of commands after "
2643                                       "command #{0}: '{1}' failed with {2}",
2644                                       (uint64_t)idx, cmd, error_msg);
2645         m_debugger.SetAsyncExecution(old_async_execution);
2646         return;
2647       } else if (options.GetPrintResults()) {
2648         result.AppendMessageWithFormatv("Command #{0} '{1}' failed with {2}",
2649                                         (uint64_t)idx + 1, cmd, error_msg);
2650       }
2651     }
2652 
2653     if (result.GetImmediateOutputStream())
2654       result.GetImmediateOutputStream()->Flush();
2655 
2656     if (result.GetImmediateErrorStream())
2657       result.GetImmediateErrorStream()->Flush();
2658 
2659     // N.B. Can't depend on DidChangeProcessState, because the state coming
2660     // into the command execution could be running (for instance in Breakpoint
2661     // Commands. So we check the return value to see if it is has running in
2662     // it.
2663     if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2664         (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2665       if (options.GetStopOnContinue()) {
2666         // If we caused the target to proceed, and we're going to stop in that
2667         // case, set the status in our real result before returning.  This is
2668         // an error if the continue was not the last command in the set of
2669         // commands to be run.
2670         if (idx != num_lines - 1)
2671           result.AppendErrorWithFormat(
2672               "Aborting reading of commands after command #%" PRIu64
2673               ": '%s' continued the target.\n",
2674               (uint64_t)idx + 1, cmd);
2675         else
2676           result.AppendMessageWithFormat("Command #%" PRIu64
2677                                          " '%s' continued the target.\n",
2678                                          (uint64_t)idx + 1, cmd);
2679 
2680         result.SetStatus(tmp_result.GetStatus());
2681         m_debugger.SetAsyncExecution(old_async_execution);
2682 
2683         return;
2684       }
2685     }
2686 
2687     // Also check for "stop on crash here:
2688     if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2689         DidProcessStopAbnormally()) {
2690       if (idx != num_lines - 1)
2691         result.AppendErrorWithFormat(
2692             "Aborting reading of commands after command #%" PRIu64
2693             ": '%s' stopped with a signal or exception.\n",
2694             (uint64_t)idx + 1, cmd);
2695       else
2696         result.AppendMessageWithFormat(
2697             "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2698             (uint64_t)idx + 1, cmd);
2699 
2700       result.SetStatus(tmp_result.GetStatus());
2701       m_debugger.SetAsyncExecution(old_async_execution);
2702 
2703       return;
2704     }
2705   }
2706 
2707   result.SetStatus(eReturnStatusSuccessFinishResult);
2708   m_debugger.SetAsyncExecution(old_async_execution);
2709 }
2710 
2711 // Make flags that we can pass into the IOHandler so our delegates can do the
2712 // right thing
2713 enum {
2714   eHandleCommandFlagStopOnContinue = (1u << 0),
2715   eHandleCommandFlagStopOnError = (1u << 1),
2716   eHandleCommandFlagEchoCommand = (1u << 2),
2717   eHandleCommandFlagEchoCommentCommand = (1u << 3),
2718   eHandleCommandFlagPrintResult = (1u << 4),
2719   eHandleCommandFlagPrintErrors = (1u << 5),
2720   eHandleCommandFlagStopOnCrash = (1u << 6),
2721   eHandleCommandFlagAllowRepeats = (1u << 7)
2722 };
2723 
2724 void CommandInterpreter::HandleCommandsFromFile(
2725     FileSpec &cmd_file, const ExecutionContext &context,
2726     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2727   OverrideExecutionContext(context);
2728   HandleCommandsFromFile(cmd_file, options, result);
2729   RestoreExecutionContext();
2730 }
2731 
2732 void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
2733     const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2734   if (!FileSystem::Instance().Exists(cmd_file)) {
2735     result.AppendErrorWithFormat(
2736         "Error reading commands from file %s - file not found.\n",
2737         cmd_file.GetFilename().AsCString("<Unknown>"));
2738     return;
2739   }
2740 
2741   std::string cmd_file_path = cmd_file.GetPath();
2742   auto input_file_up =
2743       FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly);
2744   if (!input_file_up) {
2745     std::string error = llvm::toString(input_file_up.takeError());
2746     result.AppendErrorWithFormatv(
2747         "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2748         llvm::fmt_consume(input_file_up.takeError()));
2749     return;
2750   }
2751   FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2752 
2753   Debugger &debugger = GetDebugger();
2754 
2755   uint32_t flags = 0;
2756 
2757   if (options.m_stop_on_continue == eLazyBoolCalculate) {
2758     if (m_command_source_flags.empty()) {
2759       // Stop on continue by default
2760       flags |= eHandleCommandFlagStopOnContinue;
2761     } else if (m_command_source_flags.back() &
2762                eHandleCommandFlagStopOnContinue) {
2763       flags |= eHandleCommandFlagStopOnContinue;
2764     }
2765   } else if (options.m_stop_on_continue == eLazyBoolYes) {
2766     flags |= eHandleCommandFlagStopOnContinue;
2767   }
2768 
2769   if (options.m_stop_on_error == eLazyBoolCalculate) {
2770     if (m_command_source_flags.empty()) {
2771       if (GetStopCmdSourceOnError())
2772         flags |= eHandleCommandFlagStopOnError;
2773     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2774       flags |= eHandleCommandFlagStopOnError;
2775     }
2776   } else if (options.m_stop_on_error == eLazyBoolYes) {
2777     flags |= eHandleCommandFlagStopOnError;
2778   }
2779 
2780   // stop-on-crash can only be set, if it is present in all levels of
2781   // pushed flag sets.
2782   if (options.GetStopOnCrash()) {
2783     if (m_command_source_flags.empty()) {
2784       flags |= eHandleCommandFlagStopOnCrash;
2785     } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2786       flags |= eHandleCommandFlagStopOnCrash;
2787     }
2788   }
2789 
2790   if (options.m_echo_commands == eLazyBoolCalculate) {
2791     if (m_command_source_flags.empty()) {
2792       // Echo command by default
2793       flags |= eHandleCommandFlagEchoCommand;
2794     } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2795       flags |= eHandleCommandFlagEchoCommand;
2796     }
2797   } else if (options.m_echo_commands == eLazyBoolYes) {
2798     flags |= eHandleCommandFlagEchoCommand;
2799   }
2800 
2801   // We will only ever ask for this flag, if we echo commands in general.
2802   if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2803     if (m_command_source_flags.empty()) {
2804       // Echo comments by default
2805       flags |= eHandleCommandFlagEchoCommentCommand;
2806     } else if (m_command_source_flags.back() &
2807                eHandleCommandFlagEchoCommentCommand) {
2808       flags |= eHandleCommandFlagEchoCommentCommand;
2809     }
2810   } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2811     flags |= eHandleCommandFlagEchoCommentCommand;
2812   }
2813 
2814   if (options.m_print_results == eLazyBoolCalculate) {
2815     if (m_command_source_flags.empty()) {
2816       // Print output by default
2817       flags |= eHandleCommandFlagPrintResult;
2818     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2819       flags |= eHandleCommandFlagPrintResult;
2820     }
2821   } else if (options.m_print_results == eLazyBoolYes) {
2822     flags |= eHandleCommandFlagPrintResult;
2823   }
2824 
2825   if (options.m_print_errors == eLazyBoolCalculate) {
2826     if (m_command_source_flags.empty()) {
2827       // Print output by default
2828       flags |= eHandleCommandFlagPrintErrors;
2829     } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2830       flags |= eHandleCommandFlagPrintErrors;
2831     }
2832   } else if (options.m_print_errors == eLazyBoolYes) {
2833     flags |= eHandleCommandFlagPrintErrors;
2834   }
2835 
2836   if (flags & eHandleCommandFlagPrintResult) {
2837     debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2838                                     cmd_file_path.c_str());
2839   }
2840 
2841   // Used for inheriting the right settings when "command source" might
2842   // have nested "command source" commands
2843   lldb::StreamFileSP empty_stream_sp;
2844   m_command_source_flags.push_back(flags);
2845   IOHandlerSP io_handler_sp(new IOHandlerEditline(
2846       debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2847       empty_stream_sp, // Pass in an empty stream so we inherit the top
2848                        // input reader output stream
2849       empty_stream_sp, // Pass in an empty stream so we inherit the top
2850                        // input reader error stream
2851       flags,
2852       nullptr, // Pass in NULL for "editline_name" so no history is saved,
2853                // or written
2854       debugger.GetPrompt(), llvm::StringRef(),
2855       false, // Not multi-line
2856       debugger.GetUseColor(), 0, *this));
2857   const bool old_async_execution = debugger.GetAsyncExecution();
2858 
2859   // Set synchronous execution if we are not stopping on continue
2860   if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2861     debugger.SetAsyncExecution(false);
2862 
2863   m_command_source_depth++;
2864   m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent());
2865 
2866   debugger.RunIOHandlerSync(io_handler_sp);
2867   if (!m_command_source_flags.empty())
2868     m_command_source_flags.pop_back();
2869 
2870   m_command_source_dirs.pop_back();
2871   m_command_source_depth--;
2872 
2873   result.SetStatus(eReturnStatusSuccessFinishNoResult);
2874   debugger.SetAsyncExecution(old_async_execution);
2875 }
2876 
2877 bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2878 
2879 void CommandInterpreter::SetSynchronous(bool value) {
2880   m_synchronous_execution = value;
2881 }
2882 
2883 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2884                                                  llvm::StringRef prefix,
2885                                                  llvm::StringRef help_text) {
2886   const uint32_t max_columns = m_debugger.GetTerminalWidth();
2887 
2888   size_t line_width_max = max_columns - prefix.size();
2889   if (line_width_max < 16)
2890     line_width_max = help_text.size() + prefix.size();
2891 
2892   strm.IndentMore(prefix.size());
2893   bool prefixed_yet = false;
2894   // Even if we have no help text we still want to emit the command name.
2895   if (help_text.empty())
2896     help_text = "No help text";
2897   while (!help_text.empty()) {
2898     // Prefix the first line, indent subsequent lines to line up
2899     if (!prefixed_yet) {
2900       strm << prefix;
2901       prefixed_yet = true;
2902     } else
2903       strm.Indent();
2904 
2905     // Never print more than the maximum on one line.
2906     llvm::StringRef this_line = help_text.substr(0, line_width_max);
2907 
2908     // Always break on an explicit newline.
2909     std::size_t first_newline = this_line.find_first_of("\n");
2910 
2911     // Don't break on space/tab unless the text is too long to fit on one line.
2912     std::size_t last_space = llvm::StringRef::npos;
2913     if (this_line.size() != help_text.size())
2914       last_space = this_line.find_last_of(" \t");
2915 
2916     // Break at whichever condition triggered first.
2917     this_line = this_line.substr(0, std::min(first_newline, last_space));
2918     strm.PutCString(this_line);
2919     strm.EOL();
2920 
2921     // Remove whitespace / newlines after breaking.
2922     help_text = help_text.drop_front(this_line.size()).ltrim();
2923   }
2924   strm.IndentLess(prefix.size());
2925 }
2926 
2927 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2928                                                  llvm::StringRef word_text,
2929                                                  llvm::StringRef separator,
2930                                                  llvm::StringRef help_text,
2931                                                  size_t max_word_len) {
2932   StreamString prefix_stream;
2933   prefix_stream.Printf("  %-*s %*s ", (int)max_word_len, word_text.data(),
2934                        (int)separator.size(), separator.data());
2935   OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2936 }
2937 
2938 void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2939                                         llvm::StringRef separator,
2940                                         llvm::StringRef help_text,
2941                                         uint32_t max_word_len) {
2942   int indent_size = max_word_len + separator.size() + 2;
2943 
2944   strm.IndentMore(indent_size);
2945 
2946   StreamString text_strm;
2947   text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2948   text_strm << separator << " " << help_text;
2949 
2950   const uint32_t max_columns = m_debugger.GetTerminalWidth();
2951 
2952   llvm::StringRef text = text_strm.GetString();
2953 
2954   uint32_t chars_left = max_columns;
2955 
2956   auto nextWordLength = [](llvm::StringRef S) {
2957     size_t pos = S.find(' ');
2958     return pos == llvm::StringRef::npos ? S.size() : pos;
2959   };
2960 
2961   while (!text.empty()) {
2962     if (text.front() == '\n' ||
2963         (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2964       strm.EOL();
2965       strm.Indent();
2966       chars_left = max_columns - indent_size;
2967       if (text.front() == '\n')
2968         text = text.drop_front();
2969       else
2970         text = text.ltrim(' ');
2971     } else {
2972       strm.PutChar(text.front());
2973       --chars_left;
2974       text = text.drop_front();
2975     }
2976   }
2977 
2978   strm.EOL();
2979   strm.IndentLess(indent_size);
2980 }
2981 
2982 void CommandInterpreter::FindCommandsForApropos(
2983     llvm::StringRef search_word, StringList &commands_found,
2984     StringList &commands_help, const CommandObject::CommandMap &command_map) {
2985   for (const auto &pair : command_map) {
2986     llvm::StringRef command_name = pair.first;
2987     CommandObject *cmd_obj = pair.second.get();
2988 
2989     const bool search_short_help = true;
2990     const bool search_long_help = false;
2991     const bool search_syntax = false;
2992     const bool search_options = false;
2993     if (command_name.contains_insensitive(search_word) ||
2994         cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2995                                       search_long_help, search_syntax,
2996                                       search_options)) {
2997       commands_found.AppendString(command_name);
2998       commands_help.AppendString(cmd_obj->GetHelp());
2999     }
3000 
3001     if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
3002       StringList subcommands_found;
3003       FindCommandsForApropos(search_word, subcommands_found, commands_help,
3004                              multiword_cmd->GetSubcommandDictionary());
3005       for (const auto &subcommand_name : subcommands_found) {
3006         std::string qualified_name =
3007             (command_name + " " + subcommand_name).str();
3008         commands_found.AppendString(qualified_name);
3009       }
3010     }
3011   }
3012 }
3013 
3014 void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
3015                                                 StringList &commands_found,
3016                                                 StringList &commands_help,
3017                                                 bool search_builtin_commands,
3018                                                 bool search_user_commands,
3019                                                 bool search_alias_commands,
3020                                                 bool search_user_mw_commands) {
3021   CommandObject::CommandMap::const_iterator pos;
3022 
3023   if (search_builtin_commands)
3024     FindCommandsForApropos(search_word, commands_found, commands_help,
3025                            m_command_dict);
3026 
3027   if (search_user_commands)
3028     FindCommandsForApropos(search_word, commands_found, commands_help,
3029                            m_user_dict);
3030 
3031   if (search_user_mw_commands)
3032     FindCommandsForApropos(search_word, commands_found, commands_help,
3033                            m_user_mw_dict);
3034 
3035   if (search_alias_commands)
3036     FindCommandsForApropos(search_word, commands_found, commands_help,
3037                            m_alias_dict);
3038 }
3039 
3040 ExecutionContext CommandInterpreter::GetExecutionContext() const {
3041   return !m_overriden_exe_contexts.empty()
3042              ? m_overriden_exe_contexts.top()
3043              : m_debugger.GetSelectedExecutionContext();
3044 }
3045 
3046 void CommandInterpreter::OverrideExecutionContext(
3047     const ExecutionContext &override_context) {
3048   m_overriden_exe_contexts.push(override_context);
3049 }
3050 
3051 void CommandInterpreter::RestoreExecutionContext() {
3052   if (!m_overriden_exe_contexts.empty())
3053     m_overriden_exe_contexts.pop();
3054 }
3055 
3056 void CommandInterpreter::GetProcessOutput() {
3057   if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
3058     m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
3059                                   /*flush_stderr*/ true);
3060 }
3061 
3062 void CommandInterpreter::StartHandlingCommand() {
3063   auto idle_state = CommandHandlingState::eIdle;
3064   if (m_command_state.compare_exchange_strong(
3065           idle_state, CommandHandlingState::eInProgress))
3066     lldbassert(m_iohandler_nesting_level == 0);
3067   else
3068     lldbassert(m_iohandler_nesting_level > 0);
3069   ++m_iohandler_nesting_level;
3070 }
3071 
3072 void CommandInterpreter::FinishHandlingCommand() {
3073   lldbassert(m_iohandler_nesting_level > 0);
3074   if (--m_iohandler_nesting_level == 0) {
3075     auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3076     lldbassert(prev_state != CommandHandlingState::eIdle);
3077   }
3078 }
3079 
3080 bool CommandInterpreter::InterruptCommand() {
3081   auto in_progress = CommandHandlingState::eInProgress;
3082   return m_command_state.compare_exchange_strong(
3083       in_progress, CommandHandlingState::eInterrupted);
3084 }
3085 
3086 bool CommandInterpreter::WasInterrupted() const {
3087   if (!m_debugger.IsIOHandlerThreadCurrentThread())
3088     return false;
3089 
3090   bool was_interrupted =
3091       (m_command_state == CommandHandlingState::eInterrupted);
3092   lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3093   return was_interrupted;
3094 }
3095 
3096 void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
3097                                             llvm::StringRef str,
3098                                             bool is_stdout) {
3099 
3100   lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3101                                         : io_handler.GetErrorStreamFileSP();
3102   // Split the output into lines and poll for interrupt requests
3103   bool had_output = !str.empty();
3104   while (!str.empty()) {
3105     llvm::StringRef line;
3106     std::tie(line, str) = str.split('\n');
3107     {
3108       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3109       stream->Write(line.data(), line.size());
3110       stream->Write("\n", 1);
3111     }
3112   }
3113 
3114   std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3115   if (had_output &&
3116       INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output"))
3117     stream->Printf("\n... Interrupted.\n");
3118   stream->Flush();
3119 }
3120 
3121 bool CommandInterpreter::EchoCommandNonInteractive(
3122     llvm::StringRef line, const Flags &io_handler_flags) const {
3123   if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3124     return false;
3125 
3126   llvm::StringRef command = line.trim();
3127   if (command.empty())
3128     return true;
3129 
3130   if (command.front() == m_comment_char)
3131     return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3132 
3133   return true;
3134 }
3135 
3136 void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
3137                                                 std::string &line) {
3138     // If we were interrupted, bail out...
3139     if (WasInterrupted())
3140       return;
3141 
3142   const bool is_interactive = io_handler.GetIsInteractive();
3143   const bool allow_repeats =
3144       io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats);
3145 
3146   if (!is_interactive && !allow_repeats) {
3147     // When we are not interactive, don't execute blank lines. This will happen
3148     // sourcing a commands file. We don't want blank lines to repeat the
3149     // previous command and cause any errors to occur (like redefining an
3150     // alias, get an error and stop parsing the commands file).
3151     // But obey the AllowRepeats flag if the user has set it.
3152     if (line.empty())
3153       return;
3154   }
3155   if (!is_interactive) {
3156     // When using a non-interactive file handle (like when sourcing commands
3157     // from a file) we need to echo the command out so we don't just see the
3158     // command output and no command...
3159     if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3160       std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3161       io_handler.GetOutputStreamFileSP()->Printf(
3162           "%s%s\n", io_handler.GetPrompt(), line.c_str());
3163     }
3164   }
3165 
3166   StartHandlingCommand();
3167 
3168   ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
3169   bool pushed_exe_ctx = false;
3170   if (exe_ctx.HasTargetScope()) {
3171     OverrideExecutionContext(exe_ctx);
3172     pushed_exe_ctx = true;
3173   }
3174   auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3175     if (pushed_exe_ctx)
3176       RestoreExecutionContext();
3177   });
3178 
3179   lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
3180   HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3181 
3182   // Now emit the command output text from the command we just executed
3183   if ((result.Succeeded() &&
3184        io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
3185       io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
3186     // Display any inline diagnostics first.
3187     const bool inline_diagnostics = !result.GetImmediateErrorStream() &&
3188                                     GetDebugger().GetShowInlineDiagnostics();
3189     if (inline_diagnostics) {
3190       unsigned prompt_len = m_debugger.GetPrompt().size();
3191       if (auto indent = result.GetDiagnosticIndent()) {
3192         std::string diags =
3193             result.GetInlineDiagnosticString(prompt_len + *indent);
3194         PrintCommandOutput(io_handler, diags, true);
3195       }
3196     }
3197 
3198     // Display any STDOUT/STDERR _prior_ to emitting the command result text.
3199     GetProcessOutput();
3200 
3201     if (!result.GetImmediateOutputStream()) {
3202       llvm::StringRef output = result.GetOutputString();
3203       PrintCommandOutput(io_handler, output, true);
3204     }
3205 
3206     // Now emit the command error text from the command we just executed.
3207     if (!result.GetImmediateErrorStream()) {
3208       std::string error = result.GetErrorString(!inline_diagnostics);
3209       PrintCommandOutput(io_handler, error, false);
3210     }
3211   }
3212 
3213   FinishHandlingCommand();
3214 
3215   switch (result.GetStatus()) {
3216   case eReturnStatusInvalid:
3217   case eReturnStatusSuccessFinishNoResult:
3218   case eReturnStatusSuccessFinishResult:
3219   case eReturnStatusStarted:
3220     break;
3221 
3222   case eReturnStatusSuccessContinuingNoResult:
3223   case eReturnStatusSuccessContinuingResult:
3224     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
3225       io_handler.SetIsDone(true);
3226     break;
3227 
3228   case eReturnStatusFailed:
3229     m_result.IncrementNumberOfErrors();
3230     if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3231       m_result.SetResult(lldb::eCommandInterpreterResultCommandError);
3232       io_handler.SetIsDone(true);
3233     }
3234     break;
3235 
3236   case eReturnStatusQuit:
3237     m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested);
3238     io_handler.SetIsDone(true);
3239     break;
3240   }
3241 
3242   // Finally, if we're going to stop on crash, check that here:
3243   if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) &&
3244       result.GetDidChangeProcessState() &&
3245       io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
3246       DidProcessStopAbnormally()) {
3247     io_handler.SetIsDone(true);
3248     m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash);
3249   }
3250 }
3251 
3252 bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
3253   ExecutionContext exe_ctx(GetExecutionContext());
3254   Process *process = exe_ctx.GetProcessPtr();
3255 
3256   if (InterruptCommand())
3257     return true;
3258 
3259   if (process) {
3260     StateType state = process->GetState();
3261     if (StateIsRunningState(state)) {
3262       process->Halt();
3263       return true; // Don't do any updating when we are running
3264     }
3265   }
3266 
3267   ScriptInterpreter *script_interpreter =
3268       m_debugger.GetScriptInterpreter(false);
3269   if (script_interpreter) {
3270     if (script_interpreter->Interrupt())
3271       return true;
3272   }
3273   return false;
3274 }
3275 
3276 bool CommandInterpreter::SaveTranscript(
3277     CommandReturnObject &result, std::optional<std::string> output_file) {
3278   if (output_file == std::nullopt || output_file->empty()) {
3279     std::string now = llvm::to_string(std::chrono::system_clock::now());
3280     std::replace(now.begin(), now.end(), ' ', '_');
3281     // Can't have file name with colons on Windows
3282     std::replace(now.begin(), now.end(), ':', '-');
3283     const std::string file_name = "lldb_session_" + now + ".log";
3284 
3285     FileSpec save_location = GetSaveSessionDirectory();
3286 
3287     if (!save_location)
3288       save_location = HostInfo::GetGlobalTempDir();
3289 
3290     FileSystem::Instance().Resolve(save_location);
3291     save_location.AppendPathComponent(file_name);
3292     output_file = save_location.GetPath();
3293   }
3294 
3295   auto error_out = [&](llvm::StringRef error_message, std::string description) {
3296     LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3297              output_file, description);
3298     result.AppendErrorWithFormatv(
3299         "Failed to save session's transcripts to {0}!", *output_file);
3300     return false;
3301   };
3302 
3303   File::OpenOptions flags = File::eOpenOptionWriteOnly |
3304                             File::eOpenOptionCanCreate |
3305                             File::eOpenOptionTruncate;
3306 
3307   auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3308 
3309   if (!opened_file)
3310     return error_out("Unable to create file",
3311                      llvm::toString(opened_file.takeError()));
3312 
3313   FileUP file = std::move(opened_file.get());
3314 
3315   size_t byte_size = m_transcript_stream.GetSize();
3316 
3317   Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3318 
3319   if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3320     return error_out("Unable to write to destination file",
3321                      "Bytes written do not match transcript size.");
3322 
3323   result.SetStatus(eReturnStatusSuccessFinishNoResult);
3324   result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3325                                  output_file->c_str());
3326   if (!GetSaveTranscript())
3327     result.AppendError(
3328         "Note: the setting interpreter.save-transcript is set to false, so the "
3329         "transcript might not have been recorded.");
3330 
3331   if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) {
3332     const FileSpec file_spec;
3333     error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3334     if (error.Success()) {
3335       if (llvm::Error e = Host::OpenFileInExternalEditor(
3336               m_debugger.GetExternalEditor(), file_spec, 1))
3337         result.AppendError(llvm::toString(std::move(e)));
3338     }
3339   }
3340 
3341   return true;
3342 }
3343 
3344 bool CommandInterpreter::IsInteractive() {
3345   return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3346 }
3347 
3348 FileSpec CommandInterpreter::GetCurrentSourceDir() {
3349   if (m_command_source_dirs.empty())
3350     return {};
3351   return m_command_source_dirs.back();
3352 }
3353 
3354 void CommandInterpreter::GetLLDBCommandsFromIOHandler(
3355     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3356   Debugger &debugger = GetDebugger();
3357   IOHandlerSP io_handler_sp(
3358       new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
3359                             "lldb", // Name of input reader for history
3360                             llvm::StringRef(prompt), // Prompt
3361                             llvm::StringRef(),       // Continuation prompt
3362                             true,                    // Get multiple lines
3363                             debugger.GetUseColor(),
3364                             0,          // Don't show line numbers
3365                             delegate)); // IOHandlerDelegate
3366 
3367   if (io_handler_sp) {
3368     io_handler_sp->SetUserData(baton);
3369     debugger.RunIOHandlerAsync(io_handler_sp);
3370   }
3371 }
3372 
3373 void CommandInterpreter::GetPythonCommandsFromIOHandler(
3374     const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3375   Debugger &debugger = GetDebugger();
3376   IOHandlerSP io_handler_sp(
3377       new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
3378                             "lldb-python", // Name of input reader for history
3379                             llvm::StringRef(prompt), // Prompt
3380                             llvm::StringRef(),       // Continuation prompt
3381                             true,                    // Get multiple lines
3382                             debugger.GetUseColor(),
3383                             0,          // Don't show line numbers
3384                             delegate)); // IOHandlerDelegate
3385 
3386   if (io_handler_sp) {
3387     io_handler_sp->SetUserData(baton);
3388     debugger.RunIOHandlerAsync(io_handler_sp);
3389   }
3390 }
3391 
3392 bool CommandInterpreter::IsActive() {
3393   return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
3394 }
3395 
3396 lldb::IOHandlerSP
3397 CommandInterpreter::GetIOHandler(bool force_create,
3398                                  CommandInterpreterRunOptions *options) {
3399   // Always re-create the IOHandlerEditline in case the input changed. The old
3400   // instance might have had a non-interactive input and now it does or vice
3401   // versa.
3402   if (force_create || !m_command_io_handler_sp) {
3403     // Always re-create the IOHandlerEditline in case the input changed. The
3404     // old instance might have had a non-interactive input and now it does or
3405     // vice versa.
3406     uint32_t flags = 0;
3407 
3408     if (options) {
3409       if (options->m_stop_on_continue == eLazyBoolYes)
3410         flags |= eHandleCommandFlagStopOnContinue;
3411       if (options->m_stop_on_error == eLazyBoolYes)
3412         flags |= eHandleCommandFlagStopOnError;
3413       if (options->m_stop_on_crash == eLazyBoolYes)
3414         flags |= eHandleCommandFlagStopOnCrash;
3415       if (options->m_echo_commands != eLazyBoolNo)
3416         flags |= eHandleCommandFlagEchoCommand;
3417       if (options->m_echo_comment_commands != eLazyBoolNo)
3418         flags |= eHandleCommandFlagEchoCommentCommand;
3419       if (options->m_print_results != eLazyBoolNo)
3420         flags |= eHandleCommandFlagPrintResult;
3421       if (options->m_print_errors != eLazyBoolNo)
3422         flags |= eHandleCommandFlagPrintErrors;
3423       if (options->m_allow_repeats == eLazyBoolYes)
3424         flags |= eHandleCommandFlagAllowRepeats;
3425     } else {
3426       flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
3427               eHandleCommandFlagPrintErrors;
3428     }
3429 
3430     m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3431         m_debugger, IOHandler::Type::CommandInterpreter,
3432         m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(),
3433         m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3434         llvm::StringRef(), // Continuation prompt
3435         false, // Don't enable multiple line input, just single line commands
3436         m_debugger.GetUseColor(),
3437         0,      // Don't show line numbers
3438         *this); // IOHandlerDelegate
3439   }
3440   return m_command_io_handler_sp;
3441 }
3442 
3443 CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter(
3444     CommandInterpreterRunOptions &options) {
3445   // Always re-create the command interpreter when we run it in case any file
3446   // handles have changed.
3447   bool force_create = true;
3448   m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3449   m_result = CommandInterpreterRunResult();
3450 
3451   if (options.GetAutoHandleEvents())
3452     m_debugger.StartEventHandlerThread();
3453 
3454   if (options.GetSpawnThread()) {
3455     m_debugger.StartIOHandlerThread();
3456   } else {
3457     // If the current thread is not managed by a host thread, we won't detect
3458     // that this IS the CommandInterpreter IOHandler thread, so make it so:
3459     HostThread new_io_handler_thread(Host::GetCurrentThread());
3460     HostThread old_io_handler_thread =
3461         m_debugger.SetIOHandlerThread(new_io_handler_thread);
3462     m_debugger.RunIOHandlers();
3463     m_debugger.SetIOHandlerThread(old_io_handler_thread);
3464 
3465     if (options.GetAutoHandleEvents())
3466       m_debugger.StopEventHandlerThread();
3467   }
3468 
3469   return m_result;
3470 }
3471 
3472 CommandObject *
3473 CommandInterpreter::ResolveCommandImpl(std::string &command_line,
3474                                        CommandReturnObject &result) {
3475   std::string scratch_command(command_line); // working copy so we don't modify
3476                                              // command_line unless we succeed
3477   CommandObject *cmd_obj = nullptr;
3478   StreamString revised_command_line;
3479   bool wants_raw_input = false;
3480   std::string next_word;
3481   StringList matches;
3482   bool done = false;
3483 
3484   auto build_alias_cmd = [&](std::string &full_name) {
3485     revised_command_line.Clear();
3486     matches.Clear();
3487     std::string alias_result;
3488     cmd_obj =
3489         BuildAliasResult(full_name, scratch_command, alias_result, result);
3490     revised_command_line.Printf("%s", alias_result.c_str());
3491     if (cmd_obj) {
3492       wants_raw_input = cmd_obj->WantsRawCommandString();
3493     }
3494   };
3495 
3496   while (!done) {
3497     char quote_char = '\0';
3498     std::string suffix;
3499     ExtractCommand(scratch_command, next_word, suffix, quote_char);
3500     if (cmd_obj == nullptr) {
3501       std::string full_name;
3502       bool is_alias = GetAliasFullName(next_word, full_name);
3503       cmd_obj = GetCommandObject(next_word, &matches);
3504       bool is_real_command =
3505           (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3506       if (!is_real_command) {
3507         build_alias_cmd(full_name);
3508       } else {
3509         if (cmd_obj) {
3510           llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3511           revised_command_line.Printf("%s", cmd_name.str().c_str());
3512           wants_raw_input = cmd_obj->WantsRawCommandString();
3513         } else {
3514           revised_command_line.Printf("%s", next_word.c_str());
3515         }
3516       }
3517     } else {
3518       if (cmd_obj->IsMultiwordObject()) {
3519         CommandObject *sub_cmd_obj =
3520             cmd_obj->GetSubcommandObject(next_word.c_str());
3521         if (sub_cmd_obj) {
3522           // The subcommand's name includes the parent command's name, so
3523           // restart rather than append to the revised_command_line.
3524           llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3525           revised_command_line.Clear();
3526           revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3527           cmd_obj = sub_cmd_obj;
3528           wants_raw_input = cmd_obj->WantsRawCommandString();
3529         } else {
3530           if (quote_char)
3531             revised_command_line.Printf(" %c%s%s%c", quote_char,
3532                                         next_word.c_str(), suffix.c_str(),
3533                                         quote_char);
3534           else
3535             revised_command_line.Printf(" %s%s", next_word.c_str(),
3536                                         suffix.c_str());
3537           done = true;
3538         }
3539       } else {
3540         if (quote_char)
3541           revised_command_line.Printf(" %c%s%s%c", quote_char,
3542                                       next_word.c_str(), suffix.c_str(),
3543                                       quote_char);
3544         else
3545           revised_command_line.Printf(" %s%s", next_word.c_str(),
3546                                       suffix.c_str());
3547         done = true;
3548       }
3549     }
3550 
3551     if (cmd_obj == nullptr) {
3552       const size_t num_matches = matches.GetSize();
3553       if (matches.GetSize() > 1) {
3554         StringList alias_matches;
3555         GetAliasCommandObject(next_word, &alias_matches);
3556 
3557         if (alias_matches.GetSize() == 1) {
3558           std::string full_name;
3559           GetAliasFullName(alias_matches.GetStringAtIndex(0), full_name);
3560           build_alias_cmd(full_name);
3561           done = static_cast<bool>(cmd_obj);
3562         } else {
3563           StreamString error_msg;
3564           error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3565                            next_word.c_str());
3566 
3567           for (uint32_t i = 0; i < num_matches; ++i) {
3568             error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3569           }
3570           result.AppendRawError(error_msg.GetString());
3571         }
3572       } else {
3573         // We didn't have only one match, otherwise we wouldn't get here.
3574         lldbassert(num_matches == 0);
3575         result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3576                                      next_word.c_str());
3577       }
3578       if (!done)
3579         return nullptr;
3580     }
3581 
3582     if (cmd_obj->IsMultiwordObject()) {
3583       if (!suffix.empty()) {
3584         result.AppendErrorWithFormat(
3585             "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3586             "might be invalid).\n",
3587             cmd_obj->GetCommandName().str().c_str(),
3588             next_word.empty() ? "" : next_word.c_str(),
3589             next_word.empty() ? " -- " : " ", suffix.c_str());
3590         return nullptr;
3591       }
3592     } else {
3593       // If we found a normal command, we are done
3594       done = true;
3595       if (!suffix.empty()) {
3596         switch (suffix[0]) {
3597         case '/':
3598           // GDB format suffixes
3599           {
3600             Options *command_options = cmd_obj->GetOptions();
3601             if (command_options &&
3602                 command_options->SupportsLongOption("gdb-format")) {
3603               std::string gdb_format_option("--gdb-format=");
3604               gdb_format_option += (suffix.c_str() + 1);
3605 
3606               std::string cmd = std::string(revised_command_line.GetString());
3607               size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3608               if (arg_terminator_idx != std::string::npos) {
3609                 // Insert the gdb format option before the "--" that terminates
3610                 // options
3611                 gdb_format_option.append(1, ' ');
3612                 cmd.insert(arg_terminator_idx, gdb_format_option);
3613                 revised_command_line.Clear();
3614                 revised_command_line.PutCString(cmd);
3615               } else
3616                 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3617 
3618               if (wants_raw_input &&
3619                   FindArgumentTerminator(cmd) == std::string::npos)
3620                 revised_command_line.PutCString(" --");
3621             } else {
3622               result.AppendErrorWithFormat(
3623                   "the '%s' command doesn't support the --gdb-format option\n",
3624                   cmd_obj->GetCommandName().str().c_str());
3625               return nullptr;
3626             }
3627           }
3628           break;
3629 
3630         default:
3631           result.AppendErrorWithFormat(
3632               "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3633           return nullptr;
3634         }
3635       }
3636     }
3637     if (scratch_command.empty())
3638       done = true;
3639   }
3640 
3641   if (!scratch_command.empty())
3642     revised_command_line.Printf(" %s", scratch_command.c_str());
3643 
3644   if (cmd_obj != nullptr)
3645     command_line = std::string(revised_command_line.GetString());
3646 
3647   return cmd_obj;
3648 }
3649 
3650 llvm::json::Value CommandInterpreter::GetStatistics() {
3651   llvm::json::Object stats;
3652   for (const auto &command_usage : m_command_usages)
3653     stats.try_emplace(command_usage.getKey(), command_usage.getValue());
3654   return stats;
3655 }
3656 
3657 const StructuredData::Array &CommandInterpreter::GetTranscript() const {
3658   return m_transcript;
3659 }
3660