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