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