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