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