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