[NFC][Coroutines] Use structured binding with llvm::enumerate in CoroSplit (#116879)
[llvm-project.git] / lldb / source / Interpreter / CommandInterpreter.cpp
blob764dcfd1903b194fa9d139025931e22ecb448494
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 //===----------------------------------------------------------------------===//
9 #include <chrono>
10 #include <cstdlib>
11 #include <limits>
12 #include <memory>
13 #include <optional>
14 #include <string>
15 #include <vector>
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"
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"
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"
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"
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"
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"
91 #if defined(__APPLE__)
92 #include <TargetConditionals.h>
93 #endif
95 using namespace lldb;
96 using namespace lldb_private;
98 static const char *k_white_space = " \t\v";
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.";
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>";
117 #define LLDB_PROPERTIES_interpreter
118 #include "InterpreterProperties.inc"
120 enum {
121 #define LLDB_PROPERTIES_interpreter
122 #include "InterpreterPropertiesEnum.inc"
125 llvm::StringRef CommandInterpreter::GetStaticBroadcasterClass() {
126 static constexpr llvm::StringLiteral class_name("lldb.commandInterpreter");
127 return class_name;
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);
150 bool CommandInterpreter::GetExpandRegexAliases() const {
151 const uint32_t idx = ePropertyExpandRegexAliases;
152 return GetPropertyAtIndexAs<bool>(
153 idx, g_interpreter_properties[idx].default_uint_value != 0);
156 bool CommandInterpreter::GetPromptOnQuit() const {
157 const uint32_t idx = ePropertyPromptOnQuit;
158 return GetPropertyAtIndexAs<bool>(
159 idx, g_interpreter_properties[idx].default_uint_value != 0);
162 void CommandInterpreter::SetPromptOnQuit(bool enable) {
163 const uint32_t idx = ePropertyPromptOnQuit;
164 SetPropertyAtIndex(idx, enable);
167 bool CommandInterpreter::GetSaveTranscript() const {
168 const uint32_t idx = ePropertySaveTranscript;
169 return GetPropertyAtIndexAs<bool>(
170 idx, g_interpreter_properties[idx].default_uint_value != 0);
173 void CommandInterpreter::SetSaveTranscript(bool enable) {
174 const uint32_t idx = ePropertySaveTranscript;
175 SetPropertyAtIndex(idx, enable);
178 bool CommandInterpreter::GetSaveSessionOnQuit() const {
179 const uint32_t idx = ePropertySaveSessionOnQuit;
180 return GetPropertyAtIndexAs<bool>(
181 idx, g_interpreter_properties[idx].default_uint_value != 0);
184 void CommandInterpreter::SetSaveSessionOnQuit(bool enable) {
185 const uint32_t idx = ePropertySaveSessionOnQuit;
186 SetPropertyAtIndex(idx, enable);
189 bool CommandInterpreter::GetOpenTranscriptInEditor() const {
190 const uint32_t idx = ePropertyOpenTranscriptInEditor;
191 return GetPropertyAtIndexAs<bool>(
192 idx, g_interpreter_properties[idx].default_uint_value != 0);
195 void CommandInterpreter::SetOpenTranscriptInEditor(bool enable) {
196 const uint32_t idx = ePropertyOpenTranscriptInEditor;
197 SetPropertyAtIndex(idx, enable);
200 FileSpec CommandInterpreter::GetSaveSessionDirectory() const {
201 const uint32_t idx = ePropertySaveSessionDirectory;
202 return GetPropertyAtIndexAs<FileSpec>(idx, {});
205 void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) {
206 const uint32_t idx = ePropertySaveSessionDirectory;
207 SetPropertyAtIndex(idx, path);
210 bool CommandInterpreter::GetEchoCommands() const {
211 const uint32_t idx = ePropertyEchoCommands;
212 return GetPropertyAtIndexAs<bool>(
213 idx, g_interpreter_properties[idx].default_uint_value != 0);
216 void CommandInterpreter::SetEchoCommands(bool enable) {
217 const uint32_t idx = ePropertyEchoCommands;
218 SetPropertyAtIndex(idx, enable);
221 bool CommandInterpreter::GetEchoCommentCommands() const {
222 const uint32_t idx = ePropertyEchoCommentCommands;
223 return GetPropertyAtIndexAs<bool>(
224 idx, g_interpreter_properties[idx].default_uint_value != 0);
227 void CommandInterpreter::SetEchoCommentCommands(bool enable) {
228 const uint32_t idx = ePropertyEchoCommentCommands;
229 SetPropertyAtIndex(idx, enable);
232 void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
233 m_allow_exit_code = allow;
234 if (!allow)
235 m_quit_exit_code.reset();
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;
245 int CommandInterpreter::GetQuitExitCode(bool &exited) const {
246 exited = m_quit_exit_code.has_value();
247 if (exited)
248 return *m_quit_exit_code;
249 return 0;
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);
261 bool CommandInterpreter::GetStopCmdSourceOnError() const {
262 const uint32_t idx = ePropertyStopCmdSourceOnError;
263 return GetPropertyAtIndexAs<bool>(
264 idx, g_interpreter_properties[idx].default_uint_value != 0);
267 bool CommandInterpreter::GetSpaceReplPrompts() const {
268 const uint32_t idx = ePropertySpaceReplPrompts;
269 return GetPropertyAtIndexAs<bool>(
270 idx, g_interpreter_properties[idx].default_uint_value != 0);
273 bool CommandInterpreter::GetRepeatPreviousCommand() const {
274 const uint32_t idx = ePropertyRepeatPreviousCommand;
275 return GetPropertyAtIndexAs<bool>(
276 idx, g_interpreter_properties[idx].default_uint_value != 0);
279 bool CommandInterpreter::GetRequireCommandOverwrite() const {
280 const uint32_t idx = ePropertyRequireCommandOverwrite;
281 return GetPropertyAtIndexAs<bool>(
282 idx, g_interpreter_properties[idx].default_uint_value != 0);
285 void CommandInterpreter::Initialize() {
286 LLDB_SCOPED_TIMER();
288 CommandReturnObject result(m_debugger.GetUseColor());
290 LoadCommandDictionary();
292 // An alias arguments vector to reuse - reset it before use...
293 OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
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);
302 cmd_obj_sp = GetCommandSPExact("_regexp-attach");
303 if (cmd_obj_sp)
304 AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
306 cmd_obj_sp = GetCommandSPExact("process detach");
307 if (cmd_obj_sp) {
308 AddAlias("detach", cmd_obj_sp);
311 cmd_obj_sp = GetCommandSPExact("process continue");
312 if (cmd_obj_sp) {
313 AddAlias("c", cmd_obj_sp);
314 AddAlias("continue", cmd_obj_sp);
317 cmd_obj_sp = GetCommandSPExact("_regexp-break");
318 if (cmd_obj_sp)
319 AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
321 cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
322 if (cmd_obj_sp)
323 AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
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);
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);
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>");
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);
357 cmd_obj_sp = GetCommandSPExact("thread step-out");
358 if (cmd_obj_sp) {
359 AddAlias("finish", cmd_obj_sp);
362 cmd_obj_sp = GetCommandSPExact("frame select");
363 if (cmd_obj_sp) {
364 AddAlias("f", cmd_obj_sp);
367 cmd_obj_sp = GetCommandSPExact("thread select");
368 if (cmd_obj_sp) {
369 AddAlias("t", cmd_obj_sp);
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());
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());
384 cmd_obj_sp = GetCommandSPExact("_regexp-env");
385 if (cmd_obj_sp)
386 AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
388 cmd_obj_sp = GetCommandSPExact("memory read");
389 if (cmd_obj_sp)
390 AddAlias("x", cmd_obj_sp);
392 cmd_obj_sp = GetCommandSPExact("_regexp-up");
393 if (cmd_obj_sp)
394 AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
396 cmd_obj_sp = GetCommandSPExact("_regexp-down");
397 if (cmd_obj_sp)
398 AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
400 cmd_obj_sp = GetCommandSPExact("_regexp-display");
401 if (cmd_obj_sp)
402 AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
404 cmd_obj_sp = GetCommandSPExact("disassemble");
405 if (cmd_obj_sp)
406 AddAlias("dis", cmd_obj_sp);
408 cmd_obj_sp = GetCommandSPExact("disassemble");
409 if (cmd_obj_sp)
410 AddAlias("di", cmd_obj_sp);
412 cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
413 if (cmd_obj_sp)
414 AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
416 cmd_obj_sp = GetCommandSPExact("_regexp-bt");
417 if (cmd_obj_sp)
418 AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
420 cmd_obj_sp = GetCommandSPExact("target create");
421 if (cmd_obj_sp)
422 AddAlias("file", cmd_obj_sp);
424 cmd_obj_sp = GetCommandSPExact("target modules");
425 if (cmd_obj_sp)
426 AddAlias("image", cmd_obj_sp);
428 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
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("");
442 cmd_obj_sp = GetCommandSPExact("expression");
443 if (cmd_obj_sp) {
444 // Ensure `e` runs `expression`.
445 AddAlias("e", cmd_obj_sp);
446 AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
447 CommandAlias *parray_alias =
448 AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
449 if (parray_alias) {
450 parray_alias->SetHelp
451 ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
452 "to get a typed-pointer-to-an-array in memory, and will display "
453 "COUNT elements of that type from the array.");
454 parray_alias->SetHelpLong("");
456 CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
457 "--object-description --element-count %1 --");
458 if (poarray_alias) {
459 poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
460 "evaluate EXPRESSION to get the address of an array of COUNT "
461 "objects in memory, and will call po on them.");
462 poarray_alias->SetHelpLong("");
466 cmd_obj_sp = GetCommandSPExact("platform shell");
467 if (cmd_obj_sp) {
468 CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
469 if (shell_alias) {
470 shell_alias->SetHelp("Run a shell command on the host.");
471 shell_alias->SetHelpLong("");
472 shell_alias->SetSyntax("shell <shell-command>");
476 cmd_obj_sp = GetCommandSPExact("process kill");
477 if (cmd_obj_sp) {
478 AddAlias("kill", cmd_obj_sp);
481 cmd_obj_sp = GetCommandSPExact("process launch");
482 if (cmd_obj_sp) {
483 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
484 #if defined(__APPLE__)
485 #if TARGET_OS_IPHONE
486 AddAlias("r", cmd_obj_sp, "--");
487 AddAlias("run", cmd_obj_sp, "--");
488 #else
489 AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
490 AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
491 #endif
492 #else
493 StreamString defaultshell;
494 defaultshell.Printf("--shell=%s --",
495 HostInfo::GetDefaultShell().GetPath().c_str());
496 AddAlias("r", cmd_obj_sp, defaultshell.GetString());
497 AddAlias("run", cmd_obj_sp, defaultshell.GetString());
498 #endif
501 cmd_obj_sp = GetCommandSPExact("target symbols add");
502 if (cmd_obj_sp) {
503 AddAlias("add-dsym", cmd_obj_sp);
506 cmd_obj_sp = GetCommandSPExact("breakpoint set");
507 if (cmd_obj_sp) {
508 AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
511 cmd_obj_sp = GetCommandSPExact("frame variable");
512 if (cmd_obj_sp) {
513 AddAlias("v", cmd_obj_sp);
514 AddAlias("var", cmd_obj_sp);
515 AddAlias("vo", cmd_obj_sp, "--object-description");
518 cmd_obj_sp = GetCommandSPExact("register");
519 if (cmd_obj_sp) {
520 AddAlias("re", cmd_obj_sp);
523 cmd_obj_sp = GetCommandSPExact("scripting run");
524 if (cmd_obj_sp) {
525 AddAlias("script", cmd_obj_sp);
528 cmd_obj_sp = GetCommandSPExact("session history");
529 if (cmd_obj_sp) {
530 AddAlias("history", cmd_obj_sp);
533 cmd_obj_sp = GetCommandSPExact("help");
534 if (cmd_obj_sp) {
535 AddAlias("h", cmd_obj_sp);
539 void CommandInterpreter::Clear() {
540 m_command_io_handler_sp.reset();
543 const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
544 // This function has not yet been implemented.
546 // Look for any embedded script command
547 // If found,
548 // get interpreter object from the command dictionary,
549 // call execute_one_command on it,
550 // get the results as a string,
551 // substitute that string for current stuff.
553 return arg;
556 #define REGISTER_COMMAND_OBJECT(NAME, CLASS) \
557 m_command_dict[NAME] = std::make_shared<CLASS>(*this);
559 void CommandInterpreter::LoadCommandDictionary() {
560 LLDB_SCOPED_TIMER();
562 REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos);
563 REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint);
564 REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands);
565 REGISTER_COMMAND_OBJECT("diagnostics", CommandObjectDiagnostics);
566 REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble);
567 REGISTER_COMMAND_OBJECT("dwim-print", CommandObjectDWIMPrint);
568 REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression);
569 REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame);
570 REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI);
571 REGISTER_COMMAND_OBJECT("help", CommandObjectHelp);
572 REGISTER_COMMAND_OBJECT("log", CommandObjectLog);
573 REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory);
574 REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform);
575 REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin);
576 REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess);
577 REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit);
578 REGISTER_COMMAND_OBJECT("register", CommandObjectRegister);
579 REGISTER_COMMAND_OBJECT("scripting", CommandObjectMultiwordScripting);
580 REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings);
581 REGISTER_COMMAND_OBJECT("session", CommandObjectSession);
582 REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource);
583 REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats);
584 REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget);
585 REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread);
586 REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace);
587 REGISTER_COMMAND_OBJECT("type", CommandObjectType);
588 REGISTER_COMMAND_OBJECT("version", CommandObjectVersion);
589 REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint);
590 REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage);
592 // clang-format off
593 const char *break_regexes[][2] = {
594 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
595 "breakpoint set --file '%1' --line %2 --column %3"},
596 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
597 "breakpoint set --file '%1' --line %2"},
598 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
599 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
600 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
601 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
602 "breakpoint set --name '%1'"},
603 {"^(-.*)$", "breakpoint set %1"},
604 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
605 "breakpoint set --name '%2' --shlib '%1'"},
606 {"^\\&(.*[^[:space:]])[[:space:]]*$",
607 "breakpoint set --name '%1' --skip-prologue=0"},
608 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
609 "breakpoint set --name '%1'"}};
610 // clang-format on
612 size_t num_regexes = std::size(break_regexes);
614 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
615 new CommandObjectRegexCommand(
616 *this, "_regexp-break",
617 "Set a breakpoint using one of several shorthand formats.",
618 "\n"
619 "_regexp-break <filename>:<linenum>:<colnum>\n"
620 " main.c:12:21 // Break at line 12 and column "
621 "21 of main.c\n\n"
622 "_regexp-break <filename>:<linenum>\n"
623 " main.c:12 // Break at line 12 of "
624 "main.c\n\n"
625 "_regexp-break <linenum>\n"
626 " 12 // Break at line 12 of current "
627 "file\n\n"
628 "_regexp-break 0x<address>\n"
629 " 0x1234000 // Break at address "
630 "0x1234000\n\n"
631 "_regexp-break <name>\n"
632 " main // Break in 'main' after the "
633 "prologue\n\n"
634 "_regexp-break &<name>\n"
635 " &main // Break at first instruction "
636 "in 'main'\n\n"
637 "_regexp-break <module>`<name>\n"
638 " libc.so`malloc // Break in 'malloc' from "
639 "'libc.so'\n\n"
640 "_regexp-break /<source-regex>/\n"
641 " /break here/ // Break on source lines in "
642 "current file\n"
643 " // containing text 'break "
644 "here'.\n",
645 lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
647 if (break_regex_cmd_up) {
648 bool success = true;
649 for (size_t i = 0; i < num_regexes; i++) {
650 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
651 break_regexes[i][1]);
652 if (!success)
653 break;
655 success =
656 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
658 if (success) {
659 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
660 m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
661 break_regex_cmd_sp;
665 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
666 new CommandObjectRegexCommand(
667 *this, "_regexp-tbreak",
668 "Set a one-shot breakpoint using one of several shorthand formats.",
669 "\n"
670 "_regexp-break <filename>:<linenum>:<colnum>\n"
671 " main.c:12:21 // Break at line 12 and column "
672 "21 of main.c\n\n"
673 "_regexp-break <filename>:<linenum>\n"
674 " main.c:12 // Break at line 12 of "
675 "main.c\n\n"
676 "_regexp-break <linenum>\n"
677 " 12 // Break at line 12 of current "
678 "file\n\n"
679 "_regexp-break 0x<address>\n"
680 " 0x1234000 // Break at address "
681 "0x1234000\n\n"
682 "_regexp-break <name>\n"
683 " main // Break in 'main' after the "
684 "prologue\n\n"
685 "_regexp-break &<name>\n"
686 " &main // Break at first instruction "
687 "in 'main'\n\n"
688 "_regexp-break <module>`<name>\n"
689 " libc.so`malloc // Break in 'malloc' from "
690 "'libc.so'\n\n"
691 "_regexp-break /<source-regex>/\n"
692 " /break here/ // Break on source lines in "
693 "current file\n"
694 " // containing text 'break "
695 "here'.\n",
696 lldb::eSymbolCompletion | lldb::eSourceFileCompletion, false));
698 if (tbreak_regex_cmd_up) {
699 bool success = true;
700 for (size_t i = 0; i < num_regexes; i++) {
701 std::string command = break_regexes[i][1];
702 command += " -o 1";
703 success =
704 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
705 if (!success)
706 break;
708 success =
709 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
711 if (success) {
712 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
713 m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
714 tbreak_regex_cmd_sp;
718 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
719 new CommandObjectRegexCommand(
720 *this, "_regexp-attach", "Attach to process by ID or name.",
721 "_regexp-attach <pid> | <process-name>", 0, false));
722 if (attach_regex_cmd_up) {
723 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
724 "process attach --pid %1") &&
725 attach_regex_cmd_up->AddRegexCommand(
726 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
727 // specified get passed to
728 // 'process attach'
729 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
730 "process attach --name '%1'") &&
731 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
732 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
733 m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
734 attach_regex_cmd_sp;
738 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
739 new CommandObjectRegexCommand(*this, "_regexp-down",
740 "Select a newer stack frame. Defaults to "
741 "moving one frame, a numeric argument can "
742 "specify an arbitrary number.",
743 "_regexp-down [<count>]", 0, false));
744 if (down_regex_cmd_up) {
745 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
746 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
747 "frame select -r -%1")) {
748 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
749 m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
750 down_regex_cmd_sp;
754 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
755 new CommandObjectRegexCommand(
756 *this, "_regexp-up",
757 "Select an older stack frame. Defaults to moving one "
758 "frame, a numeric argument can specify an arbitrary number.",
759 "_regexp-up [<count>]", 0, false));
760 if (up_regex_cmd_up) {
761 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
762 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
763 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
764 m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
765 up_regex_cmd_sp;
769 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
770 new CommandObjectRegexCommand(
771 *this, "_regexp-display",
772 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
773 "_regexp-display expression", 0, false));
774 if (display_regex_cmd_up) {
775 if (display_regex_cmd_up->AddRegexCommand(
776 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
777 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
778 m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
779 display_regex_cmd_sp;
783 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
784 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
785 "Stop displaying expression at every "
786 "stop (specified by stop-hook index.)",
787 "_regexp-undisplay stop-hook-number", 0,
788 false));
789 if (undisplay_regex_cmd_up) {
790 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
791 "target stop-hook delete %1")) {
792 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
793 m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
794 undisplay_regex_cmd_sp;
798 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
799 new CommandObjectRegexCommand(
800 *this, "gdb-remote",
801 "Connect to a process via remote GDB server.\n"
802 "If no host is specified, localhost is assumed.\n"
803 "gdb-remote is an abbreviation for 'process connect --plugin "
804 "gdb-remote connect://<hostname>:<port>'\n",
805 "gdb-remote [<hostname>:]<portnum>", 0, false));
806 if (connect_gdb_remote_cmd_up) {
807 if (connect_gdb_remote_cmd_up->AddRegexCommand(
808 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
809 "process connect --plugin gdb-remote connect://%1:%2") &&
810 connect_gdb_remote_cmd_up->AddRegexCommand(
811 "^([[:digit:]]+)$",
812 "process connect --plugin gdb-remote connect://localhost:%1")) {
813 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
814 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
818 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
819 new CommandObjectRegexCommand(
820 *this, "kdp-remote",
821 "Connect to a process via remote KDP server.\n"
822 "If no UDP port is specified, port 41139 is assumed.\n"
823 "kdp-remote is an abbreviation for 'process connect --plugin "
824 "kdp-remote udp://<hostname>:<port>'\n",
825 "kdp-remote <hostname>[:<portnum>]", 0, false));
826 if (connect_kdp_remote_cmd_up) {
827 if (connect_kdp_remote_cmd_up->AddRegexCommand(
828 "^([^:]+:[[:digit:]]+)$",
829 "process connect --plugin kdp-remote udp://%1") &&
830 connect_kdp_remote_cmd_up->AddRegexCommand(
831 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
832 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
833 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
837 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
838 new CommandObjectRegexCommand(
839 *this, "_regexp-bt",
840 "Show backtrace of the current thread's call stack. Any numeric "
841 "argument displays at most that many frames. The argument 'all' "
842 "displays all threads. Use 'settings set frame-format' to customize "
843 "the printing of individual frames and 'settings set thread-format' "
844 "to customize the thread header. Frame recognizers may filter the "
845 "list. Use 'thread backtrace -u (--unfiltered)' to see them all.",
846 "bt [<digit> | all]", 0, false));
847 if (bt_regex_cmd_up) {
848 // accept but don't document "bt -c <number>" -- before bt was a regex
849 // command if you wanted to backtrace three frames you would do "bt -c 3"
850 // but the intention is to have this emulate the gdb "bt" command and so
851 // now "bt 3" is the preferred form, in line with gdb.
852 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
853 "thread backtrace -c %1") &&
854 bt_regex_cmd_up->AddRegexCommand("^(-[^[:space:]].*)$", "thread backtrace %1") &&
855 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
856 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
857 CommandObjectSP command_sp(bt_regex_cmd_up.release());
858 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
862 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
863 new CommandObjectRegexCommand(
864 *this, "_regexp-list",
865 "List relevant source code using one of several shorthand formats.",
866 "\n"
867 "_regexp-list <file>:<line> // List around specific file/line\n"
868 "_regexp-list <line> // List current file around specified "
869 "line\n"
870 "_regexp-list <function-name> // List specified function\n"
871 "_regexp-list 0x<address> // List around specified address\n"
872 "_regexp-list -[<count>] // List previous <count> lines\n"
873 "_regexp-list // List subsequent lines",
874 lldb::eSourceFileCompletion, false));
875 if (list_regex_cmd_up) {
876 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
877 "source list --line %1") &&
878 list_regex_cmd_up->AddRegexCommand(
879 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
880 "]*$",
881 "source list --file '%1' --line %2") &&
882 list_regex_cmd_up->AddRegexCommand(
883 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
884 "source list --address %1") &&
885 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
886 "source list --reverse") &&
887 list_regex_cmd_up->AddRegexCommand(
888 "^-([[:digit:]]+)[[:space:]]*$",
889 "source list --reverse --count %1") &&
890 list_regex_cmd_up->AddRegexCommand("^(.+)$",
891 "source list --name \"%1\"") &&
892 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
893 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
894 m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
895 list_regex_cmd_sp;
899 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
900 new CommandObjectRegexCommand(
901 *this, "_regexp-env",
902 "Shorthand for viewing and setting environment variables.",
903 "\n"
904 "_regexp-env // Show environment\n"
905 "_regexp-env <name>=<value> // Set an environment variable",
906 0, false));
907 if (env_regex_cmd_up) {
908 if (env_regex_cmd_up->AddRegexCommand("^$",
909 "settings show target.env-vars") &&
910 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
911 "settings set target.env-vars %1")) {
912 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
913 m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
914 env_regex_cmd_sp;
918 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
919 new CommandObjectRegexCommand(
920 *this, "_regexp-jump", "Set the program counter to a new address.",
921 "\n"
922 "_regexp-jump <line>\n"
923 "_regexp-jump +<line-offset> | -<line-offset>\n"
924 "_regexp-jump <file>:<line>\n"
925 "_regexp-jump *<addr>\n",
926 0, false));
927 if (jump_regex_cmd_up) {
928 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
929 "thread jump --addr %1") &&
930 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
931 "thread jump --line %1") &&
932 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
933 "thread jump --file %1 --line %2") &&
934 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
935 "thread jump --by %1")) {
936 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
937 m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
938 jump_regex_cmd_sp;
943 int CommandInterpreter::GetCommandNamesMatchingPartialString(
944 const char *cmd_str, bool include_aliases, StringList &matches,
945 StringList &descriptions) {
946 AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
947 &descriptions);
949 if (include_aliases) {
950 AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
951 &descriptions);
954 return matches.GetSize();
957 CommandObjectMultiword *CommandInterpreter::VerifyUserMultiwordCmdPath(
958 Args &path, bool leaf_is_command, Status &result) {
959 result.Clear();
961 auto get_multi_or_report_error =
962 [&result](CommandObjectSP cmd_sp,
963 const char *name) -> CommandObjectMultiword * {
964 if (!cmd_sp) {
965 result = Status::FromErrorStringWithFormat(
966 "Path component: '%s' not found", name);
967 return nullptr;
969 if (!cmd_sp->IsUserCommand()) {
970 result = Status::FromErrorStringWithFormat(
971 "Path component: '%s' is not a user "
972 "command",
973 name);
974 return nullptr;
976 CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
977 if (!cmd_as_multi) {
978 result = Status::FromErrorStringWithFormat(
979 "Path component: '%s' is not a container "
980 "command",
981 name);
982 return nullptr;
984 return cmd_as_multi;
987 size_t num_args = path.GetArgumentCount();
988 if (num_args == 0) {
989 result = Status::FromErrorString("empty command path");
990 return nullptr;
993 if (num_args == 1 && leaf_is_command) {
994 // We just got a leaf command to be added to the root. That's not an error,
995 // just return null for the container.
996 return nullptr;
999 // Start by getting the root command from the interpreter.
1000 const char *cur_name = path.GetArgumentAtIndex(0);
1001 CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
1002 CommandObjectMultiword *cur_as_multi =
1003 get_multi_or_report_error(cur_cmd_sp, cur_name);
1004 if (cur_as_multi == nullptr)
1005 return nullptr;
1007 size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
1008 for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
1009 cursor++) {
1010 cur_name = path.GetArgumentAtIndex(cursor);
1011 cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
1012 cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
1014 return cur_as_multi;
1017 CommandObjectSP
1018 CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
1019 bool exact, StringList *matches,
1020 StringList *descriptions) const {
1021 CommandObjectSP command_sp;
1023 std::string cmd = std::string(cmd_str);
1025 if (HasCommands()) {
1026 auto pos = m_command_dict.find(cmd);
1027 if (pos != m_command_dict.end())
1028 command_sp = pos->second;
1031 if (include_aliases && HasAliases()) {
1032 auto alias_pos = m_alias_dict.find(cmd);
1033 if (alias_pos != m_alias_dict.end())
1034 command_sp = alias_pos->second;
1037 if (HasUserCommands()) {
1038 auto pos = m_user_dict.find(cmd);
1039 if (pos != m_user_dict.end())
1040 command_sp = pos->second;
1043 if (HasUserMultiwordCommands()) {
1044 auto pos = m_user_mw_dict.find(cmd);
1045 if (pos != m_user_mw_dict.end())
1046 command_sp = pos->second;
1049 if (!exact && !command_sp) {
1050 // We will only get into here if we didn't find any exact matches.
1052 CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1053 real_match_sp;
1055 StringList local_matches;
1056 if (matches == nullptr)
1057 matches = &local_matches;
1059 unsigned int num_cmd_matches = 0;
1060 unsigned int num_alias_matches = 0;
1061 unsigned int num_user_matches = 0;
1062 unsigned int num_user_mw_matches = 0;
1064 // Look through the command dictionaries one by one, and if we get only one
1065 // match from any of them in toto, then return that, otherwise return an
1066 // empty CommandObjectSP and the list of matches.
1068 if (HasCommands()) {
1069 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
1070 *matches, descriptions);
1073 if (num_cmd_matches == 1) {
1074 cmd.assign(matches->GetStringAtIndex(0));
1075 auto pos = m_command_dict.find(cmd);
1076 if (pos != m_command_dict.end())
1077 real_match_sp = pos->second;
1080 if (include_aliases && HasAliases()) {
1081 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
1082 *matches, descriptions);
1085 if (num_alias_matches == 1) {
1086 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
1087 auto alias_pos = m_alias_dict.find(cmd);
1088 if (alias_pos != m_alias_dict.end())
1089 alias_match_sp = alias_pos->second;
1092 if (HasUserCommands()) {
1093 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
1094 *matches, descriptions);
1097 if (num_user_matches == 1) {
1098 cmd.assign(
1099 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
1101 auto pos = m_user_dict.find(cmd);
1102 if (pos != m_user_dict.end())
1103 user_match_sp = pos->second;
1106 if (HasUserMultiwordCommands()) {
1107 num_user_mw_matches = AddNamesMatchingPartialString(
1108 m_user_mw_dict, cmd_str, *matches, descriptions);
1111 if (num_user_mw_matches == 1) {
1112 cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1113 num_user_matches));
1115 auto pos = m_user_mw_dict.find(cmd);
1116 if (pos != m_user_mw_dict.end())
1117 user_mw_match_sp = pos->second;
1120 // If we got exactly one match, return that, otherwise return the match
1121 // list.
1123 if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1124 num_alias_matches ==
1125 1) {
1126 if (num_cmd_matches)
1127 return real_match_sp;
1128 else if (num_alias_matches)
1129 return alias_match_sp;
1130 else if (num_user_mw_matches)
1131 return user_mw_match_sp;
1132 else
1133 return user_match_sp;
1135 } else if (matches && command_sp) {
1136 matches->AppendString(cmd_str);
1137 if (descriptions)
1138 descriptions->AppendString(command_sp->GetHelp());
1141 return command_sp;
1144 bool CommandInterpreter::AddCommand(llvm::StringRef name,
1145 const lldb::CommandObjectSP &cmd_sp,
1146 bool can_replace) {
1147 if (cmd_sp.get())
1148 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1149 "tried to add a CommandObject from a different interpreter");
1151 if (name.empty())
1152 return false;
1154 cmd_sp->SetIsUserCommand(false);
1156 std::string name_sstr(name);
1157 auto name_iter = m_command_dict.find(name_sstr);
1158 if (name_iter != m_command_dict.end()) {
1159 if (!can_replace || !name_iter->second->IsRemovable())
1160 return false;
1161 name_iter->second = cmd_sp;
1162 } else {
1163 m_command_dict[name_sstr] = cmd_sp;
1165 return true;
1168 Status CommandInterpreter::AddUserCommand(llvm::StringRef name,
1169 const lldb::CommandObjectSP &cmd_sp,
1170 bool can_replace) {
1171 Status result;
1172 if (cmd_sp.get())
1173 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1174 "tried to add a CommandObject from a different interpreter");
1175 if (name.empty()) {
1176 result = Status::FromErrorString(
1177 "can't use the empty string for a command name");
1178 return result;
1180 // do not allow replacement of internal commands
1181 if (CommandExists(name)) {
1182 result = Status::FromErrorString("can't replace builtin command");
1183 return result;
1186 if (UserCommandExists(name)) {
1187 if (!can_replace) {
1188 result = Status::FromErrorStringWithFormatv(
1189 "user command \"{0}\" already exists and force replace was not set "
1190 "by --overwrite or 'settings set interpreter.require-overwrite "
1191 "false'",
1192 name);
1193 return result;
1195 if (cmd_sp->IsMultiwordObject()) {
1196 if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1197 result = Status::FromErrorString(
1198 "can't replace explicitly non-removable multi-word command");
1199 return result;
1201 } else {
1202 if (!m_user_dict[std::string(name)]->IsRemovable()) {
1203 result = Status::FromErrorString(
1204 "can't replace explicitly non-removable command");
1205 return result;
1210 cmd_sp->SetIsUserCommand(true);
1212 if (cmd_sp->IsMultiwordObject())
1213 m_user_mw_dict[std::string(name)] = cmd_sp;
1214 else
1215 m_user_dict[std::string(name)] = cmd_sp;
1216 return result;
1219 CommandObjectSP
1220 CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1221 bool include_aliases) const {
1222 // Break up the command string into words, in case it's a multi-word command.
1223 Args cmd_words(cmd_str);
1225 if (cmd_str.empty())
1226 return {};
1228 if (cmd_words.GetArgumentCount() == 1)
1229 return GetCommandSP(cmd_str, include_aliases, true);
1231 // We have a multi-word command (seemingly), so we need to do more work.
1232 // First, get the cmd_obj_sp for the first word in the command.
1233 CommandObjectSP cmd_obj_sp =
1234 GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1235 if (!cmd_obj_sp)
1236 return {};
1238 // Loop through the rest of the words in the command (everything passed in
1239 // was supposed to be part of a command name), and find the appropriate
1240 // sub-command SP for each command word....
1241 size_t end = cmd_words.GetArgumentCount();
1242 for (size_t i = 1; i < end; ++i) {
1243 if (!cmd_obj_sp->IsMultiwordObject()) {
1244 // We have more words in the command name, but we don't have a
1245 // multiword object. Fail and return.
1246 return {};
1249 cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1250 if (!cmd_obj_sp) {
1251 // The sub-command name was invalid. Fail and return.
1252 return {};
1256 // We successfully looped through all the command words and got valid
1257 // command objects for them.
1258 return cmd_obj_sp;
1261 CommandObject *
1262 CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1263 StringList *matches,
1264 StringList *descriptions) const {
1265 // Try to find a match among commands and aliases. Allowing inexact matches,
1266 // but perferring exact matches.
1267 return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
1268 matches, descriptions)
1269 .get();
1272 CommandObject *CommandInterpreter::GetUserCommandObject(
1273 llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1274 std::string cmd_str(cmd);
1275 auto find_exact = [&](const CommandObject::CommandMap &map) {
1276 auto found_elem = map.find(cmd);
1277 if (found_elem == map.end())
1278 return (CommandObject *)nullptr;
1279 CommandObject *exact_cmd = found_elem->second.get();
1280 if (exact_cmd) {
1281 if (matches)
1282 matches->AppendString(exact_cmd->GetCommandName());
1283 if (descriptions)
1284 descriptions->AppendString(exact_cmd->GetHelp());
1285 return exact_cmd;
1287 return (CommandObject *)nullptr;
1290 CommandObject *exact_cmd = find_exact(GetUserCommands());
1291 if (exact_cmd)
1292 return exact_cmd;
1294 exact_cmd = find_exact(GetUserMultiwordCommands());
1295 if (exact_cmd)
1296 return exact_cmd;
1298 // We didn't have an exact command, so now look for partial matches.
1299 StringList tmp_list;
1300 StringList *matches_ptr = matches ? matches : &tmp_list;
1301 AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1302 AddNamesMatchingPartialString(GetUserMultiwordCommands(),
1303 cmd_str, *matches_ptr);
1305 return {};
1308 CommandObject *CommandInterpreter::GetAliasCommandObject(
1309 llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1310 auto find_exact =
1311 [&](const CommandObject::CommandMap &map) -> CommandObject * {
1312 auto found_elem = map.find(cmd);
1313 if (found_elem == map.end())
1314 return (CommandObject *)nullptr;
1315 CommandObject *exact_cmd = found_elem->second.get();
1316 if (!exact_cmd)
1317 return nullptr;
1319 if (matches)
1320 matches->AppendString(exact_cmd->GetCommandName());
1322 if (descriptions)
1323 descriptions->AppendString(exact_cmd->GetHelp());
1325 return exact_cmd;
1326 return nullptr;
1329 CommandObject *exact_cmd = find_exact(GetAliases());
1330 if (exact_cmd)
1331 return exact_cmd;
1333 // We didn't have an exact command, so now look for partial matches.
1334 StringList tmp_list;
1335 StringList *matches_ptr = matches ? matches : &tmp_list;
1336 AddNamesMatchingPartialString(GetAliases(), cmd, *matches_ptr);
1338 return {};
1341 bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1342 return m_command_dict.find(cmd) != m_command_dict.end();
1345 bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1346 std::string &full_name) const {
1347 bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
1348 if (exact_match) {
1349 full_name.assign(std::string(cmd));
1350 return exact_match;
1351 } else {
1352 StringList matches;
1353 size_t num_alias_matches;
1354 num_alias_matches =
1355 AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1356 if (num_alias_matches == 1) {
1357 // Make sure this isn't shadowing a command in the regular command space:
1358 StringList regular_matches;
1359 const bool include_aliases = false;
1360 const bool exact = false;
1361 CommandObjectSP cmd_obj_sp(
1362 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1363 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1364 return false;
1365 else {
1366 full_name.assign(matches.GetStringAtIndex(0));
1367 return true;
1369 } else
1370 return false;
1374 bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1375 return m_alias_dict.find(cmd) != m_alias_dict.end();
1378 bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1379 return m_user_dict.find(cmd) != m_user_dict.end();
1382 bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1383 return m_user_mw_dict.find(cmd) != m_user_mw_dict.end();
1386 CommandAlias *
1387 CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1388 lldb::CommandObjectSP &command_obj_sp,
1389 llvm::StringRef args_string) {
1390 if (command_obj_sp.get())
1391 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1392 "tried to add a CommandObject from a different interpreter");
1394 std::unique_ptr<CommandAlias> command_alias_up(
1395 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1397 if (command_alias_up && command_alias_up->IsValid()) {
1398 m_alias_dict[std::string(alias_name)] =
1399 CommandObjectSP(command_alias_up.get());
1400 return command_alias_up.release();
1403 return nullptr;
1406 bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1407 auto pos = m_alias_dict.find(alias_name);
1408 if (pos != m_alias_dict.end()) {
1409 m_alias_dict.erase(pos);
1410 return true;
1412 return false;
1415 bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
1416 auto pos = m_command_dict.find(cmd);
1417 if (pos != m_command_dict.end()) {
1418 if (force || pos->second->IsRemovable()) {
1419 // Only regular expression objects or python commands are removable under
1420 // normal circumstances.
1421 m_command_dict.erase(pos);
1422 return true;
1425 return false;
1428 bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1429 CommandObject::CommandMap::iterator pos = m_user_dict.find(user_name);
1430 if (pos != m_user_dict.end()) {
1431 m_user_dict.erase(pos);
1432 return true;
1434 return false;
1437 bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1438 CommandObject::CommandMap::iterator pos = m_user_mw_dict.find(multi_name);
1439 if (pos != m_user_mw_dict.end()) {
1440 m_user_mw_dict.erase(pos);
1441 return true;
1443 return false;
1446 void CommandInterpreter::GetHelp(CommandReturnObject &result,
1447 uint32_t cmd_types) {
1448 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1449 if (!help_prologue.empty()) {
1450 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1451 help_prologue);
1454 CommandObject::CommandMap::const_iterator pos;
1455 size_t max_len = FindLongestCommandWord(m_command_dict);
1457 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1458 result.AppendMessage("Debugger commands:");
1459 result.AppendMessage("");
1461 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1462 if (!(cmd_types & eCommandTypesHidden) &&
1463 (pos->first.compare(0, 1, "_") == 0))
1464 continue;
1466 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1467 pos->second->GetHelp(), max_len);
1469 result.AppendMessage("");
1472 if (!m_alias_dict.empty() &&
1473 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1474 result.AppendMessageWithFormat(
1475 "Current command abbreviations "
1476 "(type '%shelp command alias' for more info):\n",
1477 GetCommandPrefix());
1478 result.AppendMessage("");
1479 max_len = FindLongestCommandWord(m_alias_dict);
1481 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1482 ++alias_pos) {
1483 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1484 alias_pos->second->GetHelp(), max_len);
1486 result.AppendMessage("");
1489 if (!m_user_dict.empty() &&
1490 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1491 result.AppendMessage("Current user-defined commands:");
1492 result.AppendMessage("");
1493 max_len = FindLongestCommandWord(m_user_dict);
1494 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1495 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1496 pos->second->GetHelp(), max_len);
1498 result.AppendMessage("");
1501 if (!m_user_mw_dict.empty() &&
1502 ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1503 result.AppendMessage("Current user-defined container commands:");
1504 result.AppendMessage("");
1505 max_len = FindLongestCommandWord(m_user_mw_dict);
1506 for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1507 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1508 pos->second->GetHelp(), max_len);
1510 result.AppendMessage("");
1513 result.AppendMessageWithFormat(
1514 "For more information on any command, type '%shelp <command-name>'.\n",
1515 GetCommandPrefix());
1518 CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1519 llvm::StringRef &command_string) {
1520 // This function finds the final, lowest-level, alias-resolved command object
1521 // whose 'Execute' function will eventually be invoked by the given command
1522 // line.
1524 CommandObject *cmd_obj = nullptr;
1525 size_t start = command_string.find_first_not_of(k_white_space);
1526 size_t end = 0;
1527 bool done = false;
1528 while (!done) {
1529 if (start != std::string::npos) {
1530 // Get the next word from command_string.
1531 end = command_string.find_first_of(k_white_space, start);
1532 if (end == std::string::npos)
1533 end = command_string.size();
1534 std::string cmd_word =
1535 std::string(command_string.substr(start, end - start));
1537 if (cmd_obj == nullptr)
1538 // Since cmd_obj is NULL we are on our first time through this loop.
1539 // Check to see if cmd_word is a valid command or alias.
1540 cmd_obj = GetCommandObject(cmd_word);
1541 else if (cmd_obj->IsMultiwordObject()) {
1542 // Our current object is a multi-word object; see if the cmd_word is a
1543 // valid sub-command for our object.
1544 CommandObject *sub_cmd_obj =
1545 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1546 if (sub_cmd_obj)
1547 cmd_obj = sub_cmd_obj;
1548 else // cmd_word was not a valid sub-command word, so we are done
1549 done = true;
1550 } else
1551 // We have a cmd_obj and it is not a multi-word object, so we are done.
1552 done = true;
1554 // If we didn't find a valid command object, or our command object is not
1555 // a multi-word object, or we are at the end of the command_string, then
1556 // we are done. Otherwise, find the start of the next word.
1558 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1559 end >= command_string.size())
1560 done = true;
1561 else
1562 start = command_string.find_first_not_of(k_white_space, end);
1563 } else
1564 // Unable to find any more words.
1565 done = true;
1568 command_string = command_string.substr(end);
1569 return cmd_obj;
1572 static const char *k_valid_command_chars =
1573 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1574 static void StripLeadingSpaces(std::string &s) {
1575 if (!s.empty()) {
1576 size_t pos = s.find_first_not_of(k_white_space);
1577 if (pos == std::string::npos)
1578 s.clear();
1579 else if (pos == 0)
1580 return;
1581 s.erase(0, pos);
1585 static size_t FindArgumentTerminator(const std::string &s) {
1586 const size_t s_len = s.size();
1587 size_t offset = 0;
1588 while (offset < s_len) {
1589 size_t pos = s.find("--", offset);
1590 if (pos == std::string::npos)
1591 break;
1592 if (pos > 0) {
1593 if (llvm::isSpace(s[pos - 1])) {
1594 // Check if the string ends "\s--" (where \s is a space character) or
1595 // if we have "\s--\s".
1596 if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1597 return pos;
1601 offset = pos + 2;
1603 return std::string::npos;
1606 static bool ExtractCommand(std::string &command_string, std::string &command,
1607 std::string &suffix, char &quote_char) {
1608 command.clear();
1609 suffix.clear();
1610 StripLeadingSpaces(command_string);
1612 bool result = false;
1613 quote_char = '\0';
1615 if (!command_string.empty()) {
1616 const char first_char = command_string[0];
1617 if (first_char == '\'' || first_char == '"') {
1618 quote_char = first_char;
1619 const size_t end_quote_pos = command_string.find(quote_char, 1);
1620 if (end_quote_pos == std::string::npos) {
1621 command.swap(command_string);
1622 command_string.erase();
1623 } else {
1624 command.assign(command_string, 1, end_quote_pos - 1);
1625 if (end_quote_pos + 1 < command_string.size())
1626 command_string.erase(0, command_string.find_first_not_of(
1627 k_white_space, end_quote_pos + 1));
1628 else
1629 command_string.erase();
1631 } else {
1632 const size_t first_space_pos =
1633 command_string.find_first_of(k_white_space);
1634 if (first_space_pos == std::string::npos) {
1635 command.swap(command_string);
1636 command_string.erase();
1637 } else {
1638 command.assign(command_string, 0, first_space_pos);
1639 command_string.erase(0, command_string.find_first_not_of(
1640 k_white_space, first_space_pos));
1643 result = true;
1646 if (!command.empty()) {
1647 // actual commands can't start with '-' or '_'
1648 if (command[0] != '-' && command[0] != '_') {
1649 size_t pos = command.find_first_not_of(k_valid_command_chars);
1650 if (pos > 0 && pos != std::string::npos) {
1651 suffix.assign(command.begin() + pos, command.end());
1652 command.erase(pos);
1657 return result;
1660 CommandObject *CommandInterpreter::BuildAliasResult(
1661 llvm::StringRef alias_name, std::string &raw_input_string,
1662 std::string &alias_result, CommandReturnObject &result) {
1663 CommandObject *alias_cmd_obj = nullptr;
1664 Args cmd_args(raw_input_string);
1665 alias_cmd_obj = GetCommandObject(alias_name);
1666 StreamString result_str;
1668 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1669 alias_result.clear();
1670 return alias_cmd_obj;
1672 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1673 ((CommandAlias *)alias_cmd_obj)->Desugar();
1674 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1675 alias_cmd_obj = desugared.first.get();
1676 std::string alias_name_str = std::string(alias_name);
1677 if ((cmd_args.GetArgumentCount() == 0) ||
1678 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1679 cmd_args.Unshift(alias_name_str);
1681 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1683 if (!option_arg_vector_sp.get()) {
1684 alias_result = std::string(result_str.GetString());
1685 return alias_cmd_obj;
1687 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1689 int value_type;
1690 std::string option;
1691 std::string value;
1692 for (const auto &entry : *option_arg_vector) {
1693 std::tie(option, value_type, value) = entry;
1694 if (option == g_argument) {
1695 result_str.Printf(" %s", value.c_str());
1696 continue;
1699 result_str.Printf(" %s", option.c_str());
1700 if (value_type == OptionParser::eNoArgument)
1701 continue;
1703 if (value_type != OptionParser::eOptionalArgument)
1704 result_str.Printf(" ");
1705 int index = GetOptionArgumentPosition(value.c_str());
1706 if (index == 0)
1707 result_str.Printf("%s", value.c_str());
1708 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1710 result.AppendErrorWithFormat("Not enough arguments provided; you "
1711 "need at least %d arguments to use "
1712 "this alias.\n",
1713 index);
1714 return nullptr;
1715 } else {
1716 const Args::ArgEntry &entry = cmd_args[index];
1717 size_t strpos = raw_input_string.find(entry.c_str());
1718 const char quote_char = entry.GetQuoteChar();
1719 if (strpos != std::string::npos) {
1720 const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1721 const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1723 // Make sure we aren't going outside the bounds of the cmd string:
1724 if (strpos < start_fudge) {
1725 result.AppendError("Unmatched quote at command beginning.");
1726 return nullptr;
1728 llvm::StringRef arg_text = entry.ref();
1729 if (strpos - start_fudge + arg_text.size() + len_fudge >
1730 raw_input_string.size()) {
1731 result.AppendError("Unmatched quote at command end.");
1732 return nullptr;
1734 raw_input_string = raw_input_string.erase(
1735 strpos - start_fudge,
1736 strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1738 if (quote_char == '\0')
1739 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1740 else
1741 result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
1745 alias_result = std::string(result_str.GetString());
1746 return alias_cmd_obj;
1749 Status CommandInterpreter::PreprocessCommand(std::string &command) {
1750 // The command preprocessor needs to do things to the command line before any
1751 // parsing of arguments or anything else is done. The only current stuff that
1752 // gets preprocessed is anything enclosed in backtick ('`') characters is
1753 // evaluated as an expression and the result of the expression must be a
1754 // scalar that can be substituted into the command. An example would be:
1755 // (lldb) memory read `$rsp + 20`
1756 Status error; // Status for any expressions that might not evaluate
1757 size_t start_backtick;
1758 size_t pos = 0;
1759 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1760 // Stop if an error was encountered during the previous iteration.
1761 if (error.Fail())
1762 break;
1764 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1765 // The backtick was preceded by a '\' character, remove the slash and
1766 // don't treat the backtick as the start of an expression.
1767 command.erase(start_backtick - 1, 1);
1768 // No need to add one to start_backtick since we just deleted a char.
1769 pos = start_backtick;
1770 continue;
1773 const size_t expr_content_start = start_backtick + 1;
1774 const size_t end_backtick = command.find('`', expr_content_start);
1776 if (end_backtick == std::string::npos) {
1777 // Stop if there's no end backtick.
1778 break;
1781 if (end_backtick == expr_content_start) {
1782 // Skip over empty expression. (two backticks in a row)
1783 command.erase(start_backtick, 2);
1784 continue;
1787 std::string expr_str(command, expr_content_start,
1788 end_backtick - expr_content_start);
1789 error = PreprocessToken(expr_str);
1790 // We always stop at the first error:
1791 if (error.Fail())
1792 break;
1794 command.erase(start_backtick, end_backtick - start_backtick + 1);
1795 command.insert(start_backtick, std::string(expr_str));
1796 pos = start_backtick + expr_str.size();
1798 return error;
1801 Status
1802 CommandInterpreter::PreprocessToken(std::string &expr_str) {
1803 Status error;
1804 ExecutionContext exe_ctx(GetExecutionContext());
1806 // Get a dummy target to allow for calculator mode while processing
1807 // backticks. This also helps break the infinite loop caused when target is
1808 // null.
1809 Target *exe_target = exe_ctx.GetTargetPtr();
1810 Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1812 ValueObjectSP expr_result_valobj_sp;
1814 EvaluateExpressionOptions options;
1815 options.SetCoerceToId(false);
1816 options.SetUnwindOnError(true);
1817 options.SetIgnoreBreakpoints(true);
1818 options.SetKeepInMemory(false);
1819 options.SetTryAllThreads(true);
1820 options.SetTimeout(std::nullopt);
1822 ExpressionResults expr_result =
1823 target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1824 expr_result_valobj_sp, options);
1826 if (expr_result == eExpressionCompleted) {
1827 Scalar scalar;
1828 if (expr_result_valobj_sp)
1829 expr_result_valobj_sp =
1830 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1831 expr_result_valobj_sp->GetDynamicValueType(), true);
1832 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1834 StreamString value_strm;
1835 const bool show_type = false;
1836 scalar.GetValue(value_strm, show_type);
1837 size_t value_string_size = value_strm.GetSize();
1838 if (value_string_size) {
1839 expr_str = value_strm.GetData();
1840 } else {
1841 error =
1842 Status::FromErrorStringWithFormat("expression value didn't result "
1843 "in a scalar value for the "
1844 "expression '%s'",
1845 expr_str.c_str());
1847 } else {
1848 error =
1849 Status::FromErrorStringWithFormat("expression value didn't result "
1850 "in a scalar value for the "
1851 "expression '%s'",
1852 expr_str.c_str());
1854 return error;
1857 // If we have an error from the expression evaluation it will be in the
1858 // ValueObject error, which won't be success and we will just report it.
1859 // But if for some reason we didn't get a value object at all, then we will
1860 // make up some helpful errors from the expression result.
1861 if (expr_result_valobj_sp)
1862 error = expr_result_valobj_sp->GetError().Clone();
1864 if (error.Success()) {
1865 std::string result = lldb_private::toString(expr_result) +
1866 "for the expression '" + expr_str + "'";
1867 error = Status(result);
1869 return error;
1872 bool CommandInterpreter::HandleCommand(const char *command_line,
1873 LazyBool lazy_add_to_history,
1874 const ExecutionContext &override_context,
1875 CommandReturnObject &result) {
1877 OverrideExecutionContext(override_context);
1878 bool status = HandleCommand(command_line, lazy_add_to_history, result);
1879 RestoreExecutionContext();
1880 return status;
1883 bool CommandInterpreter::HandleCommand(const char *command_line,
1884 LazyBool lazy_add_to_history,
1885 CommandReturnObject &result,
1886 bool force_repeat_command) {
1887 std::string command_string(command_line);
1888 std::string original_command_string(command_string);
1889 std::string real_original_command_string(command_string);
1891 Log *log = GetLog(LLDBLog::Commands);
1892 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1893 command_line);
1895 LLDB_LOGF(log, "Processing command: %s", command_line);
1896 LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1898 if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
1899 result.AppendError("... Interrupted");
1900 return false;
1903 bool add_to_history;
1904 if (lazy_add_to_history == eLazyBoolCalculate)
1905 add_to_history = (m_command_source_depth == 0);
1906 else
1907 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1909 // The same `transcript_item` will be used below to add output and error of
1910 // the command.
1911 StructuredData::DictionarySP transcript_item;
1912 if (GetSaveTranscript()) {
1913 m_transcript_stream << "(lldb) " << command_line << '\n';
1915 transcript_item = std::make_shared<StructuredData::Dictionary>();
1916 transcript_item->AddStringItem("command", command_line);
1917 transcript_item->AddIntegerItem(
1918 "timestampInEpochSeconds",
1919 std::chrono::duration_cast<std::chrono::seconds>(
1920 std::chrono::system_clock::now().time_since_epoch())
1921 .count());
1922 m_transcript.AddItem(transcript_item);
1925 bool empty_command = false;
1926 bool comment_command = false;
1927 if (command_string.empty())
1928 empty_command = true;
1929 else {
1930 const char *k_space_characters = "\t\n\v\f\r ";
1932 size_t non_space = command_string.find_first_not_of(k_space_characters);
1933 // Check for empty line or comment line (lines whose first non-space
1934 // character is the comment character for this interpreter)
1935 if (non_space == std::string::npos)
1936 empty_command = true;
1937 else if (command_string[non_space] == m_comment_char)
1938 comment_command = true;
1939 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1940 llvm::StringRef search_str(command_string);
1941 search_str = search_str.drop_front(non_space);
1942 if (auto hist_str = m_command_history.FindString(search_str)) {
1943 add_to_history = false;
1944 command_string = std::string(*hist_str);
1945 original_command_string = std::string(*hist_str);
1946 } else {
1947 result.AppendErrorWithFormat("Could not find entry: %s in history",
1948 command_string.c_str());
1949 return false;
1954 if (empty_command) {
1955 if (!GetRepeatPreviousCommand()) {
1956 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1957 return true;
1960 if (m_command_history.IsEmpty()) {
1961 result.AppendError("empty command");
1962 return false;
1965 command_line = m_repeat_command.c_str();
1966 command_string = command_line;
1967 original_command_string = command_line;
1968 if (m_repeat_command.empty()) {
1969 result.AppendError("No auto repeat.");
1970 return false;
1973 add_to_history = false;
1974 } else if (comment_command) {
1975 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1976 return true;
1979 // Phase 1.
1981 // Before we do ANY kind of argument processing, we need to figure out what
1982 // the real/final command object is for the specified command. This gets
1983 // complicated by the fact that the user could have specified an alias, and,
1984 // in translating the alias, there may also be command options and/or even
1985 // data (including raw text strings) that need to be found and inserted into
1986 // the command line as part of the translation. So this first step is plain
1987 // look-up and replacement, resulting in:
1988 // 1. the command object whose Execute method will actually be called
1989 // 2. a revised command string, with all substitutions and replacements
1990 // taken care of
1991 // From 1 above, we can determine whether the Execute function wants raw
1992 // input or not.
1994 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1996 // We have to preprocess the whole command string for Raw commands, since we
1997 // don't know the structure of the command. For parsed commands, we only
1998 // treat backticks as quote characters specially.
1999 // FIXME: We probably want to have raw commands do their own preprocessing.
2000 // For instance, I don't think people expect substitution in expr expressions.
2001 if (cmd_obj && cmd_obj->WantsRawCommandString()) {
2002 Status error(PreprocessCommand(command_string));
2004 if (error.Fail()) {
2005 result.AppendError(error.AsCString());
2006 return false;
2010 // Although the user may have abbreviated the command, the command_string now
2011 // has the command expanded to the full name. For example, if the input was
2012 // "br s -n main", command_string is now "breakpoint set -n main".
2013 if (log) {
2014 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
2015 LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
2016 LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
2017 command_string.c_str());
2018 const bool wants_raw_input =
2019 (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
2020 LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
2021 wants_raw_input ? "True" : "False");
2024 // Phase 2.
2025 // Take care of things like setting up the history command & calling the
2026 // appropriate Execute method on the CommandObject, with the appropriate
2027 // arguments.
2028 StatsDuration execute_time;
2029 if (cmd_obj != nullptr) {
2030 bool generate_repeat_command = add_to_history;
2031 // If we got here when empty_command was true, then this command is a
2032 // stored "repeat command" which we should give a chance to produce it's
2033 // repeat command, even though we don't add repeat commands to the history.
2034 generate_repeat_command |= empty_command;
2035 // For `command regex`, the regex command (ex `bt`) is added to history, but
2036 // the resolved command (ex `thread backtrace`) is _not_ added to history.
2037 // However, the resolved command must be given the opportunity to provide a
2038 // repeat command. `force_repeat_command` supports this case.
2039 generate_repeat_command |= force_repeat_command;
2040 if (generate_repeat_command) {
2041 Args command_args(command_string);
2042 std::optional<std::string> repeat_command =
2043 cmd_obj->GetRepeatCommand(command_args, 0);
2044 if (repeat_command) {
2045 LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
2046 m_repeat_command.assign(*repeat_command);
2047 } else {
2048 m_repeat_command.assign(original_command_string);
2052 if (add_to_history)
2053 m_command_history.AppendString(original_command_string);
2055 std::string remainder;
2056 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2057 if (actual_cmd_name_len < command_string.length())
2058 remainder = command_string.substr(actual_cmd_name_len);
2060 // Remove any initial spaces
2061 size_t pos = remainder.find_first_not_of(k_white_space);
2062 if (pos != 0 && pos != std::string::npos)
2063 remainder.erase(0, pos);
2065 LLDB_LOGF(
2066 log, "HandleCommand, command line after removing command name(s): '%s'",
2067 remainder.c_str());
2069 // To test whether or not transcript should be saved, `transcript_item` is
2070 // used instead of `GetSaveTranscript()`. This is because the latter will
2071 // fail when the command is "settings set interpreter.save-transcript true".
2072 if (transcript_item) {
2073 transcript_item->AddStringItem("commandName", cmd_obj->GetCommandName());
2074 transcript_item->AddStringItem("commandArguments", remainder);
2077 ElapsedTime elapsed(execute_time);
2078 cmd_obj->SetOriginalCommandString(real_original_command_string);
2079 // Set the indent to the position of the command in the command line.
2080 pos = real_original_command_string.rfind(remainder);
2081 std::optional<uint16_t> indent;
2082 if (pos != std::string::npos)
2083 indent = pos;
2084 result.SetDiagnosticIndent(indent);
2085 cmd_obj->Execute(remainder.c_str(), result);
2088 LLDB_LOGF(log, "HandleCommand, command %s",
2089 (result.Succeeded() ? "succeeded" : "did not succeed"));
2091 // To test whether or not transcript should be saved, `transcript_item` is
2092 // used instead of `GetSaveTrasncript()`. This is because the latter will
2093 // fail when the command is "settings set interpreter.save-transcript true".
2094 if (transcript_item) {
2095 m_transcript_stream << result.GetOutputString();
2096 m_transcript_stream << result.GetErrorString();
2098 transcript_item->AddStringItem("output", result.GetOutputString());
2099 transcript_item->AddStringItem("error", result.GetErrorString());
2100 transcript_item->AddFloatItem("durationInSeconds",
2101 execute_time.get().count());
2104 return result.Succeeded();
2107 void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
2108 bool look_for_subcommand = false;
2110 // For any of the command completions a unique match will be a complete word.
2112 if (request.GetParsedLine().GetArgumentCount() == 0) {
2113 // We got nothing on the command line, so return the list of commands
2114 bool include_aliases = true;
2115 StringList new_matches, descriptions;
2116 GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2117 descriptions);
2118 request.AddCompletions(new_matches, descriptions);
2119 } else if (request.GetCursorIndex() == 0) {
2120 // The cursor is in the first argument, so just do a lookup in the
2121 // dictionary.
2122 StringList new_matches, new_descriptions;
2123 CommandObject *cmd_obj =
2124 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
2125 &new_matches, &new_descriptions);
2127 if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2128 new_matches.GetStringAtIndex(0) != nullptr &&
2129 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2130 new_matches.GetStringAtIndex(0)) == 0) {
2131 if (request.GetParsedLine().GetArgumentCount() != 1) {
2132 look_for_subcommand = true;
2133 new_matches.DeleteStringAtIndex(0);
2134 new_descriptions.DeleteStringAtIndex(0);
2135 request.AppendEmptyArgument();
2138 request.AddCompletions(new_matches, new_descriptions);
2141 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2142 // We are completing further on into a commands arguments, so find the
2143 // command and tell it to complete the command. First see if there is a
2144 // matching initial command:
2145 CommandObject *command_object =
2146 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
2147 if (command_object) {
2148 request.ShiftArguments();
2149 command_object->HandleCompletion(request);
2154 void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
2156 // Don't complete comments, and if the line we are completing is just the
2157 // history repeat character, substitute the appropriate history line.
2158 llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2160 if (!first_arg.empty()) {
2161 if (first_arg.front() == m_comment_char)
2162 return;
2163 if (first_arg.front() == CommandHistory::g_repeat_char) {
2164 if (auto hist_str = m_command_history.FindString(first_arg))
2165 request.AddCompletion(*hist_str, "Previous command history event",
2166 CompletionMode::RewriteLine);
2167 return;
2171 HandleCompletionMatches(request);
2174 std::optional<std::string>
2175 CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) {
2176 if (line.empty())
2177 return std::nullopt;
2178 const size_t s = m_command_history.GetSize();
2179 for (int i = s - 1; i >= 0; --i) {
2180 llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2181 if (entry.consume_front(line))
2182 return entry.str();
2184 return std::nullopt;
2187 void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2188 EventSP prompt_change_event_sp(
2189 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2191 BroadcastEvent(prompt_change_event_sp);
2192 if (m_command_io_handler_sp)
2193 m_command_io_handler_sp->SetPrompt(new_prompt);
2196 bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2197 // Check AutoConfirm first:
2198 if (m_debugger.GetAutoConfirm())
2199 return default_answer;
2201 IOHandlerConfirm *confirm =
2202 new IOHandlerConfirm(m_debugger, message, default_answer);
2203 IOHandlerSP io_handler_sp(confirm);
2204 m_debugger.RunIOHandlerSync(io_handler_sp);
2205 return confirm->GetResponse();
2208 const CommandAlias *
2209 CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2210 OptionArgVectorSP ret_val;
2212 auto pos = m_alias_dict.find(alias_name);
2213 if (pos != m_alias_dict.end())
2214 return (CommandAlias *)pos->second.get();
2216 return nullptr;
2219 bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2221 bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2223 bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2225 bool CommandInterpreter::HasUserMultiwordCommands() const {
2226 return (!m_user_mw_dict.empty());
2229 bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
2231 void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
2232 const char *alias_name,
2233 Args &cmd_args,
2234 std::string &raw_input_string,
2235 CommandReturnObject &result) {
2236 OptionArgVectorSP option_arg_vector_sp =
2237 GetAlias(alias_name)->GetOptionArguments();
2239 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2241 // Make sure that the alias name is the 0th element in cmd_args
2242 std::string alias_name_str = alias_name;
2243 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2244 cmd_args.Unshift(alias_name_str);
2246 Args new_args(alias_cmd_obj->GetCommandName());
2247 if (new_args.GetArgumentCount() == 2)
2248 new_args.Shift();
2250 if (option_arg_vector_sp.get()) {
2251 if (wants_raw_input) {
2252 // We have a command that both has command options and takes raw input.
2253 // Make *sure* it has a " -- " in the right place in the
2254 // raw_input_string.
2255 size_t pos = raw_input_string.find(" -- ");
2256 if (pos == std::string::npos) {
2257 // None found; assume it goes at the beginning of the raw input string
2258 raw_input_string.insert(0, " -- ");
2262 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2263 const size_t old_size = cmd_args.GetArgumentCount();
2264 std::vector<bool> used(old_size + 1, false);
2266 used[0] = true;
2268 int value_type;
2269 std::string option;
2270 std::string value;
2271 for (const auto &option_entry : *option_arg_vector) {
2272 std::tie(option, value_type, value) = option_entry;
2273 if (option == g_argument) {
2274 if (!wants_raw_input || (value != "--")) {
2275 // Since we inserted this above, make sure we don't insert it twice
2276 new_args.AppendArgument(value);
2278 continue;
2281 if (value_type != OptionParser::eOptionalArgument)
2282 new_args.AppendArgument(option);
2284 if (value == g_no_argument)
2285 continue;
2287 int index = GetOptionArgumentPosition(value.c_str());
2288 if (index == 0) {
2289 // value was NOT a positional argument; must be a real value
2290 if (value_type != OptionParser::eOptionalArgument)
2291 new_args.AppendArgument(value);
2292 else {
2293 new_args.AppendArgument(option + value);
2296 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2297 result.AppendErrorWithFormat("Not enough arguments provided; you "
2298 "need at least %d arguments to use "
2299 "this alias.\n",
2300 index);
2301 return;
2302 } else {
2303 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2304 size_t strpos =
2305 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2306 if (strpos != std::string::npos) {
2307 raw_input_string = raw_input_string.erase(
2308 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2311 if (value_type != OptionParser::eOptionalArgument)
2312 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2313 else {
2314 new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2316 used[index] = true;
2320 for (auto entry : llvm::enumerate(cmd_args.entries())) {
2321 if (!used[entry.index()] && !wants_raw_input)
2322 new_args.AppendArgument(entry.value().ref());
2325 cmd_args.Clear();
2326 cmd_args.SetArguments(new_args.GetArgumentCount(),
2327 new_args.GetConstArgumentVector());
2328 } else {
2329 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2330 // This alias was not created with any options; nothing further needs to be
2331 // done, unless it is a command that wants raw input, in which case we need
2332 // to clear the rest of the data from cmd_args, since its in the raw input
2333 // string.
2334 if (wants_raw_input) {
2335 cmd_args.Clear();
2336 cmd_args.SetArguments(new_args.GetArgumentCount(),
2337 new_args.GetConstArgumentVector());
2339 return;
2342 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2345 int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2346 int position = 0; // Any string that isn't an argument position, i.e. '%'
2347 // followed by an integer, gets a position
2348 // of zero.
2350 const char *cptr = in_string;
2352 // Does it start with '%'
2353 if (cptr[0] == '%') {
2354 ++cptr;
2356 // Is the rest of it entirely digits?
2357 if (isdigit(cptr[0])) {
2358 const char *start = cptr;
2359 while (isdigit(cptr[0]))
2360 ++cptr;
2362 // We've gotten to the end of the digits; are we at the end of the
2363 // string?
2364 if (cptr[0] == '\0')
2365 position = atoi(start);
2369 return position;
2372 static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2373 llvm::StringRef suffix = {}) {
2374 std::string init_file_name = ".lldbinit";
2375 if (!suffix.empty()) {
2376 init_file_name.append("-");
2377 init_file_name.append(suffix.str());
2380 FileSystem::Instance().GetHomeDirectory(init_file);
2381 llvm::sys::path::append(init_file, init_file_name);
2383 FileSystem::Instance().Resolve(init_file);
2386 static void GetHomeREPLInitFile(llvm::SmallVectorImpl<char> &init_file,
2387 LanguageType language) {
2388 if (language == eLanguageTypeUnknown) {
2389 LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs();
2390 if (auto main_repl_language = repl_languages.GetSingularLanguage())
2391 language = *main_repl_language;
2392 else
2393 return;
2396 std::string init_file_name =
2397 (llvm::Twine(".lldbinit-") +
2398 llvm::Twine(Language::GetNameForLanguageType(language)) +
2399 llvm::Twine("-repl"))
2400 .str();
2401 FileSystem::Instance().GetHomeDirectory(init_file);
2402 llvm::sys::path::append(init_file, init_file_name);
2403 FileSystem::Instance().Resolve(init_file);
2406 static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
2407 llvm::StringRef s = ".lldbinit";
2408 init_file.assign(s.begin(), s.end());
2409 FileSystem::Instance().Resolve(init_file);
2412 void CommandInterpreter::SourceInitFile(FileSpec file,
2413 CommandReturnObject &result) {
2414 assert(!m_skip_lldbinit_files);
2416 if (!FileSystem::Instance().Exists(file)) {
2417 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2418 return;
2421 // Use HandleCommand to 'source' the given file; this will do the actual
2422 // broadcasting of the commands back to any appropriate listener (see
2423 // CommandObjectSource::Execute for more details).
2424 const bool saved_batch = SetBatchCommandMode(true);
2425 CommandInterpreterRunOptions options;
2426 options.SetSilent(true);
2427 options.SetPrintErrors(true);
2428 options.SetStopOnError(false);
2429 options.SetStopOnContinue(true);
2430 HandleCommandsFromFile(file, options, result);
2431 SetBatchCommandMode(saved_batch);
2434 void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
2435 if (m_skip_lldbinit_files) {
2436 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2437 return;
2440 llvm::SmallString<128> init_file;
2441 GetCwdInitFile(init_file);
2442 if (!FileSystem::Instance().Exists(init_file)) {
2443 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2444 return;
2447 LoadCWDlldbinitFile should_load =
2448 Target::GetGlobalProperties().GetLoadCWDlldbinitFile();
2450 switch (should_load) {
2451 case eLoadCWDlldbinitFalse:
2452 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2453 break;
2454 case eLoadCWDlldbinitTrue:
2455 SourceInitFile(FileSpec(init_file.str()), result);
2456 break;
2457 case eLoadCWDlldbinitWarn: {
2458 llvm::SmallString<128> home_init_file;
2459 GetHomeInitFile(home_init_file);
2460 if (llvm::sys::path::parent_path(init_file) ==
2461 llvm::sys::path::parent_path(home_init_file)) {
2462 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2463 } else {
2464 result.AppendError(InitFileWarning);
2470 /// We will first see if there is an application specific ".lldbinit" file
2471 /// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2472 /// If this file doesn't exist, we fall back to the REPL init file or the
2473 /// default home init file in "~/.lldbinit".
2474 void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result,
2475 bool is_repl) {
2476 if (m_skip_lldbinit_files) {
2477 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2478 return;
2481 llvm::SmallString<128> init_file;
2483 if (is_repl)
2484 GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2486 if (init_file.empty())
2487 GetHomeInitFile(init_file);
2489 if (!m_skip_app_init_files) {
2490 llvm::StringRef program_name =
2491 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2492 llvm::SmallString<128> program_init_file;
2493 GetHomeInitFile(program_init_file, program_name);
2494 if (FileSystem::Instance().Exists(program_init_file))
2495 init_file = program_init_file;
2498 SourceInitFile(FileSpec(init_file.str()), result);
2501 void CommandInterpreter::SourceInitFileGlobal(CommandReturnObject &result) {
2502 #ifdef LLDB_GLOBAL_INIT_DIRECTORY
2503 if (!m_skip_lldbinit_files) {
2504 FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2505 if (init_file)
2506 init_file.MakeAbsolute(HostInfo::GetShlibDir());
2508 init_file.AppendPathComponent("lldbinit");
2509 SourceInitFile(init_file, result);
2510 return;
2512 #endif
2513 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2516 const char *CommandInterpreter::GetCommandPrefix() {
2517 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2518 return prefix == nullptr ? "" : prefix;
2521 PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2522 PlatformSP platform_sp;
2523 if (prefer_target_platform) {
2524 ExecutionContext exe_ctx(GetExecutionContext());
2525 Target *target = exe_ctx.GetTargetPtr();
2526 if (target)
2527 platform_sp = target->GetPlatform();
2530 if (!platform_sp)
2531 platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2532 return platform_sp;
2535 bool CommandInterpreter::DidProcessStopAbnormally() const {
2536 auto exe_ctx = GetExecutionContext();
2537 TargetSP target_sp = exe_ctx.GetTargetSP();
2538 if (!target_sp)
2539 return false;
2541 ProcessSP process_sp(target_sp->GetProcessSP());
2542 if (!process_sp)
2543 return false;
2545 if (eStateStopped != process_sp->GetState())
2546 return false;
2548 for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2549 StopInfoSP stop_info = thread_sp->GetStopInfo();
2550 if (!stop_info) {
2551 // If there's no stop_info, keep iterating through the other threads;
2552 // it's enough that any thread has got a stop_info that indicates
2553 // an abnormal stop, to consider the process to be stopped abnormally.
2554 continue;
2557 const StopReason reason = stop_info->GetStopReason();
2558 if (reason == eStopReasonException ||
2559 reason == eStopReasonInstrumentation ||
2560 reason == eStopReasonProcessorTrace || reason == eStopReasonInterrupt)
2561 return true;
2563 if (reason == eStopReasonSignal) {
2564 const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2565 UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2566 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2567 // The signal is unknown, treat it as abnormal.
2568 return true;
2570 const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2571 const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2572 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2573 // The signal very likely implies a crash.
2574 return true;
2578 return false;
2581 void
2582 CommandInterpreter::HandleCommands(const StringList &commands,
2583 const ExecutionContext &override_context,
2584 const CommandInterpreterRunOptions &options,
2585 CommandReturnObject &result) {
2587 OverrideExecutionContext(override_context);
2588 HandleCommands(commands, options, result);
2589 RestoreExecutionContext();
2592 void CommandInterpreter::HandleCommands(const StringList &commands,
2593 const CommandInterpreterRunOptions &options,
2594 CommandReturnObject &result) {
2595 size_t num_lines = commands.GetSize();
2597 // If we are going to continue past a "continue" then we need to run the
2598 // commands synchronously. Make sure you reset this value anywhere you return
2599 // from the function.
2601 bool old_async_execution = m_debugger.GetAsyncExecution();
2603 if (!options.GetStopOnContinue()) {
2604 m_debugger.SetAsyncExecution(false);
2607 for (size_t idx = 0; idx < num_lines; idx++) {
2608 const char *cmd = commands.GetStringAtIndex(idx);
2609 if (cmd[0] == '\0')
2610 continue;
2612 if (options.GetEchoCommands()) {
2613 // TODO: Add Stream support.
2614 result.AppendMessageWithFormat("%s %s\n",
2615 m_debugger.GetPrompt().str().c_str(), cmd);
2618 CommandReturnObject tmp_result(m_debugger.GetUseColor());
2619 tmp_result.SetInteractive(result.GetInteractive());
2620 tmp_result.SetSuppressImmediateOutput(true);
2622 // We might call into a regex or alias command, in which case the
2623 // add_to_history will get lost. This m_command_source_depth dingus is the
2624 // way we turn off adding to the history in that case, so set it up here.
2625 if (!options.GetAddToHistory())
2626 m_command_source_depth++;
2627 bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2628 if (!options.GetAddToHistory())
2629 m_command_source_depth--;
2631 if (options.GetPrintResults()) {
2632 if (tmp_result.Succeeded())
2633 result.AppendMessage(tmp_result.GetOutputString());
2636 if (!success || !tmp_result.Succeeded()) {
2637 std::string error_msg = tmp_result.GetErrorString();
2638 if (error_msg.empty())
2639 error_msg = "<unknown error>.\n";
2640 if (options.GetStopOnError()) {
2641 result.AppendErrorWithFormatv("Aborting reading of commands after "
2642 "command #{0}: '{1}' failed with {2}",
2643 (uint64_t)idx, cmd, error_msg);
2644 m_debugger.SetAsyncExecution(old_async_execution);
2645 return;
2646 } else if (options.GetPrintResults()) {
2647 result.AppendMessageWithFormatv("Command #{0} '{1}' failed with {2}",
2648 (uint64_t)idx + 1, cmd, error_msg);
2652 if (result.GetImmediateOutputStream())
2653 result.GetImmediateOutputStream()->Flush();
2655 if (result.GetImmediateErrorStream())
2656 result.GetImmediateErrorStream()->Flush();
2658 // N.B. Can't depend on DidChangeProcessState, because the state coming
2659 // into the command execution could be running (for instance in Breakpoint
2660 // Commands. So we check the return value to see if it is has running in
2661 // it.
2662 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2663 (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2664 if (options.GetStopOnContinue()) {
2665 // If we caused the target to proceed, and we're going to stop in that
2666 // case, set the status in our real result before returning. This is
2667 // an error if the continue was not the last command in the set of
2668 // commands to be run.
2669 if (idx != num_lines - 1)
2670 result.AppendErrorWithFormat(
2671 "Aborting reading of commands after command #%" PRIu64
2672 ": '%s' continued the target.\n",
2673 (uint64_t)idx + 1, cmd);
2674 else
2675 result.AppendMessageWithFormat("Command #%" PRIu64
2676 " '%s' continued the target.\n",
2677 (uint64_t)idx + 1, cmd);
2679 result.SetStatus(tmp_result.GetStatus());
2680 m_debugger.SetAsyncExecution(old_async_execution);
2682 return;
2686 // Also check for "stop on crash here:
2687 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2688 DidProcessStopAbnormally()) {
2689 if (idx != num_lines - 1)
2690 result.AppendErrorWithFormat(
2691 "Aborting reading of commands after command #%" PRIu64
2692 ": '%s' stopped with a signal or exception.\n",
2693 (uint64_t)idx + 1, cmd);
2694 else
2695 result.AppendMessageWithFormat(
2696 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2697 (uint64_t)idx + 1, cmd);
2699 result.SetStatus(tmp_result.GetStatus());
2700 m_debugger.SetAsyncExecution(old_async_execution);
2702 return;
2706 result.SetStatus(eReturnStatusSuccessFinishResult);
2707 m_debugger.SetAsyncExecution(old_async_execution);
2710 // Make flags that we can pass into the IOHandler so our delegates can do the
2711 // right thing
2712 enum {
2713 eHandleCommandFlagStopOnContinue = (1u << 0),
2714 eHandleCommandFlagStopOnError = (1u << 1),
2715 eHandleCommandFlagEchoCommand = (1u << 2),
2716 eHandleCommandFlagEchoCommentCommand = (1u << 3),
2717 eHandleCommandFlagPrintResult = (1u << 4),
2718 eHandleCommandFlagPrintErrors = (1u << 5),
2719 eHandleCommandFlagStopOnCrash = (1u << 6),
2720 eHandleCommandFlagAllowRepeats = (1u << 7)
2723 void CommandInterpreter::HandleCommandsFromFile(
2724 FileSpec &cmd_file, const ExecutionContext &context,
2725 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2726 OverrideExecutionContext(context);
2727 HandleCommandsFromFile(cmd_file, options, result);
2728 RestoreExecutionContext();
2731 void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file,
2732 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2733 if (!FileSystem::Instance().Exists(cmd_file)) {
2734 result.AppendErrorWithFormat(
2735 "Error reading commands from file %s - file not found.\n",
2736 cmd_file.GetFilename().AsCString("<Unknown>"));
2737 return;
2740 std::string cmd_file_path = cmd_file.GetPath();
2741 auto input_file_up =
2742 FileSystem::Instance().Open(cmd_file, File::eOpenOptionReadOnly);
2743 if (!input_file_up) {
2744 std::string error = llvm::toString(input_file_up.takeError());
2745 result.AppendErrorWithFormatv(
2746 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2747 llvm::fmt_consume(input_file_up.takeError()));
2748 return;
2750 FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2752 Debugger &debugger = GetDebugger();
2754 uint32_t flags = 0;
2756 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2757 if (m_command_source_flags.empty()) {
2758 // Stop on continue by default
2759 flags |= eHandleCommandFlagStopOnContinue;
2760 } else if (m_command_source_flags.back() &
2761 eHandleCommandFlagStopOnContinue) {
2762 flags |= eHandleCommandFlagStopOnContinue;
2764 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2765 flags |= eHandleCommandFlagStopOnContinue;
2768 if (options.m_stop_on_error == eLazyBoolCalculate) {
2769 if (m_command_source_flags.empty()) {
2770 if (GetStopCmdSourceOnError())
2771 flags |= eHandleCommandFlagStopOnError;
2772 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2773 flags |= eHandleCommandFlagStopOnError;
2775 } else if (options.m_stop_on_error == eLazyBoolYes) {
2776 flags |= eHandleCommandFlagStopOnError;
2779 // stop-on-crash can only be set, if it is present in all levels of
2780 // pushed flag sets.
2781 if (options.GetStopOnCrash()) {
2782 if (m_command_source_flags.empty()) {
2783 flags |= eHandleCommandFlagStopOnCrash;
2784 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2785 flags |= eHandleCommandFlagStopOnCrash;
2789 if (options.m_echo_commands == eLazyBoolCalculate) {
2790 if (m_command_source_flags.empty()) {
2791 // Echo command by default
2792 flags |= eHandleCommandFlagEchoCommand;
2793 } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2794 flags |= eHandleCommandFlagEchoCommand;
2796 } else if (options.m_echo_commands == eLazyBoolYes) {
2797 flags |= eHandleCommandFlagEchoCommand;
2800 // We will only ever ask for this flag, if we echo commands in general.
2801 if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2802 if (m_command_source_flags.empty()) {
2803 // Echo comments by default
2804 flags |= eHandleCommandFlagEchoCommentCommand;
2805 } else if (m_command_source_flags.back() &
2806 eHandleCommandFlagEchoCommentCommand) {
2807 flags |= eHandleCommandFlagEchoCommentCommand;
2809 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2810 flags |= eHandleCommandFlagEchoCommentCommand;
2813 if (options.m_print_results == eLazyBoolCalculate) {
2814 if (m_command_source_flags.empty()) {
2815 // Print output by default
2816 flags |= eHandleCommandFlagPrintResult;
2817 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2818 flags |= eHandleCommandFlagPrintResult;
2820 } else if (options.m_print_results == eLazyBoolYes) {
2821 flags |= eHandleCommandFlagPrintResult;
2824 if (options.m_print_errors == eLazyBoolCalculate) {
2825 if (m_command_source_flags.empty()) {
2826 // Print output by default
2827 flags |= eHandleCommandFlagPrintErrors;
2828 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2829 flags |= eHandleCommandFlagPrintErrors;
2831 } else if (options.m_print_errors == eLazyBoolYes) {
2832 flags |= eHandleCommandFlagPrintErrors;
2835 if (flags & eHandleCommandFlagPrintResult) {
2836 debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2837 cmd_file_path.c_str());
2840 // Used for inheriting the right settings when "command source" might
2841 // have nested "command source" commands
2842 lldb::StreamFileSP empty_stream_sp;
2843 m_command_source_flags.push_back(flags);
2844 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2845 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2846 empty_stream_sp, // Pass in an empty stream so we inherit the top
2847 // input reader output stream
2848 empty_stream_sp, // Pass in an empty stream so we inherit the top
2849 // input reader error stream
2850 flags,
2851 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2852 // or written
2853 debugger.GetPrompt(), llvm::StringRef(),
2854 false, // Not multi-line
2855 debugger.GetUseColor(), 0, *this));
2856 const bool old_async_execution = debugger.GetAsyncExecution();
2858 // Set synchronous execution if we are not stopping on continue
2859 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2860 debugger.SetAsyncExecution(false);
2862 m_command_source_depth++;
2863 m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent());
2865 debugger.RunIOHandlerSync(io_handler_sp);
2866 if (!m_command_source_flags.empty())
2867 m_command_source_flags.pop_back();
2869 m_command_source_dirs.pop_back();
2870 m_command_source_depth--;
2872 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2873 debugger.SetAsyncExecution(old_async_execution);
2876 bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2878 void CommandInterpreter::SetSynchronous(bool value) {
2879 m_synchronous_execution = value;
2882 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2883 llvm::StringRef prefix,
2884 llvm::StringRef help_text) {
2885 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2887 size_t line_width_max = max_columns - prefix.size();
2888 if (line_width_max < 16)
2889 line_width_max = help_text.size() + prefix.size();
2891 strm.IndentMore(prefix.size());
2892 bool prefixed_yet = false;
2893 // Even if we have no help text we still want to emit the command name.
2894 if (help_text.empty())
2895 help_text = "No help text";
2896 while (!help_text.empty()) {
2897 // Prefix the first line, indent subsequent lines to line up
2898 if (!prefixed_yet) {
2899 strm << prefix;
2900 prefixed_yet = true;
2901 } else
2902 strm.Indent();
2904 // Never print more than the maximum on one line.
2905 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2907 // Always break on an explicit newline.
2908 std::size_t first_newline = this_line.find_first_of("\n");
2910 // Don't break on space/tab unless the text is too long to fit on one line.
2911 std::size_t last_space = llvm::StringRef::npos;
2912 if (this_line.size() != help_text.size())
2913 last_space = this_line.find_last_of(" \t");
2915 // Break at whichever condition triggered first.
2916 this_line = this_line.substr(0, std::min(first_newline, last_space));
2917 strm.PutCString(this_line);
2918 strm.EOL();
2920 // Remove whitespace / newlines after breaking.
2921 help_text = help_text.drop_front(this_line.size()).ltrim();
2923 strm.IndentLess(prefix.size());
2926 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2927 llvm::StringRef word_text,
2928 llvm::StringRef separator,
2929 llvm::StringRef help_text,
2930 size_t max_word_len) {
2931 StreamString prefix_stream;
2932 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2933 (int)separator.size(), separator.data());
2934 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2937 void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2938 llvm::StringRef separator,
2939 llvm::StringRef help_text,
2940 uint32_t max_word_len) {
2941 int indent_size = max_word_len + separator.size() + 2;
2943 strm.IndentMore(indent_size);
2945 StreamString text_strm;
2946 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2947 text_strm << separator << " " << help_text;
2949 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2951 llvm::StringRef text = text_strm.GetString();
2953 uint32_t chars_left = max_columns;
2955 auto nextWordLength = [](llvm::StringRef S) {
2956 size_t pos = S.find(' ');
2957 return pos == llvm::StringRef::npos ? S.size() : pos;
2960 while (!text.empty()) {
2961 if (text.front() == '\n' ||
2962 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2963 strm.EOL();
2964 strm.Indent();
2965 chars_left = max_columns - indent_size;
2966 if (text.front() == '\n')
2967 text = text.drop_front();
2968 else
2969 text = text.ltrim(' ');
2970 } else {
2971 strm.PutChar(text.front());
2972 --chars_left;
2973 text = text.drop_front();
2977 strm.EOL();
2978 strm.IndentLess(indent_size);
2981 void CommandInterpreter::FindCommandsForApropos(
2982 llvm::StringRef search_word, StringList &commands_found,
2983 StringList &commands_help, const CommandObject::CommandMap &command_map) {
2984 for (const auto &pair : command_map) {
2985 llvm::StringRef command_name = pair.first;
2986 CommandObject *cmd_obj = pair.second.get();
2988 const bool search_short_help = true;
2989 const bool search_long_help = false;
2990 const bool search_syntax = false;
2991 const bool search_options = false;
2992 if (command_name.contains_insensitive(search_word) ||
2993 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2994 search_long_help, search_syntax,
2995 search_options)) {
2996 commands_found.AppendString(command_name);
2997 commands_help.AppendString(cmd_obj->GetHelp());
3000 if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
3001 StringList subcommands_found;
3002 FindCommandsForApropos(search_word, subcommands_found, commands_help,
3003 multiword_cmd->GetSubcommandDictionary());
3004 for (const auto &subcommand_name : subcommands_found) {
3005 std::string qualified_name =
3006 (command_name + " " + subcommand_name).str();
3007 commands_found.AppendString(qualified_name);
3013 void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
3014 StringList &commands_found,
3015 StringList &commands_help,
3016 bool search_builtin_commands,
3017 bool search_user_commands,
3018 bool search_alias_commands,
3019 bool search_user_mw_commands) {
3020 CommandObject::CommandMap::const_iterator pos;
3022 if (search_builtin_commands)
3023 FindCommandsForApropos(search_word, commands_found, commands_help,
3024 m_command_dict);
3026 if (search_user_commands)
3027 FindCommandsForApropos(search_word, commands_found, commands_help,
3028 m_user_dict);
3030 if (search_user_mw_commands)
3031 FindCommandsForApropos(search_word, commands_found, commands_help,
3032 m_user_mw_dict);
3034 if (search_alias_commands)
3035 FindCommandsForApropos(search_word, commands_found, commands_help,
3036 m_alias_dict);
3039 ExecutionContext CommandInterpreter::GetExecutionContext() const {
3040 return !m_overriden_exe_contexts.empty()
3041 ? m_overriden_exe_contexts.top()
3042 : m_debugger.GetSelectedExecutionContext();
3045 void CommandInterpreter::OverrideExecutionContext(
3046 const ExecutionContext &override_context) {
3047 m_overriden_exe_contexts.push(override_context);
3050 void CommandInterpreter::RestoreExecutionContext() {
3051 if (!m_overriden_exe_contexts.empty())
3052 m_overriden_exe_contexts.pop();
3055 void CommandInterpreter::GetProcessOutput() {
3056 if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
3057 m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
3058 /*flush_stderr*/ true);
3061 void CommandInterpreter::StartHandlingCommand() {
3062 auto idle_state = CommandHandlingState::eIdle;
3063 if (m_command_state.compare_exchange_strong(
3064 idle_state, CommandHandlingState::eInProgress))
3065 lldbassert(m_iohandler_nesting_level == 0);
3066 else
3067 lldbassert(m_iohandler_nesting_level > 0);
3068 ++m_iohandler_nesting_level;
3071 void CommandInterpreter::FinishHandlingCommand() {
3072 lldbassert(m_iohandler_nesting_level > 0);
3073 if (--m_iohandler_nesting_level == 0) {
3074 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3075 lldbassert(prev_state != CommandHandlingState::eIdle);
3079 bool CommandInterpreter::InterruptCommand() {
3080 auto in_progress = CommandHandlingState::eInProgress;
3081 return m_command_state.compare_exchange_strong(
3082 in_progress, CommandHandlingState::eInterrupted);
3085 bool CommandInterpreter::WasInterrupted() const {
3086 if (!m_debugger.IsIOHandlerThreadCurrentThread())
3087 return false;
3089 bool was_interrupted =
3090 (m_command_state == CommandHandlingState::eInterrupted);
3091 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3092 return was_interrupted;
3095 void CommandInterpreter::PrintCommandOutput(IOHandler &io_handler,
3096 llvm::StringRef str,
3097 bool is_stdout) {
3099 lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3100 : io_handler.GetErrorStreamFileSP();
3101 // Split the output into lines and poll for interrupt requests
3102 bool had_output = !str.empty();
3103 while (!str.empty()) {
3104 llvm::StringRef line;
3105 std::tie(line, str) = str.split('\n');
3107 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3108 stream->Write(line.data(), line.size());
3109 stream->Write("\n", 1);
3113 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3114 if (had_output &&
3115 INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output"))
3116 stream->Printf("\n... Interrupted.\n");
3117 stream->Flush();
3120 bool CommandInterpreter::EchoCommandNonInteractive(
3121 llvm::StringRef line, const Flags &io_handler_flags) const {
3122 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3123 return false;
3125 llvm::StringRef command = line.trim();
3126 if (command.empty())
3127 return true;
3129 if (command.front() == m_comment_char)
3130 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3132 return true;
3135 void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
3136 std::string &line) {
3137 // If we were interrupted, bail out...
3138 if (WasInterrupted())
3139 return;
3141 const bool is_interactive = io_handler.GetIsInteractive();
3142 const bool allow_repeats =
3143 io_handler.GetFlags().Test(eHandleCommandFlagAllowRepeats);
3145 if (!is_interactive && !allow_repeats) {
3146 // When we are not interactive, don't execute blank lines. This will happen
3147 // sourcing a commands file. We don't want blank lines to repeat the
3148 // previous command and cause any errors to occur (like redefining an
3149 // alias, get an error and stop parsing the commands file).
3150 // But obey the AllowRepeats flag if the user has set it.
3151 if (line.empty())
3152 return;
3154 if (!is_interactive) {
3155 // When using a non-interactive file handle (like when sourcing commands
3156 // from a file) we need to echo the command out so we don't just see the
3157 // command output and no command...
3158 if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3159 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3160 io_handler.GetOutputStreamFileSP()->Printf(
3161 "%s%s\n", io_handler.GetPrompt(), line.c_str());
3165 StartHandlingCommand();
3167 ExecutionContext exe_ctx = m_debugger.GetSelectedExecutionContext();
3168 bool pushed_exe_ctx = false;
3169 if (exe_ctx.HasTargetScope()) {
3170 OverrideExecutionContext(exe_ctx);
3171 pushed_exe_ctx = true;
3173 auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3174 if (pushed_exe_ctx)
3175 RestoreExecutionContext();
3178 lldb_private::CommandReturnObject result(m_debugger.GetUseColor());
3179 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3181 // Now emit the command output text from the command we just executed
3182 if ((result.Succeeded() &&
3183 io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
3184 io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
3185 // Display any inline diagnostics first.
3186 const bool inline_diagnostics = !result.GetImmediateErrorStream() &&
3187 GetDebugger().GetShowInlineDiagnostics();
3188 if (inline_diagnostics) {
3189 unsigned prompt_len = m_debugger.GetPrompt().size();
3190 if (auto indent = result.GetDiagnosticIndent()) {
3191 std::string diags =
3192 result.GetInlineDiagnosticString(prompt_len + *indent);
3193 PrintCommandOutput(io_handler, diags, true);
3197 // Display any STDOUT/STDERR _prior_ to emitting the command result text.
3198 GetProcessOutput();
3200 if (!result.GetImmediateOutputStream()) {
3201 llvm::StringRef output = result.GetOutputString();
3202 PrintCommandOutput(io_handler, output, true);
3205 // Now emit the command error text from the command we just executed.
3206 if (!result.GetImmediateErrorStream()) {
3207 std::string error = result.GetErrorString(!inline_diagnostics);
3208 PrintCommandOutput(io_handler, error, false);
3212 FinishHandlingCommand();
3214 switch (result.GetStatus()) {
3215 case eReturnStatusInvalid:
3216 case eReturnStatusSuccessFinishNoResult:
3217 case eReturnStatusSuccessFinishResult:
3218 case eReturnStatusStarted:
3219 break;
3221 case eReturnStatusSuccessContinuingNoResult:
3222 case eReturnStatusSuccessContinuingResult:
3223 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
3224 io_handler.SetIsDone(true);
3225 break;
3227 case eReturnStatusFailed:
3228 m_result.IncrementNumberOfErrors();
3229 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3230 m_result.SetResult(lldb::eCommandInterpreterResultCommandError);
3231 io_handler.SetIsDone(true);
3233 break;
3235 case eReturnStatusQuit:
3236 m_result.SetResult(lldb::eCommandInterpreterResultQuitRequested);
3237 io_handler.SetIsDone(true);
3238 break;
3241 // Finally, if we're going to stop on crash, check that here:
3242 if (m_result.IsResult(lldb::eCommandInterpreterResultSuccess) &&
3243 result.GetDidChangeProcessState() &&
3244 io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
3245 DidProcessStopAbnormally()) {
3246 io_handler.SetIsDone(true);
3247 m_result.SetResult(lldb::eCommandInterpreterResultInferiorCrash);
3251 bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
3252 ExecutionContext exe_ctx(GetExecutionContext());
3253 Process *process = exe_ctx.GetProcessPtr();
3255 if (InterruptCommand())
3256 return true;
3258 if (process) {
3259 StateType state = process->GetState();
3260 if (StateIsRunningState(state)) {
3261 process->Halt();
3262 return true; // Don't do any updating when we are running
3266 ScriptInterpreter *script_interpreter =
3267 m_debugger.GetScriptInterpreter(false);
3268 if (script_interpreter) {
3269 if (script_interpreter->Interrupt())
3270 return true;
3272 return false;
3275 bool CommandInterpreter::SaveTranscript(
3276 CommandReturnObject &result, std::optional<std::string> output_file) {
3277 if (output_file == std::nullopt || output_file->empty()) {
3278 std::string now = llvm::to_string(std::chrono::system_clock::now());
3279 std::replace(now.begin(), now.end(), ' ', '_');
3280 // Can't have file name with colons on Windows
3281 std::replace(now.begin(), now.end(), ':', '-');
3282 const std::string file_name = "lldb_session_" + now + ".log";
3284 FileSpec save_location = GetSaveSessionDirectory();
3286 if (!save_location)
3287 save_location = HostInfo::GetGlobalTempDir();
3289 FileSystem::Instance().Resolve(save_location);
3290 save_location.AppendPathComponent(file_name);
3291 output_file = save_location.GetPath();
3294 auto error_out = [&](llvm::StringRef error_message, std::string description) {
3295 LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3296 output_file, description);
3297 result.AppendErrorWithFormatv(
3298 "Failed to save session's transcripts to {0}!", *output_file);
3299 return false;
3302 File::OpenOptions flags = File::eOpenOptionWriteOnly |
3303 File::eOpenOptionCanCreate |
3304 File::eOpenOptionTruncate;
3306 auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3308 if (!opened_file)
3309 return error_out("Unable to create file",
3310 llvm::toString(opened_file.takeError()));
3312 FileUP file = std::move(opened_file.get());
3314 size_t byte_size = m_transcript_stream.GetSize();
3316 Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3318 if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3319 return error_out("Unable to write to destination file",
3320 "Bytes written do not match transcript size.");
3322 result.SetStatus(eReturnStatusSuccessFinishNoResult);
3323 result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3324 output_file->c_str());
3325 if (!GetSaveTranscript())
3326 result.AppendError(
3327 "Note: the setting interpreter.save-transcript is set to false, so the "
3328 "transcript might not have been recorded.");
3330 if (GetOpenTranscriptInEditor() && Host::IsInteractiveGraphicSession()) {
3331 const FileSpec file_spec;
3332 error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3333 if (error.Success()) {
3334 if (llvm::Error e = Host::OpenFileInExternalEditor(
3335 m_debugger.GetExternalEditor(), file_spec, 1))
3336 result.AppendError(llvm::toString(std::move(e)));
3340 return true;
3343 bool CommandInterpreter::IsInteractive() {
3344 return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3347 FileSpec CommandInterpreter::GetCurrentSourceDir() {
3348 if (m_command_source_dirs.empty())
3349 return {};
3350 return m_command_source_dirs.back();
3353 void CommandInterpreter::GetLLDBCommandsFromIOHandler(
3354 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3355 Debugger &debugger = GetDebugger();
3356 IOHandlerSP io_handler_sp(
3357 new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
3358 "lldb", // Name of input reader for history
3359 llvm::StringRef(prompt), // Prompt
3360 llvm::StringRef(), // Continuation prompt
3361 true, // Get multiple lines
3362 debugger.GetUseColor(),
3363 0, // Don't show line numbers
3364 delegate)); // IOHandlerDelegate
3366 if (io_handler_sp) {
3367 io_handler_sp->SetUserData(baton);
3368 debugger.RunIOHandlerAsync(io_handler_sp);
3372 void CommandInterpreter::GetPythonCommandsFromIOHandler(
3373 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3374 Debugger &debugger = GetDebugger();
3375 IOHandlerSP io_handler_sp(
3376 new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
3377 "lldb-python", // Name of input reader for history
3378 llvm::StringRef(prompt), // Prompt
3379 llvm::StringRef(), // Continuation prompt
3380 true, // Get multiple lines
3381 debugger.GetUseColor(),
3382 0, // Don't show line numbers
3383 delegate)); // IOHandlerDelegate
3385 if (io_handler_sp) {
3386 io_handler_sp->SetUserData(baton);
3387 debugger.RunIOHandlerAsync(io_handler_sp);
3391 bool CommandInterpreter::IsActive() {
3392 return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
3395 lldb::IOHandlerSP
3396 CommandInterpreter::GetIOHandler(bool force_create,
3397 CommandInterpreterRunOptions *options) {
3398 // Always re-create the IOHandlerEditline in case the input changed. The old
3399 // instance might have had a non-interactive input and now it does or vice
3400 // versa.
3401 if (force_create || !m_command_io_handler_sp) {
3402 // Always re-create the IOHandlerEditline in case the input changed. The
3403 // old instance might have had a non-interactive input and now it does or
3404 // vice versa.
3405 uint32_t flags = 0;
3407 if (options) {
3408 if (options->m_stop_on_continue == eLazyBoolYes)
3409 flags |= eHandleCommandFlagStopOnContinue;
3410 if (options->m_stop_on_error == eLazyBoolYes)
3411 flags |= eHandleCommandFlagStopOnError;
3412 if (options->m_stop_on_crash == eLazyBoolYes)
3413 flags |= eHandleCommandFlagStopOnCrash;
3414 if (options->m_echo_commands != eLazyBoolNo)
3415 flags |= eHandleCommandFlagEchoCommand;
3416 if (options->m_echo_comment_commands != eLazyBoolNo)
3417 flags |= eHandleCommandFlagEchoCommentCommand;
3418 if (options->m_print_results != eLazyBoolNo)
3419 flags |= eHandleCommandFlagPrintResult;
3420 if (options->m_print_errors != eLazyBoolNo)
3421 flags |= eHandleCommandFlagPrintErrors;
3422 if (options->m_allow_repeats == eLazyBoolYes)
3423 flags |= eHandleCommandFlagAllowRepeats;
3424 } else {
3425 flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
3426 eHandleCommandFlagPrintErrors;
3429 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3430 m_debugger, IOHandler::Type::CommandInterpreter,
3431 m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(),
3432 m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3433 llvm::StringRef(), // Continuation prompt
3434 false, // Don't enable multiple line input, just single line commands
3435 m_debugger.GetUseColor(),
3436 0, // Don't show line numbers
3437 *this); // IOHandlerDelegate
3439 return m_command_io_handler_sp;
3442 CommandInterpreterRunResult CommandInterpreter::RunCommandInterpreter(
3443 CommandInterpreterRunOptions &options) {
3444 // Always re-create the command interpreter when we run it in case any file
3445 // handles have changed.
3446 bool force_create = true;
3447 m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3448 m_result = CommandInterpreterRunResult();
3450 if (options.GetAutoHandleEvents())
3451 m_debugger.StartEventHandlerThread();
3453 if (options.GetSpawnThread()) {
3454 m_debugger.StartIOHandlerThread();
3455 } else {
3456 // If the current thread is not managed by a host thread, we won't detect
3457 // that this IS the CommandInterpreter IOHandler thread, so make it so:
3458 HostThread new_io_handler_thread(Host::GetCurrentThread());
3459 HostThread old_io_handler_thread =
3460 m_debugger.SetIOHandlerThread(new_io_handler_thread);
3461 m_debugger.RunIOHandlers();
3462 m_debugger.SetIOHandlerThread(old_io_handler_thread);
3464 if (options.GetAutoHandleEvents())
3465 m_debugger.StopEventHandlerThread();
3468 return m_result;
3471 CommandObject *
3472 CommandInterpreter::ResolveCommandImpl(std::string &command_line,
3473 CommandReturnObject &result) {
3474 std::string scratch_command(command_line); // working copy so we don't modify
3475 // command_line unless we succeed
3476 CommandObject *cmd_obj = nullptr;
3477 StreamString revised_command_line;
3478 bool wants_raw_input = false;
3479 std::string next_word;
3480 StringList matches;
3481 bool done = false;
3483 auto build_alias_cmd = [&](std::string &full_name) {
3484 revised_command_line.Clear();
3485 matches.Clear();
3486 std::string alias_result;
3487 cmd_obj =
3488 BuildAliasResult(full_name, scratch_command, alias_result, result);
3489 revised_command_line.Printf("%s", alias_result.c_str());
3490 if (cmd_obj) {
3491 wants_raw_input = cmd_obj->WantsRawCommandString();
3495 while (!done) {
3496 char quote_char = '\0';
3497 std::string suffix;
3498 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3499 if (cmd_obj == nullptr) {
3500 std::string full_name;
3501 bool is_alias = GetAliasFullName(next_word, full_name);
3502 cmd_obj = GetCommandObject(next_word, &matches);
3503 bool is_real_command =
3504 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3505 if (!is_real_command) {
3506 build_alias_cmd(full_name);
3507 } else {
3508 if (cmd_obj) {
3509 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3510 revised_command_line.Printf("%s", cmd_name.str().c_str());
3511 wants_raw_input = cmd_obj->WantsRawCommandString();
3512 } else {
3513 revised_command_line.Printf("%s", next_word.c_str());
3516 } else {
3517 if (cmd_obj->IsMultiwordObject()) {
3518 CommandObject *sub_cmd_obj =
3519 cmd_obj->GetSubcommandObject(next_word.c_str());
3520 if (sub_cmd_obj) {
3521 // The subcommand's name includes the parent command's name, so
3522 // restart rather than append to the revised_command_line.
3523 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3524 revised_command_line.Clear();
3525 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3526 cmd_obj = sub_cmd_obj;
3527 wants_raw_input = cmd_obj->WantsRawCommandString();
3528 } else {
3529 if (quote_char)
3530 revised_command_line.Printf(" %c%s%s%c", quote_char,
3531 next_word.c_str(), suffix.c_str(),
3532 quote_char);
3533 else
3534 revised_command_line.Printf(" %s%s", next_word.c_str(),
3535 suffix.c_str());
3536 done = true;
3538 } else {
3539 if (quote_char)
3540 revised_command_line.Printf(" %c%s%s%c", quote_char,
3541 next_word.c_str(), suffix.c_str(),
3542 quote_char);
3543 else
3544 revised_command_line.Printf(" %s%s", next_word.c_str(),
3545 suffix.c_str());
3546 done = true;
3550 if (cmd_obj == nullptr) {
3551 const size_t num_matches = matches.GetSize();
3552 if (matches.GetSize() > 1) {
3553 StringList alias_matches;
3554 GetAliasCommandObject(next_word, &alias_matches);
3556 if (alias_matches.GetSize() == 1) {
3557 std::string full_name;
3558 GetAliasFullName(alias_matches.GetStringAtIndex(0), full_name);
3559 build_alias_cmd(full_name);
3560 done = static_cast<bool>(cmd_obj);
3561 } else {
3562 StreamString error_msg;
3563 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3564 next_word.c_str());
3566 for (uint32_t i = 0; i < num_matches; ++i) {
3567 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3569 result.AppendRawError(error_msg.GetString());
3571 } else {
3572 // We didn't have only one match, otherwise we wouldn't get here.
3573 lldbassert(num_matches == 0);
3574 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3575 next_word.c_str());
3577 if (!done)
3578 return nullptr;
3581 if (cmd_obj->IsMultiwordObject()) {
3582 if (!suffix.empty()) {
3583 result.AppendErrorWithFormat(
3584 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3585 "might be invalid).\n",
3586 cmd_obj->GetCommandName().str().c_str(),
3587 next_word.empty() ? "" : next_word.c_str(),
3588 next_word.empty() ? " -- " : " ", suffix.c_str());
3589 return nullptr;
3591 } else {
3592 // If we found a normal command, we are done
3593 done = true;
3594 if (!suffix.empty()) {
3595 switch (suffix[0]) {
3596 case '/':
3597 // GDB format suffixes
3599 Options *command_options = cmd_obj->GetOptions();
3600 if (command_options &&
3601 command_options->SupportsLongOption("gdb-format")) {
3602 std::string gdb_format_option("--gdb-format=");
3603 gdb_format_option += (suffix.c_str() + 1);
3605 std::string cmd = std::string(revised_command_line.GetString());
3606 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3607 if (arg_terminator_idx != std::string::npos) {
3608 // Insert the gdb format option before the "--" that terminates
3609 // options
3610 gdb_format_option.append(1, ' ');
3611 cmd.insert(arg_terminator_idx, gdb_format_option);
3612 revised_command_line.Clear();
3613 revised_command_line.PutCString(cmd);
3614 } else
3615 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3617 if (wants_raw_input &&
3618 FindArgumentTerminator(cmd) == std::string::npos)
3619 revised_command_line.PutCString(" --");
3620 } else {
3621 result.AppendErrorWithFormat(
3622 "the '%s' command doesn't support the --gdb-format option\n",
3623 cmd_obj->GetCommandName().str().c_str());
3624 return nullptr;
3627 break;
3629 default:
3630 result.AppendErrorWithFormat(
3631 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3632 return nullptr;
3636 if (scratch_command.empty())
3637 done = true;
3640 if (!scratch_command.empty())
3641 revised_command_line.Printf(" %s", scratch_command.c_str());
3643 if (cmd_obj != nullptr)
3644 command_line = std::string(revised_command_line.GetString());
3646 return cmd_obj;
3649 llvm::json::Value CommandInterpreter::GetStatistics() {
3650 llvm::json::Object stats;
3651 for (const auto &command_usage : m_command_usages)
3652 stats.try_emplace(command_usage.getKey(), command_usage.getValue());
3653 return stats;
3656 const StructuredData::Array &CommandInterpreter::GetTranscript() const {
3657 return m_transcript;