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