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