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 <cstdlib>
10#include <limits>
11#include <memory>
12#include <optional>
13#include <string>
14#include <vector>
15
46
47#include "lldb/Core/Debugger.h"
51#include "lldb/Utility/Log.h"
52#include "lldb/Utility/State.h"
53#include "lldb/Utility/Stream.h"
54#include "lldb/Utility/Timer.h"
55
56#include "lldb/Host/Config.h"
57#if LLDB_ENABLE_LIBEDIT
58#include "lldb/Host/Editline.h"
59#endif
60#include "lldb/Host/File.h"
61#include "lldb/Host/FileCache.h"
62#include "lldb/Host/Host.h"
63#include "lldb/Host/HostInfo.h"
64
71#include "lldb/Utility/Args.h"
72
74#include "lldb/Target/Process.h"
77#include "lldb/Target/Thread.h"
79
80#include "llvm/ADT/STLExtras.h"
81#include "llvm/ADT/ScopeExit.h"
82#include "llvm/ADT/SmallString.h"
83#include "llvm/Support/FormatAdapters.h"
84#include "llvm/Support/Path.h"
85#include "llvm/Support/PrettyStackTrace.h"
86#include "llvm/Support/ScopedPrinter.h"
87
88#if defined(__APPLE__)
89#include <TargetConditionals.h>
90#endif
91
92using namespace lldb;
93using namespace lldb_private;
94
95static const char *k_white_space = " \t\v";
96
97static constexpr const char *InitFileWarning =
98 "There is a .lldbinit file in the current directory which is not being "
99 "read.\n"
100 "To silence this warning without sourcing in the local .lldbinit,\n"
101 "add the following to the lldbinit file in your home directory:\n"
102 " settings set target.load-cwd-lldbinit false\n"
103 "To allow lldb to source .lldbinit files in the current working "
104 "directory,\n"
105 "set the value of this variable to true. Only do so if you understand "
106 "and\n"
107 "accept the security risk.";
108
109const char *CommandInterpreter::g_no_argument = "<no-argument>";
110const char *CommandInterpreter::g_need_argument = "<need-argument>";
111const char *CommandInterpreter::g_argument = "<argument>";
112
113
114#define LLDB_PROPERTIES_interpreter
115#include "InterpreterProperties.inc"
116
117enum {
118#define LLDB_PROPERTIES_interpreter
119#include "InterpreterPropertiesEnum.inc"
120};
121
123 static ConstString class_name("lldb.commandInterpreter");
124 return class_name;
125}
126
128 bool synchronous_execution)
129 : Broadcaster(debugger.GetBroadcasterManager(),
130 CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
131 Properties(OptionValuePropertiesSP(
132 new OptionValueProperties(ConstString("interpreter")))),
134 m_debugger(debugger), m_synchronous_execution(true),
135 m_skip_lldbinit_files(false), m_skip_app_init_files(false),
136 m_comment_char('#'), m_batch_command_mode(false),
137 m_truncation_warning(eNoOmission), m_max_depth_warning(eNoOmission),
138 m_command_source_depth(0) {
139 SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
140 SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
142 SetSynchronous(synchronous_execution);
144 m_collection_sp->Initialize(g_interpreter_properties);
145}
146
148 const uint32_t idx = ePropertyExpandRegexAliases;
149 return GetPropertyAtIndexAs<bool>(
150 idx, g_interpreter_properties[idx].default_uint_value != 0);
151}
152
154 const uint32_t idx = ePropertyPromptOnQuit;
155 return GetPropertyAtIndexAs<bool>(
156 idx, g_interpreter_properties[idx].default_uint_value != 0);
157}
158
160 const uint32_t idx = ePropertyPromptOnQuit;
161 SetPropertyAtIndex(idx, enable);
162}
163
165 const uint32_t idx = ePropertySaveSessionOnQuit;
166 return GetPropertyAtIndexAs<bool>(
167 idx, g_interpreter_properties[idx].default_uint_value != 0);
168}
169
171 const uint32_t idx = ePropertySaveSessionOnQuit;
172 SetPropertyAtIndex(idx, enable);
173}
174
176 const uint32_t idx = ePropertyOpenTranscriptInEditor;
177 return GetPropertyAtIndexAs<bool>(
178 idx, g_interpreter_properties[idx].default_uint_value != 0);
179}
180
182 const uint32_t idx = ePropertyOpenTranscriptInEditor;
183 SetPropertyAtIndex(idx, enable);
184}
185
187 const uint32_t idx = ePropertySaveSessionDirectory;
188 return GetPropertyAtIndexAs<FileSpec>(idx, {});
189}
190
192 const uint32_t idx = ePropertySaveSessionDirectory;
193 SetPropertyAtIndex(idx, path);
194}
195
197 const uint32_t idx = ePropertyEchoCommands;
198 return GetPropertyAtIndexAs<bool>(
199 idx, g_interpreter_properties[idx].default_uint_value != 0);
200}
201
203 const uint32_t idx = ePropertyEchoCommands;
204 SetPropertyAtIndex(idx, enable);
205}
206
208 const uint32_t idx = ePropertyEchoCommentCommands;
209 return GetPropertyAtIndexAs<bool>(
210 idx, g_interpreter_properties[idx].default_uint_value != 0);
211}
212
214 const uint32_t idx = ePropertyEchoCommentCommands;
215 SetPropertyAtIndex(idx, enable);
216}
217
219 m_allow_exit_code = allow;
220 if (!allow)
221 m_quit_exit_code.reset();
222}
223
226 return false;
227 m_quit_exit_code = exit_code;
228 return true;
229}
230
231int CommandInterpreter::GetQuitExitCode(bool &exited) const {
232 exited = m_quit_exit_code.has_value();
233 if (exited)
234 return *m_quit_exit_code;
235 return 0;
236}
237
238void CommandInterpreter::ResolveCommand(const char *command_line,
239 CommandReturnObject &result) {
240 std::string command = command_line;
241 if (ResolveCommandImpl(command, result) != nullptr) {
242 result.AppendMessageWithFormat("%s", command.c_str());
244 }
245}
246
248 const uint32_t idx = ePropertyStopCmdSourceOnError;
249 return GetPropertyAtIndexAs<bool>(
250 idx, g_interpreter_properties[idx].default_uint_value != 0);
251}
252
254 const uint32_t idx = ePropertySpaceReplPrompts;
255 return GetPropertyAtIndexAs<bool>(
256 idx, g_interpreter_properties[idx].default_uint_value != 0);
257}
258
260 const uint32_t idx = ePropertyRepeatPreviousCommand;
261 return GetPropertyAtIndexAs<bool>(
262 idx, g_interpreter_properties[idx].default_uint_value != 0);
263}
264
266 const uint32_t idx = ePropertyRequireCommandOverwrite;
267 return GetPropertyAtIndexAs<bool>(
268 idx, g_interpreter_properties[idx].default_uint_value != 0);
269}
270
273
275
277
278 // An alias arguments vector to reuse - reset it before use...
279 OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
280
281 // Set up some initial aliases.
282 CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit");
283 if (cmd_obj_sp) {
284 AddAlias("q", cmd_obj_sp);
285 AddAlias("exit", cmd_obj_sp);
286 }
287
288 cmd_obj_sp = GetCommandSPExact("_regexp-attach");
289 if (cmd_obj_sp)
290 AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
291
292 cmd_obj_sp = GetCommandSPExact("process detach");
293 if (cmd_obj_sp) {
294 AddAlias("detach", cmd_obj_sp);
295 }
296
297 cmd_obj_sp = GetCommandSPExact("process continue");
298 if (cmd_obj_sp) {
299 AddAlias("c", cmd_obj_sp);
300 AddAlias("continue", cmd_obj_sp);
301 }
302
303 cmd_obj_sp = GetCommandSPExact("_regexp-break");
304 if (cmd_obj_sp)
305 AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
306
307 cmd_obj_sp = GetCommandSPExact("_regexp-tbreak");
308 if (cmd_obj_sp)
309 AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
310
311 cmd_obj_sp = GetCommandSPExact("thread step-inst");
312 if (cmd_obj_sp) {
313 AddAlias("stepi", cmd_obj_sp);
314 AddAlias("si", cmd_obj_sp);
315 }
316
317 cmd_obj_sp = GetCommandSPExact("thread step-inst-over");
318 if (cmd_obj_sp) {
319 AddAlias("nexti", cmd_obj_sp);
320 AddAlias("ni", cmd_obj_sp);
321 }
322
323 cmd_obj_sp = GetCommandSPExact("thread step-in");
324 if (cmd_obj_sp) {
325 AddAlias("s", cmd_obj_sp);
326 AddAlias("step", cmd_obj_sp);
327 CommandAlias *sif_alias = AddAlias(
328 "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
329 if (sif_alias) {
330 sif_alias->SetHelp("Step through the current block, stopping if you step "
331 "directly into a function whose name matches the "
332 "TargetFunctionName.");
333 sif_alias->SetSyntax("sif <TargetFunctionName>");
334 }
335 }
336
337 cmd_obj_sp = GetCommandSPExact("thread step-over");
338 if (cmd_obj_sp) {
339 AddAlias("n", cmd_obj_sp);
340 AddAlias("next", cmd_obj_sp);
341 }
342
343 cmd_obj_sp = GetCommandSPExact("thread step-out");
344 if (cmd_obj_sp) {
345 AddAlias("finish", cmd_obj_sp);
346 }
347
348 cmd_obj_sp = GetCommandSPExact("frame select");
349 if (cmd_obj_sp) {
350 AddAlias("f", cmd_obj_sp);
351 }
352
353 cmd_obj_sp = GetCommandSPExact("thread select");
354 if (cmd_obj_sp) {
355 AddAlias("t", cmd_obj_sp);
356 }
357
358 cmd_obj_sp = GetCommandSPExact("_regexp-jump");
359 if (cmd_obj_sp) {
360 AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
361 AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
362 }
363
364 cmd_obj_sp = GetCommandSPExact("_regexp-list");
365 if (cmd_obj_sp) {
366 AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
367 AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
368 }
369
370 cmd_obj_sp = GetCommandSPExact("_regexp-env");
371 if (cmd_obj_sp)
372 AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
373
374 cmd_obj_sp = GetCommandSPExact("memory read");
375 if (cmd_obj_sp)
376 AddAlias("x", cmd_obj_sp);
377
378 cmd_obj_sp = GetCommandSPExact("_regexp-up");
379 if (cmd_obj_sp)
380 AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
381
382 cmd_obj_sp = GetCommandSPExact("_regexp-down");
383 if (cmd_obj_sp)
384 AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
385
386 cmd_obj_sp = GetCommandSPExact("_regexp-display");
387 if (cmd_obj_sp)
388 AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
389
390 cmd_obj_sp = GetCommandSPExact("disassemble");
391 if (cmd_obj_sp)
392 AddAlias("dis", cmd_obj_sp);
393
394 cmd_obj_sp = GetCommandSPExact("disassemble");
395 if (cmd_obj_sp)
396 AddAlias("di", cmd_obj_sp);
397
398 cmd_obj_sp = GetCommandSPExact("_regexp-undisplay");
399 if (cmd_obj_sp)
400 AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
401
402 cmd_obj_sp = GetCommandSPExact("_regexp-bt");
403 if (cmd_obj_sp)
404 AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
405
406 cmd_obj_sp = GetCommandSPExact("target create");
407 if (cmd_obj_sp)
408 AddAlias("file", cmd_obj_sp);
409
410 cmd_obj_sp = GetCommandSPExact("target modules");
411 if (cmd_obj_sp)
412 AddAlias("image", cmd_obj_sp);
413
414 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
415
416 cmd_obj_sp = GetCommandSPExact("dwim-print");
417 if (cmd_obj_sp) {
418 AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
419 AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
420 if (auto *po = AddAlias("po", cmd_obj_sp, "-O --")) {
421 po->SetHelp("Evaluate an expression on the current thread. Displays any "
422 "returned value with formatting "
423 "controlled by the type's author.");
424 po->SetHelpLong("");
425 }
426 }
427
428 cmd_obj_sp = GetCommandSPExact("expression");
429 if (cmd_obj_sp) {
430 AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
431 CommandAlias *parray_alias =
432 AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
433 if (parray_alias) {
434 parray_alias->SetHelp
435 ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
436 "to get a typed-pointer-to-an-array in memory, and will display "
437 "COUNT elements of that type from the array.");
438 parray_alias->SetHelpLong("");
439 }
440 CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
441 "--object-description --element-count %1 --");
442 if (poarray_alias) {
443 poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
444 "evaluate EXPRESSION to get the address of an array of COUNT "
445 "objects in memory, and will call po on them.");
446 poarray_alias->SetHelpLong("");
447 }
448 }
449
450 cmd_obj_sp = GetCommandSPExact("platform shell");
451 if (cmd_obj_sp) {
452 CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --");
453 if (shell_alias) {
454 shell_alias->SetHelp("Run a shell command on the host.");
455 shell_alias->SetHelpLong("");
456 shell_alias->SetSyntax("shell <shell-command>");
457 }
458 }
459
460 cmd_obj_sp = GetCommandSPExact("process kill");
461 if (cmd_obj_sp) {
462 AddAlias("kill", cmd_obj_sp);
463 }
464
465 cmd_obj_sp = GetCommandSPExact("process launch");
466 if (cmd_obj_sp) {
467 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
468#if defined(__APPLE__)
469#if TARGET_OS_IPHONE
470 AddAlias("r", cmd_obj_sp, "--");
471 AddAlias("run", cmd_obj_sp, "--");
472#else
473 AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
474 AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
475#endif
476#else
477 StreamString defaultshell;
478 defaultshell.Printf("--shell=%s --",
479 HostInfo::GetDefaultShell().GetPath().c_str());
480 AddAlias("r", cmd_obj_sp, defaultshell.GetString());
481 AddAlias("run", cmd_obj_sp, defaultshell.GetString());
482#endif
483 }
484
485 cmd_obj_sp = GetCommandSPExact("target symbols add");
486 if (cmd_obj_sp) {
487 AddAlias("add-dsym", cmd_obj_sp);
488 }
489
490 cmd_obj_sp = GetCommandSPExact("breakpoint set");
491 if (cmd_obj_sp) {
492 AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
493 }
494
495 cmd_obj_sp = GetCommandSPExact("frame variable");
496 if (cmd_obj_sp) {
497 AddAlias("v", cmd_obj_sp);
498 AddAlias("var", cmd_obj_sp);
499 AddAlias("vo", cmd_obj_sp, "--object-description");
500 }
501
502 cmd_obj_sp = GetCommandSPExact("register");
503 if (cmd_obj_sp) {
504 AddAlias("re", cmd_obj_sp);
505 }
506
507 cmd_obj_sp = GetCommandSPExact("session history");
508 if (cmd_obj_sp) {
509 AddAlias("history", cmd_obj_sp);
510 }
511}
512
515}
516
518 // This function has not yet been implemented.
519
520 // Look for any embedded script command
521 // If found,
522 // get interpreter object from the command dictionary,
523 // call execute_one_command on it,
524 // get the results as a string,
525 // substitute that string for current stuff.
526
527 return arg;
528}
529
530#define REGISTER_COMMAND_OBJECT(NAME, CLASS) \
531 m_command_dict[NAME] = std::make_shared<CLASS>(*this);
532
535
565
566 // clang-format off
567 const char *break_regexes[][2] = {
568 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
569 "breakpoint set --file '%1' --line %2 --column %3"},
570 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
571 "breakpoint set --file '%1' --line %2"},
572 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
573 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
574 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
575 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
576 "breakpoint set --name '%1'"},
577 {"^(-.*)$", "breakpoint set %1"},
578 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
579 "breakpoint set --name '%2' --shlib '%1'"},
580 {"^\\&(.*[^[:space:]])[[:space:]]*$",
581 "breakpoint set --name '%1' --skip-prologue=0"},
582 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
583 "breakpoint set --name '%1'"}};
584 // clang-format on
585
586 size_t num_regexes = std::size(break_regexes);
587
588 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
590 *this, "_regexp-break",
591 "Set a breakpoint using one of several shorthand formats.",
592 "\n"
593 "_regexp-break <filename>:<linenum>:<colnum>\n"
594 " main.c:12:21 // Break at line 12 and column "
595 "21 of main.c\n\n"
596 "_regexp-break <filename>:<linenum>\n"
597 " main.c:12 // Break at line 12 of "
598 "main.c\n\n"
599 "_regexp-break <linenum>\n"
600 " 12 // Break at line 12 of current "
601 "file\n\n"
602 "_regexp-break 0x<address>\n"
603 " 0x1234000 // Break at address "
604 "0x1234000\n\n"
605 "_regexp-break <name>\n"
606 " main // Break in 'main' after the "
607 "prologue\n\n"
608 "_regexp-break &<name>\n"
609 " &main // Break at first instruction "
610 "in 'main'\n\n"
611 "_regexp-break <module>`<name>\n"
612 " libc.so`malloc // Break in 'malloc' from "
613 "'libc.so'\n\n"
614 "_regexp-break /<source-regex>/\n"
615 " /break here/ // Break on source lines in "
616 "current file\n"
617 " // containing text 'break "
618 "here'.\n",
621 false));
622
623 if (break_regex_cmd_up) {
624 bool success = true;
625 for (size_t i = 0; i < num_regexes; i++) {
626 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
627 break_regexes[i][1]);
628 if (!success)
629 break;
630 }
631 success =
632 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
633
634 if (success) {
635 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
636 m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
637 break_regex_cmd_sp;
638 }
639 }
640
641 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
643 *this, "_regexp-tbreak",
644 "Set a one-shot breakpoint using one of several shorthand formats.",
645 "\n"
646 "_regexp-break <filename>:<linenum>:<colnum>\n"
647 " main.c:12:21 // Break at line 12 and column "
648 "21 of main.c\n\n"
649 "_regexp-break <filename>:<linenum>\n"
650 " main.c:12 // Break at line 12 of "
651 "main.c\n\n"
652 "_regexp-break <linenum>\n"
653 " 12 // Break at line 12 of current "
654 "file\n\n"
655 "_regexp-break 0x<address>\n"
656 " 0x1234000 // Break at address "
657 "0x1234000\n\n"
658 "_regexp-break <name>\n"
659 " main // Break in 'main' after the "
660 "prologue\n\n"
661 "_regexp-break &<name>\n"
662 " &main // Break at first instruction "
663 "in 'main'\n\n"
664 "_regexp-break <module>`<name>\n"
665 " libc.so`malloc // Break in 'malloc' from "
666 "'libc.so'\n\n"
667 "_regexp-break /<source-regex>/\n"
668 " /break here/ // Break on source lines in "
669 "current file\n"
670 " // containing text 'break "
671 "here'.\n",
674 false));
675
676 if (tbreak_regex_cmd_up) {
677 bool success = true;
678 for (size_t i = 0; i < num_regexes; i++) {
679 std::string command = break_regexes[i][1];
680 command += " -o 1";
681 success =
682 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
683 if (!success)
684 break;
685 }
686 success =
687 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
688
689 if (success) {
690 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
691 m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
692 tbreak_regex_cmd_sp;
693 }
694 }
695
696 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
698 *this, "_regexp-attach", "Attach to process by ID or name.",
699 "_regexp-attach <pid> | <process-name>", 0, false));
700 if (attach_regex_cmd_up) {
701 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
702 "process attach --pid %1") &&
703 attach_regex_cmd_up->AddRegexCommand(
704 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
705 // specified get passed to
706 // 'process attach'
707 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
708 "process attach --name '%1'") &&
709 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
710 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
711 m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
712 attach_regex_cmd_sp;
713 }
714 }
715
716 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
717 new CommandObjectRegexCommand(*this, "_regexp-down",
718 "Select a newer stack frame. Defaults to "
719 "moving one frame, a numeric argument can "
720 "specify an arbitrary number.",
721 "_regexp-down [<count>]", 0, false));
722 if (down_regex_cmd_up) {
723 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
724 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
725 "frame select -r -%1")) {
726 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
727 m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
728 down_regex_cmd_sp;
729 }
730 }
731
732 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
734 *this, "_regexp-up",
735 "Select an older stack frame. Defaults to moving one "
736 "frame, a numeric argument can specify an arbitrary number.",
737 "_regexp-up [<count>]", 0, false));
738 if (up_regex_cmd_up) {
739 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
740 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
741 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
742 m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
743 up_regex_cmd_sp;
744 }
745 }
746
747 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
749 *this, "_regexp-display",
750 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
751 "_regexp-display expression", 0, false));
752 if (display_regex_cmd_up) {
753 if (display_regex_cmd_up->AddRegexCommand(
754 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
755 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
756 m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
757 display_regex_cmd_sp;
758 }
759 }
760
761 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
762 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
763 "Stop displaying expression at every "
764 "stop (specified by stop-hook index.)",
765 "_regexp-undisplay stop-hook-number", 0,
766 false));
767 if (undisplay_regex_cmd_up) {
768 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
769 "target stop-hook delete %1")) {
770 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
771 m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
772 undisplay_regex_cmd_sp;
773 }
774 }
775
776 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
778 *this, "gdb-remote",
779 "Connect to a process via remote GDB server.\n"
780 "If no host is specifed, localhost is assumed.\n"
781 "gdb-remote is an abbreviation for 'process connect --plugin "
782 "gdb-remote connect://<hostname>:<port>'\n",
783 "gdb-remote [<hostname>:]<portnum>", 0, false));
784 if (connect_gdb_remote_cmd_up) {
785 if (connect_gdb_remote_cmd_up->AddRegexCommand(
786 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
787 "process connect --plugin gdb-remote connect://%1:%2") &&
788 connect_gdb_remote_cmd_up->AddRegexCommand(
789 "^([[:digit:]]+)$",
790 "process connect --plugin gdb-remote connect://localhost:%1")) {
791 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
792 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
793 }
794 }
795
796 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
798 *this, "kdp-remote",
799 "Connect to a process via remote KDP server.\n"
800 "If no UDP port is specified, port 41139 is assumed.\n"
801 "kdp-remote is an abbreviation for 'process connect --plugin "
802 "kdp-remote udp://<hostname>:<port>'\n",
803 "kdp-remote <hostname>[:<portnum>]", 0, false));
804 if (connect_kdp_remote_cmd_up) {
805 if (connect_kdp_remote_cmd_up->AddRegexCommand(
806 "^([^:]+:[[:digit:]]+)$",
807 "process connect --plugin kdp-remote udp://%1") &&
808 connect_kdp_remote_cmd_up->AddRegexCommand(
809 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
810 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
811 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
812 }
813 }
814
815 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
817 *this, "_regexp-bt",
818 "Show the current thread's call stack. Any numeric argument "
819 "displays at most that many "
820 "frames. The argument 'all' displays all threads. Use 'settings"
821 " set frame-format' to customize the printing of individual frames "
822 "and 'settings set thread-format' to customize the thread header.",
823 "bt [<digit> | all]", 0, false));
824 if (bt_regex_cmd_up) {
825 // accept but don't document "bt -c <number>" -- before bt was a regex
826 // command if you wanted to backtrace three frames you would do "bt -c 3"
827 // but the intention is to have this emulate the gdb "bt" command and so
828 // now "bt 3" is the preferred form, in line with gdb.
829 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
830 "thread backtrace -c %1") &&
831 bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
832 "thread backtrace -c %1") &&
833 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
834 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
835 CommandObjectSP command_sp(bt_regex_cmd_up.release());
836 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
837 }
838 }
839
840 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
842 *this, "_regexp-list",
843 "List relevant source code using one of several shorthand formats.",
844 "\n"
845 "_regexp-list <file>:<line> // List around specific file/line\n"
846 "_regexp-list <line> // List current file around specified "
847 "line\n"
848 "_regexp-list <function-name> // List specified function\n"
849 "_regexp-list 0x<address> // List around specified address\n"
850 "_regexp-list -[<count>] // List previous <count> lines\n"
851 "_regexp-list // List subsequent lines",
853 if (list_regex_cmd_up) {
854 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
855 "source list --line %1") &&
856 list_regex_cmd_up->AddRegexCommand(
857 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
858 "]*$",
859 "source list --file '%1' --line %2") &&
860 list_regex_cmd_up->AddRegexCommand(
861 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
862 "source list --address %1") &&
863 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
864 "source list --reverse") &&
865 list_regex_cmd_up->AddRegexCommand(
866 "^-([[:digit:]]+)[[:space:]]*$",
867 "source list --reverse --count %1") &&
868 list_regex_cmd_up->AddRegexCommand("^(.+)$",
869 "source list --name \"%1\"") &&
870 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
871 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
872 m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
873 list_regex_cmd_sp;
874 }
875 }
876
877 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
879 *this, "_regexp-env",
880 "Shorthand for viewing and setting environment variables.",
881 "\n"
882 "_regexp-env // Show environment\n"
883 "_regexp-env <name>=<value> // Set an environment variable",
884 0, false));
885 if (env_regex_cmd_up) {
886 if (env_regex_cmd_up->AddRegexCommand("^$",
887 "settings show target.env-vars") &&
888 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
889 "settings set target.env-vars %1")) {
890 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
891 m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
892 env_regex_cmd_sp;
893 }
894 }
895
896 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
898 *this, "_regexp-jump", "Set the program counter to a new address.",
899 "\n"
900 "_regexp-jump <line>\n"
901 "_regexp-jump +<line-offset> | -<line-offset>\n"
902 "_regexp-jump <file>:<line>\n"
903 "_regexp-jump *<addr>\n",
904 0, false));
905 if (jump_regex_cmd_up) {
906 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
907 "thread jump --addr %1") &&
908 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
909 "thread jump --line %1") &&
910 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
911 "thread jump --file %1 --line %2") &&
912 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
913 "thread jump --by %1")) {
914 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
915 m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
916 jump_regex_cmd_sp;
917 }
918 }
919}
920
922 const char *cmd_str, bool include_aliases, StringList &matches,
923 StringList &descriptions) {
925 &descriptions);
926
927 if (include_aliases) {
929 &descriptions);
930 }
931
932 return matches.GetSize();
933}
934
936 Args &path, bool leaf_is_command, Status &result) {
937 result.Clear();
938
939 auto get_multi_or_report_error =
940 [&result](CommandObjectSP cmd_sp,
941 const char *name) -> CommandObjectMultiword * {
942 if (!cmd_sp) {
943 result.SetErrorStringWithFormat("Path component: '%s' not found", name);
944 return nullptr;
945 }
946 if (!cmd_sp->IsUserCommand()) {
947 result.SetErrorStringWithFormat("Path component: '%s' is not a user "
948 "command",
949 name);
950 return nullptr;
951 }
952 CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
953 if (!cmd_as_multi) {
954 result.SetErrorStringWithFormat("Path component: '%s' is not a container "
955 "command",
956 name);
957 return nullptr;
958 }
959 return cmd_as_multi;
960 };
961
962 size_t num_args = path.GetArgumentCount();
963 if (num_args == 0) {
964 result.SetErrorString("empty command path");
965 return nullptr;
966 }
967
968 if (num_args == 1 && leaf_is_command) {
969 // We just got a leaf command to be added to the root. That's not an error,
970 // just return null for the container.
971 return nullptr;
972 }
973
974 // Start by getting the root command from the interpreter.
975 const char *cur_name = path.GetArgumentAtIndex(0);
976 CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
977 CommandObjectMultiword *cur_as_multi =
978 get_multi_or_report_error(cur_cmd_sp, cur_name);
979 if (cur_as_multi == nullptr)
980 return nullptr;
981
982 size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
983 for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
984 cursor++) {
985 cur_name = path.GetArgumentAtIndex(cursor);
986 cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
987 cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
988 }
989 return cur_as_multi;
990}
991
992CommandObjectSP
993CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
994 bool exact, StringList *matches,
995 StringList *descriptions) const {
996 CommandObjectSP command_sp;
997
998 std::string cmd = std::string(cmd_str);
999
1000 if (HasCommands()) {
1001 auto pos = m_command_dict.find(cmd);
1002 if (pos != m_command_dict.end())
1003 command_sp = pos->second;
1004 }
1005
1006 if (include_aliases && HasAliases()) {
1007 auto alias_pos = m_alias_dict.find(cmd);
1008 if (alias_pos != m_alias_dict.end())
1009 command_sp = alias_pos->second;
1010 }
1011
1012 if (HasUserCommands()) {
1013 auto pos = m_user_dict.find(cmd);
1014 if (pos != m_user_dict.end())
1015 command_sp = pos->second;
1016 }
1017
1019 auto pos = m_user_mw_dict.find(cmd);
1020 if (pos != m_user_mw_dict.end())
1021 command_sp = pos->second;
1022 }
1023
1024 if (!exact && !command_sp) {
1025 // We will only get into here if we didn't find any exact matches.
1026
1027 CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1028 real_match_sp;
1029
1030 StringList local_matches;
1031 if (matches == nullptr)
1032 matches = &local_matches;
1033
1034 unsigned int num_cmd_matches = 0;
1035 unsigned int num_alias_matches = 0;
1036 unsigned int num_user_matches = 0;
1037 unsigned int num_user_mw_matches = 0;
1038
1039 // Look through the command dictionaries one by one, and if we get only one
1040 // match from any of them in toto, then return that, otherwise return an
1041 // empty CommandObjectSP and the list of matches.
1042
1043 if (HasCommands()) {
1044 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
1045 *matches, descriptions);
1046 }
1047
1048 if (num_cmd_matches == 1) {
1049 cmd.assign(matches->GetStringAtIndex(0));
1050 auto pos = m_command_dict.find(cmd);
1051 if (pos != m_command_dict.end())
1052 real_match_sp = pos->second;
1053 }
1054
1055 if (include_aliases && HasAliases()) {
1056 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
1057 *matches, descriptions);
1058 }
1059
1060 if (num_alias_matches == 1) {
1061 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
1062 auto alias_pos = m_alias_dict.find(cmd);
1063 if (alias_pos != m_alias_dict.end())
1064 alias_match_sp = alias_pos->second;
1065 }
1066
1067 if (HasUserCommands()) {
1068 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
1069 *matches, descriptions);
1070 }
1071
1072 if (num_user_matches == 1) {
1073 cmd.assign(
1074 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
1075
1076 auto pos = m_user_dict.find(cmd);
1077 if (pos != m_user_dict.end())
1078 user_match_sp = pos->second;
1079 }
1080
1082 num_user_mw_matches = AddNamesMatchingPartialString(
1083 m_user_mw_dict, cmd_str, *matches, descriptions);
1084 }
1085
1086 if (num_user_mw_matches == 1) {
1087 cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1088 num_user_matches));
1089
1090 auto pos = m_user_mw_dict.find(cmd);
1091 if (pos != m_user_mw_dict.end())
1092 user_mw_match_sp = pos->second;
1093 }
1094
1095 // If we got exactly one match, return that, otherwise return the match
1096 // list.
1097
1098 if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1099 num_alias_matches ==
1100 1) {
1101 if (num_cmd_matches)
1102 return real_match_sp;
1103 else if (num_alias_matches)
1104 return alias_match_sp;
1105 else if (num_user_mw_matches)
1106 return user_mw_match_sp;
1107 else
1108 return user_match_sp;
1109 }
1110 } else if (matches && command_sp) {
1111 matches->AppendString(cmd_str);
1112 if (descriptions)
1113 descriptions->AppendString(command_sp->GetHelp());
1114 }
1115
1116 return command_sp;
1117}
1118
1119bool CommandInterpreter::AddCommand(llvm::StringRef name,
1120 const lldb::CommandObjectSP &cmd_sp,
1121 bool can_replace) {
1122 if (cmd_sp.get())
1123 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1124 "tried to add a CommandObject from a different interpreter");
1125
1126 if (name.empty())
1127 return false;
1128
1129 cmd_sp->SetIsUserCommand(false);
1130
1131 std::string name_sstr(name);
1132 auto name_iter = m_command_dict.find(name_sstr);
1133 if (name_iter != m_command_dict.end()) {
1134 if (!can_replace || !name_iter->second->IsRemovable())
1135 return false;
1136 name_iter->second = cmd_sp;
1137 } else {
1138 m_command_dict[name_sstr] = cmd_sp;
1139 }
1140 return true;
1141}
1142
1144 const lldb::CommandObjectSP &cmd_sp,
1145 bool can_replace) {
1146 Status result;
1147 if (cmd_sp.get())
1148 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1149 "tried to add a CommandObject from a different interpreter");
1150 if (name.empty()) {
1151 result.SetErrorString("can't use the empty string for a command name");
1152 return result;
1153 }
1154 // do not allow replacement of internal commands
1155 if (CommandExists(name)) {
1156 result.SetErrorString("can't replace builtin command");
1157 return result;
1158 }
1159
1160 if (UserCommandExists(name)) {
1161 if (!can_replace) {
1162 result.SetErrorString("user command exists and force replace not set");
1163 return result;
1164 }
1165 if (cmd_sp->IsMultiwordObject()) {
1166 if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1167 result.SetErrorString(
1168 "can't replace explicitly non-removable multi-word command");
1169 return result;
1170 }
1171 } else {
1172 if (!m_user_dict[std::string(name)]->IsRemovable()) {
1173 result.SetErrorString("can't replace explicitly non-removable command");
1174 return result;
1175 }
1176 }
1177 }
1178
1179 cmd_sp->SetIsUserCommand(true);
1180
1181 if (cmd_sp->IsMultiwordObject())
1182 m_user_mw_dict[std::string(name)] = cmd_sp;
1183 else
1184 m_user_dict[std::string(name)] = cmd_sp;
1185 return result;
1186}
1187
1188CommandObjectSP
1190 bool include_aliases) const {
1191 // Break up the command string into words, in case it's a multi-word command.
1192 Args cmd_words(cmd_str);
1193
1194 if (cmd_str.empty())
1195 return {};
1196
1197 if (cmd_words.GetArgumentCount() == 1)
1198 return GetCommandSP(cmd_str, include_aliases, true);
1199
1200 // We have a multi-word command (seemingly), so we need to do more work.
1201 // First, get the cmd_obj_sp for the first word in the command.
1202 CommandObjectSP cmd_obj_sp =
1203 GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1204 if (!cmd_obj_sp)
1205 return {};
1206
1207 // Loop through the rest of the words in the command (everything passed in
1208 // was supposed to be part of a command name), and find the appropriate
1209 // sub-command SP for each command word....
1210 size_t end = cmd_words.GetArgumentCount();
1211 for (size_t i = 1; i < end; ++i) {
1212 if (!cmd_obj_sp->IsMultiwordObject()) {
1213 // We have more words in the command name, but we don't have a
1214 // multiword object. Fail and return.
1215 return {};
1216 }
1217
1218 cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1219 if (!cmd_obj_sp) {
1220 // The sub-command name was invalid. Fail and return.
1221 return {};
1222 }
1223 }
1224
1225 // We successfully looped through all the command words and got valid
1226 // command objects for them.
1227 return cmd_obj_sp;
1228}
1229
1232 StringList *matches,
1233 StringList *descriptions) const {
1234 CommandObject *command_obj =
1235 GetCommandSP(cmd_str, false, true, matches, descriptions).get();
1236
1237 // If we didn't find an exact match to the command string in the commands,
1238 // look in the aliases.
1239
1240 if (command_obj)
1241 return command_obj;
1242
1243 command_obj = GetCommandSP(cmd_str, true, true, matches, descriptions).get();
1244
1245 if (command_obj)
1246 return command_obj;
1247
1248 // If there wasn't an exact match then look for an inexact one in just the
1249 // commands
1250 command_obj = GetCommandSP(cmd_str, false, false, nullptr).get();
1251
1252 // Finally, if there wasn't an inexact match among the commands, look for an
1253 // inexact match in both the commands and aliases.
1254
1255 if (command_obj) {
1256 if (matches)
1257 matches->AppendString(command_obj->GetCommandName());
1258 if (descriptions)
1259 descriptions->AppendString(command_obj->GetHelp());
1260 return command_obj;
1261 }
1262
1263 return GetCommandSP(cmd_str, true, false, matches, descriptions).get();
1264}
1265
1267 llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1268 std::string cmd_str(cmd);
1269 auto find_exact = [&](const CommandObject::CommandMap &map) {
1270 auto found_elem = map.find(std::string(cmd));
1271 if (found_elem == map.end())
1272 return (CommandObject *)nullptr;
1273 CommandObject *exact_cmd = found_elem->second.get();
1274 if (exact_cmd) {
1275 if (matches)
1276 matches->AppendString(exact_cmd->GetCommandName());
1277 if (descriptions)
1278 descriptions->AppendString(exact_cmd->GetHelp());
1279 return exact_cmd;
1280 }
1281 return (CommandObject *)nullptr;
1282 };
1283
1284 CommandObject *exact_cmd = find_exact(GetUserCommands());
1285 if (exact_cmd)
1286 return exact_cmd;
1287
1288 exact_cmd = find_exact(GetUserMultiwordCommands());
1289 if (exact_cmd)
1290 return exact_cmd;
1291
1292 // We didn't have an exact command, so now look for partial matches.
1293 StringList tmp_list;
1294 StringList *matches_ptr = matches ? matches : &tmp_list;
1295 AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1297 cmd_str, *matches_ptr);
1298
1299 return {};
1300}
1301
1302bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1303 return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
1304}
1305
1307 std::string &full_name) const {
1308 bool exact_match =
1309 (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
1310 if (exact_match) {
1311 full_name.assign(std::string(cmd));
1312 return exact_match;
1313 } else {
1314 StringList matches;
1315 size_t num_alias_matches;
1316 num_alias_matches =
1318 if (num_alias_matches == 1) {
1319 // Make sure this isn't shadowing a command in the regular command space:
1320 StringList regular_matches;
1321 const bool include_aliases = false;
1322 const bool exact = false;
1323 CommandObjectSP cmd_obj_sp(
1324 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1325 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1326 return false;
1327 else {
1328 full_name.assign(matches.GetStringAtIndex(0));
1329 return true;
1330 }
1331 } else
1332 return false;
1333 }
1334}
1335
1336bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1337 return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
1338}
1339
1340bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1341 return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
1342}
1343
1344bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1345 return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
1346}
1347
1349CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1350 lldb::CommandObjectSP &command_obj_sp,
1351 llvm::StringRef args_string) {
1352 if (command_obj_sp.get())
1353 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1354 "tried to add a CommandObject from a different interpreter");
1355
1356 std::unique_ptr<CommandAlias> command_alias_up(
1357 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1358
1359 if (command_alias_up && command_alias_up->IsValid()) {
1360 m_alias_dict[std::string(alias_name)] =
1361 CommandObjectSP(command_alias_up.get());
1362 return command_alias_up.release();
1363 }
1364
1365 return nullptr;
1366}
1367
1368bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1369 auto pos = m_alias_dict.find(std::string(alias_name));
1370 if (pos != m_alias_dict.end()) {
1371 m_alias_dict.erase(pos);
1372 return true;
1373 }
1374 return false;
1375}
1376
1377bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
1378 auto pos = m_command_dict.find(std::string(cmd));
1379 if (pos != m_command_dict.end()) {
1380 if (force || pos->second->IsRemovable()) {
1381 // Only regular expression objects or python commands are removable under
1382 // normal circumstances.
1383 m_command_dict.erase(pos);
1384 return true;
1385 }
1386 }
1387 return false;
1388}
1389
1390bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1391 CommandObject::CommandMap::iterator pos =
1392 m_user_dict.find(std::string(user_name));
1393 if (pos != m_user_dict.end()) {
1394 m_user_dict.erase(pos);
1395 return true;
1396 }
1397 return false;
1398}
1399
1400bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1401 CommandObject::CommandMap::iterator pos =
1402 m_user_mw_dict.find(std::string(multi_name));
1403 if (pos != m_user_mw_dict.end()) {
1404 m_user_mw_dict.erase(pos);
1405 return true;
1406 }
1407 return false;
1408}
1409
1411 uint32_t cmd_types) {
1412 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1413 if (!help_prologue.empty()) {
1414 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1415 help_prologue);
1416 }
1417
1418 CommandObject::CommandMap::const_iterator pos;
1419 size_t max_len = FindLongestCommandWord(m_command_dict);
1420
1421 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1422 result.AppendMessage("Debugger commands:");
1423 result.AppendMessage("");
1424
1425 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1426 if (!(cmd_types & eCommandTypesHidden) &&
1427 (pos->first.compare(0, 1, "_") == 0))
1428 continue;
1429
1430 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1431 pos->second->GetHelp(), max_len);
1432 }
1433 result.AppendMessage("");
1434 }
1435
1436 if (!m_alias_dict.empty() &&
1437 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1439 "Current command abbreviations "
1440 "(type '%shelp command alias' for more info):\n",
1442 result.AppendMessage("");
1444
1445 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1446 ++alias_pos) {
1447 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1448 alias_pos->second->GetHelp(), max_len);
1449 }
1450 result.AppendMessage("");
1451 }
1452
1453 if (!m_user_dict.empty() &&
1454 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1455 result.AppendMessage("Current user-defined commands:");
1456 result.AppendMessage("");
1458 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1459 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1460 pos->second->GetHelp(), max_len);
1461 }
1462 result.AppendMessage("");
1463 }
1464
1465 if (!m_user_mw_dict.empty() &&
1466 ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1467 result.AppendMessage("Current user-defined container commands:");
1468 result.AppendMessage("");
1470 for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1471 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1472 pos->second->GetHelp(), max_len);
1473 }
1474 result.AppendMessage("");
1475 }
1476
1478 "For more information on any command, type '%shelp <command-name>'.\n",
1480}
1481
1483 llvm::StringRef &command_string) {
1484 // This function finds the final, lowest-level, alias-resolved command object
1485 // whose 'Execute' function will eventually be invoked by the given command
1486 // line.
1487
1488 CommandObject *cmd_obj = nullptr;
1489 size_t start = command_string.find_first_not_of(k_white_space);
1490 size_t end = 0;
1491 bool done = false;
1492 while (!done) {
1493 if (start != std::string::npos) {
1494 // Get the next word from command_string.
1495 end = command_string.find_first_of(k_white_space, start);
1496 if (end == std::string::npos)
1497 end = command_string.size();
1498 std::string cmd_word =
1499 std::string(command_string.substr(start, end - start));
1500
1501 if (cmd_obj == nullptr)
1502 // Since cmd_obj is NULL we are on our first time through this loop.
1503 // Check to see if cmd_word is a valid command or alias.
1504 cmd_obj = GetCommandObject(cmd_word);
1505 else if (cmd_obj->IsMultiwordObject()) {
1506 // Our current object is a multi-word object; see if the cmd_word is a
1507 // valid sub-command for our object.
1508 CommandObject *sub_cmd_obj =
1509 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1510 if (sub_cmd_obj)
1511 cmd_obj = sub_cmd_obj;
1512 else // cmd_word was not a valid sub-command word, so we are done
1513 done = true;
1514 } else
1515 // We have a cmd_obj and it is not a multi-word object, so we are done.
1516 done = true;
1517
1518 // If we didn't find a valid command object, or our command object is not
1519 // a multi-word object, or we are at the end of the command_string, then
1520 // we are done. Otherwise, find the start of the next word.
1521
1522 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1523 end >= command_string.size())
1524 done = true;
1525 else
1526 start = command_string.find_first_not_of(k_white_space, end);
1527 } else
1528 // Unable to find any more words.
1529 done = true;
1530 }
1531
1532 command_string = command_string.substr(end);
1533 return cmd_obj;
1534}
1535
1536static const char *k_valid_command_chars =
1537 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1538static void StripLeadingSpaces(std::string &s) {
1539 if (!s.empty()) {
1540 size_t pos = s.find_first_not_of(k_white_space);
1541 if (pos == std::string::npos)
1542 s.clear();
1543 else if (pos == 0)
1544 return;
1545 s.erase(0, pos);
1546 }
1547}
1548
1549static size_t FindArgumentTerminator(const std::string &s) {
1550 const size_t s_len = s.size();
1551 size_t offset = 0;
1552 while (offset < s_len) {
1553 size_t pos = s.find("--", offset);
1554 if (pos == std::string::npos)
1555 break;
1556 if (pos > 0) {
1557 if (llvm::isSpace(s[pos - 1])) {
1558 // Check if the string ends "\s--" (where \s is a space character) or
1559 // if we have "\s--\s".
1560 if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1561 return pos;
1562 }
1563 }
1564 }
1565 offset = pos + 2;
1566 }
1567 return std::string::npos;
1568}
1569
1570static bool ExtractCommand(std::string &command_string, std::string &command,
1571 std::string &suffix, char &quote_char) {
1572 command.clear();
1573 suffix.clear();
1574 StripLeadingSpaces(command_string);
1575
1576 bool result = false;
1577 quote_char = '\0';
1578
1579 if (!command_string.empty()) {
1580 const char first_char = command_string[0];
1581 if (first_char == '\'' || first_char == '"') {
1582 quote_char = first_char;
1583 const size_t end_quote_pos = command_string.find(quote_char, 1);
1584 if (end_quote_pos == std::string::npos) {
1585 command.swap(command_string);
1586 command_string.erase();
1587 } else {
1588 command.assign(command_string, 1, end_quote_pos - 1);
1589 if (end_quote_pos + 1 < command_string.size())
1590 command_string.erase(0, command_string.find_first_not_of(
1591 k_white_space, end_quote_pos + 1));
1592 else
1593 command_string.erase();
1594 }
1595 } else {
1596 const size_t first_space_pos =
1597 command_string.find_first_of(k_white_space);
1598 if (first_space_pos == std::string::npos) {
1599 command.swap(command_string);
1600 command_string.erase();
1601 } else {
1602 command.assign(command_string, 0, first_space_pos);
1603 command_string.erase(0, command_string.find_first_not_of(
1604 k_white_space, first_space_pos));
1605 }
1606 }
1607 result = true;
1608 }
1609
1610 if (!command.empty()) {
1611 // actual commands can't start with '-' or '_'
1612 if (command[0] != '-' && command[0] != '_') {
1613 size_t pos = command.find_first_not_of(k_valid_command_chars);
1614 if (pos > 0 && pos != std::string::npos) {
1615 suffix.assign(command.begin() + pos, command.end());
1616 command.erase(pos);
1617 }
1618 }
1619 }
1620
1621 return result;
1622}
1623
1625 llvm::StringRef alias_name, std::string &raw_input_string,
1626 std::string &alias_result, CommandReturnObject &result) {
1627 CommandObject *alias_cmd_obj = nullptr;
1628 Args cmd_args(raw_input_string);
1629 alias_cmd_obj = GetCommandObject(alias_name);
1630 StreamString result_str;
1631
1632 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1633 alias_result.clear();
1634 return alias_cmd_obj;
1635 }
1636 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1637 ((CommandAlias *)alias_cmd_obj)->Desugar();
1638 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1639 alias_cmd_obj = desugared.first.get();
1640 std::string alias_name_str = std::string(alias_name);
1641 if ((cmd_args.GetArgumentCount() == 0) ||
1642 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1643 cmd_args.Unshift(alias_name_str);
1644
1645 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1646
1647 if (!option_arg_vector_sp.get()) {
1648 alias_result = std::string(result_str.GetString());
1649 return alias_cmd_obj;
1650 }
1651 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1652
1653 int value_type;
1654 std::string option;
1655 std::string value;
1656 for (const auto &entry : *option_arg_vector) {
1657 std::tie(option, value_type, value) = entry;
1658 if (option == g_argument) {
1659 result_str.Printf(" %s", value.c_str());
1660 continue;
1661 }
1662
1663 result_str.Printf(" %s", option.c_str());
1664 if (value_type == OptionParser::eNoArgument)
1665 continue;
1666
1667 if (value_type != OptionParser::eOptionalArgument)
1668 result_str.Printf(" ");
1669 int index = GetOptionArgumentPosition(value.c_str());
1670 if (index == 0)
1671 result_str.Printf("%s", value.c_str());
1672 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1673
1674 result.AppendErrorWithFormat("Not enough arguments provided; you "
1675 "need at least %d arguments to use "
1676 "this alias.\n",
1677 index);
1678 return nullptr;
1679 } else {
1680 const Args::ArgEntry &entry = cmd_args[index];
1681 size_t strpos = raw_input_string.find(entry.c_str());
1682 const char quote_char = entry.GetQuoteChar();
1683 if (strpos != std::string::npos) {
1684 const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1685 const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1686
1687 // Make sure we aren't going outside the bounds of the cmd string:
1688 if (strpos < start_fudge) {
1689 result.AppendError("Unmatched quote at command beginning.");
1690 return nullptr;
1691 }
1692 llvm::StringRef arg_text = entry.ref();
1693 if (strpos - start_fudge + arg_text.size() + len_fudge >
1694 raw_input_string.size()) {
1695 result.AppendError("Unmatched quote at command end.");
1696 return nullptr;
1697 }
1698 raw_input_string = raw_input_string.erase(
1699 strpos - start_fudge,
1700 strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1701 }
1702 if (quote_char == '\0')
1703 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1704 else
1705 result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
1706 }
1707 }
1708
1709 alias_result = std::string(result_str.GetString());
1710 return alias_cmd_obj;
1711}
1712
1714 // The command preprocessor needs to do things to the command line before any
1715 // parsing of arguments or anything else is done. The only current stuff that
1716 // gets preprocessed is anything enclosed in backtick ('`') characters is
1717 // evaluated as an expression and the result of the expression must be a
1718 // scalar that can be substituted into the command. An example would be:
1719 // (lldb) memory read `$rsp + 20`
1720 Status error; // Status for any expressions that might not evaluate
1721 size_t start_backtick;
1722 size_t pos = 0;
1723 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1724 // Stop if an error was encountered during the previous iteration.
1725 if (error.Fail())
1726 break;
1727
1728 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1729 // The backtick was preceded by a '\' character, remove the slash and
1730 // don't treat the backtick as the start of an expression.
1731 command.erase(start_backtick - 1, 1);
1732 // No need to add one to start_backtick since we just deleted a char.
1733 pos = start_backtick;
1734 continue;
1735 }
1736
1737 const size_t expr_content_start = start_backtick + 1;
1738 const size_t end_backtick = command.find('`', expr_content_start);
1739
1740 if (end_backtick == std::string::npos) {
1741 // Stop if there's no end backtick.
1742 break;
1743 }
1744
1745 if (end_backtick == expr_content_start) {
1746 // Skip over empty expression. (two backticks in a row)
1747 command.erase(start_backtick, 2);
1748 continue;
1749 }
1750
1751 std::string expr_str(command, expr_content_start,
1752 end_backtick - expr_content_start);
1753 error = PreprocessToken(expr_str);
1754 // We always stop at the first error:
1755 if (error.Fail())
1756 break;
1757
1758 command.erase(start_backtick, end_backtick - start_backtick + 1);
1759 command.insert(start_backtick, std::string(expr_str));
1760 pos = start_backtick + expr_str.size();
1761 }
1762 return error;
1763}
1764
1765Status
1767 Status error;
1769
1770 // Get a dummy target to allow for calculator mode while processing
1771 // backticks. This also helps break the infinite loop caused when target is
1772 // null.
1773 Target *exe_target = exe_ctx.GetTargetPtr();
1774 Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1775
1776 ValueObjectSP expr_result_valobj_sp;
1777
1779 options.SetCoerceToId(false);
1780 options.SetUnwindOnError(true);
1781 options.SetIgnoreBreakpoints(true);
1782 options.SetKeepInMemory(false);
1783 options.SetTryAllThreads(true);
1784 options.SetTimeout(std::nullopt);
1785
1786 ExpressionResults expr_result =
1787 target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1788 expr_result_valobj_sp, options);
1789
1790 if (expr_result == eExpressionCompleted) {
1791 Scalar scalar;
1792 if (expr_result_valobj_sp)
1793 expr_result_valobj_sp =
1794 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1795 expr_result_valobj_sp->GetDynamicValueType(), true);
1796 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1797
1798 StreamString value_strm;
1799 const bool show_type = false;
1800 scalar.GetValue(&value_strm, show_type);
1801 size_t value_string_size = value_strm.GetSize();
1802 if (value_string_size) {
1803 expr_str = value_strm.GetData();
1804 } else {
1805 error.SetErrorStringWithFormat("expression value didn't result "
1806 "in a scalar value for the "
1807 "expression '%s'",
1808 expr_str.c_str());
1809 }
1810 } else {
1811 error.SetErrorStringWithFormat("expression value didn't result "
1812 "in a scalar value for the "
1813 "expression '%s'",
1814 expr_str.c_str());
1815 }
1816 return error;
1817 }
1818
1819 // If we have an error from the expression evaluation it will be in the
1820 // ValueObject error, which won't be success and we will just report it.
1821 // But if for some reason we didn't get a value object at all, then we will
1822 // make up some helpful errors from the expression result.
1823 if (expr_result_valobj_sp)
1824 error = expr_result_valobj_sp->GetError();
1825
1826 if (error.Success()) {
1827 switch (expr_result) {
1829 error.SetErrorStringWithFormat(
1830 "expression setup error for the expression '%s'", expr_str.c_str());
1831 break;
1833 error.SetErrorStringWithFormat(
1834 "expression parse error for the expression '%s'", expr_str.c_str());
1835 break;
1837 error.SetErrorStringWithFormat(
1838 "expression error fetching result for the expression '%s'",
1839 expr_str.c_str());
1840 break;
1842 break;
1844 error.SetErrorStringWithFormat(
1845 "expression discarded for the expression '%s'", expr_str.c_str());
1846 break;
1848 error.SetErrorStringWithFormat(
1849 "expression interrupted for the expression '%s'", expr_str.c_str());
1850 break;
1852 error.SetErrorStringWithFormat(
1853 "expression hit breakpoint for the expression '%s'",
1854 expr_str.c_str());
1855 break;
1857 error.SetErrorStringWithFormat(
1858 "expression timed out for the expression '%s'", expr_str.c_str());
1859 break;
1861 error.SetErrorStringWithFormat("expression stop at entry point "
1862 "for debugging for the "
1863 "expression '%s'",
1864 expr_str.c_str());
1865 break;
1867 error.SetErrorStringWithFormat(
1868 "expression thread vanished for the expression '%s'",
1869 expr_str.c_str());
1870 break;
1871 }
1872 }
1873 return error;
1874}
1875
1876bool CommandInterpreter::HandleCommand(const char *command_line,
1877 LazyBool lazy_add_to_history,
1878 const ExecutionContext &override_context,
1879 CommandReturnObject &result) {
1880
1881 OverrideExecutionContext(override_context);
1882 bool status = HandleCommand(command_line, lazy_add_to_history, result);
1884 return status;
1885}
1886
1887bool CommandInterpreter::HandleCommand(const char *command_line,
1888 LazyBool lazy_add_to_history,
1889 CommandReturnObject &result,
1890 bool force_repeat_command) {
1891 std::string command_string(command_line);
1892 std::string original_command_string(command_line);
1893
1895 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1896 command_line);
1897
1898 LLDB_LOGF(log, "Processing command: %s", command_line);
1899 LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1900
1901 if (GetDebugger().InterruptRequested()) {
1902 result.AppendError("... Interrupted");
1903 return false;
1904 }
1905
1906 bool add_to_history;
1907 if (lazy_add_to_history == eLazyBoolCalculate)
1908 add_to_history = (m_command_source_depth == 0);
1909 else
1910 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1911
1912 m_transcript_stream << "(lldb) " << command_line << '\n';
1913
1914 bool empty_command = false;
1915 bool comment_command = false;
1916 if (command_string.empty())
1917 empty_command = true;
1918 else {
1919 const char *k_space_characters = "\t\n\v\f\r ";
1920
1921 size_t non_space = command_string.find_first_not_of(k_space_characters);
1922 // Check for empty line or comment line (lines whose first non-space
1923 // character is the comment character for this interpreter)
1924 if (non_space == std::string::npos)
1925 empty_command = true;
1926 else if (command_string[non_space] == m_comment_char)
1927 comment_command = true;
1928 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1929 llvm::StringRef search_str(command_string);
1930 search_str = search_str.drop_front(non_space);
1931 if (auto hist_str = m_command_history.FindString(search_str)) {
1932 add_to_history = false;
1933 command_string = std::string(*hist_str);
1934 original_command_string = std::string(*hist_str);
1935 } else {
1936 result.AppendErrorWithFormat("Could not find entry: %s in history",
1937 command_string.c_str());
1938 return false;
1939 }
1940 }
1941 }
1942
1943 if (empty_command) {
1944 if (!GetRepeatPreviousCommand()) {
1946 return true;
1947 }
1948
1949 if (m_command_history.IsEmpty()) {
1950 result.AppendError("empty command");
1951 return false;
1952 }
1953
1954 command_line = m_repeat_command.c_str();
1955 command_string = command_line;
1956 original_command_string = command_line;
1957 if (m_repeat_command.empty()) {
1958 result.AppendError("No auto repeat.");
1959 return false;
1960 }
1961
1962 add_to_history = false;
1963 } else if (comment_command) {
1965 return true;
1966 }
1967
1968 // Phase 1.
1969
1970 // Before we do ANY kind of argument processing, we need to figure out what
1971 // the real/final command object is for the specified command. This gets
1972 // complicated by the fact that the user could have specified an alias, and,
1973 // in translating the alias, there may also be command options and/or even
1974 // data (including raw text strings) that need to be found and inserted into
1975 // the command line as part of the translation. So this first step is plain
1976 // look-up and replacement, resulting in:
1977 // 1. the command object whose Execute method will actually be called
1978 // 2. a revised command string, with all substitutions and replacements
1979 // taken care of
1980 // From 1 above, we can determine whether the Execute function wants raw
1981 // input or not.
1982
1983 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1984
1985 // We have to preprocess the whole command string for Raw commands, since we
1986 // don't know the structure of the command. For parsed commands, we only
1987 // treat backticks as quote characters specially.
1988 // FIXME: We probably want to have raw commands do their own preprocessing.
1989 // For instance, I don't think people expect substitution in expr expressions.
1990 if (cmd_obj && cmd_obj->WantsRawCommandString()) {
1991 Status error(PreprocessCommand(command_string));
1992
1993 if (error.Fail()) {
1994 result.AppendError(error.AsCString());
1995 return false;
1996 }
1997 }
1998
1999 // Although the user may have abbreviated the command, the command_string now
2000 // has the command expanded to the full name. For example, if the input was
2001 // "br s -n main", command_string is now "breakpoint set -n main".
2002 if (log) {
2003 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
2004 LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
2005 LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
2006 command_string.c_str());
2007 const bool wants_raw_input =
2008 (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
2009 LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
2010 wants_raw_input ? "True" : "False");
2011 }
2012
2013 // Phase 2.
2014 // Take care of things like setting up the history command & calling the
2015 // appropriate Execute method on the CommandObject, with the appropriate
2016 // arguments.
2017
2018 if (cmd_obj != nullptr) {
2019 bool generate_repeat_command = add_to_history;
2020 // If we got here when empty_command was true, then this command is a
2021 // stored "repeat command" which we should give a chance to produce it's
2022 // repeat command, even though we don't add repeat commands to the history.
2023 generate_repeat_command |= empty_command;
2024 // For `command regex`, the regex command (ex `bt`) is added to history, but
2025 // the resolved command (ex `thread backtrace`) is _not_ added to history.
2026 // However, the resolved command must be given the opportunity to provide a
2027 // repeat command. `force_repeat_command` supports this case.
2028 generate_repeat_command |= force_repeat_command;
2029 if (generate_repeat_command) {
2030 Args command_args(command_string);
2031 std::optional<std::string> repeat_command =
2032 cmd_obj->GetRepeatCommand(command_args, 0);
2033 if (repeat_command) {
2034 LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
2035 m_repeat_command.assign(*repeat_command);
2036 } else {
2037 m_repeat_command.assign(original_command_string);
2038 }
2039 }
2040
2041 if (add_to_history)
2042 m_command_history.AppendString(original_command_string);
2043
2044 std::string remainder;
2045 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2046 if (actual_cmd_name_len < command_string.length())
2047 remainder = command_string.substr(actual_cmd_name_len);
2048
2049 // Remove any initial spaces
2050 size_t pos = remainder.find_first_not_of(k_white_space);
2051 if (pos != 0 && pos != std::string::npos)
2052 remainder.erase(0, pos);
2053
2054 LLDB_LOGF(
2055 log, "HandleCommand, command line after removing command name(s): '%s'",
2056 remainder.c_str());
2057
2058 cmd_obj->Execute(remainder.c_str(), result);
2059 }
2060
2061 LLDB_LOGF(log, "HandleCommand, command %s",
2062 (result.Succeeded() ? "succeeded" : "did not succeed"));
2063
2066
2067 return result.Succeeded();
2068}
2069
2071 bool look_for_subcommand = false;
2072
2073 // For any of the command completions a unique match will be a complete word.
2074
2075 if (request.GetParsedLine().GetArgumentCount() == 0) {
2076 // We got nothing on the command line, so return the list of commands
2077 bool include_aliases = true;
2078 StringList new_matches, descriptions;
2079 GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2080 descriptions);
2081 request.AddCompletions(new_matches, descriptions);
2082 } else if (request.GetCursorIndex() == 0) {
2083 // The cursor is in the first argument, so just do a lookup in the
2084 // dictionary.
2085 StringList new_matches, new_descriptions;
2086 CommandObject *cmd_obj =
2088 &new_matches, &new_descriptions);
2089
2090 if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2091 new_matches.GetStringAtIndex(0) != nullptr &&
2092 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2093 new_matches.GetStringAtIndex(0)) == 0) {
2094 if (request.GetParsedLine().GetArgumentCount() != 1) {
2095 look_for_subcommand = true;
2096 new_matches.DeleteStringAtIndex(0);
2097 new_descriptions.DeleteStringAtIndex(0);
2098 request.AppendEmptyArgument();
2099 }
2100 }
2101 request.AddCompletions(new_matches, new_descriptions);
2102 }
2103
2104 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2105 // We are completing further on into a commands arguments, so find the
2106 // command and tell it to complete the command. First see if there is a
2107 // matching initial command:
2108 CommandObject *command_object =
2110 if (command_object) {
2111 request.ShiftArguments();
2112 command_object->HandleCompletion(request);
2113 }
2114 }
2115}
2116
2118
2119 // Don't complete comments, and if the line we are completing is just the
2120 // history repeat character, substitute the appropriate history line.
2121 llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2122
2123 if (!first_arg.empty()) {
2124 if (first_arg.front() == m_comment_char)
2125 return;
2126 if (first_arg.front() == CommandHistory::g_repeat_char) {
2127 if (auto hist_str = m_command_history.FindString(first_arg))
2128 request.AddCompletion(*hist_str, "Previous command history event",
2130 return;
2131 }
2132 }
2133
2134 HandleCompletionMatches(request);
2135}
2136
2137std::optional<std::string>
2139 if (line.empty())
2140 return std::nullopt;
2141 const size_t s = m_command_history.GetSize();
2142 for (int i = s - 1; i >= 0; --i) {
2143 llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2144 if (entry.consume_front(line))
2145 return entry.str();
2146 }
2147 return std::nullopt;
2148}
2149
2150void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2151 EventSP prompt_change_event_sp(
2152 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2153 ;
2154 BroadcastEvent(prompt_change_event_sp);
2156 m_command_io_handler_sp->SetPrompt(new_prompt);
2157}
2158
2159bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2160 // Check AutoConfirm first:
2162 return default_answer;
2163
2164 IOHandlerConfirm *confirm =
2165 new IOHandlerConfirm(m_debugger, message, default_answer);
2166 IOHandlerSP io_handler_sp(confirm);
2167 m_debugger.RunIOHandlerSync(io_handler_sp);
2168 return confirm->GetResponse();
2169}
2170
2171const CommandAlias *
2172CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2173 OptionArgVectorSP ret_val;
2174
2175 auto pos = m_alias_dict.find(std::string(alias_name));
2176 if (pos != m_alias_dict.end())
2177 return (CommandAlias *)pos->second.get();
2178
2179 return nullptr;
2180}
2181
2182bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2183
2184bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2185
2186bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2187
2189 return (!m_user_mw_dict.empty());
2190}
2191
2193
2195 const char *alias_name,
2196 Args &cmd_args,
2197 std::string &raw_input_string,
2198 CommandReturnObject &result) {
2199 OptionArgVectorSP option_arg_vector_sp =
2200 GetAlias(alias_name)->GetOptionArguments();
2201
2202 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2203
2204 // Make sure that the alias name is the 0th element in cmd_args
2205 std::string alias_name_str = alias_name;
2206 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2207 cmd_args.Unshift(alias_name_str);
2208
2209 Args new_args(alias_cmd_obj->GetCommandName());
2210 if (new_args.GetArgumentCount() == 2)
2211 new_args.Shift();
2212
2213 if (option_arg_vector_sp.get()) {
2214 if (wants_raw_input) {
2215 // We have a command that both has command options and takes raw input.
2216 // Make *sure* it has a " -- " in the right place in the
2217 // raw_input_string.
2218 size_t pos = raw_input_string.find(" -- ");
2219 if (pos == std::string::npos) {
2220 // None found; assume it goes at the beginning of the raw input string
2221 raw_input_string.insert(0, " -- ");
2222 }
2223 }
2224
2225 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2226 const size_t old_size = cmd_args.GetArgumentCount();
2227 std::vector<bool> used(old_size + 1, false);
2228
2229 used[0] = true;
2230
2231 int value_type;
2232 std::string option;
2233 std::string value;
2234 for (const auto &option_entry : *option_arg_vector) {
2235 std::tie(option, value_type, value) = option_entry;
2236 if (option == g_argument) {
2237 if (!wants_raw_input || (value != "--")) {
2238 // Since we inserted this above, make sure we don't insert it twice
2239 new_args.AppendArgument(value);
2240 }
2241 continue;
2242 }
2243
2244 if (value_type != OptionParser::eOptionalArgument)
2245 new_args.AppendArgument(option);
2246
2247 if (value == g_no_argument)
2248 continue;
2249
2250 int index = GetOptionArgumentPosition(value.c_str());
2251 if (index == 0) {
2252 // value was NOT a positional argument; must be a real value
2253 if (value_type != OptionParser::eOptionalArgument)
2254 new_args.AppendArgument(value);
2255 else {
2256 new_args.AppendArgument(option + value);
2257 }
2258
2259 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2260 result.AppendErrorWithFormat("Not enough arguments provided; you "
2261 "need at least %d arguments to use "
2262 "this alias.\n",
2263 index);
2264 return;
2265 } else {
2266 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2267 size_t strpos =
2268 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2269 if (strpos != std::string::npos) {
2270 raw_input_string = raw_input_string.erase(
2271 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2272 }
2273
2274 if (value_type != OptionParser::eOptionalArgument)
2275 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2276 else {
2277 new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2278 }
2279 used[index] = true;
2280 }
2281 }
2282
2283 for (auto entry : llvm::enumerate(cmd_args.entries())) {
2284 if (!used[entry.index()] && !wants_raw_input)
2285 new_args.AppendArgument(entry.value().ref());
2286 }
2287
2288 cmd_args.Clear();
2289 cmd_args.SetArguments(new_args.GetArgumentCount(),
2290 new_args.GetConstArgumentVector());
2291 } else {
2293 // This alias was not created with any options; nothing further needs to be
2294 // done, unless it is a command that wants raw input, in which case we need
2295 // to clear the rest of the data from cmd_args, since its in the raw input
2296 // string.
2297 if (wants_raw_input) {
2298 cmd_args.Clear();
2299 cmd_args.SetArguments(new_args.GetArgumentCount(),
2300 new_args.GetConstArgumentVector());
2301 }
2302 return;
2303 }
2304
2306}
2307
2309 int position = 0; // Any string that isn't an argument position, i.e. '%'
2310 // followed by an integer, gets a position
2311 // of zero.
2312
2313 const char *cptr = in_string;
2314
2315 // Does it start with '%'
2316 if (cptr[0] == '%') {
2317 ++cptr;
2318
2319 // Is the rest of it entirely digits?
2320 if (isdigit(cptr[0])) {
2321 const char *start = cptr;
2322 while (isdigit(cptr[0]))
2323 ++cptr;
2324
2325 // We've gotten to the end of the digits; are we at the end of the
2326 // string?
2327 if (cptr[0] == '\0')
2328 position = atoi(start);
2329 }
2330 }
2331
2332 return position;
2333}
2334
2336 llvm::StringRef suffix = {}) {
2337 std::string init_file_name = ".lldbinit";
2338 if (!suffix.empty()) {
2339 init_file_name.append("-");
2340 init_file_name.append(suffix.str());
2341 }
2342
2344 llvm::sys::path::append(init_file, init_file_name);
2345
2346 FileSystem::Instance().Resolve(init_file);
2347}
2348
2350 LanguageType language) {
2351 if (language == eLanguageTypeUnknown) {
2353 if (auto main_repl_language = repl_languages.GetSingularLanguage())
2354 language = *main_repl_language;
2355 else
2356 return;
2357 }
2358
2359 std::string init_file_name =
2360 (llvm::Twine(".lldbinit-") +
2361 llvm::Twine(Language::GetNameForLanguageType(language)) +
2362 llvm::Twine("-repl"))
2363 .str();
2365 llvm::sys::path::append(init_file, init_file_name);
2366 FileSystem::Instance().Resolve(init_file);
2367}
2368
2370 llvm::StringRef s = ".lldbinit";
2371 init_file.assign(s.begin(), s.end());
2372 FileSystem::Instance().Resolve(init_file);
2373}
2374
2376 CommandReturnObject &result) {
2377 assert(!m_skip_lldbinit_files);
2378
2379 if (!FileSystem::Instance().Exists(file)) {
2381 return;
2382 }
2383
2384 // Use HandleCommand to 'source' the given file; this will do the actual
2385 // broadcasting of the commands back to any appropriate listener (see
2386 // CommandObjectSource::Execute for more details).
2387 const bool saved_batch = SetBatchCommandMode(true);
2389 options.SetSilent(true);
2390 options.SetPrintErrors(true);
2391 options.SetStopOnError(false);
2392 options.SetStopOnContinue(true);
2393 HandleCommandsFromFile(file, options, result);
2394 SetBatchCommandMode(saved_batch);
2395}
2396
2400 return;
2401 }
2402
2403 llvm::SmallString<128> init_file;
2404 GetCwdInitFile(init_file);
2405 if (!FileSystem::Instance().Exists(init_file)) {
2407 return;
2408 }
2409
2410 LoadCWDlldbinitFile should_load =
2412
2413 switch (should_load) {
2416 break;
2418 SourceInitFile(FileSpec(init_file.str()), result);
2419 break;
2420 case eLoadCWDlldbinitWarn: {
2421 llvm::SmallString<128> home_init_file;
2422 GetHomeInitFile(home_init_file);
2423 if (llvm::sys::path::parent_path(init_file) ==
2424 llvm::sys::path::parent_path(home_init_file)) {
2426 } else {
2428 }
2429 }
2430 }
2431}
2432
2433/// We will first see if there is an application specific ".lldbinit" file
2434/// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2435/// If this file doesn't exist, we fall back to the REPL init file or the
2436/// default home init file in "~/.lldbinit".
2438 bool is_repl) {
2441 return;
2442 }
2443
2444 llvm::SmallString<128> init_file;
2445
2446 if (is_repl)
2447 GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2448
2449 if (init_file.empty())
2450 GetHomeInitFile(init_file);
2451
2452 if (!m_skip_app_init_files) {
2453 llvm::StringRef program_name =
2454 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2455 llvm::SmallString<128> program_init_file;
2456 GetHomeInitFile(program_init_file, program_name);
2457 if (FileSystem::Instance().Exists(program_init_file))
2458 init_file = program_init_file;
2459 }
2460
2461 SourceInitFile(FileSpec(init_file.str()), result);
2462}
2463
2465#ifdef LLDB_GLOBAL_INIT_DIRECTORY
2466 if (!m_skip_lldbinit_files) {
2467 FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2468 if (init_file)
2469 init_file.MakeAbsolute(HostInfo::GetShlibDir());
2470
2471 init_file.AppendPathComponent("lldbinit");
2472 SourceInitFile(init_file, result);
2473 return;
2474 }
2475#endif
2477}
2478
2480 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2481 return prefix == nullptr ? "" : prefix;
2482}
2483
2484PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2485 PlatformSP platform_sp;
2486 if (prefer_target_platform) {
2488 Target *target = exe_ctx.GetTargetPtr();
2489 if (target)
2490 platform_sp = target->GetPlatform();
2491 }
2492
2493 if (!platform_sp)
2495 return platform_sp;
2496}
2497
2499 auto exe_ctx = GetExecutionContext();
2500 TargetSP target_sp = exe_ctx.GetTargetSP();
2501 if (!target_sp)
2502 return false;
2503
2504 ProcessSP process_sp(target_sp->GetProcessSP());
2505 if (!process_sp)
2506 return false;
2507
2508 if (eStateStopped != process_sp->GetState())
2509 return false;
2510
2511 for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2512 StopInfoSP stop_info = thread_sp->GetStopInfo();
2513 if (!stop_info) {
2514 // If there's no stop_info, keep iterating through the other threads;
2515 // it's enough that any thread has got a stop_info that indicates
2516 // an abnormal stop, to consider the process to be stopped abnormally.
2517 continue;
2518 }
2519
2520 const StopReason reason = stop_info->GetStopReason();
2521 if (reason == eStopReasonException ||
2522 reason == eStopReasonInstrumentation ||
2523 reason == eStopReasonProcessorTrace)
2524 return true;
2525
2526 if (reason == eStopReasonSignal) {
2527 const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2528 UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2529 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2530 // The signal is unknown, treat it as abnormal.
2531 return true;
2532
2533 const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2534 const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2535 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2536 // The signal very likely implies a crash.
2537 return true;
2538 }
2539 }
2540
2541 return false;
2542}
2543
2544void
2546 const ExecutionContext &override_context,
2547 const CommandInterpreterRunOptions &options,
2548 CommandReturnObject &result) {
2549
2550 OverrideExecutionContext(override_context);
2551 HandleCommands(commands, options, result);
2553}
2554
2556 const CommandInterpreterRunOptions &options,
2557 CommandReturnObject &result) {
2558 size_t num_lines = commands.GetSize();
2559
2560 // If we are going to continue past a "continue" then we need to run the
2561 // commands synchronously. Make sure you reset this value anywhere you return
2562 // from the function.
2563
2564 bool old_async_execution = m_debugger.GetAsyncExecution();
2565
2566 if (!options.GetStopOnContinue()) {
2568 }
2569
2570 for (size_t idx = 0; idx < num_lines; idx++) {
2571 const char *cmd = commands.GetStringAtIndex(idx);
2572 if (cmd[0] == '\0')
2573 continue;
2574
2575 if (options.GetEchoCommands()) {
2576 // TODO: Add Stream support.
2577 result.AppendMessageWithFormat("%s %s\n",
2578 m_debugger.GetPrompt().str().c_str(), cmd);
2579 }
2580
2582 tmp_result.SetInteractive(result.GetInteractive());
2583 tmp_result.SetSuppressImmediateOutput(true);
2584
2585 // We might call into a regex or alias command, in which case the
2586 // add_to_history will get lost. This m_command_source_depth dingus is the
2587 // way we turn off adding to the history in that case, so set it up here.
2588 if (!options.GetAddToHistory())
2590 bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2591 if (!options.GetAddToHistory())
2593
2594 if (options.GetPrintResults()) {
2595 if (tmp_result.Succeeded())
2596 result.AppendMessage(tmp_result.GetOutputData());
2597 }
2598
2599 if (!success || !tmp_result.Succeeded()) {
2600 llvm::StringRef error_msg = tmp_result.GetErrorData();
2601 if (error_msg.empty())
2602 error_msg = "<unknown error>.\n";
2603 if (options.GetStopOnError()) {
2604 result.AppendErrorWithFormat(
2605 "Aborting reading of commands after command #%" PRIu64
2606 ": '%s' failed with %s",
2607 (uint64_t)idx, cmd, error_msg.str().c_str());
2608 m_debugger.SetAsyncExecution(old_async_execution);
2609 return;
2610 } else if (options.GetPrintResults()) {
2612 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2613 error_msg.str().c_str());
2614 }
2615 }
2616
2617 if (result.GetImmediateOutputStream())
2618 result.GetImmediateOutputStream()->Flush();
2619
2620 if (result.GetImmediateErrorStream())
2621 result.GetImmediateErrorStream()->Flush();
2622
2623 // N.B. Can't depend on DidChangeProcessState, because the state coming
2624 // into the command execution could be running (for instance in Breakpoint
2625 // Commands. So we check the return value to see if it is has running in
2626 // it.
2627 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2629 if (options.GetStopOnContinue()) {
2630 // If we caused the target to proceed, and we're going to stop in that
2631 // case, set the status in our real result before returning. This is
2632 // an error if the continue was not the last command in the set of
2633 // commands to be run.
2634 if (idx != num_lines - 1)
2635 result.AppendErrorWithFormat(
2636 "Aborting reading of commands after command #%" PRIu64
2637 ": '%s' continued the target.\n",
2638 (uint64_t)idx + 1, cmd);
2639 else
2640 result.AppendMessageWithFormat("Command #%" PRIu64
2641 " '%s' continued the target.\n",
2642 (uint64_t)idx + 1, cmd);
2643
2644 result.SetStatus(tmp_result.GetStatus());
2645 m_debugger.SetAsyncExecution(old_async_execution);
2646
2647 return;
2648 }
2649 }
2650
2651 // Also check for "stop on crash here:
2652 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2654 if (idx != num_lines - 1)
2655 result.AppendErrorWithFormat(
2656 "Aborting reading of commands after command #%" PRIu64
2657 ": '%s' stopped with a signal or exception.\n",
2658 (uint64_t)idx + 1, cmd);
2659 else
2661 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2662 (uint64_t)idx + 1, cmd);
2663
2664 result.SetStatus(tmp_result.GetStatus());
2665 m_debugger.SetAsyncExecution(old_async_execution);
2666
2667 return;
2668 }
2669 }
2670
2672 m_debugger.SetAsyncExecution(old_async_execution);
2673}
2674
2675// Make flags that we can pass into the IOHandler so our delegates can do the
2676// right thing
2677enum {
2686
2688 FileSpec &cmd_file, const ExecutionContext &context,
2689 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2690 OverrideExecutionContext(context);
2691 HandleCommandsFromFile(cmd_file, options, result);
2693}
2694
2696 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2697 if (!FileSystem::Instance().Exists(cmd_file)) {
2698 result.AppendErrorWithFormat(
2699 "Error reading commands from file %s - file not found.\n",
2700 cmd_file.GetFilename().AsCString("<Unknown>"));
2701 return;
2702 }
2703
2704 std::string cmd_file_path = cmd_file.GetPath();
2705 auto input_file_up =
2707 if (!input_file_up) {
2708 std::string error = llvm::toString(input_file_up.takeError());
2710 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2711 llvm::fmt_consume(input_file_up.takeError()));
2712 return;
2713 }
2714 FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2715
2716 Debugger &debugger = GetDebugger();
2717
2718 uint32_t flags = 0;
2719
2720 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2721 if (m_command_source_flags.empty()) {
2722 // Stop on continue by default
2724 } else if (m_command_source_flags.back() &
2727 }
2728 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2730 }
2731
2732 if (options.m_stop_on_error == eLazyBoolCalculate) {
2733 if (m_command_source_flags.empty()) {
2738 }
2739 } else if (options.m_stop_on_error == eLazyBoolYes) {
2741 }
2742
2743 // stop-on-crash can only be set, if it is present in all levels of
2744 // pushed flag sets.
2745 if (options.GetStopOnCrash()) {
2746 if (m_command_source_flags.empty()) {
2750 }
2751 }
2752
2753 if (options.m_echo_commands == eLazyBoolCalculate) {
2754 if (m_command_source_flags.empty()) {
2755 // Echo command by default
2759 }
2760 } else if (options.m_echo_commands == eLazyBoolYes) {
2762 }
2763
2764 // We will only ever ask for this flag, if we echo commands in general.
2766 if (m_command_source_flags.empty()) {
2767 // Echo comments by default
2769 } else if (m_command_source_flags.back() &
2772 }
2773 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2775 }
2776
2777 if (options.m_print_results == eLazyBoolCalculate) {
2778 if (m_command_source_flags.empty()) {
2779 // Print output by default
2783 }
2784 } else if (options.m_print_results == eLazyBoolYes) {
2786 }
2787
2788 if (options.m_print_errors == eLazyBoolCalculate) {
2789 if (m_command_source_flags.empty()) {
2790 // Print output by default
2794 }
2795 } else if (options.m_print_errors == eLazyBoolYes) {
2797 }
2798
2799 if (flags & eHandleCommandFlagPrintResult) {
2800 debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2801 cmd_file_path.c_str());
2802 }
2803
2804 // Used for inheriting the right settings when "command source" might
2805 // have nested "command source" commands
2806 lldb::StreamFileSP empty_stream_sp;
2807 m_command_source_flags.push_back(flags);
2808 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2809 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2810 empty_stream_sp, // Pass in an empty stream so we inherit the top
2811 // input reader output stream
2812 empty_stream_sp, // Pass in an empty stream so we inherit the top
2813 // input reader error stream
2814 flags,
2815 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2816 // or written
2817 debugger.GetPrompt(), llvm::StringRef(),
2818 false, // Not multi-line
2819 debugger.GetUseColor(), 0, *this));
2820 const bool old_async_execution = debugger.GetAsyncExecution();
2821
2822 // Set synchronous execution if we are not stopping on continue
2823 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2824 debugger.SetAsyncExecution(false);
2825
2828
2829 debugger.RunIOHandlerSync(io_handler_sp);
2830 if (!m_command_source_flags.empty())
2831 m_command_source_flags.pop_back();
2832
2833 m_command_source_dirs.pop_back();
2835
2837 debugger.SetAsyncExecution(old_async_execution);
2838}
2839
2841
2844}
2845
2847 llvm::StringRef prefix,
2848 llvm::StringRef help_text) {
2849 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2850
2851 size_t line_width_max = max_columns - prefix.size();
2852 if (line_width_max < 16)
2853 line_width_max = help_text.size() + prefix.size();
2854
2855 strm.IndentMore(prefix.size());
2856 bool prefixed_yet = false;
2857 // Even if we have no help text we still want to emit the command name.
2858 if (help_text.empty())
2859 help_text = "No help text";
2860 while (!help_text.empty()) {
2861 // Prefix the first line, indent subsequent lines to line up
2862 if (!prefixed_yet) {
2863 strm << prefix;
2864 prefixed_yet = true;
2865 } else
2866 strm.Indent();
2867
2868 // Never print more than the maximum on one line.
2869 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2870
2871 // Always break on an explicit newline.
2872 std::size_t first_newline = this_line.find_first_of("\n");
2873
2874 // Don't break on space/tab unless the text is too long to fit on one line.
2875 std::size_t last_space = llvm::StringRef::npos;
2876 if (this_line.size() != help_text.size())
2877 last_space = this_line.find_last_of(" \t");
2878
2879 // Break at whichever condition triggered first.
2880 this_line = this_line.substr(0, std::min(first_newline, last_space));
2881 strm.PutCString(this_line);
2882 strm.EOL();
2883
2884 // Remove whitespace / newlines after breaking.
2885 help_text = help_text.drop_front(this_line.size()).ltrim();
2886 }
2887 strm.IndentLess(prefix.size());
2888}
2889
2891 llvm::StringRef word_text,
2892 llvm::StringRef separator,
2893 llvm::StringRef help_text,
2894 size_t max_word_len) {
2895 StreamString prefix_stream;
2896 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2897 (int)separator.size(), separator.data());
2898 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2899}
2900
2901void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2902 llvm::StringRef separator,
2903 llvm::StringRef help_text,
2904 uint32_t max_word_len) {
2905 int indent_size = max_word_len + separator.size() + 2;
2906
2907 strm.IndentMore(indent_size);
2908
2909 StreamString text_strm;
2910 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2911 text_strm << separator << " " << help_text;
2912
2913 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2914
2915 llvm::StringRef text = text_strm.GetString();
2916
2917 uint32_t chars_left = max_columns;
2918
2919 auto nextWordLength = [](llvm::StringRef S) {
2920 size_t pos = S.find(' ');
2921 return pos == llvm::StringRef::npos ? S.size() : pos;
2922 };
2923
2924 while (!text.empty()) {
2925 if (text.front() == '\n' ||
2926 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2927 strm.EOL();
2928 strm.Indent();
2929 chars_left = max_columns - indent_size;
2930 if (text.front() == '\n')
2931 text = text.drop_front();
2932 else
2933 text = text.ltrim(' ');
2934 } else {
2935 strm.PutChar(text.front());
2936 --chars_left;
2937 text = text.drop_front();
2938 }
2939 }
2940
2941 strm.EOL();
2942 strm.IndentLess(indent_size);
2943}
2944
2946 llvm::StringRef search_word, StringList &commands_found,
2947 StringList &commands_help, const CommandObject::CommandMap &command_map) {
2948 for (const auto &pair : command_map) {
2949 llvm::StringRef command_name = pair.first;
2950 CommandObject *cmd_obj = pair.second.get();
2951
2952 const bool search_short_help = true;
2953 const bool search_long_help = false;
2954 const bool search_syntax = false;
2955 const bool search_options = false;
2956 if (command_name.contains_insensitive(search_word) ||
2957 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2958 search_long_help, search_syntax,
2959 search_options)) {
2960 commands_found.AppendString(command_name);
2961 commands_help.AppendString(cmd_obj->GetHelp());
2962 }
2963
2964 if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
2965 StringList subcommands_found;
2966 FindCommandsForApropos(search_word, subcommands_found, commands_help,
2967 multiword_cmd->GetSubcommandDictionary());
2968 for (const auto &subcommand_name : subcommands_found) {
2969 std::string qualified_name =
2970 (command_name + " " + subcommand_name).str();
2971 commands_found.AppendString(qualified_name);
2972 }
2973 }
2974 }
2975}
2976
2977void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
2978 StringList &commands_found,
2979 StringList &commands_help,
2980 bool search_builtin_commands,
2981 bool search_user_commands,
2982 bool search_alias_commands,
2983 bool search_user_mw_commands) {
2984 CommandObject::CommandMap::const_iterator pos;
2985
2986 if (search_builtin_commands)
2987 FindCommandsForApropos(search_word, commands_found, commands_help,
2989
2990 if (search_user_commands)
2991 FindCommandsForApropos(search_word, commands_found, commands_help,
2992 m_user_dict);
2993
2994 if (search_user_mw_commands)
2995 FindCommandsForApropos(search_word, commands_found, commands_help,
2997
2998 if (search_alias_commands)
2999 FindCommandsForApropos(search_word, commands_found, commands_help,
3000 m_alias_dict);
3001}
3002
3004 return !m_overriden_exe_contexts.empty()
3007}
3008
3010 const ExecutionContext &override_context) {
3011 m_overriden_exe_contexts.push(override_context);
3012}
3013
3015 if (!m_overriden_exe_contexts.empty())
3017}
3018
3020 if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
3021 m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
3022 /*flush_stderr*/ true);
3023}
3024
3026 auto idle_state = CommandHandlingState::eIdle;
3027 if (m_command_state.compare_exchange_strong(
3030 else
3033}
3034
3037 if (--m_iohandler_nesting_level == 0) {
3038 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3040 }
3041}
3042
3044 auto in_progress = CommandHandlingState::eInProgress;
3045 return m_command_state.compare_exchange_strong(
3047}
3048
3051 return false;
3052
3053 bool was_interrupted =
3055 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3056 return was_interrupted;
3057}
3058
3060 llvm::StringRef str,
3061 bool is_stdout) {
3062
3063 lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3064 : io_handler.GetErrorStreamFileSP();
3065 // Split the output into lines and poll for interrupt requests
3066 bool had_output = !str.empty();
3067 while (!str.empty()) {
3068 llvm::StringRef line;
3069 std::tie(line, str) = str.split('\n');
3070 {
3071 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3072 stream->Write(line.data(), line.size());
3073 stream->Write("\n", 1);
3074 }
3075 }
3076
3077 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3078 if (had_output && GetDebugger().InterruptRequested())
3079 stream->Printf("\n... Interrupted.\n");
3080 stream->Flush();
3081}
3082
3084 llvm::StringRef line, const Flags &io_handler_flags) const {
3085 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3086 return false;
3087
3088 llvm::StringRef command = line.trim();
3089 if (command.empty())
3090 return true;
3091
3092 if (command.front() == m_comment_char)
3093 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3094
3095 return true;
3096}
3097
3099 std::string &line) {
3100 // If we were interrupted, bail out...
3101 if (WasInterrupted())
3102 return;
3103
3104 const bool is_interactive = io_handler.GetIsInteractive();
3105 if (!is_interactive) {
3106 // When we are not interactive, don't execute blank lines. This will happen
3107 // sourcing a commands file. We don't want blank lines to repeat the
3108 // previous command and cause any errors to occur (like redefining an
3109 // alias, get an error and stop parsing the commands file).
3110 if (line.empty())
3111 return;
3112
3113 // When using a non-interactive file handle (like when sourcing commands
3114 // from a file) we need to echo the command out so we don't just see the
3115 // command output and no command...
3116 if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3117 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3118 io_handler.GetOutputStreamFileSP()->Printf(
3119 "%s%s\n", io_handler.GetPrompt(), line.c_str());
3120 }
3121 }
3122
3124
3126 bool pushed_exe_ctx = false;
3127 if (exe_ctx.HasTargetScope()) {
3128 OverrideExecutionContext(exe_ctx);
3129 pushed_exe_ctx = true;
3130 }
3131 auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3132 if (pushed_exe_ctx)
3134 });
3135
3137 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3138
3139 // Now emit the command output text from the command we just executed
3140 if ((result.Succeeded() &&
3143 // Display any STDOUT/STDERR _prior_ to emitting the command result text
3145
3146 if (!result.GetImmediateOutputStream()) {
3147 llvm::StringRef output = result.GetOutputData();
3148 PrintCommandOutput(io_handler, output, true);
3149 }
3150
3151 // Now emit the command error text from the command we just executed
3152 if (!result.GetImmediateErrorStream()) {
3153 llvm::StringRef error = result.GetErrorData();
3154 PrintCommandOutput(io_handler, error, false);
3155 }
3156 }
3157
3159
3160 switch (result.GetStatus()) {
3165 break;
3166
3170 io_handler.SetIsDone(true);
3171 break;
3172
3175 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3177 io_handler.SetIsDone(true);
3178 }
3179 break;
3180
3181 case eReturnStatusQuit:
3183 io_handler.SetIsDone(true);
3184 break;
3185 }
3186
3187 // Finally, if we're going to stop on crash, check that here:
3189 result.GetDidChangeProcessState() &&
3192 io_handler.SetIsDone(true);
3194 }
3195}
3196
3199 Process *process = exe_ctx.GetProcessPtr();
3200
3201 if (InterruptCommand())
3202 return true;
3203
3204 if (process) {
3205 StateType state = process->GetState();
3206 if (StateIsRunningState(state)) {
3207 process->Halt();
3208 return true; // Don't do any updating when we are running
3209 }
3210 }
3211
3212 ScriptInterpreter *script_interpreter =
3214 if (script_interpreter) {
3215 if (script_interpreter->Interrupt())
3216 return true;
3217 }
3218 return false;
3219}
3220
3222 CommandReturnObject &result, std::optional<std::string> output_file) {
3223 if (output_file == std::nullopt || output_file->empty()) {
3224 std::string now = llvm::to_string(std::chrono::system_clock::now());
3225 std::replace(now.begin(), now.end(), ' ', '_');
3226 const std::string file_name = "lldb_session_" + now + ".log";
3227
3228 FileSpec save_location = GetSaveSessionDirectory();
3229
3230 if (!save_location)
3231 save_location = HostInfo::GetGlobalTempDir();
3232
3233 FileSystem::Instance().Resolve(save_location);
3234 save_location.AppendPathComponent(file_name);
3235 output_file = save_location.GetPath();
3236 }
3237
3238 auto error_out = [&](llvm::StringRef error_message, std::string description) {
3239 LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3240 output_file, description);
3242 "Failed to save session's transcripts to {0}!", *output_file);
3243 return false;
3244 };
3245
3249
3250 auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3251
3252 if (!opened_file)
3253 return error_out("Unable to create file",
3254 llvm::toString(opened_file.takeError()));
3255
3256 FileUP file = std::move(opened_file.get());
3257
3258 size_t byte_size = m_transcript_stream.GetSize();
3259
3260 Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3261
3262 if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3263 return error_out("Unable to write to destination file",
3264 "Bytes written do not match transcript size.");
3265
3267 result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3268 output_file->c_str());
3269
3271 const FileSpec file_spec;
3272 error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3273 if (error.Success()) {
3274 if (llvm::Error e = Host::OpenFileInExternalEditor(
3275 m_debugger.GetExternalEditor(), file_spec, 1))
3276 result.AppendError(llvm::toString(std::move(e)));
3277 }
3278 }
3279
3280 return true;
3281}
3282
3284 return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3285}
3286
3288 if (m_command_source_dirs.empty())
3289 return {};
3290 return m_command_source_dirs.back();
3291}
3292
3294 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3295 Debugger &debugger = GetDebugger();
3296 IOHandlerSP io_handler_sp(
3298 "lldb", // Name of input reader for history
3299 llvm::StringRef(prompt), // Prompt
3300 llvm::StringRef(), // Continuation prompt
3301 true, // Get multiple lines
3302 debugger.GetUseColor(),
3303 0, // Don't show line numbers
3304 delegate)); // IOHandlerDelegate
3305
3306 if (io_handler_sp) {
3307 io_handler_sp->SetUserData(baton);
3308 debugger.RunIOHandlerAsync(io_handler_sp);
3309 }
3310}
3311
3313 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3314 Debugger &debugger = GetDebugger();
3315 IOHandlerSP io_handler_sp(
3317 "lldb-python", // Name of input reader for history
3318 llvm::StringRef(prompt), // Prompt
3319 llvm::StringRef(), // Continuation prompt
3320 true, // Get multiple lines
3321 debugger.GetUseColor(),
3322 0, // Don't show line numbers
3323 delegate)); // IOHandlerDelegate
3324
3325 if (io_handler_sp) {
3326 io_handler_sp->SetUserData(baton);
3327 debugger.RunIOHandlerAsync(io_handler_sp);
3328 }
3329}
3330
3333}
3334
3335lldb::IOHandlerSP
3338 // Always re-create the IOHandlerEditline in case the input changed. The old
3339 // instance might have had a non-interactive input and now it does or vice
3340 // versa.
3341 if (force_create || !m_command_io_handler_sp) {
3342 // Always re-create the IOHandlerEditline in case the input changed. The
3343 // old instance might have had a non-interactive input and now it does or
3344 // vice versa.
3345 uint32_t flags = 0;
3346
3347 if (options) {
3348 if (options->m_stop_on_continue == eLazyBoolYes)
3350 if (options->m_stop_on_error == eLazyBoolYes)
3352 if (options->m_stop_on_crash == eLazyBoolYes)
3354 if (options->m_echo_commands != eLazyBoolNo)
3356 if (options->m_echo_comment_commands != eLazyBoolNo)
3358 if (options->m_print_results != eLazyBoolNo)
3360 if (options->m_print_errors != eLazyBoolNo)
3362 } else {
3365 }
3366
3367 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3370 m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3371 llvm::StringRef(), // Continuation prompt
3372 false, // Don't enable multiple line input, just single line commands
3374 0, // Don't show line numbers
3375 *this); // IOHandlerDelegate
3376 }
3378}
3379
3382 // Always re-create the command interpreter when we run it in case any file
3383 // handles have changed.
3384 bool force_create = true;
3385 m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3387
3388 if (options.GetAutoHandleEvents())
3390
3391 if (options.GetSpawnThread()) {
3393 } else {
3394 // If the current thread is not managed by a host thread, we won't detect
3395 // that this IS the CommandInterpreter IOHandler thread, so make it so:
3396 HostThread new_io_handler_thread(Host::GetCurrentThread());
3397 HostThread old_io_handler_thread =
3398 m_debugger.SetIOHandlerThread(new_io_handler_thread);
3400 m_debugger.SetIOHandlerThread(old_io_handler_thread);
3401
3402 if (options.GetAutoHandleEvents())
3404 }
3405
3406 return m_result;
3407}
3408
3411 CommandReturnObject &result) {
3412 std::string scratch_command(command_line); // working copy so we don't modify
3413 // command_line unless we succeed
3414 CommandObject *cmd_obj = nullptr;
3415 StreamString revised_command_line;
3416 bool wants_raw_input = false;
3417 std::string next_word;
3418 StringList matches;
3419 bool done = false;
3420 while (!done) {
3421 char quote_char = '\0';
3422 std::string suffix;
3423 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3424 if (cmd_obj == nullptr) {
3425 std::string full_name;
3426 bool is_alias = GetAliasFullName(next_word, full_name);
3427 cmd_obj = GetCommandObject(next_word, &matches);
3428 bool is_real_command =
3429 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3430 if (!is_real_command) {
3431 matches.Clear();
3432 std::string alias_result;
3433 cmd_obj =
3434 BuildAliasResult(full_name, scratch_command, alias_result, result);
3435 revised_command_line.Printf("%s", alias_result.c_str());
3436 if (cmd_obj) {
3437 wants_raw_input = cmd_obj->WantsRawCommandString();
3438 }
3439 } else {
3440 if (cmd_obj) {
3441 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3442 revised_command_line.Printf("%s", cmd_name.str().c_str());
3443 wants_raw_input = cmd_obj->WantsRawCommandString();
3444 } else {
3445 revised_command_line.Printf("%s", next_word.c_str());
3446 }
3447 }
3448 } else {
3449 if (cmd_obj->IsMultiwordObject()) {
3450 CommandObject *sub_cmd_obj =
3451 cmd_obj->GetSubcommandObject(next_word.c_str());
3452 if (sub_cmd_obj) {
3453 // The subcommand's name includes the parent command's name, so
3454 // restart rather than append to the revised_command_line.
3455 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3456 revised_command_line.Clear();
3457 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3458 cmd_obj = sub_cmd_obj;
3459 wants_raw_input = cmd_obj->WantsRawCommandString();
3460 } else {
3461 if (quote_char)
3462 revised_command_line.Printf(" %c%s%s%c", quote_char,
3463 next_word.c_str(), suffix.c_str(),
3464 quote_char);
3465 else
3466 revised_command_line.Printf(" %s%s", next_word.c_str(),
3467 suffix.c_str());
3468 done = true;
3469 }
3470 } else {
3471 if (quote_char)
3472 revised_command_line.Printf(" %c%s%s%c", quote_char,
3473 next_word.c_str(), suffix.c_str(),
3474 quote_char);
3475 else
3476 revised_command_line.Printf(" %s%s", next_word.c_str(),
3477 suffix.c_str());
3478 done = true;
3479 }
3480 }
3481
3482 if (cmd_obj == nullptr) {
3483 const size_t num_matches = matches.GetSize();
3484 if (matches.GetSize() > 1) {
3485 StreamString error_msg;
3486 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3487 next_word.c_str());
3488
3489 for (uint32_t i = 0; i < num_matches; ++i) {
3490 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3491 }
3492 result.AppendRawError(error_msg.GetString());
3493 } else {
3494 // We didn't have only one match, otherwise we wouldn't get here.
3495 lldbassert(num_matches == 0);
3496 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3497 next_word.c_str());
3498 }
3499 return nullptr;
3500 }
3501
3502 if (cmd_obj->IsMultiwordObject()) {
3503 if (!suffix.empty()) {
3504 result.AppendErrorWithFormat(
3505 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3506 "might be invalid).\n",
3507 cmd_obj->GetCommandName().str().c_str(),
3508 next_word.empty() ? "" : next_word.c_str(),
3509 next_word.empty() ? " -- " : " ", suffix.c_str());
3510 return nullptr;
3511 }
3512 } else {
3513 // If we found a normal command, we are done
3514 done = true;
3515 if (!suffix.empty()) {
3516 switch (suffix[0]) {
3517 case '/':
3518 // GDB format suffixes
3519 {
3520 Options *command_options = cmd_obj->GetOptions();
3521 if (command_options &&
3522 command_options->SupportsLongOption("gdb-format")) {
3523 std::string gdb_format_option("--gdb-format=");
3524 gdb_format_option += (suffix.c_str() + 1);
3525
3526 std::string cmd = std::string(revised_command_line.GetString());
3527 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3528 if (arg_terminator_idx != std::string::npos) {
3529 // Insert the gdb format option before the "--" that terminates
3530 // options
3531 gdb_format_option.append(1, ' ');
3532 cmd.insert(arg_terminator_idx, gdb_format_option);
3533 revised_command_line.Clear();
3534 revised_command_line.PutCString(cmd);
3535 } else
3536 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3537
3538 if (wants_raw_input &&
3539 FindArgumentTerminator(cmd) == std::string::npos)
3540 revised_command_line.PutCString(" --");
3541 } else {
3542 result.AppendErrorWithFormat(
3543 "the '%s' command doesn't support the --gdb-format option\n",
3544 cmd_obj->GetCommandName().str().c_str());
3545 return nullptr;
3546 }
3547 }
3548 break;
3549
3550 default:
3551 result.AppendErrorWithFormat(
3552 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3553 return nullptr;
3554 }
3555 }
3556 }
3557 if (scratch_command.empty())
3558 done = true;
3559 }
3560
3561 if (!scratch_command.empty())
3562 revised_command_line.Printf(" %s", scratch_command.c_str());
3563
3564 if (cmd_obj != nullptr)
3565 command_line = std::string(revised_command_line.GetString());
3566
3567 return cmd_obj;
3568}
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={})
static bool ExtractCommand(std::string &command_string, std::string &command, std::string &suffix, char &quote_char)
@ eHandleCommandFlagStopOnCrash
@ eHandleCommandFlagEchoCommentCommand
@ eHandleCommandFlagStopOnError
@ eHandleCommandFlagStopOnContinue
@ eHandleCommandFlagPrintErrors
@ eHandleCommandFlagEchoCommand
@ eHandleCommandFlagPrintResult
static llvm::raw_ostream & error(Stream &strm)
#define lldbassert(x)
Definition: LLDBAssert.h:13
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:337
#define LLDB_LOGF(log,...)
Definition: Log.h:344
#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:293
void Shift()
Shifts the first argument C string value of the array off the argument array.
Definition: Args.cpp:285
void SetArguments(size_t argc, const char **argv)
Sets the argument vector value, optionally copying all arguments into an internal buffer.
Definition: Args.cpp:357
size_t GetArgumentCount() const
Gets the number of arguments left in this command object.
Definition: Args.h:116
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:322
llvm::ArrayRef< ArgEntry > entries() const
Definition: Args.h:128
const char * GetArgumentAtIndex(size_t idx) const
Gets the NULL terminated C string argument pointer for the argument at index idx.
Definition: Args.cpp:263
const char ** GetConstArgumentVector() const
Gets the argument vector.
Definition: Args.cpp:279
void Clear()
Clear the arguments.
Definition: Args.cpp:378
An event broadcasting class.
Definition: Broadcaster.h:145
void SetEventName(uint32_t event_mask, const char *name)
Set the name for an event bit.
Definition: Broadcaster.h:240
void BroadcastEvent(lldb::EventSP &event_sp)
Broadcast an event which has no associated data.
Definition: Broadcaster.h:165
OptionArgVectorSP GetOptionArguments() const
Definition: CommandAlias.h:64
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)
void SetStopOnContinue(bool stop_on_continue)
bool IsResult(lldb::CommandInterpreterResult result)
void SetResult(lldb::CommandInterpreterResult result)
bool EchoCommandNonInteractive(llvm::StringRef line, const Flags &io_handler_flags) const
void UpdatePrompt(llvm::StringRef prompt)
bool IOHandlerInterrupt(IOHandler &io_handler) override
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.
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.
bool RemoveAlias(llvm::StringRef alias_name)
void SetSaveSessionDirectory(llvm::StringRef path)
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 HandleCompletion(CompletionRequest &request)
CommandInterpreterRunResult m_result
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.
static ConstString & GetStaticBroadcasterClass()
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)
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
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.
bool RemoveCommand(llvm::StringRef cmd, bool force=false)
Remove a command if it is removable (python or regex command).
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 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 bool Execute(const char *args_string, CommandReturnObject &result)=0
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)
void void AppendError(llvm::StringRef in_string)
void AppendRawError(llvm::StringRef in_string)
void SetStatus(lldb::ReturnStatus status)
void AppendErrorWithFormat(const char *format,...) __attribute__((format(printf
void AppendMessageWithFormat(const char *format,...) __attribute__((format(printf
lldb::ReturnStatus GetStatus() const
"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.
A uniqued constant string class.
Definition: ConstString.h:39
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:195
A class to manage flag bits.
Definition: Debugger.h:78
ExecutionContext GetSelectedExecutionContext()
Definition: Debugger.cpp:1022
bool StartEventHandlerThread()
Manually start the global event handler thread.
Definition: Debugger.cpp:1884
void StopEventHandlerThread()
Manually stop the debugger's default event handler.
Definition: Debugger.cpp:1924
void SetAsyncExecution(bool async)
Definition: Debugger.cpp:938
HostThread SetIOHandlerThread(HostThread &new_thread)
Definition: Debugger.cpp:2036
lldb::FileSP GetInputFileSP()
Definition: Debugger.h:137
bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp)
Definition: Debugger.cpp:1112
bool IsIOHandlerThreadCurrentThread() const
Definition: Debugger.cpp:2072
uint64_t GetTerminalWidth() const
Definition: Debugger.cpp:346
const char * GetIOHandlerCommandPrefix()
Definition: Debugger.cpp:1134
bool GetUseColor() const
Definition: Debugger.cpp:382
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, bool cancel_top_handler=true)
Run the given IO handler and return immediately.
Definition: Debugger.cpp:1146
lldb::StreamFileSP GetErrorStreamSP()
Definition: Debugger.h:141
bool GetAutoConfirm() const
Definition: Debugger.cpp:264
PlatformList & GetPlatformList()
Definition: Debugger.h:203
Target & GetDummyTarget()
Definition: Debugger.h:424
void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp)
Run the given IO handler and block until it's complete.
Definition: Debugger.cpp:1078
lldb::StreamFileSP GetOutputStreamSP()
Definition: Debugger.h:139
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
Definition: Debugger.cpp:1581
llvm::StringRef GetExternalEditor() const
Definition: Debugger.cpp:371
File & GetOutputFile()
Definition: Debugger.h:145
llvm::StringRef GetPrompt() const
Definition: Debugger.cpp:297
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...
Definition: Debugger.cpp:1651
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:330
void SetKeepInMemory(bool keep=true)
Definition: Target.h:340
void SetCoerceToId(bool coerce=true)
Definition: Target.h:326
void SetTryAllThreads(bool try_others=true)
Definition: Target.h:363
void SetTimeout(const Timeout< std::micro > &timeout)
Definition: Target.h:351
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:334
"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.
A file utility class.
Definition: FileSpec.h:56
void AppendPathComponent(llvm::StringRef component)
Definition: FileSpec.cpp:446
const ConstString & GetFilename() const
Filename string const get accessor.
Definition: FileSpec.h:240
void MakeAbsolute(const FileSpec &dir)
Make the FileSpec absolute by treating it relative to dir.
Definition: FileSpec.cpp:529
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:366
FileSpec CopyByRemovingLastPathComponent() const
Definition: FileSpec.cpp:423
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)
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.
Definition: File.cpp:210
@ 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)
A delegate class for use with IOHandler subclasses.
Definition: IOHandler.h:191
lldb::StreamFileSP GetErrorStreamFileSP()
Definition: IOHandler.cpp:107
virtual const char * GetPrompt()
Definition: IOHandler.h:99
std::recursive_mutex & GetOutputMutex()
Definition: IOHandler.h:165
lldb::StreamFileSP GetOutputStreamFileSP()
Definition: IOHandler.cpp:105
bool GetIsInteractive()
Check if the input is being supplied interactively by a user.
Definition: IOHandler.cpp:109
void SetIsDone(bool b)
Definition: IOHandler.h:87
static LanguageSet GetLanguagesSupportingREPLs()
Definition: Language.cpp:397
static const char * GetNameForLanguageType(lldb::LanguageType language)
Definition: Language.cpp:232
A command line option parsing protocol class.
Definition: Options.h:58
bool SupportsLongOption(const char *long_option)
Definition: Options.cpp:330
lldb::PlatformSP GetSelectedPlatform()
Select the active platform.
Definition: Platform.h:1009
A plug-in interface definition class for debugging a process.
Definition: Process.h:335
lldb::StateType GetState()
Get accessor for the current process state.
Definition: Process.cpp:1312
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
Definition: Process.cpp:3152
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
Definition: Scalar.cpp:155
An error handling class.
Definition: Status.h:44
void Clear()
Clear the object state.
Definition: Status.cpp:167
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:255
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:241
const char * GetData() const
Definition: StreamString.h:43
llvm::StringRef GetString() const
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition: Stream.cpp:130
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
size_t PutChar(char ch)
Definition: Stream.cpp:104
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:171
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:168
void AppendString(const std::string &s)
Definition: StringList.cpp:43
const char * GetStringAtIndex(size_t idx) const
Definition: StringList.cpp:86
size_t GetSize() const
Definition: StringList.cpp:74
void DeleteStringAtIndex(size_t id)
Definition: StringList.cpp:147
LoadCWDlldbinitFile GetLoadCWDlldbinitFile() const
Definition: Target.cpp:4620
static TargetProperties & GetGlobalProperties()
Definition: Target.cpp:2953
lldb::PlatformSP GetPlatform()
Definition: Target.h:1415
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:2553
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:309
int AddNamesMatchingPartialString(const std::map< std::string, ValueType > &in_map, llvm::StringRef cmd_str, StringList &matches, StringList *descriptions=nullptr)
Definition: CommandObject.h:37
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
size_t FindLongestCommandWord(std::map< std::string, ValueType > &dict)
Definition: CommandObject.h:57
@ RewriteLine
The full line has been rewritten by the completion.
LoadCWDlldbinitFile
Definition: Target.h:56
@ eLoadCWDlldbinitTrue
Definition: Target.h:57
@ eLoadCWDlldbinitFalse
Definition: Target.h:58
@ eLoadCWDlldbinitWarn
Definition: Target.h:59
std::vector< std::tuple< std::string, int, std::string > > OptionArgVector
Definition: Options.h:29
Definition: SBAddress.h:15
@ 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.
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.
@ eExpressionTimedOut
@ eExpressionCompleted
@ eExpressionHitBreakpoint
@ eExpressionInterrupted
@ eExpressionDiscarded
@ eExpressionParseError
@ eExpressionStoppedForDebug
@ eExpressionResultUnavailable
@ eExpressionThreadVanished
@ eExpressionSetupError
@ eReturnStatusStarted
@ eReturnStatusSuccessContinuingResult
@ eReturnStatusFailed
@ eReturnStatusSuccessContinuingNoResult
@ eReturnStatusQuit
@ eReturnStatusSuccessFinishResult
@ eReturnStatusInvalid
@ eReturnStatusSuccessFinishNoResult
StopReason
Thread stop reasons.
@ eStopReasonInstrumentation
@ eStopReasonProcessorTrace
@ eStopReasonException
@ eStopReasonSignal
const char * c_str() const
Definition: Args.h:49
llvm::StringRef ref() const
Definition: Args.h:48
char GetQuoteChar() const
Definition: Args.h:53
A SmallBitVector that represents a set of source languages (lldb::LanguageType).
Definition: TypeSystem.h:45
std::optional< lldb::LanguageType > GetSingularLanguage()
If the set contains a single language only, return it.
Definition: TypeSystem.cpp:28