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