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