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