59#include "lldb/Host/Config.h"
60#if LLDB_ENABLE_LIBEDIT
83#include "llvm/ADT/STLExtras.h"
84#include "llvm/ADT/ScopeExit.h"
85#include "llvm/ADT/SmallString.h"
86#include "llvm/Support/FormatAdapters.h"
87#include "llvm/Support/Path.h"
88#include "llvm/Support/PrettyStackTrace.h"
89#include "llvm/Support/ScopedPrinter.h"
92#include <TargetConditionals.h>
101 "There is a .lldbinit file in the current directory which is not being "
103 "To silence this warning without sourcing in the local .lldbinit,\n"
104 "add the following to the lldbinit file in your home directory:\n"
105 " settings set target.load-cwd-lldbinit false\n"
106 "To allow lldb to source .lldbinit files in the current working "
108 "set the value of this variable to true. Only do so if you understand "
110 "accept the security risk.";
117#define LLDB_PROPERTIES_interpreter
118#include "InterpreterProperties.inc"
121#define LLDB_PROPERTIES_interpreter
122#include "InterpreterPropertiesEnum.inc"
126 static constexpr llvm::StringLiteral class_name(
"lldb.commandInterpreter");
131 bool synchronous_execution)
137 m_debugger(debugger), m_synchronous_execution(true),
138 m_skip_lldbinit_files(false), m_skip_app_init_files(false),
139 m_comment_char(
'#'), m_batch_command_mode(false),
140 m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
141 m_command_source_depth(0) {
151 const uint32_t idx = ePropertyExpandRegexAliases;
152 return GetPropertyAtIndexAs<bool>(
153 idx, g_interpreter_properties[idx].default_uint_value != 0);
157 const uint32_t idx = ePropertyPromptOnQuit;
158 return GetPropertyAtIndexAs<bool>(
159 idx, g_interpreter_properties[idx].default_uint_value != 0);
163 const uint32_t idx = ePropertyPromptOnQuit;
168 const uint32_t idx = ePropertySaveTranscript;
169 return GetPropertyAtIndexAs<bool>(
170 idx, g_interpreter_properties[idx].default_uint_value != 0);
174 const uint32_t idx = ePropertySaveTranscript;
179 const uint32_t idx = ePropertySaveSessionOnQuit;
180 return GetPropertyAtIndexAs<bool>(
181 idx, g_interpreter_properties[idx].default_uint_value != 0);
185 const uint32_t idx = ePropertySaveSessionOnQuit;
190 const uint32_t idx = ePropertyOpenTranscriptInEditor;
191 return GetPropertyAtIndexAs<bool>(
192 idx, g_interpreter_properties[idx].default_uint_value != 0);
196 const uint32_t idx = ePropertyOpenTranscriptInEditor;
201 const uint32_t idx = ePropertySaveSessionDirectory;
202 return GetPropertyAtIndexAs<FileSpec>(idx, {});
206 const uint32_t idx = ePropertySaveSessionDirectory;
211 const uint32_t idx = ePropertyEchoCommands;
212 return GetPropertyAtIndexAs<bool>(
213 idx, g_interpreter_properties[idx].default_uint_value != 0);
217 const uint32_t idx = ePropertyEchoCommands;
222 const uint32_t idx = ePropertyEchoCommentCommands;
223 return GetPropertyAtIndexAs<bool>(
224 idx, g_interpreter_properties[idx].default_uint_value != 0);
228 const uint32_t idx = ePropertyEchoCommentCommands;
254 std::string command = command_line;
262 const uint32_t idx = ePropertyStopCmdSourceOnError;
263 return GetPropertyAtIndexAs<bool>(
264 idx, g_interpreter_properties[idx].default_uint_value != 0);
268 const uint32_t idx = ePropertySpaceReplPrompts;
269 return GetPropertyAtIndexAs<bool>(
270 idx, g_interpreter_properties[idx].default_uint_value != 0);
274 const uint32_t idx = ePropertyRepeatPreviousCommand;
275 return GetPropertyAtIndexAs<bool>(
276 idx, g_interpreter_properties[idx].default_uint_value != 0);
280 const uint32_t idx = ePropertyRequireCommandOverwrite;
281 return GetPropertyAtIndexAs<bool>(
282 idx, g_interpreter_properties[idx].default_uint_value != 0);
342 "sif", cmd_obj_sp,
"--end-linenumber block --step-in-target %1");
344 sif_alias->
SetHelp(
"Step through the current block, stopping if you step "
345 "directly into a function whose name matches the "
346 "TargetFunctionName.");
347 sif_alias->
SetSyntax(
"sif <TargetFunctionName>");
428 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
434 if (
auto *po =
AddAlias(
"po", cmd_obj_sp,
"-O --")) {
435 po->SetHelp(
"Evaluate an expression on the current thread. Displays any "
436 "returned value with formatting "
437 "controlled by the type's author.");
446 AddAlias(
"parray", cmd_obj_sp,
"--element-count %1 --");
449 (
"parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
450 "to get a typed-pointer-to-an-array in memory, and will display "
451 "COUNT elements of that type from the array.");
455 "--object-description --element-count %1 --");
457 poarray_alias->
SetHelp(
"poarray <COUNT> <EXPRESSION> -- lldb will "
458 "evaluate EXPRESSION to get the address of an array of COUNT "
459 "objects in memory, and will call po on them.");
468 shell_alias->
SetHelp(
"Run a shell command on the host.");
470 shell_alias->
SetSyntax(
"shell <shell-command>");
481 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
482#if defined(__APPLE__)
487 AddAlias(
"r", cmd_obj_sp,
"--shell-expand-args true --");
488 AddAlias(
"run", cmd_obj_sp,
"--shell-expand-args true --");
492 defaultshell.
Printf(
"--shell=%s --",
493 HostInfo::GetDefaultShell().GetPath().c_str());
506 AddAlias(
"rbreak", cmd_obj_sp,
"--func-regex %1");
513 AddAlias(
"vo", cmd_obj_sp,
"--object-description");
554#define REGISTER_COMMAND_OBJECT(NAME, CLASS) \
555 m_command_dict[NAME] = std::make_shared<CLASS>(*this);
591 const char *break_regexes[][2] = {
592 {
"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
593 "breakpoint set --file '%1' --line %2 --column %3"},
594 {
"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
595 "breakpoint set --file '%1' --line %2"},
596 {
"^/([^/]+)/$",
"breakpoint set --source-pattern-regexp '%1'"},
597 {
"^([[:digit:]]+)[[:space:]]*$",
"breakpoint set --line %1"},
598 {
"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
"breakpoint set --address %1"},
599 {
"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
600 "breakpoint set --name '%1'"},
601 {
"^(-.*)$",
"breakpoint set %1"},
602 {
"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
603 "breakpoint set --name '%2' --shlib '%1'"},
604 {
"^\\&(.*[^[:space:]])[[:space:]]*$",
605 "breakpoint set --name '%1' --skip-prologue=0"},
606 {
"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
607 "breakpoint set --name '%1'"}};
610 size_t num_regexes = std::size(break_regexes);
612 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
614 *
this,
"_regexp-break",
615 "Set a breakpoint using one of several shorthand formats.",
617 "_regexp-break <filename>:<linenum>:<colnum>\n"
618 " main.c:12:21 // Break at line 12 and column "
620 "_regexp-break <filename>:<linenum>\n"
621 " main.c:12 // Break at line 12 of "
623 "_regexp-break <linenum>\n"
624 " 12 // Break at line 12 of current "
626 "_regexp-break 0x<address>\n"
627 " 0x1234000 // Break at address "
629 "_regexp-break <name>\n"
630 " main // Break in 'main' after the "
632 "_regexp-break &<name>\n"
633 " &main // Break at first instruction "
635 "_regexp-break <module>`<name>\n"
636 " libc.so`malloc // Break in 'malloc' from "
638 "_regexp-break /<source-regex>/\n"
639 " /break here/ // Break on source lines in "
641 " // containing text 'break "
645 if (break_regex_cmd_up) {
647 for (
size_t i = 0; i < num_regexes; i++) {
648 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
649 break_regexes[i][1]);
654 break_regex_cmd_up->AddRegexCommand(
"^$",
"breakpoint list --full");
658 m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
663 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
665 *
this,
"_regexp-tbreak",
666 "Set a one-shot breakpoint using one of several shorthand formats.",
668 "_regexp-break <filename>:<linenum>:<colnum>\n"
669 " main.c:12:21 // Break at line 12 and column "
671 "_regexp-break <filename>:<linenum>\n"
672 " main.c:12 // Break at line 12 of "
674 "_regexp-break <linenum>\n"
675 " 12 // Break at line 12 of current "
677 "_regexp-break 0x<address>\n"
678 " 0x1234000 // Break at address "
680 "_regexp-break <name>\n"
681 " main // Break in 'main' after the "
683 "_regexp-break &<name>\n"
684 " &main // Break at first instruction "
686 "_regexp-break <module>`<name>\n"
687 " libc.so`malloc // Break in 'malloc' from "
689 "_regexp-break /<source-regex>/\n"
690 " /break here/ // Break on source lines in "
692 " // containing text 'break "
696 if (tbreak_regex_cmd_up) {
698 for (
size_t i = 0; i < num_regexes; i++) {
699 std::string command = break_regexes[i][1];
702 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
707 tbreak_regex_cmd_up->AddRegexCommand(
"^$",
"breakpoint list --full");
711 m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
716 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
718 *
this,
"_regexp-attach",
"Attach to process by ID or name.",
719 "_regexp-attach <pid> | <process-name>", 0,
false));
720 if (attach_regex_cmd_up) {
721 if (attach_regex_cmd_up->AddRegexCommand(
"^([0-9]+)[[:space:]]*$",
722 "process attach --pid %1") &&
723 attach_regex_cmd_up->AddRegexCommand(
724 "^(-.*|.* -.*)$",
"process attach %1") &&
727 attach_regex_cmd_up->AddRegexCommand(
"^(.+)$",
728 "process attach --name '%1'") &&
729 attach_regex_cmd_up->AddRegexCommand(
"^$",
"process attach")) {
731 m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
736 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
738 "Select a newer stack frame. Defaults to "
739 "moving one frame, a numeric argument can "
740 "specify an arbitrary number.",
741 "_regexp-down [<count>]", 0,
false));
742 if (down_regex_cmd_up) {
743 if (down_regex_cmd_up->AddRegexCommand(
"^$",
"frame select -r -1") &&
744 down_regex_cmd_up->AddRegexCommand(
"^([0-9]+)$",
745 "frame select -r -%1")) {
747 m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
752 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
755 "Select an older stack frame. Defaults to moving one "
756 "frame, a numeric argument can specify an arbitrary number.",
757 "_regexp-up [<count>]", 0,
false));
758 if (up_regex_cmd_up) {
759 if (up_regex_cmd_up->AddRegexCommand(
"^$",
"frame select -r 1") &&
760 up_regex_cmd_up->AddRegexCommand(
"^([0-9]+)$",
"frame select -r %1")) {
767 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
769 *
this,
"_regexp-display",
770 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
771 "_regexp-display expression", 0,
false));
772 if (display_regex_cmd_up) {
773 if (display_regex_cmd_up->AddRegexCommand(
774 "^(.+)$",
"target stop-hook add -o \"expr -- %1\"")) {
776 m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
777 display_regex_cmd_sp;
781 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
783 "Stop displaying expression at every "
784 "stop (specified by stop-hook index.)",
785 "_regexp-undisplay stop-hook-number", 0,
787 if (undisplay_regex_cmd_up) {
788 if (undisplay_regex_cmd_up->AddRegexCommand(
"^([0-9]+)$",
789 "target stop-hook delete %1")) {
790 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
791 m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
792 undisplay_regex_cmd_sp;
796 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
799 "Connect to a process via remote GDB server.\n"
800 "If no host is specifed, localhost is assumed.\n"
801 "gdb-remote is an abbreviation for 'process connect --plugin "
802 "gdb-remote connect://<hostname>:<port>'\n",
803 "gdb-remote [<hostname>:]<portnum>", 0,
false));
804 if (connect_gdb_remote_cmd_up) {
805 if (connect_gdb_remote_cmd_up->AddRegexCommand(
806 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
807 "process connect --plugin gdb-remote connect://%1:%2") &&
808 connect_gdb_remote_cmd_up->AddRegexCommand(
810 "process connect --plugin gdb-remote connect://localhost:%1")) {
812 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
816 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
819 "Connect to a process via remote KDP server.\n"
820 "If no UDP port is specified, port 41139 is assumed.\n"
821 "kdp-remote is an abbreviation for 'process connect --plugin "
822 "kdp-remote udp://<hostname>:<port>'\n",
823 "kdp-remote <hostname>[:<portnum>]", 0,
false));
824 if (connect_kdp_remote_cmd_up) {
825 if (connect_kdp_remote_cmd_up->AddRegexCommand(
826 "^([^:]+:[[:digit:]]+)$",
827 "process connect --plugin kdp-remote udp://%1") &&
828 connect_kdp_remote_cmd_up->AddRegexCommand(
829 "^(.+)$",
"process connect --plugin kdp-remote udp://%1:41139")) {
831 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
835 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
838 "Show backtrace of the current thread's call stack. Any numeric "
839 "argument displays at most that many frames. The argument 'all' "
840 "displays all threads. Use 'settings set frame-format' to customize "
841 "the printing of individual frames and 'settings set thread-format' "
842 "to customize the thread header. Frame recognizers may filter the"
843 "list. Use 'thread backtrace -u (--unfiltered)' to see them all.",
844 "bt [<digit> | all]", 0,
false));
845 if (bt_regex_cmd_up) {
850 if (bt_regex_cmd_up->AddRegexCommand(
"^([[:digit:]]+)[[:space:]]*$",
851 "thread backtrace -c %1") &&
852 bt_regex_cmd_up->AddRegexCommand(
"^-c ([[:digit:]]+)[[:space:]]*$",
853 "thread backtrace -c %1") &&
854 bt_regex_cmd_up->AddRegexCommand(
"^all[[:space:]]*$",
"thread backtrace all") &&
855 bt_regex_cmd_up->AddRegexCommand(
"^[[:space:]]*$",
"thread backtrace")) {
857 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
861 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
863 *
this,
"_regexp-list",
864 "List relevant source code using one of several shorthand formats.",
866 "_regexp-list <file>:<line> // List around specific file/line\n"
867 "_regexp-list <line> // List current file around specified "
869 "_regexp-list <function-name> // List specified function\n"
870 "_regexp-list 0x<address> // List around specified address\n"
871 "_regexp-list -[<count>] // List previous <count> lines\n"
872 "_regexp-list // List subsequent lines",
874 if (list_regex_cmd_up) {
875 if (list_regex_cmd_up->AddRegexCommand(
"^([0-9]+)[[:space:]]*$",
876 "source list --line %1") &&
877 list_regex_cmd_up->AddRegexCommand(
878 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
880 "source list --file '%1' --line %2") &&
881 list_regex_cmd_up->AddRegexCommand(
882 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
883 "source list --address %1") &&
884 list_regex_cmd_up->AddRegexCommand(
"^-[[:space:]]*$",
885 "source list --reverse") &&
886 list_regex_cmd_up->AddRegexCommand(
887 "^-([[:digit:]]+)[[:space:]]*$",
888 "source list --reverse --count %1") &&
889 list_regex_cmd_up->AddRegexCommand(
"^(.+)$",
890 "source list --name \"%1\"") &&
891 list_regex_cmd_up->AddRegexCommand(
"^$",
"source list")) {
893 m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
898 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
900 *
this,
"_regexp-env",
901 "Shorthand for viewing and setting environment variables.",
903 "_regexp-env // Show environment\n"
904 "_regexp-env <name>=<value> // Set an environment variable",
906 if (env_regex_cmd_up) {
907 if (env_regex_cmd_up->AddRegexCommand(
"^$",
908 "settings show target.env-vars") &&
909 env_regex_cmd_up->AddRegexCommand(
"^([A-Za-z_][A-Za-z_0-9]*=.*)$",
910 "settings set target.env-vars %1")) {
917 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
919 *
this,
"_regexp-jump",
"Set the program counter to a new address.",
921 "_regexp-jump <line>\n"
922 "_regexp-jump +<line-offset> | -<line-offset>\n"
923 "_regexp-jump <file>:<line>\n"
924 "_regexp-jump *<addr>\n",
926 if (jump_regex_cmd_up) {
927 if (jump_regex_cmd_up->AddRegexCommand(
"^\\*(.*)$",
928 "thread jump --addr %1") &&
929 jump_regex_cmd_up->AddRegexCommand(
"^([0-9]+)$",
930 "thread jump --line %1") &&
931 jump_regex_cmd_up->AddRegexCommand(
"^([^:]+):([0-9]+)$",
932 "thread jump --file %1 --line %2") &&
933 jump_regex_cmd_up->AddRegexCommand(
"^([+\\-][0-9]+)$",
934 "thread jump --by %1")) {
936 m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
943 const char *cmd_str,
bool include_aliases,
StringList &matches,
948 if (include_aliases) {
957 Args &path,
bool leaf_is_command,
Status &result) {
960 auto get_multi_or_report_error =
967 if (!cmd_sp->IsUserCommand()) {
989 if (num_args == 1 && leaf_is_command) {
999 get_multi_or_report_error(cur_cmd_sp, cur_name);
1000 if (cur_as_multi ==
nullptr)
1003 size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
1004 for (
size_t cursor = 1; cursor < num_path_elements && cur_as_multi !=
nullptr;
1008 cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
1010 return cur_as_multi;
1019 std::string cmd = std::string(cmd_str);
1024 command_sp = pos->second;
1030 command_sp = alias_pos->second;
1036 command_sp = pos->second;
1042 command_sp = pos->second;
1045 if (!exact && !command_sp) {
1052 if (matches ==
nullptr)
1053 matches = &local_matches;
1055 unsigned int num_cmd_matches = 0;
1056 unsigned int num_alias_matches = 0;
1057 unsigned int num_user_matches = 0;
1058 unsigned int num_user_mw_matches = 0;
1066 *matches, descriptions);
1069 if (num_cmd_matches == 1) {
1073 real_match_sp = pos->second;
1078 *matches, descriptions);
1081 if (num_alias_matches == 1) {
1085 alias_match_sp = alias_pos->second;
1090 *matches, descriptions);
1093 if (num_user_matches == 1) {
1099 user_match_sp = pos->second;
1107 if (num_user_mw_matches == 1) {
1113 user_mw_match_sp = pos->second;
1119 if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1120 num_alias_matches ==
1122 if (num_cmd_matches)
1123 return real_match_sp;
1124 else if (num_alias_matches)
1125 return alias_match_sp;
1126 else if (num_user_mw_matches)
1127 return user_mw_match_sp;
1129 return user_match_sp;
1131 }
else if (matches && command_sp) {
1144 lldbassert((
this == &cmd_sp->GetCommandInterpreter()) &&
1145 "tried to add a CommandObject from a different interpreter");
1150 cmd_sp->SetIsUserCommand(
false);
1152 std::string name_sstr(name);
1155 if (!can_replace || !name_iter->second->IsRemovable())
1157 name_iter->second = cmd_sp;
1169 lldbassert((
this == &cmd_sp->GetCommandInterpreter()) &&
1170 "tried to add a CommandObject from a different interpreter");
1172 result.
SetErrorString(
"can't use the empty string for a command name");
1184 "user command \"{0}\" already exists and force replace was not set "
1185 "by --overwrite or 'settings set interpreter.require-overwrite "
1190 if (cmd_sp->IsMultiwordObject()) {
1193 "can't replace explicitly non-removable multi-word command");
1197 if (!
m_user_dict[std::string(name)]->IsRemovable()) {
1198 result.
SetErrorString(
"can't replace explicitly non-removable command");
1204 cmd_sp->SetIsUserCommand(
true);
1206 if (cmd_sp->IsMultiwordObject())
1215 bool include_aliases)
const {
1217 Args cmd_words(cmd_str);
1219 if (cmd_str.empty())
1236 for (
size_t i = 1; i < end; ++i) {
1237 if (!cmd_obj_sp->IsMultiwordObject()) {
1262 matches, descriptions)
1268 std::string cmd_str(cmd);
1270 auto found_elem = map.find(std::string(cmd));
1271 if (found_elem == map.end())
1294 StringList *matches_ptr = matches ? matches : &tmp_list;
1297 cmd_str, *matches_ptr);
1306 auto found_elem = map.find(cmd.str());
1307 if (found_elem == map.end())
1329 StringList *matches_ptr = matches ? matches : &tmp_list;
1340 std::string &full_name)
const {
1344 full_name.assign(std::string(cmd));
1348 size_t num_alias_matches;
1351 if (num_alias_matches == 1) {
1354 const bool include_aliases =
false;
1355 const bool exact =
false;
1357 GetCommandSP(cmd, include_aliases, exact, ®ular_matches));
1358 if (cmd_obj_sp || regular_matches.
GetSize() > 0)
1384 llvm::StringRef args_string) {
1385 if (command_obj_sp.get())
1386 lldbassert((
this == &command_obj_sp->GetCommandInterpreter()) &&
1387 "tried to add a CommandObject from a different interpreter");
1389 std::unique_ptr<CommandAlias> command_alias_up(
1390 new CommandAlias(*
this, command_obj_sp, args_string, alias_name));
1392 if (command_alias_up && command_alias_up->IsValid()) {
1395 return command_alias_up.release();
1413 if (force || pos->second->IsRemovable()) {
1424 CommandObject::CommandMap::iterator pos =
1434 CommandObject::CommandMap::iterator pos =
1444 uint32_t cmd_types) {
1445 llvm::StringRef help_prologue(
GetDebugger().GetIOHandlerHelpPrologue());
1446 if (!help_prologue.empty()) {
1451 CommandObject::CommandMap::const_iterator pos;
1460 (pos->first.compare(0, 1,
"_") == 0))
1464 pos->second->GetHelp(), max_len);
1472 "Current command abbreviations "
1473 "(type '%shelp command alias' for more info):\n",
1481 alias_pos->second->GetHelp(), max_len);
1493 pos->second->GetHelp(), max_len);
1500 result.
AppendMessage(
"Current user-defined container commands:");
1505 pos->second->GetHelp(), max_len);
1511 "For more information on any command, type '%shelp <command-name>'.\n",
1516 llvm::StringRef &command_string) {
1522 size_t start = command_string.find_first_not_of(
k_white_space);
1526 if (start != std::string::npos) {
1529 if (end == std::string::npos)
1530 end = command_string.size();
1531 std::string cmd_word =
1532 std::string(command_string.substr(start, end - start));
1534 if (cmd_obj ==
nullptr)
1544 cmd_obj = sub_cmd_obj;
1556 end >= command_string.size())
1559 start = command_string.find_first_not_of(
k_white_space, end);
1565 command_string = command_string.substr(end);
1570 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1574 if (pos == std::string::npos)
1583 const size_t s_len = s.size();
1585 while (offset < s_len) {
1586 size_t pos = s.find(
"--", offset);
1587 if (pos == std::string::npos)
1590 if (llvm::isSpace(s[pos - 1])) {
1593 if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1600 return std::string::npos;
1604 std::string &suffix,
char "e_char) {
1609 bool result =
false;
1612 if (!command_string.empty()) {
1613 const char first_char = command_string[0];
1614 if (first_char ==
'\'' || first_char ==
'"') {
1615 quote_char = first_char;
1616 const size_t end_quote_pos = command_string.find(quote_char, 1);
1617 if (end_quote_pos == std::string::npos) {
1618 command.swap(command_string);
1619 command_string.erase();
1621 command.assign(command_string, 1, end_quote_pos - 1);
1622 if (end_quote_pos + 1 < command_string.size())
1623 command_string.erase(0, command_string.find_first_not_of(
1626 command_string.erase();
1629 const size_t first_space_pos =
1631 if (first_space_pos == std::string::npos) {
1632 command.swap(command_string);
1633 command_string.erase();
1635 command.assign(command_string, 0, first_space_pos);
1636 command_string.erase(0, command_string.find_first_not_of(
1643 if (!command.empty()) {
1645 if (command[0] !=
'-' && command[0] !=
'_') {
1647 if (pos > 0 && pos != std::string::npos) {
1648 suffix.assign(command.begin() + pos, command.end());
1658 llvm::StringRef alias_name, std::string &raw_input_string,
1661 Args cmd_args(raw_input_string);
1665 if (!alias_cmd_obj || !alias_cmd_obj->
IsAlias()) {
1666 alias_result.clear();
1667 return alias_cmd_obj;
1669 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1672 alias_cmd_obj = desugared.first.get();
1673 std::string alias_name_str = std::string(alias_name);
1676 cmd_args.
Unshift(alias_name_str);
1680 if (!option_arg_vector_sp.get()) {
1681 alias_result = std::string(result_str.
GetString());
1682 return alias_cmd_obj;
1689 for (
const auto &entry : *option_arg_vector) {
1690 std::tie(option, value_type, value) = entry;
1692 result_str.
Printf(
" %s", value.c_str());
1696 result_str.
Printf(
" %s", option.c_str());
1704 result_str.
Printf(
"%s", value.c_str());
1708 "need at least %d arguments to use "
1714 size_t strpos = raw_input_string.find(entry.
c_str());
1716 if (strpos != std::string::npos) {
1717 const size_t start_fudge = quote_char ==
'\0' ? 0 : 1;
1718 const size_t len_fudge = quote_char ==
'\0' ? 0 : 2;
1721 if (strpos < start_fudge) {
1722 result.
AppendError(
"Unmatched quote at command beginning.");
1725 llvm::StringRef arg_text = entry.
ref();
1726 if (strpos - start_fudge + arg_text.size() + len_fudge >
1727 raw_input_string.size()) {
1728 result.
AppendError(
"Unmatched quote at command end.");
1731 raw_input_string = raw_input_string.erase(
1732 strpos - start_fudge,
1735 if (quote_char ==
'\0')
1738 result_str.
Printf(
"%c%s%c", quote_char, entry.
c_str(), quote_char);
1742 alias_result = std::string(result_str.
GetString());
1743 return alias_cmd_obj;
1754 size_t start_backtick;
1756 while ((start_backtick = command.find(
'`', pos)) != std::string::npos) {
1761 if (start_backtick > 0 && command[start_backtick - 1] ==
'\\') {
1764 command.erase(start_backtick - 1, 1);
1766 pos = start_backtick;
1770 const size_t expr_content_start = start_backtick + 1;
1771 const size_t end_backtick = command.find(
'`', expr_content_start);
1773 if (end_backtick == std::string::npos) {
1778 if (end_backtick == expr_content_start) {
1780 command.erase(start_backtick, 2);
1784 std::string expr_str(command, expr_content_start,
1785 end_backtick - expr_content_start);
1791 command.erase(start_backtick, end_backtick - start_backtick + 1);
1792 command.insert(start_backtick, std::string(expr_str));
1793 pos = start_backtick + expr_str.size();
1821 expr_result_valobj_sp, options);
1825 if (expr_result_valobj_sp)
1826 expr_result_valobj_sp =
1827 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1828 expr_result_valobj_sp->GetDynamicValueType(),
true);
1829 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1832 const bool show_type =
false;
1833 scalar.
GetValue(value_strm, show_type);
1834 size_t value_string_size = value_strm.
GetSize();
1835 if (value_string_size) {
1836 expr_str = value_strm.
GetData();
1838 error.SetErrorStringWithFormat(
"expression value didn't result "
1839 "in a scalar value for the "
1844 error.SetErrorStringWithFormat(
"expression value didn't result "
1845 "in a scalar value for the "
1856 if (expr_result_valobj_sp)
1857 error = expr_result_valobj_sp->GetError();
1859 if (
error.Success()) {
1861 error.SetErrorString(result +
"for the expression '" + expr_str +
"'");
1872 bool status =
HandleCommand(command_line, lazy_add_to_history, result);
1880 bool force_repeat_command) {
1881 std::string command_string(command_line);
1882 std::string original_command_string(command_line);
1885 llvm::PrettyStackTraceFormat stack_trace(
"HandleCommand(command = \"%s\")",
1888 LLDB_LOGF(log,
"Processing command: %s", command_line);
1896 bool add_to_history;
1900 add_to_history = (lazy_add_to_history ==
eLazyBoolYes);
1908 transcript_item = std::make_shared<StructuredData::Dictionary>();
1909 transcript_item->AddStringItem(
"command", command_line);
1910 transcript_item->AddIntegerItem(
1911 "timestampInEpochSeconds",
1912 std::chrono::duration_cast<std::chrono::seconds>(
1913 std::chrono::system_clock::now().time_since_epoch())
1918 bool empty_command =
false;
1919 bool comment_command =
false;
1920 if (command_string.empty())
1921 empty_command =
true;
1923 const char *k_space_characters =
"\t\n\v\f\r ";
1925 size_t non_space = command_string.find_first_not_of(k_space_characters);
1928 if (non_space == std::string::npos)
1929 empty_command =
true;
1931 comment_command =
true;
1933 llvm::StringRef search_str(command_string);
1934 search_str = search_str.drop_front(non_space);
1936 add_to_history =
false;
1937 command_string = std::string(*hist_str);
1938 original_command_string = std::string(*hist_str);
1941 command_string.c_str());
1947 if (empty_command) {
1959 command_string = command_line;
1960 original_command_string = command_line;
1966 add_to_history =
false;
1967 }
else if (comment_command) {
2007 llvm::StringRef command_name = cmd_obj ? cmd_obj->
GetCommandName() :
"<not found>";
2008 LLDB_LOGF(log,
"HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
2009 LLDB_LOGF(log,
"HandleCommand, (revised) command_string: '%s'",
2010 command_string.c_str());
2011 const bool wants_raw_input =
2013 LLDB_LOGF(log,
"HandleCommand, wants_raw_input:'%s'",
2014 wants_raw_input ?
"True" :
"False");
2022 if (cmd_obj !=
nullptr) {
2023 bool generate_repeat_command = add_to_history;
2027 generate_repeat_command |= empty_command;
2032 generate_repeat_command |= force_repeat_command;
2033 if (generate_repeat_command) {
2034 Args command_args(command_string);
2035 std::optional<std::string> repeat_command =
2037 if (repeat_command) {
2038 LLDB_LOGF(log,
"Repeat command: %s", repeat_command->data());
2048 std::string remainder;
2049 const std::size_t actual_cmd_name_len = cmd_obj->
GetCommandName().size();
2050 if (actual_cmd_name_len < command_string.length())
2051 remainder = command_string.substr(actual_cmd_name_len);
2055 if (pos != 0 && pos != std::string::npos)
2056 remainder.erase(0, pos);
2059 log,
"HandleCommand, command line after removing command name(s): '%s'",
2065 if (transcript_item) {
2066 transcript_item->AddStringItem(
"commandName", cmd_obj->
GetCommandName());
2067 transcript_item->AddStringItem(
"commandArguments", remainder);
2071 cmd_obj->
Execute(remainder.c_str(), result);
2074 LLDB_LOGF(log,
"HandleCommand, command %s",
2075 (result.
Succeeded() ?
"succeeded" :
"did not succeed"));
2080 if (transcript_item) {
2084 transcript_item->AddStringItem(
"output", result.
GetOutputData());
2085 transcript_item->AddStringItem(
"error", result.
GetErrorData());
2086 transcript_item->AddFloatItem(
"durationInSeconds",
2087 execute_time.
get().count());
2094 bool look_for_subcommand =
false;
2100 bool include_aliases =
true;
2111 &new_matches, &new_descriptions);
2118 look_for_subcommand =
true;
2133 if (command_object) {
2146 if (!first_arg.empty()) {
2151 request.
AddCompletion(*hist_str,
"Previous command history event",
2160std::optional<std::string>
2163 return std::nullopt;
2165 for (
int i = s - 1; i >= 0; --i) {
2167 if (entry.consume_front(line))
2170 return std::nullopt;
2174 EventSP prompt_change_event_sp(
2185 return default_answer;
2218 const char *alias_name,
2220 std::string &raw_input_string,
2228 std::string alias_name_str = alias_name;
2230 cmd_args.
Unshift(alias_name_str);
2236 if (option_arg_vector_sp.get()) {
2237 if (wants_raw_input) {
2241 size_t pos = raw_input_string.find(
" -- ");
2242 if (pos == std::string::npos) {
2244 raw_input_string.insert(0,
" -- ");
2250 std::vector<bool> used(old_size + 1,
false);
2257 for (
const auto &option_entry : *option_arg_vector) {
2258 std::tie(option, value_type, value) = option_entry;
2260 if (!wants_raw_input || (value !=
"--")) {
2284 "need at least %d arguments to use "
2292 if (strpos != std::string::npos) {
2293 raw_input_string = raw_input_string.erase(
2306 for (
auto entry : llvm::enumerate(cmd_args.
entries())) {
2307 if (!used[entry.index()] && !wants_raw_input)
2320 if (wants_raw_input) {
2336 const char *cptr = in_string;
2339 if (cptr[0] ==
'%') {
2343 if (isdigit(cptr[0])) {
2344 const char *start = cptr;
2345 while (isdigit(cptr[0]))
2350 if (cptr[0] ==
'\0')
2351 position = atoi(start);
2359 llvm::StringRef suffix = {}) {
2360 std::string init_file_name =
".lldbinit";
2361 if (!suffix.empty()) {
2362 init_file_name.append(
"-");
2363 init_file_name.append(suffix.str());
2367 llvm::sys::path::append(init_file, init_file_name);
2377 language = *main_repl_language;
2382 std::string init_file_name =
2383 (llvm::Twine(
".lldbinit-") +
2385 llvm::Twine(
"-repl"))
2388 llvm::sys::path::append(init_file, init_file_name);
2393 llvm::StringRef s =
".lldbinit";
2394 init_file.assign(s.begin(), s.end());
2426 llvm::SmallString<128> init_file;
2436 switch (should_load) {
2444 llvm::SmallString<128> home_init_file;
2446 if (llvm::sys::path::parent_path(init_file) ==
2447 llvm::sys::path::parent_path(home_init_file)) {
2467 llvm::SmallString<128> init_file;
2472 if (init_file.empty())
2476 llvm::StringRef program_name =
2477 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2478 llvm::SmallString<128> program_init_file;
2481 init_file = program_init_file;
2488#ifdef LLDB_GLOBAL_INIT_DIRECTORY
2490 FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2504 return prefix ==
nullptr ?
"" : prefix;
2509 if (prefer_target_platform) {
2523 TargetSP target_sp = exe_ctx.GetTargetSP();
2527 ProcessSP process_sp(target_sp->GetProcessSP());
2534 for (
const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2535 StopInfoSP stop_info = thread_sp->GetStopInfo();
2543 const StopReason reason = stop_info->GetStopReason();
2550 const auto stop_signal =
static_cast<int32_t
>(stop_info->GetValue());
2552 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2556 const auto sigint_num = signals_sp->GetSignalNumberFromName(
"SIGINT");
2557 const auto sigstop_num = signals_sp->GetSignalNumberFromName(
"SIGSTOP");
2558 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2581 size_t num_lines = commands.
GetSize();
2593 for (
size_t idx = 0; idx < num_lines; idx++) {
2622 if (!success || !tmp_result.
Succeeded()) {
2624 if (error_msg.empty())
2625 error_msg =
"<unknown error>.\n";
2628 "Aborting reading of commands after command #%" PRIu64
2629 ": '%s' failed with %s",
2630 (uint64_t)idx, cmd, error_msg.str().c_str());
2635 "Command #%" PRIu64
" '%s' failed with %s", (uint64_t)idx + 1, cmd,
2636 error_msg.str().c_str());
2657 if (idx != num_lines - 1)
2659 "Aborting reading of commands after command #%" PRIu64
2660 ": '%s' continued the target.\n",
2661 (uint64_t)idx + 1, cmd);
2664 " '%s' continued the target.\n",
2665 (uint64_t)idx + 1, cmd);
2677 if (idx != num_lines - 1)
2679 "Aborting reading of commands after command #%" PRIu64
2680 ": '%s' stopped with a signal or exception.\n",
2681 (uint64_t)idx + 1, cmd);
2684 "Command #%" PRIu64
" '%s' stopped with a signal or exception.\n",
2685 (uint64_t)idx + 1, cmd);
2723 "Error reading commands from file %s - file not found.\n",
2728 std::string cmd_file_path = cmd_file.
GetPath();
2729 auto input_file_up =
2731 if (!input_file_up) {
2732 std::string
error = llvm::toString(input_file_up.takeError());
2734 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2735 llvm::fmt_consume(input_file_up.takeError()));
2738 FileSP input_file_sp =
FileSP(std::move(input_file_up.get()));
2825 cmd_file_path.c_str());
2841 debugger.
GetPrompt(), llvm::StringRef(),
2871 llvm::StringRef prefix,
2872 llvm::StringRef help_text) {
2875 size_t line_width_max = max_columns - prefix.size();
2876 if (line_width_max < 16)
2877 line_width_max = help_text.size() + prefix.size();
2880 bool prefixed_yet =
false;
2882 if (help_text.empty())
2883 help_text =
"No help text";
2884 while (!help_text.empty()) {
2886 if (!prefixed_yet) {
2888 prefixed_yet =
true;
2893 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2896 std::size_t first_newline = this_line.find_first_of(
"\n");
2899 std::size_t last_space = llvm::StringRef::npos;
2900 if (this_line.size() != help_text.size())
2901 last_space = this_line.find_last_of(
" \t");
2904 this_line = this_line.substr(0, std::min(first_newline, last_space));
2909 help_text = help_text.drop_front(this_line.size()).ltrim();
2915 llvm::StringRef word_text,
2916 llvm::StringRef separator,
2917 llvm::StringRef help_text,
2918 size_t max_word_len) {
2920 prefix_stream.
Printf(
" %-*s %*s ", (
int)max_word_len, word_text.data(),
2921 (
int)separator.size(), separator.data());
2926 llvm::StringRef separator,
2927 llvm::StringRef help_text,
2928 uint32_t max_word_len) {
2929 int indent_size = max_word_len + separator.size() + 2;
2934 text_strm.
Printf(
"%-*s ", (
int)max_word_len, word_text.data());
2935 text_strm << separator <<
" " << help_text;
2939 llvm::StringRef text = text_strm.
GetString();
2941 uint32_t chars_left = max_columns;
2943 auto nextWordLength = [](llvm::StringRef S) {
2944 size_t pos = S.find(
' ');
2945 return pos == llvm::StringRef::npos ? S.size() : pos;
2948 while (!text.empty()) {
2949 if (text.front() ==
'\n' ||
2950 (text.front() ==
' ' && nextWordLength(text.ltrim(
' ')) > chars_left)) {
2953 chars_left = max_columns - indent_size;
2954 if (text.front() ==
'\n')
2955 text = text.drop_front();
2957 text = text.ltrim(
' ');
2961 text = text.drop_front();
2970 llvm::StringRef search_word,
StringList &commands_found,
2972 for (
const auto &pair : command_map) {
2973 llvm::StringRef command_name = pair.first;
2976 const bool search_short_help =
true;
2977 const bool search_long_help =
false;
2978 const bool search_syntax =
false;
2979 const bool search_options =
false;
2980 if (command_name.contains_insensitive(search_word) ||
2982 search_long_help, search_syntax,
2991 multiword_cmd->GetSubcommandDictionary());
2992 for (
const auto &subcommand_name : subcommands_found) {
2993 std::string qualified_name =
2994 (command_name +
" " + subcommand_name).str();
3004 bool search_builtin_commands,
3005 bool search_user_commands,
3006 bool search_alias_commands,
3007 bool search_user_mw_commands) {
3008 CommandObject::CommandMap::const_iterator pos;
3010 if (search_builtin_commands)
3014 if (search_user_commands)
3018 if (search_user_mw_commands)
3022 if (search_alias_commands)
3077 bool was_interrupted =
3080 return was_interrupted;
3084 llvm::StringRef str,
3090 bool had_output = !str.empty();
3091 while (!str.empty()) {
3092 llvm::StringRef line;
3093 std::tie(line, str) = str.split(
'\n');
3095 std::lock_guard<std::recursive_mutex> guard(io_handler.
GetOutputMutex());
3096 stream->Write(line.data(), line.size());
3097 stream->Write(
"\n", 1);
3101 std::lock_guard<std::recursive_mutex> guard(io_handler.
GetOutputMutex());
3104 stream->Printf(
"\n... Interrupted.\n");
3109 llvm::StringRef line,
const Flags &io_handler_flags)
const {
3113 llvm::StringRef command = line.trim();
3114 if (command.empty())
3124 std::string &line) {
3130 const bool allow_repeats =
3133 if (!is_interactive && !allow_repeats) {
3142 if (!is_interactive) {
3147 std::lock_guard<std::recursive_mutex> guard(io_handler.
GetOutputMutex());
3149 "%s%s\n", io_handler.
GetPrompt(), line.c_str());
3156 bool pushed_exe_ctx =
false;
3159 pushed_exe_ctx =
true;
3161 auto finalize = llvm::make_scope_exit([
this, pushed_exe_ctx]() {
3170 if ((result.Succeeded() &&
3176 if (!result.GetImmediateOutputStream()) {
3177 llvm::StringRef output = result.GetOutputData();
3182 if (!result.GetImmediateErrorStream()) {
3183 llvm::StringRef
error = result.GetErrorData();
3190 switch (result.GetStatus()) {
3219 result.GetDidChangeProcessState() &&
3244 if (script_interpreter) {
3253 if (output_file == std::nullopt || output_file->empty()) {
3254 std::string now = llvm::to_string(std::chrono::system_clock::now());
3255 std::replace(now.begin(), now.end(),
' ',
'_');
3257 std::replace(now.begin(), now.end(),
':',
'-');
3258 const std::string file_name =
"lldb_session_" + now +
".log";
3263 save_location = HostInfo::GetGlobalTempDir();
3267 output_file = save_location.
GetPath();
3270 auto error_out = [&](llvm::StringRef error_message, std::string description) {
3272 output_file, description);
3274 "Failed to save session's transcripts to {0}!", *output_file);
3285 return error_out(
"Unable to create file",
3286 llvm::toString(opened_file.takeError()));
3288 FileUP file = std::move(opened_file.get());
3295 return error_out(
"Unable to write to destination file",
3296 "Bytes written do not match transcript size.");
3300 output_file->c_str());
3304 error = file->GetFileSpec(
const_cast<FileSpec &
>(file_spec));
3305 if (
error.Success()) {
3331 llvm::StringRef(prompt),
3338 if (io_handler_sp) {
3339 io_handler_sp->SetUserData(baton);
3350 llvm::StringRef(prompt),
3357 if (io_handler_sp) {
3358 io_handler_sp->SetUserData(baton);
3418 bool force_create =
true;
3446 std::string scratch_command(command_line);
3450 bool wants_raw_input =
false;
3451 std::string next_word;
3455 auto build_alias_cmd = [&](std::string &full_name) {
3456 revised_command_line.
Clear();
3458 std::string alias_result;
3461 revised_command_line.
Printf(
"%s", alias_result.c_str());
3468 char quote_char =
'\0';
3471 if (cmd_obj ==
nullptr) {
3472 std::string full_name;
3475 bool is_real_command =
3476 (!is_alias) || (cmd_obj !=
nullptr && !cmd_obj->
IsAlias());
3477 if (!is_real_command) {
3478 build_alias_cmd(full_name);
3482 revised_command_line.
Printf(
"%s", cmd_name.str().c_str());
3485 revised_command_line.
Printf(
"%s", next_word.c_str());
3496 revised_command_line.
Clear();
3497 revised_command_line.
Printf(
"%s", sub_cmd_name.str().c_str());
3498 cmd_obj = sub_cmd_obj;
3502 revised_command_line.
Printf(
" %c%s%s%c", quote_char,
3503 next_word.c_str(), suffix.c_str(),
3506 revised_command_line.
Printf(
" %s%s", next_word.c_str(),
3512 revised_command_line.
Printf(
" %c%s%s%c", quote_char,
3513 next_word.c_str(), suffix.c_str(),
3516 revised_command_line.
Printf(
" %s%s", next_word.c_str(),
3522 if (cmd_obj ==
nullptr) {
3523 const size_t num_matches = matches.
GetSize();
3528 if (alias_matches.
GetSize() == 1) {
3529 std::string full_name;
3531 build_alias_cmd(full_name);
3532 done =
static_cast<bool>(cmd_obj);
3535 error_msg.
Printf(
"Ambiguous command '%s'. Possible matches:\n",
3538 for (uint32_t i = 0; i < num_matches; ++i) {
3554 if (!suffix.empty()) {
3556 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3557 "might be invalid).\n",
3559 next_word.empty() ?
"" : next_word.c_str(),
3560 next_word.empty() ?
" -- " :
" ", suffix.c_str());
3566 if (!suffix.empty()) {
3567 switch (suffix[0]) {
3572 if (command_options &&
3574 std::string gdb_format_option(
"--gdb-format=");
3575 gdb_format_option += (suffix.c_str() + 1);
3577 std::string cmd = std::string(revised_command_line.
GetString());
3579 if (arg_terminator_idx != std::string::npos) {
3582 gdb_format_option.append(1,
' ');
3583 cmd.insert(arg_terminator_idx, gdb_format_option);
3584 revised_command_line.
Clear();
3587 revised_command_line.
Printf(
" %s", gdb_format_option.c_str());
3589 if (wants_raw_input &&
3594 "the '%s' command doesn't support the --gdb-format option\n",
3603 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3608 if (scratch_command.empty())
3612 if (!scratch_command.empty())
3613 revised_command_line.
Printf(
" %s", scratch_command.c_str());
3615 if (cmd_obj !=
nullptr)
3616 command_line = std::string(revised_command_line.
GetString());
3622 llvm::json::Object stats;
3624 stats.try_emplace(command_usage.getKey(), command_usage.getValue());
static const char * k_valid_command_chars
static constexpr const char * InitFileWarning
static size_t FindArgumentTerminator(const std::string &s)
#define REGISTER_COMMAND_OBJECT(NAME, CLASS)
static void StripLeadingSpaces(std::string &s)
static void GetHomeREPLInitFile(llvm::SmallVectorImpl< char > &init_file, LanguageType language)
static void GetCwdInitFile(llvm::SmallVectorImpl< char > &init_file)
static const char * k_white_space
static void GetHomeInitFile(llvm::SmallVectorImpl< char > &init_file, llvm::StringRef suffix={})
@ eHandleCommandFlagAllowRepeats
@ eHandleCommandFlagStopOnCrash
@ eHandleCommandFlagEchoCommentCommand
@ eHandleCommandFlagStopOnError
@ eHandleCommandFlagStopOnContinue
@ eHandleCommandFlagPrintErrors
@ eHandleCommandFlagEchoCommand
@ eHandleCommandFlagPrintResult
static bool ExtractCommand(std::string &command_string, std::string &command, std::string &suffix, char "e_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.
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
static double elapsed(const StatsTimepoint &start, const StatsTimepoint &end)
#define LLDB_SCOPED_TIMER()
#define LLDB_SCOPED_TIMERF(...)
A command line argument class.
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.
void Shift()
Shifts the first argument C string value of the array off the argument array.
void SetArguments(size_t argc, const char **argv)
Sets the argument vector value, optionally copying all arguments into an internal buffer.
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
void AppendArgument(llvm::StringRef arg_str, char quote_char='\0')
Appends a new argument to the end of the list argument list.
llvm::ArrayRef< ArgEntry > entries() const
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
const char ** GetConstArgumentVector() const
Gets the argument vector.
void Clear()
Clear the arguments.
An event broadcasting class.
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.
void CheckInWithManager()
OptionArgVectorSP GetOptionArguments() const
void SetHelp(llvm::StringRef str) override
void SetHelpLong(llvm::StringRef str) override
std::optional< llvm::StringRef > FindString(llvm::StringRef input_str) const
static const char g_repeat_char
llvm::StringRef GetStringAtIndex(size_t idx) const
void AppendString(llvm::StringRef str, bool reject_if_dupe=true)
bool GetSpawnThread() const
void SetStopOnContinue(bool stop_on_continue)
void SetSilent(bool silent)
bool GetAutoHandleEvents() const
void SetPrintErrors(bool print_errors)
LazyBool m_add_to_history
bool GetStopOnCrash() const
bool GetAddToHistory() const
bool GetStopOnContinue() const
bool GetPrintResults() const
void SetStopOnError(bool stop_on_error)
bool GetStopOnError() const
bool GetEchoCommands() const
LazyBool m_echo_comment_commands
LazyBool m_stop_on_continue
bool IsResult(lldb::CommandInterpreterResult result)
void SetResult(lldb::CommandInterpreterResult result)
void IncrementNumberOfErrors()
CommandUsageMap m_command_usages
bool m_skip_lldbinit_files
bool GetSaveTranscript() const
bool EchoCommandNonInteractive(llvm::StringRef line, const Flags &io_handler_flags) const
void UpdatePrompt(llvm::StringRef prompt)
bool IOHandlerInterrupt(IOHandler &io_handler) override
lldb::IOHandlerSP m_command_io_handler_sp
void SetPromptOnQuit(bool enable)
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.
llvm::json::Value GetStatistics()
void LoadCommandDictionary()
std::stack< ExecutionContext > m_overriden_exe_contexts
bool GetStopCmdSourceOnError() const
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
static const char * g_no_argument
void SetEchoCommands(bool enable)
bool RemoveAlias(llvm::StringRef alias_name)
void SetSaveSessionDirectory(llvm::StringRef path)
bool HasAliasOptions() const
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
void SetOpenTranscriptInEditor(bool enable)
void HandleCompletion(CompletionRequest &request)
CommandInterpreterRunResult m_result
bool GetSpaceReplPrompts() const
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)
bool DidProcessStopAbnormally() const
CommandObject::CommandMap m_user_dict
std::optional< int > m_quit_exit_code
ExecutionContext GetExecutionContext() const
const CommandObject::CommandMap & GetUserCommands() const
CommandObject * GetUserCommandObject(llvm::StringRef cmd, StringList *matches=nullptr, StringList *descriptions=nullptr) const
void SourceInitFileGlobal(CommandReturnObject &result)
@ eBroadcastBitQuitCommandReceived
@ eBroadcastBitResetPrompt
@ eBroadcastBitThreadShouldExit
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.
bool GetEchoCommentCommands() const
bool WasInterrupted() const
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)
int m_iohandler_nesting_level
bool GetOpenTranscriptInEditor() const
bool AliasExists(llvm::StringRef cmd) const
Determine whether an alias command with this name exists.
bool GetExpandRegexAliases() const
int GetOptionArgumentPosition(const char *in_string)
Picks the number out of a string of the form "%NNN", otherwise return 0.
bool HasUserMultiwordCommands() const
void StartHandlingCommand()
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 GetPromptOnQuit() const
std::string m_repeat_command
const char * GetCommandPrefix()
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)
bool GetRequireCommandOverwrite() const
void RestoreExecutionContext()
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
void FinishHandlingCommand()
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)
static const char * g_need_argument
bool m_skip_app_init_files
void SetSynchronous(bool value)
uint32_t m_command_source_depth
Status PreprocessToken(std::string &token)
bool RemoveUserMultiword(llvm::StringRef multiword_name)
bool GetSaveSessionOnQuit() const
FileSpec GetSaveSessionDirectory() const
bool UserCommandExists(llvm::StringRef cmd) const
Determine whether a root-level user command with this name exists.
bool GetRepeatPreviousCommand() const
lldb::IOHandlerSP GetIOHandler(bool force_create=false, CommandInterpreterRunOptions *options=nullptr)
bool HasUserCommands() const
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
CommandHistory m_command_history
CommandObject * BuildAliasResult(llvm::StringRef alias_name, std::string &raw_input_string, std::string &alias_result, CommandReturnObject &result)
void OverrideExecutionContext(const ExecutionContext &override_context)
bool SetBatchCommandMode(bool value)
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
bool m_synchronous_execution
StreamString m_transcript_stream
Turn on settings interpreter.save-transcript for LLDB to populate this stream.
void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context, const CommandInterpreterRunOptions &options, CommandReturnObject &result)
Execute a list of commands from a file.
void SourceInitFileCwd(CommandReturnObject &result)
void SetSaveSessionOnQuit(bool enable)
static const char * g_argument
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.
void SetSaveTranscript(bool enable)
FileSpec GetCurrentSourceDir()
void SetEchoCommentCommands(bool enable)
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
bool GetEchoCommands() const
Implements dwim-print, a printing command that chooses the most direct, efficient,...
lldb::CommandObjectSP GetSubcommandSPExact(llvm::StringRef sub_cmd) override
CommandObjectMultiword * GetAsMultiwordCommand() override
virtual bool WantsRawCommandString()=0
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 bool IsMultiwordObject()
virtual void Execute(const char *args_string, CommandReturnObject &result)=0
virtual std::optional< std::string > GetRepeatCommand(Args ¤t_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...
std::map< std::string, lldb::CommandObjectSP > CommandMap
virtual llvm::StringRef GetHelp()
void AppendErrorWithFormatv(const char *format, Args &&... args)
void AppendMessage(llvm::StringRef in_string)
bool GetInteractive() const
void void AppendError(llvm::StringRef in_string)
lldb::StreamSP GetImmediateOutputStream()
bool GetDidChangeProcessState() const
void SetSuppressImmediateOutput(bool b)
llvm::StringRef GetErrorData()
void SetInteractive(bool b)
void AppendRawError(llvm::StringRef in_string)
llvm::StringRef GetOutputData()
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void AppendMessageWithFormat(const char *format,...) __attribute__((format(printf
lldb::StreamSP GetImmediateErrorStream()
lldb::ReturnStatus GetStatus() const
Stream & GetOutputStream()
"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.
const Args & GetParsedLine() const
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.
size_t GetCursorIndex() const
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
A class to manage flag bits.
ExecutionContext GetSelectedExecutionContext()
bool StartEventHandlerThread()
Manually start the global event handler thread.
void StopEventHandlerThread()
Manually stop the debugger's default event handler.
void SetAsyncExecution(bool async)
HostThread SetIOHandlerThread(HostThread &new_thread)
lldb::FileSP GetInputFileSP()
bool StartIOHandlerThread()
bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp)
bool IsIOHandlerThreadCurrentThread() const
uint64_t GetTerminalWidth() const
const char * GetIOHandlerCommandPrefix()
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, bool cancel_top_handler=true)
Run the given IO handler and return immediately.
lldb::StreamFileSP GetErrorStreamSP()
bool GetAutoConfirm() const
PlatformList & GetPlatformList()
Target & GetDummyTarget()
void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp)
Run the given IO handler and block until it's complete.
lldb::StreamFileSP GetOutputStreamSP()
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
llvm::StringRef GetExternalEditor() const
llvm::StringRef GetPrompt() const
void FlushProcessOutput(Process &process, bool flush_stdout, bool flush_stderr)
Force flushing the process's pending stdout and stderr to the debugger's asynchronous stdout and stde...
A class that measures elapsed time in an exception safe way.
void SetUnwindOnError(bool unwind=false)
void SetKeepInMemory(bool keep=true)
void SetCoerceToId(bool coerce=true)
void SetTryAllThreads(bool try_others=true)
void SetTimeout(const Timeout< std::micro > &timeout)
void SetIgnoreBreakpoints(bool ignore=false)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
StackFrame * GetFramePtr() const
Returns a pointer to the frame object.
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.
void AppendPathComponent(llvm::StringRef component)
const ConstString & GetFilename() const
Filename string const get accessor.
void MakeAbsolute(const FileSpec &dir)
Make the FileSpec absolute by treating it relative to dir.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
FileSpec CopyByRemovingLastPathComponent() const
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
bool GetHomeDirectory(llvm::SmallVectorImpl< char > &path) const
Get the user home directory.
int Open(const char *path, int flags, int mode=0600)
Wraps ::open in a platform-independent way.
static FileSystem & Instance()
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
bool Test(ValueType bit) const
Test a single flag bit.
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)
A delegate class for use with IOHandler subclasses.
lldb::StreamFileSP GetErrorStreamFileSP()
virtual const char * GetPrompt()
std::recursive_mutex & GetOutputMutex()
lldb::StreamFileSP GetOutputStreamFileSP()
bool GetIsInteractive()
Check if the input is being supplied interactively by a user.
static LanguageSet GetLanguagesSupportingREPLs()
static const char * GetNameForLanguageType(lldb::LanguageType language)
A command line option parsing protocol class.
bool SupportsLongOption(const char *long_option)
A plug-in interface definition class for debugging a process.
lldb::StateType GetState()
Get accessor for the current process state.
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
lldb::OptionValuePropertiesSP m_collection_sp
bool SetPropertyAtIndex(uint32_t idx, T t, const ExecutionContext *exe_ctx=nullptr) const
void GetValue(Stream &s, bool show_type) const
void SetErrorStringWithFormatv(const char *format, Args &&... args)
void Clear()
Clear the object state.
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
const char * GetData() const
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
size_t EOL()
Output and End of Line character to the stream.
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
void IndentMore(unsigned amount=2)
Increment the current indentation level.
void AppendString(const std::string &s)
const char * GetStringAtIndex(size_t idx) const
void DeleteStringAtIndex(size_t id)
void AddItem(const ObjectSP &item)
std::shared_ptr< Dictionary > DictionarySP
LoadCWDlldbinitFile GetLoadCWDlldbinitFile() const
static TargetProperties & GetGlobalProperties()
lldb::PlatformSP GetPlatform()
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)
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.
int AddNamesMatchingPartialString(const std::map< std::string, ValueType > &in_map, llvm::StringRef cmd_str, StringList &matches, StringList *descriptions=nullptr)
std::shared_ptr< OptionArgVector > OptionArgVectorSP
bool StateIsRunningState(lldb::StateType state)
Check if a state represents a state where the process or thread is running.
size_t FindLongestCommandWord(std::map< std::string, ValueType > &dict)
@ RewriteLine
The full line has been rewritten by the completion.
const char * toString(AppleArm64ExceptionClass EC)
std::vector< std::tuple< std::string, int, std::string > > OptionArgVector
std::shared_ptr< lldb_private::OptionValueProperties > OptionValuePropertiesSP
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.
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Event > EventSP
@ eReturnStatusSuccessContinuingResult
@ eReturnStatusSuccessContinuingNoResult
@ eReturnStatusSuccessFinishResult
@ eReturnStatusSuccessFinishNoResult
std::shared_ptr< lldb_private::StreamFile > StreamFileSP
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
StopReason
Thread stop reasons.
@ eStopReasonInstrumentation
@ eStopReasonInterrupt
Thread requested interrupt.
@ eStopReasonProcessorTrace
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::File > FileSP
const char * c_str() const
llvm::StringRef ref() const
char GetQuoteChar() const
A SmallBitVector that represents a set of source languages (lldb::LanguageType).
std::optional< lldb::LanguageType > GetSingularLanguage()
If the set contains a single language only, return it.