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 constexpr llvm::StringLiteral class_name("lldb.commandInterpreter");
124 return class_name;
125}
126
128 bool synchronous_execution)
129 : Broadcaster(debugger.GetBroadcasterManager(),
130 CommandInterpreter::GetStaticBroadcasterClass().str()),
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 cmd_obj_sp = GetCommandSPExact("help");
513 if (cmd_obj_sp) {
514 AddAlias("h", cmd_obj_sp);
515 }
516}
517
520}
521
523 // This function has not yet been implemented.
524
525 // Look for any embedded script command
526 // If found,
527 // get interpreter object from the command dictionary,
528 // call execute_one_command on it,
529 // get the results as a string,
530 // substitute that string for current stuff.
531
532 return arg;
533}
534
535#define REGISTER_COMMAND_OBJECT(NAME, CLASS) \
536 m_command_dict[NAME] = std::make_shared<CLASS>(*this);
537
540
570
571 // clang-format off
572 const char *break_regexes[][2] = {
573 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
574 "breakpoint set --file '%1' --line %2 --column %3"},
575 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
576 "breakpoint set --file '%1' --line %2"},
577 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
578 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
579 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
580 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
581 "breakpoint set --name '%1'"},
582 {"^(-.*)$", "breakpoint set %1"},
583 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
584 "breakpoint set --name '%2' --shlib '%1'"},
585 {"^\\&(.*[^[:space:]])[[:space:]]*$",
586 "breakpoint set --name '%1' --skip-prologue=0"},
587 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
588 "breakpoint set --name '%1'"}};
589 // clang-format on
590
591 size_t num_regexes = std::size(break_regexes);
592
593 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
595 *this, "_regexp-break",
596 "Set a breakpoint using one of several shorthand formats.",
597 "\n"
598 "_regexp-break <filename>:<linenum>:<colnum>\n"
599 " main.c:12:21 // Break at line 12 and column "
600 "21 of main.c\n\n"
601 "_regexp-break <filename>:<linenum>\n"
602 " main.c:12 // Break at line 12 of "
603 "main.c\n\n"
604 "_regexp-break <linenum>\n"
605 " 12 // Break at line 12 of current "
606 "file\n\n"
607 "_regexp-break 0x<address>\n"
608 " 0x1234000 // Break at address "
609 "0x1234000\n\n"
610 "_regexp-break <name>\n"
611 " main // Break in 'main' after the "
612 "prologue\n\n"
613 "_regexp-break &<name>\n"
614 " &main // Break at first instruction "
615 "in 'main'\n\n"
616 "_regexp-break <module>`<name>\n"
617 " libc.so`malloc // Break in 'malloc' from "
618 "'libc.so'\n\n"
619 "_regexp-break /<source-regex>/\n"
620 " /break here/ // Break on source lines in "
621 "current file\n"
622 " // containing text 'break "
623 "here'.\n",
625
626 if (break_regex_cmd_up) {
627 bool success = true;
628 for (size_t i = 0; i < num_regexes; i++) {
629 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
630 break_regexes[i][1]);
631 if (!success)
632 break;
633 }
634 success =
635 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
636
637 if (success) {
638 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
639 m_command_dict[std::string(break_regex_cmd_sp->GetCommandName())] =
640 break_regex_cmd_sp;
641 }
642 }
643
644 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
646 *this, "_regexp-tbreak",
647 "Set a one-shot breakpoint using one of several shorthand formats.",
648 "\n"
649 "_regexp-break <filename>:<linenum>:<colnum>\n"
650 " main.c:12:21 // Break at line 12 and column "
651 "21 of main.c\n\n"
652 "_regexp-break <filename>:<linenum>\n"
653 " main.c:12 // Break at line 12 of "
654 "main.c\n\n"
655 "_regexp-break <linenum>\n"
656 " 12 // Break at line 12 of current "
657 "file\n\n"
658 "_regexp-break 0x<address>\n"
659 " 0x1234000 // Break at address "
660 "0x1234000\n\n"
661 "_regexp-break <name>\n"
662 " main // Break in 'main' after the "
663 "prologue\n\n"
664 "_regexp-break &<name>\n"
665 " &main // Break at first instruction "
666 "in 'main'\n\n"
667 "_regexp-break <module>`<name>\n"
668 " libc.so`malloc // Break in 'malloc' from "
669 "'libc.so'\n\n"
670 "_regexp-break /<source-regex>/\n"
671 " /break here/ // Break on source lines in "
672 "current file\n"
673 " // containing text 'break "
674 "here'.\n",
676
677 if (tbreak_regex_cmd_up) {
678 bool success = true;
679 for (size_t i = 0; i < num_regexes; i++) {
680 std::string command = break_regexes[i][1];
681 command += " -o 1";
682 success =
683 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command);
684 if (!success)
685 break;
686 }
687 success =
688 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
689
690 if (success) {
691 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
692 m_command_dict[std::string(tbreak_regex_cmd_sp->GetCommandName())] =
693 tbreak_regex_cmd_sp;
694 }
695 }
696
697 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
699 *this, "_regexp-attach", "Attach to process by ID or name.",
700 "_regexp-attach <pid> | <process-name>", 0, false));
701 if (attach_regex_cmd_up) {
702 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
703 "process attach --pid %1") &&
704 attach_regex_cmd_up->AddRegexCommand(
705 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
706 // specified get passed to
707 // 'process attach'
708 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
709 "process attach --name '%1'") &&
710 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
711 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
712 m_command_dict[std::string(attach_regex_cmd_sp->GetCommandName())] =
713 attach_regex_cmd_sp;
714 }
715 }
716
717 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
718 new CommandObjectRegexCommand(*this, "_regexp-down",
719 "Select a newer stack frame. Defaults to "
720 "moving one frame, a numeric argument can "
721 "specify an arbitrary number.",
722 "_regexp-down [<count>]", 0, false));
723 if (down_regex_cmd_up) {
724 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
725 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
726 "frame select -r -%1")) {
727 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
728 m_command_dict[std::string(down_regex_cmd_sp->GetCommandName())] =
729 down_regex_cmd_sp;
730 }
731 }
732
733 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
735 *this, "_regexp-up",
736 "Select an older stack frame. Defaults to moving one "
737 "frame, a numeric argument can specify an arbitrary number.",
738 "_regexp-up [<count>]", 0, false));
739 if (up_regex_cmd_up) {
740 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
741 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
742 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
743 m_command_dict[std::string(up_regex_cmd_sp->GetCommandName())] =
744 up_regex_cmd_sp;
745 }
746 }
747
748 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
750 *this, "_regexp-display",
751 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
752 "_regexp-display expression", 0, false));
753 if (display_regex_cmd_up) {
754 if (display_regex_cmd_up->AddRegexCommand(
755 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
756 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
757 m_command_dict[std::string(display_regex_cmd_sp->GetCommandName())] =
758 display_regex_cmd_sp;
759 }
760 }
761
762 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
763 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
764 "Stop displaying expression at every "
765 "stop (specified by stop-hook index.)",
766 "_regexp-undisplay stop-hook-number", 0,
767 false));
768 if (undisplay_regex_cmd_up) {
769 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
770 "target stop-hook delete %1")) {
771 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
772 m_command_dict[std::string(undisplay_regex_cmd_sp->GetCommandName())] =
773 undisplay_regex_cmd_sp;
774 }
775 }
776
777 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
779 *this, "gdb-remote",
780 "Connect to a process via remote GDB server.\n"
781 "If no host is specifed, localhost is assumed.\n"
782 "gdb-remote is an abbreviation for 'process connect --plugin "
783 "gdb-remote connect://<hostname>:<port>'\n",
784 "gdb-remote [<hostname>:]<portnum>", 0, false));
785 if (connect_gdb_remote_cmd_up) {
786 if (connect_gdb_remote_cmd_up->AddRegexCommand(
787 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
788 "process connect --plugin gdb-remote connect://%1:%2") &&
789 connect_gdb_remote_cmd_up->AddRegexCommand(
790 "^([[:digit:]]+)$",
791 "process connect --plugin gdb-remote connect://localhost:%1")) {
792 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
793 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
794 }
795 }
796
797 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
799 *this, "kdp-remote",
800 "Connect to a process via remote KDP server.\n"
801 "If no UDP port is specified, port 41139 is assumed.\n"
802 "kdp-remote is an abbreviation for 'process connect --plugin "
803 "kdp-remote udp://<hostname>:<port>'\n",
804 "kdp-remote <hostname>[:<portnum>]", 0, false));
805 if (connect_kdp_remote_cmd_up) {
806 if (connect_kdp_remote_cmd_up->AddRegexCommand(
807 "^([^:]+:[[:digit:]]+)$",
808 "process connect --plugin kdp-remote udp://%1") &&
809 connect_kdp_remote_cmd_up->AddRegexCommand(
810 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
811 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
812 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
813 }
814 }
815
816 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
818 *this, "_regexp-bt",
819 "Show the current thread's call stack. Any numeric argument "
820 "displays at most that many "
821 "frames. The argument 'all' displays all threads. Use 'settings"
822 " set frame-format' to customize the printing of individual frames "
823 "and 'settings set thread-format' to customize the thread header.",
824 "bt [<digit> | all]", 0, false));
825 if (bt_regex_cmd_up) {
826 // accept but don't document "bt -c <number>" -- before bt was a regex
827 // command if you wanted to backtrace three frames you would do "bt -c 3"
828 // but the intention is to have this emulate the gdb "bt" command and so
829 // now "bt 3" is the preferred form, in line with gdb.
830 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
831 "thread backtrace -c %1") &&
832 bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
833 "thread backtrace -c %1") &&
834 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
835 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
836 CommandObjectSP command_sp(bt_regex_cmd_up.release());
837 m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
838 }
839 }
840
841 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
843 *this, "_regexp-list",
844 "List relevant source code using one of several shorthand formats.",
845 "\n"
846 "_regexp-list <file>:<line> // List around specific file/line\n"
847 "_regexp-list <line> // List current file around specified "
848 "line\n"
849 "_regexp-list <function-name> // List specified function\n"
850 "_regexp-list 0x<address> // List around specified address\n"
851 "_regexp-list -[<count>] // List previous <count> lines\n"
852 "_regexp-list // List subsequent lines",
854 if (list_regex_cmd_up) {
855 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
856 "source list --line %1") &&
857 list_regex_cmd_up->AddRegexCommand(
858 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
859 "]*$",
860 "source list --file '%1' --line %2") &&
861 list_regex_cmd_up->AddRegexCommand(
862 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
863 "source list --address %1") &&
864 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
865 "source list --reverse") &&
866 list_regex_cmd_up->AddRegexCommand(
867 "^-([[:digit:]]+)[[:space:]]*$",
868 "source list --reverse --count %1") &&
869 list_regex_cmd_up->AddRegexCommand("^(.+)$",
870 "source list --name \"%1\"") &&
871 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
872 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
873 m_command_dict[std::string(list_regex_cmd_sp->GetCommandName())] =
874 list_regex_cmd_sp;
875 }
876 }
877
878 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
880 *this, "_regexp-env",
881 "Shorthand for viewing and setting environment variables.",
882 "\n"
883 "_regexp-env // Show environment\n"
884 "_regexp-env <name>=<value> // Set an environment variable",
885 0, false));
886 if (env_regex_cmd_up) {
887 if (env_regex_cmd_up->AddRegexCommand("^$",
888 "settings show target.env-vars") &&
889 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
890 "settings set target.env-vars %1")) {
891 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
892 m_command_dict[std::string(env_regex_cmd_sp->GetCommandName())] =
893 env_regex_cmd_sp;
894 }
895 }
896
897 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
899 *this, "_regexp-jump", "Set the program counter to a new address.",
900 "\n"
901 "_regexp-jump <line>\n"
902 "_regexp-jump +<line-offset> | -<line-offset>\n"
903 "_regexp-jump <file>:<line>\n"
904 "_regexp-jump *<addr>\n",
905 0, false));
906 if (jump_regex_cmd_up) {
907 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
908 "thread jump --addr %1") &&
909 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
910 "thread jump --line %1") &&
911 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
912 "thread jump --file %1 --line %2") &&
913 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
914 "thread jump --by %1")) {
915 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
916 m_command_dict[std::string(jump_regex_cmd_sp->GetCommandName())] =
917 jump_regex_cmd_sp;
918 }
919 }
920}
921
923 const char *cmd_str, bool include_aliases, StringList &matches,
924 StringList &descriptions) {
926 &descriptions);
927
928 if (include_aliases) {
930 &descriptions);
931 }
932
933 return matches.GetSize();
934}
935
937 Args &path, bool leaf_is_command, Status &result) {
938 result.Clear();
939
940 auto get_multi_or_report_error =
941 [&result](CommandObjectSP cmd_sp,
942 const char *name) -> CommandObjectMultiword * {
943 if (!cmd_sp) {
944 result.SetErrorStringWithFormat("Path component: '%s' not found", name);
945 return nullptr;
946 }
947 if (!cmd_sp->IsUserCommand()) {
948 result.SetErrorStringWithFormat("Path component: '%s' is not a user "
949 "command",
950 name);
951 return nullptr;
952 }
953 CommandObjectMultiword *cmd_as_multi = cmd_sp->GetAsMultiwordCommand();
954 if (!cmd_as_multi) {
955 result.SetErrorStringWithFormat("Path component: '%s' is not a container "
956 "command",
957 name);
958 return nullptr;
959 }
960 return cmd_as_multi;
961 };
962
963 size_t num_args = path.GetArgumentCount();
964 if (num_args == 0) {
965 result.SetErrorString("empty command path");
966 return nullptr;
967 }
968
969 if (num_args == 1 && leaf_is_command) {
970 // We just got a leaf command to be added to the root. That's not an error,
971 // just return null for the container.
972 return nullptr;
973 }
974
975 // Start by getting the root command from the interpreter.
976 const char *cur_name = path.GetArgumentAtIndex(0);
977 CommandObjectSP cur_cmd_sp = GetCommandSPExact(cur_name);
978 CommandObjectMultiword *cur_as_multi =
979 get_multi_or_report_error(cur_cmd_sp, cur_name);
980 if (cur_as_multi == nullptr)
981 return nullptr;
982
983 size_t num_path_elements = num_args - (leaf_is_command ? 1 : 0);
984 for (size_t cursor = 1; cursor < num_path_elements && cur_as_multi != nullptr;
985 cursor++) {
986 cur_name = path.GetArgumentAtIndex(cursor);
987 cur_cmd_sp = cur_as_multi->GetSubcommandSPExact(cur_name);
988 cur_as_multi = get_multi_or_report_error(cur_cmd_sp, cur_name);
989 }
990 return cur_as_multi;
991}
992
994CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
995 bool exact, StringList *matches,
996 StringList *descriptions) const {
997 CommandObjectSP command_sp;
998
999 std::string cmd = std::string(cmd_str);
1000
1001 if (HasCommands()) {
1002 auto pos = m_command_dict.find(cmd);
1003 if (pos != m_command_dict.end())
1004 command_sp = pos->second;
1005 }
1006
1007 if (include_aliases && HasAliases()) {
1008 auto alias_pos = m_alias_dict.find(cmd);
1009 if (alias_pos != m_alias_dict.end())
1010 command_sp = alias_pos->second;
1011 }
1012
1013 if (HasUserCommands()) {
1014 auto pos = m_user_dict.find(cmd);
1015 if (pos != m_user_dict.end())
1016 command_sp = pos->second;
1017 }
1018
1020 auto pos = m_user_mw_dict.find(cmd);
1021 if (pos != m_user_mw_dict.end())
1022 command_sp = pos->second;
1023 }
1024
1025 if (!exact && !command_sp) {
1026 // We will only get into here if we didn't find any exact matches.
1027
1028 CommandObjectSP user_match_sp, user_mw_match_sp, alias_match_sp,
1029 real_match_sp;
1030
1031 StringList local_matches;
1032 if (matches == nullptr)
1033 matches = &local_matches;
1034
1035 unsigned int num_cmd_matches = 0;
1036 unsigned int num_alias_matches = 0;
1037 unsigned int num_user_matches = 0;
1038 unsigned int num_user_mw_matches = 0;
1039
1040 // Look through the command dictionaries one by one, and if we get only one
1041 // match from any of them in toto, then return that, otherwise return an
1042 // empty CommandObjectSP and the list of matches.
1043
1044 if (HasCommands()) {
1045 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
1046 *matches, descriptions);
1047 }
1048
1049 if (num_cmd_matches == 1) {
1050 cmd.assign(matches->GetStringAtIndex(0));
1051 auto pos = m_command_dict.find(cmd);
1052 if (pos != m_command_dict.end())
1053 real_match_sp = pos->second;
1054 }
1055
1056 if (include_aliases && HasAliases()) {
1057 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
1058 *matches, descriptions);
1059 }
1060
1061 if (num_alias_matches == 1) {
1062 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
1063 auto alias_pos = m_alias_dict.find(cmd);
1064 if (alias_pos != m_alias_dict.end())
1065 alias_match_sp = alias_pos->second;
1066 }
1067
1068 if (HasUserCommands()) {
1069 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
1070 *matches, descriptions);
1071 }
1072
1073 if (num_user_matches == 1) {
1074 cmd.assign(
1075 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
1076
1077 auto pos = m_user_dict.find(cmd);
1078 if (pos != m_user_dict.end())
1079 user_match_sp = pos->second;
1080 }
1081
1083 num_user_mw_matches = AddNamesMatchingPartialString(
1084 m_user_mw_dict, cmd_str, *matches, descriptions);
1085 }
1086
1087 if (num_user_mw_matches == 1) {
1088 cmd.assign(matches->GetStringAtIndex(num_cmd_matches + num_alias_matches +
1089 num_user_matches));
1090
1091 auto pos = m_user_mw_dict.find(cmd);
1092 if (pos != m_user_mw_dict.end())
1093 user_mw_match_sp = pos->second;
1094 }
1095
1096 // If we got exactly one match, return that, otherwise return the match
1097 // list.
1098
1099 if (num_user_matches + num_user_mw_matches + num_cmd_matches +
1100 num_alias_matches ==
1101 1) {
1102 if (num_cmd_matches)
1103 return real_match_sp;
1104 else if (num_alias_matches)
1105 return alias_match_sp;
1106 else if (num_user_mw_matches)
1107 return user_mw_match_sp;
1108 else
1109 return user_match_sp;
1110 }
1111 } else if (matches && command_sp) {
1112 matches->AppendString(cmd_str);
1113 if (descriptions)
1114 descriptions->AppendString(command_sp->GetHelp());
1115 }
1116
1117 return command_sp;
1118}
1119
1120bool CommandInterpreter::AddCommand(llvm::StringRef name,
1121 const lldb::CommandObjectSP &cmd_sp,
1122 bool can_replace) {
1123 if (cmd_sp.get())
1124 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1125 "tried to add a CommandObject from a different interpreter");
1126
1127 if (name.empty())
1128 return false;
1129
1130 cmd_sp->SetIsUserCommand(false);
1131
1132 std::string name_sstr(name);
1133 auto name_iter = m_command_dict.find(name_sstr);
1134 if (name_iter != m_command_dict.end()) {
1135 if (!can_replace || !name_iter->second->IsRemovable())
1136 return false;
1137 name_iter->second = cmd_sp;
1138 } else {
1139 m_command_dict[name_sstr] = cmd_sp;
1140 }
1141 return true;
1142}
1143
1145 const lldb::CommandObjectSP &cmd_sp,
1146 bool can_replace) {
1147 Status result;
1148 if (cmd_sp.get())
1149 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1150 "tried to add a CommandObject from a different interpreter");
1151 if (name.empty()) {
1152 result.SetErrorString("can't use the empty string for a command name");
1153 return result;
1154 }
1155 // do not allow replacement of internal commands
1156 if (CommandExists(name)) {
1157 result.SetErrorString("can't replace builtin command");
1158 return result;
1159 }
1160
1161 if (UserCommandExists(name)) {
1162 if (!can_replace) {
1164 "user command \"{0}\" already exists and force replace was not set "
1165 "by --overwrite or 'settings set interpreter.require-overwrite "
1166 "false'",
1167 name);
1168 return result;
1169 }
1170 if (cmd_sp->IsMultiwordObject()) {
1171 if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1172 result.SetErrorString(
1173 "can't replace explicitly non-removable multi-word command");
1174 return result;
1175 }
1176 } else {
1177 if (!m_user_dict[std::string(name)]->IsRemovable()) {
1178 result.SetErrorString("can't replace explicitly non-removable command");
1179 return result;
1180 }
1181 }
1182 }
1183
1184 cmd_sp->SetIsUserCommand(true);
1185
1186 if (cmd_sp->IsMultiwordObject())
1187 m_user_mw_dict[std::string(name)] = cmd_sp;
1188 else
1189 m_user_dict[std::string(name)] = cmd_sp;
1190 return result;
1191}
1192
1195 bool include_aliases) const {
1196 // Break up the command string into words, in case it's a multi-word command.
1197 Args cmd_words(cmd_str);
1198
1199 if (cmd_str.empty())
1200 return {};
1201
1202 if (cmd_words.GetArgumentCount() == 1)
1203 return GetCommandSP(cmd_str, include_aliases, true);
1204
1205 // We have a multi-word command (seemingly), so we need to do more work.
1206 // First, get the cmd_obj_sp for the first word in the command.
1207 CommandObjectSP cmd_obj_sp =
1208 GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1209 if (!cmd_obj_sp)
1210 return {};
1211
1212 // Loop through the rest of the words in the command (everything passed in
1213 // was supposed to be part of a command name), and find the appropriate
1214 // sub-command SP for each command word....
1215 size_t end = cmd_words.GetArgumentCount();
1216 for (size_t i = 1; i < end; ++i) {
1217 if (!cmd_obj_sp->IsMultiwordObject()) {
1218 // We have more words in the command name, but we don't have a
1219 // multiword object. Fail and return.
1220 return {};
1221 }
1222
1223 cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1224 if (!cmd_obj_sp) {
1225 // The sub-command name was invalid. Fail and return.
1226 return {};
1227 }
1228 }
1229
1230 // We successfully looped through all the command words and got valid
1231 // command objects for them.
1232 return cmd_obj_sp;
1233}
1234
1237 StringList *matches,
1238 StringList *descriptions) const {
1239 // Try to find a match among commands and aliases. Allowing inexact matches,
1240 // but perferring exact matches.
1241 return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
1242 matches, descriptions)
1243 .get();
1244}
1245
1247 llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1248 std::string cmd_str(cmd);
1249 auto find_exact = [&](const CommandObject::CommandMap &map) {
1250 auto found_elem = map.find(std::string(cmd));
1251 if (found_elem == map.end())
1252 return (CommandObject *)nullptr;
1253 CommandObject *exact_cmd = found_elem->second.get();
1254 if (exact_cmd) {
1255 if (matches)
1256 matches->AppendString(exact_cmd->GetCommandName());
1257 if (descriptions)
1258 descriptions->AppendString(exact_cmd->GetHelp());
1259 return exact_cmd;
1260 }
1261 return (CommandObject *)nullptr;
1262 };
1263
1264 CommandObject *exact_cmd = find_exact(GetUserCommands());
1265 if (exact_cmd)
1266 return exact_cmd;
1267
1268 exact_cmd = find_exact(GetUserMultiwordCommands());
1269 if (exact_cmd)
1270 return exact_cmd;
1271
1272 // We didn't have an exact command, so now look for partial matches.
1273 StringList tmp_list;
1274 StringList *matches_ptr = matches ? matches : &tmp_list;
1275 AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1277 cmd_str, *matches_ptr);
1278
1279 return {};
1280}
1281
1282bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1283 return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
1284}
1285
1287 std::string &full_name) const {
1288 bool exact_match =
1289 (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
1290 if (exact_match) {
1291 full_name.assign(std::string(cmd));
1292 return exact_match;
1293 } else {
1294 StringList matches;
1295 size_t num_alias_matches;
1296 num_alias_matches =
1298 if (num_alias_matches == 1) {
1299 // Make sure this isn't shadowing a command in the regular command space:
1300 StringList regular_matches;
1301 const bool include_aliases = false;
1302 const bool exact = false;
1303 CommandObjectSP cmd_obj_sp(
1304 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1305 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1306 return false;
1307 else {
1308 full_name.assign(matches.GetStringAtIndex(0));
1309 return true;
1310 }
1311 } else
1312 return false;
1313 }
1314}
1315
1316bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1317 return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
1318}
1319
1320bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1321 return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
1322}
1323
1324bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1325 return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
1326}
1327
1329CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1330 lldb::CommandObjectSP &command_obj_sp,
1331 llvm::StringRef args_string) {
1332 if (command_obj_sp.get())
1333 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1334 "tried to add a CommandObject from a different interpreter");
1335
1336 std::unique_ptr<CommandAlias> command_alias_up(
1337 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1338
1339 if (command_alias_up && command_alias_up->IsValid()) {
1340 m_alias_dict[std::string(alias_name)] =
1341 CommandObjectSP(command_alias_up.get());
1342 return command_alias_up.release();
1343 }
1344
1345 return nullptr;
1346}
1347
1348bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1349 auto pos = m_alias_dict.find(std::string(alias_name));
1350 if (pos != m_alias_dict.end()) {
1351 m_alias_dict.erase(pos);
1352 return true;
1353 }
1354 return false;
1355}
1356
1357bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
1358 auto pos = m_command_dict.find(std::string(cmd));
1359 if (pos != m_command_dict.end()) {
1360 if (force || pos->second->IsRemovable()) {
1361 // Only regular expression objects or python commands are removable under
1362 // normal circumstances.
1363 m_command_dict.erase(pos);
1364 return true;
1365 }
1366 }
1367 return false;
1368}
1369
1370bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1371 CommandObject::CommandMap::iterator pos =
1372 m_user_dict.find(std::string(user_name));
1373 if (pos != m_user_dict.end()) {
1374 m_user_dict.erase(pos);
1375 return true;
1376 }
1377 return false;
1378}
1379
1380bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1381 CommandObject::CommandMap::iterator pos =
1382 m_user_mw_dict.find(std::string(multi_name));
1383 if (pos != m_user_mw_dict.end()) {
1384 m_user_mw_dict.erase(pos);
1385 return true;
1386 }
1387 return false;
1388}
1389
1391 uint32_t cmd_types) {
1392 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1393 if (!help_prologue.empty()) {
1394 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1395 help_prologue);
1396 }
1397
1398 CommandObject::CommandMap::const_iterator pos;
1399 size_t max_len = FindLongestCommandWord(m_command_dict);
1400
1401 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1402 result.AppendMessage("Debugger commands:");
1403 result.AppendMessage("");
1404
1405 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1406 if (!(cmd_types & eCommandTypesHidden) &&
1407 (pos->first.compare(0, 1, "_") == 0))
1408 continue;
1409
1410 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1411 pos->second->GetHelp(), max_len);
1412 }
1413 result.AppendMessage("");
1414 }
1415
1416 if (!m_alias_dict.empty() &&
1417 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1419 "Current command abbreviations "
1420 "(type '%shelp command alias' for more info):\n",
1422 result.AppendMessage("");
1424
1425 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1426 ++alias_pos) {
1427 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1428 alias_pos->second->GetHelp(), max_len);
1429 }
1430 result.AppendMessage("");
1431 }
1432
1433 if (!m_user_dict.empty() &&
1434 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1435 result.AppendMessage("Current user-defined commands:");
1436 result.AppendMessage("");
1438 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1439 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1440 pos->second->GetHelp(), max_len);
1441 }
1442 result.AppendMessage("");
1443 }
1444
1445 if (!m_user_mw_dict.empty() &&
1446 ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1447 result.AppendMessage("Current user-defined container commands:");
1448 result.AppendMessage("");
1450 for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1451 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1452 pos->second->GetHelp(), max_len);
1453 }
1454 result.AppendMessage("");
1455 }
1456
1458 "For more information on any command, type '%shelp <command-name>'.\n",
1460}
1461
1463 llvm::StringRef &command_string) {
1464 // This function finds the final, lowest-level, alias-resolved command object
1465 // whose 'Execute' function will eventually be invoked by the given command
1466 // line.
1467
1468 CommandObject *cmd_obj = nullptr;
1469 size_t start = command_string.find_first_not_of(k_white_space);
1470 size_t end = 0;
1471 bool done = false;
1472 while (!done) {
1473 if (start != std::string::npos) {
1474 // Get the next word from command_string.
1475 end = command_string.find_first_of(k_white_space, start);
1476 if (end == std::string::npos)
1477 end = command_string.size();
1478 std::string cmd_word =
1479 std::string(command_string.substr(start, end - start));
1480
1481 if (cmd_obj == nullptr)
1482 // Since cmd_obj is NULL we are on our first time through this loop.
1483 // Check to see if cmd_word is a valid command or alias.
1484 cmd_obj = GetCommandObject(cmd_word);
1485 else if (cmd_obj->IsMultiwordObject()) {
1486 // Our current object is a multi-word object; see if the cmd_word is a
1487 // valid sub-command for our object.
1488 CommandObject *sub_cmd_obj =
1489 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1490 if (sub_cmd_obj)
1491 cmd_obj = sub_cmd_obj;
1492 else // cmd_word was not a valid sub-command word, so we are done
1493 done = true;
1494 } else
1495 // We have a cmd_obj and it is not a multi-word object, so we are done.
1496 done = true;
1497
1498 // If we didn't find a valid command object, or our command object is not
1499 // a multi-word object, or we are at the end of the command_string, then
1500 // we are done. Otherwise, find the start of the next word.
1501
1502 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1503 end >= command_string.size())
1504 done = true;
1505 else
1506 start = command_string.find_first_not_of(k_white_space, end);
1507 } else
1508 // Unable to find any more words.
1509 done = true;
1510 }
1511
1512 command_string = command_string.substr(end);
1513 return cmd_obj;
1514}
1515
1516static const char *k_valid_command_chars =
1517 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1518static void StripLeadingSpaces(std::string &s) {
1519 if (!s.empty()) {
1520 size_t pos = s.find_first_not_of(k_white_space);
1521 if (pos == std::string::npos)
1522 s.clear();
1523 else if (pos == 0)
1524 return;
1525 s.erase(0, pos);
1526 }
1527}
1528
1529static size_t FindArgumentTerminator(const std::string &s) {
1530 const size_t s_len = s.size();
1531 size_t offset = 0;
1532 while (offset < s_len) {
1533 size_t pos = s.find("--", offset);
1534 if (pos == std::string::npos)
1535 break;
1536 if (pos > 0) {
1537 if (llvm::isSpace(s[pos - 1])) {
1538 // Check if the string ends "\s--" (where \s is a space character) or
1539 // if we have "\s--\s".
1540 if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1541 return pos;
1542 }
1543 }
1544 }
1545 offset = pos + 2;
1546 }
1547 return std::string::npos;
1548}
1549
1550static bool ExtractCommand(std::string &command_string, std::string &command,
1551 std::string &suffix, char &quote_char) {
1552 command.clear();
1553 suffix.clear();
1554 StripLeadingSpaces(command_string);
1555
1556 bool result = false;
1557 quote_char = '\0';
1558
1559 if (!command_string.empty()) {
1560 const char first_char = command_string[0];
1561 if (first_char == '\'' || first_char == '"') {
1562 quote_char = first_char;
1563 const size_t end_quote_pos = command_string.find(quote_char, 1);
1564 if (end_quote_pos == std::string::npos) {
1565 command.swap(command_string);
1566 command_string.erase();
1567 } else {
1568 command.assign(command_string, 1, end_quote_pos - 1);
1569 if (end_quote_pos + 1 < command_string.size())
1570 command_string.erase(0, command_string.find_first_not_of(
1571 k_white_space, end_quote_pos + 1));
1572 else
1573 command_string.erase();
1574 }
1575 } else {
1576 const size_t first_space_pos =
1577 command_string.find_first_of(k_white_space);
1578 if (first_space_pos == std::string::npos) {
1579 command.swap(command_string);
1580 command_string.erase();
1581 } else {
1582 command.assign(command_string, 0, first_space_pos);
1583 command_string.erase(0, command_string.find_first_not_of(
1584 k_white_space, first_space_pos));
1585 }
1586 }
1587 result = true;
1588 }
1589
1590 if (!command.empty()) {
1591 // actual commands can't start with '-' or '_'
1592 if (command[0] != '-' && command[0] != '_') {
1593 size_t pos = command.find_first_not_of(k_valid_command_chars);
1594 if (pos > 0 && pos != std::string::npos) {
1595 suffix.assign(command.begin() + pos, command.end());
1596 command.erase(pos);
1597 }
1598 }
1599 }
1600
1601 return result;
1602}
1603
1605 llvm::StringRef alias_name, std::string &raw_input_string,
1606 std::string &alias_result, CommandReturnObject &result) {
1607 CommandObject *alias_cmd_obj = nullptr;
1608 Args cmd_args(raw_input_string);
1609 alias_cmd_obj = GetCommandObject(alias_name);
1610 StreamString result_str;
1611
1612 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1613 alias_result.clear();
1614 return alias_cmd_obj;
1615 }
1616 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1617 ((CommandAlias *)alias_cmd_obj)->Desugar();
1618 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1619 alias_cmd_obj = desugared.first.get();
1620 std::string alias_name_str = std::string(alias_name);
1621 if ((cmd_args.GetArgumentCount() == 0) ||
1622 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1623 cmd_args.Unshift(alias_name_str);
1624
1625 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1626
1627 if (!option_arg_vector_sp.get()) {
1628 alias_result = std::string(result_str.GetString());
1629 return alias_cmd_obj;
1630 }
1631 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1632
1633 int value_type;
1634 std::string option;
1635 std::string value;
1636 for (const auto &entry : *option_arg_vector) {
1637 std::tie(option, value_type, value) = entry;
1638 if (option == g_argument) {
1639 result_str.Printf(" %s", value.c_str());
1640 continue;
1641 }
1642
1643 result_str.Printf(" %s", option.c_str());
1644 if (value_type == OptionParser::eNoArgument)
1645 continue;
1646
1647 if (value_type != OptionParser::eOptionalArgument)
1648 result_str.Printf(" ");
1649 int index = GetOptionArgumentPosition(value.c_str());
1650 if (index == 0)
1651 result_str.Printf("%s", value.c_str());
1652 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1653
1654 result.AppendErrorWithFormat("Not enough arguments provided; you "
1655 "need at least %d arguments to use "
1656 "this alias.\n",
1657 index);
1658 return nullptr;
1659 } else {
1660 const Args::ArgEntry &entry = cmd_args[index];
1661 size_t strpos = raw_input_string.find(entry.c_str());
1662 const char quote_char = entry.GetQuoteChar();
1663 if (strpos != std::string::npos) {
1664 const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1665 const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1666
1667 // Make sure we aren't going outside the bounds of the cmd string:
1668 if (strpos < start_fudge) {
1669 result.AppendError("Unmatched quote at command beginning.");
1670 return nullptr;
1671 }
1672 llvm::StringRef arg_text = entry.ref();
1673 if (strpos - start_fudge + arg_text.size() + len_fudge >
1674 raw_input_string.size()) {
1675 result.AppendError("Unmatched quote at command end.");
1676 return nullptr;
1677 }
1678 raw_input_string = raw_input_string.erase(
1679 strpos - start_fudge,
1680 strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1681 }
1682 if (quote_char == '\0')
1683 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1684 else
1685 result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
1686 }
1687 }
1688
1689 alias_result = std::string(result_str.GetString());
1690 return alias_cmd_obj;
1691}
1692
1694 // The command preprocessor needs to do things to the command line before any
1695 // parsing of arguments or anything else is done. The only current stuff that
1696 // gets preprocessed is anything enclosed in backtick ('`') characters is
1697 // evaluated as an expression and the result of the expression must be a
1698 // scalar that can be substituted into the command. An example would be:
1699 // (lldb) memory read `$rsp + 20`
1700 Status error; // Status for any expressions that might not evaluate
1701 size_t start_backtick;
1702 size_t pos = 0;
1703 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1704 // Stop if an error was encountered during the previous iteration.
1705 if (error.Fail())
1706 break;
1707
1708 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1709 // The backtick was preceded by a '\' character, remove the slash and
1710 // don't treat the backtick as the start of an expression.
1711 command.erase(start_backtick - 1, 1);
1712 // No need to add one to start_backtick since we just deleted a char.
1713 pos = start_backtick;
1714 continue;
1715 }
1716
1717 const size_t expr_content_start = start_backtick + 1;
1718 const size_t end_backtick = command.find('`', expr_content_start);
1719
1720 if (end_backtick == std::string::npos) {
1721 // Stop if there's no end backtick.
1722 break;
1723 }
1724
1725 if (end_backtick == expr_content_start) {
1726 // Skip over empty expression. (two backticks in a row)
1727 command.erase(start_backtick, 2);
1728 continue;
1729 }
1730
1731 std::string expr_str(command, expr_content_start,
1732 end_backtick - expr_content_start);
1733 error = PreprocessToken(expr_str);
1734 // We always stop at the first error:
1735 if (error.Fail())
1736 break;
1737
1738 command.erase(start_backtick, end_backtick - start_backtick + 1);
1739 command.insert(start_backtick, std::string(expr_str));
1740 pos = start_backtick + expr_str.size();
1741 }
1742 return error;
1743}
1744
1745Status
1747 Status error;
1749
1750 // Get a dummy target to allow for calculator mode while processing
1751 // backticks. This also helps break the infinite loop caused when target is
1752 // null.
1753 Target *exe_target = exe_ctx.GetTargetPtr();
1754 Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1755
1756 ValueObjectSP expr_result_valobj_sp;
1757
1759 options.SetCoerceToId(false);
1760 options.SetUnwindOnError(true);
1761 options.SetIgnoreBreakpoints(true);
1762 options.SetKeepInMemory(false);
1763 options.SetTryAllThreads(true);
1764 options.SetTimeout(std::nullopt);
1765
1766 ExpressionResults expr_result =
1767 target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1768 expr_result_valobj_sp, options);
1769
1770 if (expr_result == eExpressionCompleted) {
1771 Scalar scalar;
1772 if (expr_result_valobj_sp)
1773 expr_result_valobj_sp =
1774 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1775 expr_result_valobj_sp->GetDynamicValueType(), true);
1776 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1777
1778 StreamString value_strm;
1779 const bool show_type = false;
1780 scalar.GetValue(value_strm, show_type);
1781 size_t value_string_size = value_strm.GetSize();
1782 if (value_string_size) {
1783 expr_str = value_strm.GetData();
1784 } else {
1785 error.SetErrorStringWithFormat("expression value didn't result "
1786 "in a scalar value for the "
1787 "expression '%s'",
1788 expr_str.c_str());
1789 }
1790 } else {
1791 error.SetErrorStringWithFormat("expression value didn't result "
1792 "in a scalar value for the "
1793 "expression '%s'",
1794 expr_str.c_str());
1795 }
1796 return error;
1797 }
1798
1799 // If we have an error from the expression evaluation it will be in the
1800 // ValueObject error, which won't be success and we will just report it.
1801 // But if for some reason we didn't get a value object at all, then we will
1802 // make up some helpful errors from the expression result.
1803 if (expr_result_valobj_sp)
1804 error = expr_result_valobj_sp->GetError();
1805
1806 if (error.Success()) {
1807 switch (expr_result) {
1809 error.SetErrorStringWithFormat(
1810 "expression setup error for the expression '%s'", expr_str.c_str());
1811 break;
1813 error.SetErrorStringWithFormat(
1814 "expression parse error for the expression '%s'", expr_str.c_str());
1815 break;
1817 error.SetErrorStringWithFormat(
1818 "expression error fetching result for the expression '%s'",
1819 expr_str.c_str());
1820 break;
1822 break;
1824 error.SetErrorStringWithFormat(
1825 "expression discarded for the expression '%s'", expr_str.c_str());
1826 break;
1828 error.SetErrorStringWithFormat(
1829 "expression interrupted for the expression '%s'", expr_str.c_str());
1830 break;
1832 error.SetErrorStringWithFormat(
1833 "expression hit breakpoint for the expression '%s'",
1834 expr_str.c_str());
1835 break;
1837 error.SetErrorStringWithFormat(
1838 "expression timed out for the expression '%s'", expr_str.c_str());
1839 break;
1841 error.SetErrorStringWithFormat("expression stop at entry point "
1842 "for debugging for the "
1843 "expression '%s'",
1844 expr_str.c_str());
1845 break;
1847 error.SetErrorStringWithFormat(
1848 "expression thread vanished for the expression '%s'",
1849 expr_str.c_str());
1850 break;
1851 }
1852 }
1853 return error;
1854}
1855
1856bool CommandInterpreter::HandleCommand(const char *command_line,
1857 LazyBool lazy_add_to_history,
1858 const ExecutionContext &override_context,
1859 CommandReturnObject &result) {
1860
1861 OverrideExecutionContext(override_context);
1862 bool status = HandleCommand(command_line, lazy_add_to_history, result);
1864 return status;
1865}
1866
1867bool CommandInterpreter::HandleCommand(const char *command_line,
1868 LazyBool lazy_add_to_history,
1869 CommandReturnObject &result,
1870 bool force_repeat_command) {
1871 std::string command_string(command_line);
1872 std::string original_command_string(command_line);
1873
1875 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1876 command_line);
1877
1878 LLDB_LOGF(log, "Processing command: %s", command_line);
1879 LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1880
1881 if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
1882 result.AppendError("... Interrupted");
1883 return false;
1884 }
1885
1886 bool add_to_history;
1887 if (lazy_add_to_history == eLazyBoolCalculate)
1888 add_to_history = (m_command_source_depth == 0);
1889 else
1890 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1891
1892 m_transcript_stream << "(lldb) " << command_line << '\n';
1893
1894 bool empty_command = false;
1895 bool comment_command = false;
1896 if (command_string.empty())
1897 empty_command = true;
1898 else {
1899 const char *k_space_characters = "\t\n\v\f\r ";
1900
1901 size_t non_space = command_string.find_first_not_of(k_space_characters);
1902 // Check for empty line or comment line (lines whose first non-space
1903 // character is the comment character for this interpreter)
1904 if (non_space == std::string::npos)
1905 empty_command = true;
1906 else if (command_string[non_space] == m_comment_char)
1907 comment_command = true;
1908 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1909 llvm::StringRef search_str(command_string);
1910 search_str = search_str.drop_front(non_space);
1911 if (auto hist_str = m_command_history.FindString(search_str)) {
1912 add_to_history = false;
1913 command_string = std::string(*hist_str);
1914 original_command_string = std::string(*hist_str);
1915 } else {
1916 result.AppendErrorWithFormat("Could not find entry: %s in history",
1917 command_string.c_str());
1918 return false;
1919 }
1920 }
1921 }
1922
1923 if (empty_command) {
1924 if (!GetRepeatPreviousCommand()) {
1926 return true;
1927 }
1928
1929 if (m_command_history.IsEmpty()) {
1930 result.AppendError("empty command");
1931 return false;
1932 }
1933
1934 command_line = m_repeat_command.c_str();
1935 command_string = command_line;
1936 original_command_string = command_line;
1937 if (m_repeat_command.empty()) {
1938 result.AppendError("No auto repeat.");
1939 return false;
1940 }
1941
1942 add_to_history = false;
1943 } else if (comment_command) {
1945 return true;
1946 }
1947
1948 // Phase 1.
1949
1950 // Before we do ANY kind of argument processing, we need to figure out what
1951 // the real/final command object is for the specified command. This gets
1952 // complicated by the fact that the user could have specified an alias, and,
1953 // in translating the alias, there may also be command options and/or even
1954 // data (including raw text strings) that need to be found and inserted into
1955 // the command line as part of the translation. So this first step is plain
1956 // look-up and replacement, resulting in:
1957 // 1. the command object whose Execute method will actually be called
1958 // 2. a revised command string, with all substitutions and replacements
1959 // taken care of
1960 // From 1 above, we can determine whether the Execute function wants raw
1961 // input or not.
1962
1963 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1964
1965 // We have to preprocess the whole command string for Raw commands, since we
1966 // don't know the structure of the command. For parsed commands, we only
1967 // treat backticks as quote characters specially.
1968 // FIXME: We probably want to have raw commands do their own preprocessing.
1969 // For instance, I don't think people expect substitution in expr expressions.
1970 if (cmd_obj && cmd_obj->WantsRawCommandString()) {
1971 Status error(PreprocessCommand(command_string));
1972
1973 if (error.Fail()) {
1974 result.AppendError(error.AsCString());
1975 return false;
1976 }
1977 }
1978
1979 // Although the user may have abbreviated the command, the command_string now
1980 // has the command expanded to the full name. For example, if the input was
1981 // "br s -n main", command_string is now "breakpoint set -n main".
1982 if (log) {
1983 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1984 LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
1985 LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
1986 command_string.c_str());
1987 const bool wants_raw_input =
1988 (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
1989 LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
1990 wants_raw_input ? "True" : "False");
1991 }
1992
1993 // Phase 2.
1994 // Take care of things like setting up the history command & calling the
1995 // appropriate Execute method on the CommandObject, with the appropriate
1996 // arguments.
1997
1998 if (cmd_obj != nullptr) {
1999 bool generate_repeat_command = add_to_history;
2000 // If we got here when empty_command was true, then this command is a
2001 // stored "repeat command" which we should give a chance to produce it's
2002 // repeat command, even though we don't add repeat commands to the history.
2003 generate_repeat_command |= empty_command;
2004 // For `command regex`, the regex command (ex `bt`) is added to history, but
2005 // the resolved command (ex `thread backtrace`) is _not_ added to history.
2006 // However, the resolved command must be given the opportunity to provide a
2007 // repeat command. `force_repeat_command` supports this case.
2008 generate_repeat_command |= force_repeat_command;
2009 if (generate_repeat_command) {
2010 Args command_args(command_string);
2011 std::optional<std::string> repeat_command =
2012 cmd_obj->GetRepeatCommand(command_args, 0);
2013 if (repeat_command) {
2014 LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
2015 m_repeat_command.assign(*repeat_command);
2016 } else {
2017 m_repeat_command.assign(original_command_string);
2018 }
2019 }
2020
2021 if (add_to_history)
2022 m_command_history.AppendString(original_command_string);
2023
2024 std::string remainder;
2025 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2026 if (actual_cmd_name_len < command_string.length())
2027 remainder = command_string.substr(actual_cmd_name_len);
2028
2029 // Remove any initial spaces
2030 size_t pos = remainder.find_first_not_of(k_white_space);
2031 if (pos != 0 && pos != std::string::npos)
2032 remainder.erase(0, pos);
2033
2034 LLDB_LOGF(
2035 log, "HandleCommand, command line after removing command name(s): '%s'",
2036 remainder.c_str());
2037
2038 cmd_obj->Execute(remainder.c_str(), result);
2039 }
2040
2041 LLDB_LOGF(log, "HandleCommand, command %s",
2042 (result.Succeeded() ? "succeeded" : "did not succeed"));
2043
2046
2047 return result.Succeeded();
2048}
2049
2051 bool look_for_subcommand = false;
2052
2053 // For any of the command completions a unique match will be a complete word.
2054
2055 if (request.GetParsedLine().GetArgumentCount() == 0) {
2056 // We got nothing on the command line, so return the list of commands
2057 bool include_aliases = true;
2058 StringList new_matches, descriptions;
2059 GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2060 descriptions);
2061 request.AddCompletions(new_matches, descriptions);
2062 } else if (request.GetCursorIndex() == 0) {
2063 // The cursor is in the first argument, so just do a lookup in the
2064 // dictionary.
2065 StringList new_matches, new_descriptions;
2066 CommandObject *cmd_obj =
2068 &new_matches, &new_descriptions);
2069
2070 if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2071 new_matches.GetStringAtIndex(0) != nullptr &&
2072 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2073 new_matches.GetStringAtIndex(0)) == 0) {
2074 if (request.GetParsedLine().GetArgumentCount() != 1) {
2075 look_for_subcommand = true;
2076 new_matches.DeleteStringAtIndex(0);
2077 new_descriptions.DeleteStringAtIndex(0);
2078 request.AppendEmptyArgument();
2079 }
2080 }
2081 request.AddCompletions(new_matches, new_descriptions);
2082 }
2083
2084 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2085 // We are completing further on into a commands arguments, so find the
2086 // command and tell it to complete the command. First see if there is a
2087 // matching initial command:
2088 CommandObject *command_object =
2090 if (command_object) {
2091 request.ShiftArguments();
2092 command_object->HandleCompletion(request);
2093 }
2094 }
2095}
2096
2098
2099 // Don't complete comments, and if the line we are completing is just the
2100 // history repeat character, substitute the appropriate history line.
2101 llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2102
2103 if (!first_arg.empty()) {
2104 if (first_arg.front() == m_comment_char)
2105 return;
2106 if (first_arg.front() == CommandHistory::g_repeat_char) {
2107 if (auto hist_str = m_command_history.FindString(first_arg))
2108 request.AddCompletion(*hist_str, "Previous command history event",
2110 return;
2111 }
2112 }
2113
2114 HandleCompletionMatches(request);
2115}
2116
2117std::optional<std::string>
2119 if (line.empty())
2120 return std::nullopt;
2121 const size_t s = m_command_history.GetSize();
2122 for (int i = s - 1; i >= 0; --i) {
2123 llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2124 if (entry.consume_front(line))
2125 return entry.str();
2126 }
2127 return std::nullopt;
2128}
2129
2130void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2131 EventSP prompt_change_event_sp(
2132 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2133 ;
2134 BroadcastEvent(prompt_change_event_sp);
2136 m_command_io_handler_sp->SetPrompt(new_prompt);
2137}
2138
2139bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2140 // Check AutoConfirm first:
2142 return default_answer;
2143
2144 IOHandlerConfirm *confirm =
2145 new IOHandlerConfirm(m_debugger, message, default_answer);
2146 IOHandlerSP io_handler_sp(confirm);
2147 m_debugger.RunIOHandlerSync(io_handler_sp);
2148 return confirm->GetResponse();
2149}
2150
2151const CommandAlias *
2152CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2153 OptionArgVectorSP ret_val;
2154
2155 auto pos = m_alias_dict.find(std::string(alias_name));
2156 if (pos != m_alias_dict.end())
2157 return (CommandAlias *)pos->second.get();
2158
2159 return nullptr;
2160}
2161
2162bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2163
2164bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2165
2166bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2167
2169 return (!m_user_mw_dict.empty());
2170}
2171
2173
2175 const char *alias_name,
2176 Args &cmd_args,
2177 std::string &raw_input_string,
2178 CommandReturnObject &result) {
2179 OptionArgVectorSP option_arg_vector_sp =
2180 GetAlias(alias_name)->GetOptionArguments();
2181
2182 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2183
2184 // Make sure that the alias name is the 0th element in cmd_args
2185 std::string alias_name_str = alias_name;
2186 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2187 cmd_args.Unshift(alias_name_str);
2188
2189 Args new_args(alias_cmd_obj->GetCommandName());
2190 if (new_args.GetArgumentCount() == 2)
2191 new_args.Shift();
2192
2193 if (option_arg_vector_sp.get()) {
2194 if (wants_raw_input) {
2195 // We have a command that both has command options and takes raw input.
2196 // Make *sure* it has a " -- " in the right place in the
2197 // raw_input_string.
2198 size_t pos = raw_input_string.find(" -- ");
2199 if (pos == std::string::npos) {
2200 // None found; assume it goes at the beginning of the raw input string
2201 raw_input_string.insert(0, " -- ");
2202 }
2203 }
2204
2205 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2206 const size_t old_size = cmd_args.GetArgumentCount();
2207 std::vector<bool> used(old_size + 1, false);
2208
2209 used[0] = true;
2210
2211 int value_type;
2212 std::string option;
2213 std::string value;
2214 for (const auto &option_entry : *option_arg_vector) {
2215 std::tie(option, value_type, value) = option_entry;
2216 if (option == g_argument) {
2217 if (!wants_raw_input || (value != "--")) {
2218 // Since we inserted this above, make sure we don't insert it twice
2219 new_args.AppendArgument(value);
2220 }
2221 continue;
2222 }
2223
2224 if (value_type != OptionParser::eOptionalArgument)
2225 new_args.AppendArgument(option);
2226
2227 if (value == g_no_argument)
2228 continue;
2229
2230 int index = GetOptionArgumentPosition(value.c_str());
2231 if (index == 0) {
2232 // value was NOT a positional argument; must be a real value
2233 if (value_type != OptionParser::eOptionalArgument)
2234 new_args.AppendArgument(value);
2235 else {
2236 new_args.AppendArgument(option + value);
2237 }
2238
2239 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2240 result.AppendErrorWithFormat("Not enough arguments provided; you "
2241 "need at least %d arguments to use "
2242 "this alias.\n",
2243 index);
2244 return;
2245 } else {
2246 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2247 size_t strpos =
2248 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2249 if (strpos != std::string::npos) {
2250 raw_input_string = raw_input_string.erase(
2251 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2252 }
2253
2254 if (value_type != OptionParser::eOptionalArgument)
2255 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2256 else {
2257 new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2258 }
2259 used[index] = true;
2260 }
2261 }
2262
2263 for (auto entry : llvm::enumerate(cmd_args.entries())) {
2264 if (!used[entry.index()] && !wants_raw_input)
2265 new_args.AppendArgument(entry.value().ref());
2266 }
2267
2268 cmd_args.Clear();
2269 cmd_args.SetArguments(new_args.GetArgumentCount(),
2270 new_args.GetConstArgumentVector());
2271 } else {
2273 // This alias was not created with any options; nothing further needs to be
2274 // done, unless it is a command that wants raw input, in which case we need
2275 // to clear the rest of the data from cmd_args, since its in the raw input
2276 // string.
2277 if (wants_raw_input) {
2278 cmd_args.Clear();
2279 cmd_args.SetArguments(new_args.GetArgumentCount(),
2280 new_args.GetConstArgumentVector());
2281 }
2282 return;
2283 }
2284
2286}
2287
2289 int position = 0; // Any string that isn't an argument position, i.e. '%'
2290 // followed by an integer, gets a position
2291 // of zero.
2292
2293 const char *cptr = in_string;
2294
2295 // Does it start with '%'
2296 if (cptr[0] == '%') {
2297 ++cptr;
2298
2299 // Is the rest of it entirely digits?
2300 if (isdigit(cptr[0])) {
2301 const char *start = cptr;
2302 while (isdigit(cptr[0]))
2303 ++cptr;
2304
2305 // We've gotten to the end of the digits; are we at the end of the
2306 // string?
2307 if (cptr[0] == '\0')
2308 position = atoi(start);
2309 }
2310 }
2311
2312 return position;
2313}
2314
2316 llvm::StringRef suffix = {}) {
2317 std::string init_file_name = ".lldbinit";
2318 if (!suffix.empty()) {
2319 init_file_name.append("-");
2320 init_file_name.append(suffix.str());
2321 }
2322
2324 llvm::sys::path::append(init_file, init_file_name);
2325
2326 FileSystem::Instance().Resolve(init_file);
2327}
2328
2330 LanguageType language) {
2331 if (language == eLanguageTypeUnknown) {
2333 if (auto main_repl_language = repl_languages.GetSingularLanguage())
2334 language = *main_repl_language;
2335 else
2336 return;
2337 }
2338
2339 std::string init_file_name =
2340 (llvm::Twine(".lldbinit-") +
2341 llvm::Twine(Language::GetNameForLanguageType(language)) +
2342 llvm::Twine("-repl"))
2343 .str();
2345 llvm::sys::path::append(init_file, init_file_name);
2346 FileSystem::Instance().Resolve(init_file);
2347}
2348
2350 llvm::StringRef s = ".lldbinit";
2351 init_file.assign(s.begin(), s.end());
2352 FileSystem::Instance().Resolve(init_file);
2353}
2354
2356 CommandReturnObject &result) {
2357 assert(!m_skip_lldbinit_files);
2358
2359 if (!FileSystem::Instance().Exists(file)) {
2361 return;
2362 }
2363
2364 // Use HandleCommand to 'source' the given file; this will do the actual
2365 // broadcasting of the commands back to any appropriate listener (see
2366 // CommandObjectSource::Execute for more details).
2367 const bool saved_batch = SetBatchCommandMode(true);
2369 options.SetSilent(true);
2370 options.SetPrintErrors(true);
2371 options.SetStopOnError(false);
2372 options.SetStopOnContinue(true);
2373 HandleCommandsFromFile(file, options, result);
2374 SetBatchCommandMode(saved_batch);
2375}
2376
2380 return;
2381 }
2382
2383 llvm::SmallString<128> init_file;
2384 GetCwdInitFile(init_file);
2385 if (!FileSystem::Instance().Exists(init_file)) {
2387 return;
2388 }
2389
2390 LoadCWDlldbinitFile should_load =
2392
2393 switch (should_load) {
2396 break;
2398 SourceInitFile(FileSpec(init_file.str()), result);
2399 break;
2400 case eLoadCWDlldbinitWarn: {
2401 llvm::SmallString<128> home_init_file;
2402 GetHomeInitFile(home_init_file);
2403 if (llvm::sys::path::parent_path(init_file) ==
2404 llvm::sys::path::parent_path(home_init_file)) {
2406 } else {
2408 }
2409 }
2410 }
2411}
2412
2413/// We will first see if there is an application specific ".lldbinit" file
2414/// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2415/// If this file doesn't exist, we fall back to the REPL init file or the
2416/// default home init file in "~/.lldbinit".
2418 bool is_repl) {
2421 return;
2422 }
2423
2424 llvm::SmallString<128> init_file;
2425
2426 if (is_repl)
2427 GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2428
2429 if (init_file.empty())
2430 GetHomeInitFile(init_file);
2431
2432 if (!m_skip_app_init_files) {
2433 llvm::StringRef program_name =
2434 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2435 llvm::SmallString<128> program_init_file;
2436 GetHomeInitFile(program_init_file, program_name);
2437 if (FileSystem::Instance().Exists(program_init_file))
2438 init_file = program_init_file;
2439 }
2440
2441 SourceInitFile(FileSpec(init_file.str()), result);
2442}
2443
2445#ifdef LLDB_GLOBAL_INIT_DIRECTORY
2446 if (!m_skip_lldbinit_files) {
2447 FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2448 if (init_file)
2449 init_file.MakeAbsolute(HostInfo::GetShlibDir());
2450
2451 init_file.AppendPathComponent("lldbinit");
2452 SourceInitFile(init_file, result);
2453 return;
2454 }
2455#endif
2457}
2458
2460 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2461 return prefix == nullptr ? "" : prefix;
2462}
2463
2464PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2465 PlatformSP platform_sp;
2466 if (prefer_target_platform) {
2468 Target *target = exe_ctx.GetTargetPtr();
2469 if (target)
2470 platform_sp = target->GetPlatform();
2471 }
2472
2473 if (!platform_sp)
2475 return platform_sp;
2476}
2477
2479 auto exe_ctx = GetExecutionContext();
2480 TargetSP target_sp = exe_ctx.GetTargetSP();
2481 if (!target_sp)
2482 return false;
2483
2484 ProcessSP process_sp(target_sp->GetProcessSP());
2485 if (!process_sp)
2486 return false;
2487
2488 if (eStateStopped != process_sp->GetState())
2489 return false;
2490
2491 for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2492 StopInfoSP stop_info = thread_sp->GetStopInfo();
2493 if (!stop_info) {
2494 // If there's no stop_info, keep iterating through the other threads;
2495 // it's enough that any thread has got a stop_info that indicates
2496 // an abnormal stop, to consider the process to be stopped abnormally.
2497 continue;
2498 }
2499
2500 const StopReason reason = stop_info->GetStopReason();
2501 if (reason == eStopReasonException ||
2502 reason == eStopReasonInstrumentation ||
2503 reason == eStopReasonProcessorTrace)
2504 return true;
2505
2506 if (reason == eStopReasonSignal) {
2507 const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2508 UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2509 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2510 // The signal is unknown, treat it as abnormal.
2511 return true;
2512
2513 const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2514 const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2515 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2516 // The signal very likely implies a crash.
2517 return true;
2518 }
2519 }
2520
2521 return false;
2522}
2523
2524void
2526 const ExecutionContext &override_context,
2527 const CommandInterpreterRunOptions &options,
2528 CommandReturnObject &result) {
2529
2530 OverrideExecutionContext(override_context);
2531 HandleCommands(commands, options, result);
2533}
2534
2536 const CommandInterpreterRunOptions &options,
2537 CommandReturnObject &result) {
2538 size_t num_lines = commands.GetSize();
2539
2540 // If we are going to continue past a "continue" then we need to run the
2541 // commands synchronously. Make sure you reset this value anywhere you return
2542 // from the function.
2543
2544 bool old_async_execution = m_debugger.GetAsyncExecution();
2545
2546 if (!options.GetStopOnContinue()) {
2548 }
2549
2550 for (size_t idx = 0; idx < num_lines; idx++) {
2551 const char *cmd = commands.GetStringAtIndex(idx);
2552 if (cmd[0] == '\0')
2553 continue;
2554
2555 if (options.GetEchoCommands()) {
2556 // TODO: Add Stream support.
2557 result.AppendMessageWithFormat("%s %s\n",
2558 m_debugger.GetPrompt().str().c_str(), cmd);
2559 }
2560
2562 tmp_result.SetInteractive(result.GetInteractive());
2563 tmp_result.SetSuppressImmediateOutput(true);
2564
2565 // We might call into a regex or alias command, in which case the
2566 // add_to_history will get lost. This m_command_source_depth dingus is the
2567 // way we turn off adding to the history in that case, so set it up here.
2568 if (!options.GetAddToHistory())
2570 bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2571 if (!options.GetAddToHistory())
2573
2574 if (options.GetPrintResults()) {
2575 if (tmp_result.Succeeded())
2576 result.AppendMessage(tmp_result.GetOutputData());
2577 }
2578
2579 if (!success || !tmp_result.Succeeded()) {
2580 llvm::StringRef error_msg = tmp_result.GetErrorData();
2581 if (error_msg.empty())
2582 error_msg = "<unknown error>.\n";
2583 if (options.GetStopOnError()) {
2584 result.AppendErrorWithFormat(
2585 "Aborting reading of commands after command #%" PRIu64
2586 ": '%s' failed with %s",
2587 (uint64_t)idx, cmd, error_msg.str().c_str());
2588 m_debugger.SetAsyncExecution(old_async_execution);
2589 return;
2590 } else if (options.GetPrintResults()) {
2592 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2593 error_msg.str().c_str());
2594 }
2595 }
2596
2597 if (result.GetImmediateOutputStream())
2598 result.GetImmediateOutputStream()->Flush();
2599
2600 if (result.GetImmediateErrorStream())
2601 result.GetImmediateErrorStream()->Flush();
2602
2603 // N.B. Can't depend on DidChangeProcessState, because the state coming
2604 // into the command execution could be running (for instance in Breakpoint
2605 // Commands. So we check the return value to see if it is has running in
2606 // it.
2607 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2609 if (options.GetStopOnContinue()) {
2610 // If we caused the target to proceed, and we're going to stop in that
2611 // case, set the status in our real result before returning. This is
2612 // an error if the continue was not the last command in the set of
2613 // commands to be run.
2614 if (idx != num_lines - 1)
2615 result.AppendErrorWithFormat(
2616 "Aborting reading of commands after command #%" PRIu64
2617 ": '%s' continued the target.\n",
2618 (uint64_t)idx + 1, cmd);
2619 else
2620 result.AppendMessageWithFormat("Command #%" PRIu64
2621 " '%s' continued the target.\n",
2622 (uint64_t)idx + 1, cmd);
2623
2624 result.SetStatus(tmp_result.GetStatus());
2625 m_debugger.SetAsyncExecution(old_async_execution);
2626
2627 return;
2628 }
2629 }
2630
2631 // Also check for "stop on crash here:
2632 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2634 if (idx != num_lines - 1)
2635 result.AppendErrorWithFormat(
2636 "Aborting reading of commands after command #%" PRIu64
2637 ": '%s' stopped with a signal or exception.\n",
2638 (uint64_t)idx + 1, cmd);
2639 else
2641 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\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
2652 m_debugger.SetAsyncExecution(old_async_execution);
2653}
2654
2655// Make flags that we can pass into the IOHandler so our delegates can do the
2656// right thing
2657enum {
2666
2668 FileSpec &cmd_file, const ExecutionContext &context,
2669 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2670 OverrideExecutionContext(context);
2671 HandleCommandsFromFile(cmd_file, options, result);
2673}
2674
2676 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2677 if (!FileSystem::Instance().Exists(cmd_file)) {
2678 result.AppendErrorWithFormat(
2679 "Error reading commands from file %s - file not found.\n",
2680 cmd_file.GetFilename().AsCString("<Unknown>"));
2681 return;
2682 }
2683
2684 std::string cmd_file_path = cmd_file.GetPath();
2685 auto input_file_up =
2687 if (!input_file_up) {
2688 std::string error = llvm::toString(input_file_up.takeError());
2690 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2691 llvm::fmt_consume(input_file_up.takeError()));
2692 return;
2693 }
2694 FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2695
2696 Debugger &debugger = GetDebugger();
2697
2698 uint32_t flags = 0;
2699
2700 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2701 if (m_command_source_flags.empty()) {
2702 // Stop on continue by default
2704 } else if (m_command_source_flags.back() &
2707 }
2708 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2710 }
2711
2712 if (options.m_stop_on_error == eLazyBoolCalculate) {
2713 if (m_command_source_flags.empty()) {
2718 }
2719 } else if (options.m_stop_on_error == eLazyBoolYes) {
2721 }
2722
2723 // stop-on-crash can only be set, if it is present in all levels of
2724 // pushed flag sets.
2725 if (options.GetStopOnCrash()) {
2726 if (m_command_source_flags.empty()) {
2730 }
2731 }
2732
2733 if (options.m_echo_commands == eLazyBoolCalculate) {
2734 if (m_command_source_flags.empty()) {
2735 // Echo command by default
2739 }
2740 } else if (options.m_echo_commands == eLazyBoolYes) {
2742 }
2743
2744 // We will only ever ask for this flag, if we echo commands in general.
2746 if (m_command_source_flags.empty()) {
2747 // Echo comments by default
2749 } else if (m_command_source_flags.back() &
2752 }
2753 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2755 }
2756
2757 if (options.m_print_results == eLazyBoolCalculate) {
2758 if (m_command_source_flags.empty()) {
2759 // Print output by default
2763 }
2764 } else if (options.m_print_results == eLazyBoolYes) {
2766 }
2767
2768 if (options.m_print_errors == eLazyBoolCalculate) {
2769 if (m_command_source_flags.empty()) {
2770 // Print output by default
2774 }
2775 } else if (options.m_print_errors == eLazyBoolYes) {
2777 }
2778
2779 if (flags & eHandleCommandFlagPrintResult) {
2780 debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2781 cmd_file_path.c_str());
2782 }
2783
2784 // Used for inheriting the right settings when "command source" might
2785 // have nested "command source" commands
2786 lldb::StreamFileSP empty_stream_sp;
2787 m_command_source_flags.push_back(flags);
2788 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2789 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2790 empty_stream_sp, // Pass in an empty stream so we inherit the top
2791 // input reader output stream
2792 empty_stream_sp, // Pass in an empty stream so we inherit the top
2793 // input reader error stream
2794 flags,
2795 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2796 // or written
2797 debugger.GetPrompt(), llvm::StringRef(),
2798 false, // Not multi-line
2799 debugger.GetUseColor(), 0, *this));
2800 const bool old_async_execution = debugger.GetAsyncExecution();
2801
2802 // Set synchronous execution if we are not stopping on continue
2803 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2804 debugger.SetAsyncExecution(false);
2805
2808
2809 debugger.RunIOHandlerSync(io_handler_sp);
2810 if (!m_command_source_flags.empty())
2811 m_command_source_flags.pop_back();
2812
2813 m_command_source_dirs.pop_back();
2815
2817 debugger.SetAsyncExecution(old_async_execution);
2818}
2819
2821
2824}
2825
2827 llvm::StringRef prefix,
2828 llvm::StringRef help_text) {
2829 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2830
2831 size_t line_width_max = max_columns - prefix.size();
2832 if (line_width_max < 16)
2833 line_width_max = help_text.size() + prefix.size();
2834
2835 strm.IndentMore(prefix.size());
2836 bool prefixed_yet = false;
2837 // Even if we have no help text we still want to emit the command name.
2838 if (help_text.empty())
2839 help_text = "No help text";
2840 while (!help_text.empty()) {
2841 // Prefix the first line, indent subsequent lines to line up
2842 if (!prefixed_yet) {
2843 strm << prefix;
2844 prefixed_yet = true;
2845 } else
2846 strm.Indent();
2847
2848 // Never print more than the maximum on one line.
2849 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2850
2851 // Always break on an explicit newline.
2852 std::size_t first_newline = this_line.find_first_of("\n");
2853
2854 // Don't break on space/tab unless the text is too long to fit on one line.
2855 std::size_t last_space = llvm::StringRef::npos;
2856 if (this_line.size() != help_text.size())
2857 last_space = this_line.find_last_of(" \t");
2858
2859 // Break at whichever condition triggered first.
2860 this_line = this_line.substr(0, std::min(first_newline, last_space));
2861 strm.PutCString(this_line);
2862 strm.EOL();
2863
2864 // Remove whitespace / newlines after breaking.
2865 help_text = help_text.drop_front(this_line.size()).ltrim();
2866 }
2867 strm.IndentLess(prefix.size());
2868}
2869
2871 llvm::StringRef word_text,
2872 llvm::StringRef separator,
2873 llvm::StringRef help_text,
2874 size_t max_word_len) {
2875 StreamString prefix_stream;
2876 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2877 (int)separator.size(), separator.data());
2878 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2879}
2880
2881void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2882 llvm::StringRef separator,
2883 llvm::StringRef help_text,
2884 uint32_t max_word_len) {
2885 int indent_size = max_word_len + separator.size() + 2;
2886
2887 strm.IndentMore(indent_size);
2888
2889 StreamString text_strm;
2890 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2891 text_strm << separator << " " << help_text;
2892
2893 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2894
2895 llvm::StringRef text = text_strm.GetString();
2896
2897 uint32_t chars_left = max_columns;
2898
2899 auto nextWordLength = [](llvm::StringRef S) {
2900 size_t pos = S.find(' ');
2901 return pos == llvm::StringRef::npos ? S.size() : pos;
2902 };
2903
2904 while (!text.empty()) {
2905 if (text.front() == '\n' ||
2906 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2907 strm.EOL();
2908 strm.Indent();
2909 chars_left = max_columns - indent_size;
2910 if (text.front() == '\n')
2911 text = text.drop_front();
2912 else
2913 text = text.ltrim(' ');
2914 } else {
2915 strm.PutChar(text.front());
2916 --chars_left;
2917 text = text.drop_front();
2918 }
2919 }
2920
2921 strm.EOL();
2922 strm.IndentLess(indent_size);
2923}
2924
2926 llvm::StringRef search_word, StringList &commands_found,
2927 StringList &commands_help, const CommandObject::CommandMap &command_map) {
2928 for (const auto &pair : command_map) {
2929 llvm::StringRef command_name = pair.first;
2930 CommandObject *cmd_obj = pair.second.get();
2931
2932 const bool search_short_help = true;
2933 const bool search_long_help = false;
2934 const bool search_syntax = false;
2935 const bool search_options = false;
2936 if (command_name.contains_insensitive(search_word) ||
2937 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2938 search_long_help, search_syntax,
2939 search_options)) {
2940 commands_found.AppendString(command_name);
2941 commands_help.AppendString(cmd_obj->GetHelp());
2942 }
2943
2944 if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
2945 StringList subcommands_found;
2946 FindCommandsForApropos(search_word, subcommands_found, commands_help,
2947 multiword_cmd->GetSubcommandDictionary());
2948 for (const auto &subcommand_name : subcommands_found) {
2949 std::string qualified_name =
2950 (command_name + " " + subcommand_name).str();
2951 commands_found.AppendString(qualified_name);
2952 }
2953 }
2954 }
2955}
2956
2957void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
2958 StringList &commands_found,
2959 StringList &commands_help,
2960 bool search_builtin_commands,
2961 bool search_user_commands,
2962 bool search_alias_commands,
2963 bool search_user_mw_commands) {
2964 CommandObject::CommandMap::const_iterator pos;
2965
2966 if (search_builtin_commands)
2967 FindCommandsForApropos(search_word, commands_found, commands_help,
2969
2970 if (search_user_commands)
2971 FindCommandsForApropos(search_word, commands_found, commands_help,
2972 m_user_dict);
2973
2974 if (search_user_mw_commands)
2975 FindCommandsForApropos(search_word, commands_found, commands_help,
2977
2978 if (search_alias_commands)
2979 FindCommandsForApropos(search_word, commands_found, commands_help,
2980 m_alias_dict);
2981}
2982
2984 return !m_overriden_exe_contexts.empty()
2987}
2988
2990 const ExecutionContext &override_context) {
2991 m_overriden_exe_contexts.push(override_context);
2992}
2993
2995 if (!m_overriden_exe_contexts.empty())
2997}
2998
3000 if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
3001 m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
3002 /*flush_stderr*/ true);
3003}
3004
3006 auto idle_state = CommandHandlingState::eIdle;
3007 if (m_command_state.compare_exchange_strong(
3010 else
3013}
3014
3017 if (--m_iohandler_nesting_level == 0) {
3018 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3020 }
3021}
3022
3024 auto in_progress = CommandHandlingState::eInProgress;
3025 return m_command_state.compare_exchange_strong(
3027}
3028
3031 return false;
3032
3033 bool was_interrupted =
3035 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3036 return was_interrupted;
3037}
3038
3040 llvm::StringRef str,
3041 bool is_stdout) {
3042
3043 lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3044 : io_handler.GetErrorStreamFileSP();
3045 // Split the output into lines and poll for interrupt requests
3046 bool had_output = !str.empty();
3047 while (!str.empty()) {
3048 llvm::StringRef line;
3049 std::tie(line, str) = str.split('\n');
3050 {
3051 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3052 stream->Write(line.data(), line.size());
3053 stream->Write("\n", 1);
3054 }
3055 }
3056
3057 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3058 if (had_output &&
3059 INTERRUPT_REQUESTED(GetDebugger(), "Interrupted dumping command output"))
3060 stream->Printf("\n... Interrupted.\n");
3061 stream->Flush();
3062}
3063
3065 llvm::StringRef line, const Flags &io_handler_flags) const {
3066 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3067 return false;
3068
3069 llvm::StringRef command = line.trim();
3070 if (command.empty())
3071 return true;
3072
3073 if (command.front() == m_comment_char)
3074 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3075
3076 return true;
3077}
3078
3080 std::string &line) {
3081 // If we were interrupted, bail out...
3082 if (WasInterrupted())
3083 return;
3084
3085 const bool is_interactive = io_handler.GetIsInteractive();
3086 if (!is_interactive) {
3087 // When we are not interactive, don't execute blank lines. This will happen
3088 // sourcing a commands file. We don't want blank lines to repeat the
3089 // previous command and cause any errors to occur (like redefining an
3090 // alias, get an error and stop parsing the commands file).
3091 if (line.empty())
3092 return;
3093
3094 // When using a non-interactive file handle (like when sourcing commands
3095 // from a file) we need to echo the command out so we don't just see the
3096 // command output and no command...
3097 if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3098 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3099 io_handler.GetOutputStreamFileSP()->Printf(
3100 "%s%s\n", io_handler.GetPrompt(), line.c_str());
3101 }
3102 }
3103
3105
3107 bool pushed_exe_ctx = false;
3108 if (exe_ctx.HasTargetScope()) {
3109 OverrideExecutionContext(exe_ctx);
3110 pushed_exe_ctx = true;
3111 }
3112 auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3113 if (pushed_exe_ctx)
3115 });
3116
3118 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3119
3120 // Now emit the command output text from the command we just executed
3121 if ((result.Succeeded() &&
3124 // Display any STDOUT/STDERR _prior_ to emitting the command result text
3126
3127 if (!result.GetImmediateOutputStream()) {
3128 llvm::StringRef output = result.GetOutputData();
3129 PrintCommandOutput(io_handler, output, true);
3130 }
3131
3132 // Now emit the command error text from the command we just executed
3133 if (!result.GetImmediateErrorStream()) {
3134 llvm::StringRef error = result.GetErrorData();
3135 PrintCommandOutput(io_handler, error, false);
3136 }
3137 }
3138
3140
3141 switch (result.GetStatus()) {
3146 break;
3147
3151 io_handler.SetIsDone(true);
3152 break;
3153
3156 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3158 io_handler.SetIsDone(true);
3159 }
3160 break;
3161
3162 case eReturnStatusQuit:
3164 io_handler.SetIsDone(true);
3165 break;
3166 }
3167
3168 // Finally, if we're going to stop on crash, check that here:
3170 result.GetDidChangeProcessState() &&
3173 io_handler.SetIsDone(true);
3175 }
3176}
3177
3180 Process *process = exe_ctx.GetProcessPtr();
3181
3182 if (InterruptCommand())
3183 return true;
3184
3185 if (process) {
3186 StateType state = process->GetState();
3187 if (StateIsRunningState(state)) {
3188 process->Halt();
3189 return true; // Don't do any updating when we are running
3190 }
3191 }
3192
3193 ScriptInterpreter *script_interpreter =
3195 if (script_interpreter) {
3196 if (script_interpreter->Interrupt())
3197 return true;
3198 }
3199 return false;
3200}
3201
3203 CommandReturnObject &result, std::optional<std::string> output_file) {
3204 if (output_file == std::nullopt || output_file->empty()) {
3205 std::string now = llvm::to_string(std::chrono::system_clock::now());
3206 std::replace(now.begin(), now.end(), ' ', '_');
3207 const std::string file_name = "lldb_session_" + now + ".log";
3208
3209 FileSpec save_location = GetSaveSessionDirectory();
3210
3211 if (!save_location)
3212 save_location = HostInfo::GetGlobalTempDir();
3213
3214 FileSystem::Instance().Resolve(save_location);
3215 save_location.AppendPathComponent(file_name);
3216 output_file = save_location.GetPath();
3217 }
3218
3219 auto error_out = [&](llvm::StringRef error_message, std::string description) {
3220 LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3221 output_file, description);
3223 "Failed to save session's transcripts to {0}!", *output_file);
3224 return false;
3225 };
3226
3230
3231 auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3232
3233 if (!opened_file)
3234 return error_out("Unable to create file",
3235 llvm::toString(opened_file.takeError()));
3236
3237 FileUP file = std::move(opened_file.get());
3238
3239 size_t byte_size = m_transcript_stream.GetSize();
3240
3241 Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3242
3243 if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3244 return error_out("Unable to write to destination file",
3245 "Bytes written do not match transcript size.");
3246
3248 result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3249 output_file->c_str());
3250
3252 const FileSpec file_spec;
3253 error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3254 if (error.Success()) {
3255 if (llvm::Error e = Host::OpenFileInExternalEditor(
3256 m_debugger.GetExternalEditor(), file_spec, 1))
3257 result.AppendError(llvm::toString(std::move(e)));
3258 }
3259 }
3260
3261 return true;
3262}
3263
3265 return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3266}
3267
3269 if (m_command_source_dirs.empty())
3270 return {};
3271 return m_command_source_dirs.back();
3272}
3273
3275 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3276 Debugger &debugger = GetDebugger();
3277 IOHandlerSP io_handler_sp(
3279 "lldb", // Name of input reader for history
3280 llvm::StringRef(prompt), // Prompt
3281 llvm::StringRef(), // Continuation prompt
3282 true, // Get multiple lines
3283 debugger.GetUseColor(),
3284 0, // Don't show line numbers
3285 delegate)); // IOHandlerDelegate
3286
3287 if (io_handler_sp) {
3288 io_handler_sp->SetUserData(baton);
3289 debugger.RunIOHandlerAsync(io_handler_sp);
3290 }
3291}
3292
3294 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3295 Debugger &debugger = GetDebugger();
3296 IOHandlerSP io_handler_sp(
3298 "lldb-python", // 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
3314}
3315
3319 // Always re-create the IOHandlerEditline in case the input changed. The old
3320 // instance might have had a non-interactive input and now it does or vice
3321 // versa.
3322 if (force_create || !m_command_io_handler_sp) {
3323 // Always re-create the IOHandlerEditline in case the input changed. The
3324 // old instance might have had a non-interactive input and now it does or
3325 // vice versa.
3326 uint32_t flags = 0;
3327
3328 if (options) {
3329 if (options->m_stop_on_continue == eLazyBoolYes)
3331 if (options->m_stop_on_error == eLazyBoolYes)
3333 if (options->m_stop_on_crash == eLazyBoolYes)
3335 if (options->m_echo_commands != eLazyBoolNo)
3337 if (options->m_echo_comment_commands != eLazyBoolNo)
3339 if (options->m_print_results != eLazyBoolNo)
3341 if (options->m_print_errors != eLazyBoolNo)
3343 } else {
3346 }
3347
3348 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3351 m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3352 llvm::StringRef(), // Continuation prompt
3353 false, // Don't enable multiple line input, just single line commands
3355 0, // Don't show line numbers
3356 *this); // IOHandlerDelegate
3357 }
3359}
3360
3363 // Always re-create the command interpreter when we run it in case any file
3364 // handles have changed.
3365 bool force_create = true;
3366 m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3368
3369 if (options.GetAutoHandleEvents())
3371
3372 if (options.GetSpawnThread()) {
3374 } else {
3375 // If the current thread is not managed by a host thread, we won't detect
3376 // that this IS the CommandInterpreter IOHandler thread, so make it so:
3377 HostThread new_io_handler_thread(Host::GetCurrentThread());
3378 HostThread old_io_handler_thread =
3379 m_debugger.SetIOHandlerThread(new_io_handler_thread);
3381 m_debugger.SetIOHandlerThread(old_io_handler_thread);
3382
3383 if (options.GetAutoHandleEvents())
3385 }
3386
3387 return m_result;
3388}
3389
3392 CommandReturnObject &result) {
3393 std::string scratch_command(command_line); // working copy so we don't modify
3394 // command_line unless we succeed
3395 CommandObject *cmd_obj = nullptr;
3396 StreamString revised_command_line;
3397 bool wants_raw_input = false;
3398 std::string next_word;
3399 StringList matches;
3400 bool done = false;
3401 while (!done) {
3402 char quote_char = '\0';
3403 std::string suffix;
3404 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3405 if (cmd_obj == nullptr) {
3406 std::string full_name;
3407 bool is_alias = GetAliasFullName(next_word, full_name);
3408 cmd_obj = GetCommandObject(next_word, &matches);
3409 bool is_real_command =
3410 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3411 if (!is_real_command) {
3412 matches.Clear();
3413 std::string alias_result;
3414 cmd_obj =
3415 BuildAliasResult(full_name, scratch_command, alias_result, result);
3416 revised_command_line.Printf("%s", alias_result.c_str());
3417 if (cmd_obj) {
3418 wants_raw_input = cmd_obj->WantsRawCommandString();
3419 }
3420 } else {
3421 if (cmd_obj) {
3422 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3423 revised_command_line.Printf("%s", cmd_name.str().c_str());
3424 wants_raw_input = cmd_obj->WantsRawCommandString();
3425 } else {
3426 revised_command_line.Printf("%s", next_word.c_str());
3427 }
3428 }
3429 } else {
3430 if (cmd_obj->IsMultiwordObject()) {
3431 CommandObject *sub_cmd_obj =
3432 cmd_obj->GetSubcommandObject(next_word.c_str());
3433 if (sub_cmd_obj) {
3434 // The subcommand's name includes the parent command's name, so
3435 // restart rather than append to the revised_command_line.
3436 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3437 revised_command_line.Clear();
3438 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3439 cmd_obj = sub_cmd_obj;
3440 wants_raw_input = cmd_obj->WantsRawCommandString();
3441 } else {
3442 if (quote_char)
3443 revised_command_line.Printf(" %c%s%s%c", quote_char,
3444 next_word.c_str(), suffix.c_str(),
3445 quote_char);
3446 else
3447 revised_command_line.Printf(" %s%s", next_word.c_str(),
3448 suffix.c_str());
3449 done = true;
3450 }
3451 } else {
3452 if (quote_char)
3453 revised_command_line.Printf(" %c%s%s%c", quote_char,
3454 next_word.c_str(), suffix.c_str(),
3455 quote_char);
3456 else
3457 revised_command_line.Printf(" %s%s", next_word.c_str(),
3458 suffix.c_str());
3459 done = true;
3460 }
3461 }
3462
3463 if (cmd_obj == nullptr) {
3464 const size_t num_matches = matches.GetSize();
3465 if (matches.GetSize() > 1) {
3466 StreamString error_msg;
3467 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3468 next_word.c_str());
3469
3470 for (uint32_t i = 0; i < num_matches; ++i) {
3471 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3472 }
3473 result.AppendRawError(error_msg.GetString());
3474 } else {
3475 // We didn't have only one match, otherwise we wouldn't get here.
3476 lldbassert(num_matches == 0);
3477 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3478 next_word.c_str());
3479 }
3480 return nullptr;
3481 }
3482
3483 if (cmd_obj->IsMultiwordObject()) {
3484 if (!suffix.empty()) {
3485 result.AppendErrorWithFormat(
3486 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3487 "might be invalid).\n",
3488 cmd_obj->GetCommandName().str().c_str(),
3489 next_word.empty() ? "" : next_word.c_str(),
3490 next_word.empty() ? " -- " : " ", suffix.c_str());
3491 return nullptr;
3492 }
3493 } else {
3494 // If we found a normal command, we are done
3495 done = true;
3496 if (!suffix.empty()) {
3497 switch (suffix[0]) {
3498 case '/':
3499 // GDB format suffixes
3500 {
3501 Options *command_options = cmd_obj->GetOptions();
3502 if (command_options &&
3503 command_options->SupportsLongOption("gdb-format")) {
3504 std::string gdb_format_option("--gdb-format=");
3505 gdb_format_option += (suffix.c_str() + 1);
3506
3507 std::string cmd = std::string(revised_command_line.GetString());
3508 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3509 if (arg_terminator_idx != std::string::npos) {
3510 // Insert the gdb format option before the "--" that terminates
3511 // options
3512 gdb_format_option.append(1, ' ');
3513 cmd.insert(arg_terminator_idx, gdb_format_option);
3514 revised_command_line.Clear();
3515 revised_command_line.PutCString(cmd);
3516 } else
3517 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3518
3519 if (wants_raw_input &&
3520 FindArgumentTerminator(cmd) == std::string::npos)
3521 revised_command_line.PutCString(" --");
3522 } else {
3523 result.AppendErrorWithFormat(
3524 "the '%s' command doesn't support the --gdb-format option\n",
3525 cmd_obj->GetCommandName().str().c_str());
3526 return nullptr;
3527 }
3528 }
3529 break;
3530
3531 default:
3532 result.AppendErrorWithFormat(
3533 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3534 return nullptr;
3535 }
3536 }
3537 }
3538 if (scratch_command.empty())
3539 done = true;
3540 }
3541
3542 if (!scratch_command.empty())
3543 revised_command_line.Printf(" %s", scratch_command.c_str());
3544
3545 if (cmd_obj != nullptr)
3546 command_line = std::string(revised_command_line.GetString());
3547
3548 return cmd_obj;
3549}
3550
3552 llvm::json::Object stats;
3553 for (const auto &command_usage : m_command_usages)
3554 stats.try_emplace(command_usage.getKey(), command_usage.getValue());
3555 return stats;
3556}
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
@ eHandleCommandFlagStopOnCrash
@ eHandleCommandFlagEchoCommentCommand
@ eHandleCommandFlagStopOnError
@ eHandleCommandFlagStopOnContinue
@ eHandleCommandFlagPrintErrors
@ eHandleCommandFlagEchoCommand
@ eHandleCommandFlagPrintResult
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)
static llvm::raw_ostream & error(Stream &strm)
#define INTERRUPT_REQUESTED(debugger,...)
This handy define will keep you from having to generate a report for the interruption by hand.
Definition: Debugger.h:454
#define lldbassert(x)
Definition: LLDBAssert.h:15
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition: Log.h:342
#define LLDB_LOGF(log,...)
Definition: Log.h:349
#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:242
void BroadcastEvent(lldb::EventSP &event_sp)
Broadcast an event which has no associated data.
Definition: Broadcaster.h:167
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.
static llvm::StringRef GetStaticBroadcasterClass()
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.
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 void Execute(const char *args_string, CommandReturnObject &result)=0
virtual std::optional< std::string > GetRepeatCommand(Args &current_command_args, uint32_t index)
Get the command that appropriate for a "repeat" of the current command.
virtual CommandObject * GetSubcommandObject(llvm::StringRef sub_cmd, StringList *matches=nullptr)
virtual CommandObjectMultiword * GetAsMultiwordCommand()
virtual Options * GetOptions()
void SetSyntax(llvm::StringRef str)
virtual void HandleCompletion(CompletionRequest &request)
This default version handles calling option argument completions and then calls HandleArgumentComplet...
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.
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:188
A class to manage flag bits.
Definition: Debugger.h:79
ExecutionContext GetSelectedExecutionContext()
Definition: Debugger.cpp:1055
bool StartEventHandlerThread()
Manually start the global event handler thread.
Definition: Debugger.cpp:1952
void StopEventHandlerThread()
Manually stop the debugger's default event handler.
Definition: Debugger.cpp:1992
void SetAsyncExecution(bool async)
Definition: Debugger.cpp:971
HostThread SetIOHandlerThread(HostThread &new_thread)
Definition: Debugger.cpp:2104
lldb::FileSP GetInputFileSP()
Definition: Debugger.h:142
bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp)
Definition: Debugger.cpp:1142
bool IsIOHandlerThreadCurrentThread() const
Definition: Debugger.cpp:2140
uint64_t GetTerminalWidth() const
Definition: Debugger.cpp:367
const char * GetIOHandlerCommandPrefix()
Definition: Debugger.cpp:1164
bool GetUseColor() const
Definition: Debugger.cpp:403
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, bool cancel_top_handler=true)
Run the given IO handler and return immediately.
Definition: Debugger.cpp:1176
lldb::StreamFileSP GetErrorStreamSP()
Definition: Debugger.h:146
bool GetAutoConfirm() const
Definition: Debugger.cpp:273
PlatformList & GetPlatformList()
Definition: Debugger.h:208
Target & GetDummyTarget()
Definition: Debugger.h:496
void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp)
Run the given IO handler and block until it's complete.
Definition: Debugger.cpp:1111
lldb::StreamFileSP GetOutputStreamSP()
Definition: Debugger.h:144
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
Definition: Debugger.cpp:1649
llvm::StringRef GetExternalEditor() const
Definition: Debugger.cpp:392
File & GetOutputFile()
Definition: Debugger.h:150
llvm::StringRef GetPrompt() const
Definition: Debugger.cpp:306
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:1719
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:334
void SetKeepInMemory(bool keep=true)
Definition: Target.h:344
void SetCoerceToId(bool coerce=true)
Definition: Target.h:330
void SetTryAllThreads(bool try_others=true)
Definition: Target.h:367
void SetTimeout(const Timeout< std::micro > &timeout)
Definition: Target.h:355
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:338
"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:447
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:530
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:367
FileSpec CopyByRemovingLastPathComponent() const
Definition: FileSpec.cpp:424
void Resolve(llvm::SmallVectorImpl< char > &path)
Resolve path to make it canonical.
bool GetHomeDirectory(llvm::SmallVectorImpl< char > &path) const
Get the user home directory.
int Open(const char *path, int flags, int mode=0600)
Wraps ::open in a platform-independent way.
static FileSystem & Instance()
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: File.cpp:211
@ 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:190
lldb::StreamFileSP GetErrorStreamFileSP()
Definition: IOHandler.cpp:107
virtual const char * GetPrompt()
Definition: IOHandler.h:98
std::recursive_mutex & GetOutputMutex()
Definition: IOHandler.h:164
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:86
static LanguageSet GetLanguagesSupportingREPLs()
Definition: Language.cpp:431
static const char * GetNameForLanguageType(lldb::LanguageType language)
Definition: Language.cpp:265
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:1060
A plug-in interface definition class for debugging a process.
Definition: Process.h:341
lldb::StateType GetState()
Get accessor for the current process state.
Definition: Process.cpp:1301
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
Definition: Process.cpp:3149
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:156
An error handling class.
Definition: Status.h:44
void SetErrorStringWithFormatv(const char *format, Args &&... args)
Definition: Status.h:169
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:247
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:233
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:157
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:65
size_t PutChar(char ch)
Definition: Stream.cpp:131
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:155
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:198
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:195
void 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:4723
static TargetProperties & GetGlobalProperties()
Definition: Target.cpp:3055
lldb::PlatformSP GetPlatform()
Definition: Target.h:1433
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:2655
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:314
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
@ eSourceFileCompletion
std::shared_ptr< lldb_private::OptionValueProperties > OptionValuePropertiesSP
Definition: lldb-forward.h:379
std::shared_ptr< lldb_private::IOHandler > IOHandlerSP
Definition: lldb-forward.h:353
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:325
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:472
std::unique_ptr< lldb_private::File > FileUP
Definition: lldb-forward.h:344
@ eCommandInterpreterResultInferiorCrash
Stopped because the corresponding option was set and the inferior crashed.
@ eCommandInterpreterResultSuccess
Command interpreter finished successfully.
@ eCommandInterpreterResultCommandError
Stopped because the corresponding option was set and a command returned an error.
@ eCommandInterpreterResultQuitRequested
Stopped because quit was requested.
std::shared_ptr< lldb_private::UnixSignals > UnixSignalsSP
Definition: lldb-forward.h:468
std::shared_ptr< lldb_private::Platform > PlatformSP
Definition: lldb-forward.h:380
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
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:381
std::shared_ptr< lldb_private::Event > EventSP
Definition: lldb-forward.h:337
@ eReturnStatusStarted
@ eReturnStatusSuccessContinuingResult
@ eReturnStatusFailed
@ eReturnStatusSuccessContinuingNoResult
@ eReturnStatusQuit
@ eReturnStatusSuccessFinishResult
@ eReturnStatusInvalid
@ eReturnStatusSuccessFinishNoResult
std::shared_ptr< lldb_private::StreamFile > StreamFileSP
Definition: lldb-forward.h:421
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:419
StopReason
Thread stop reasons.
@ eStopReasonInstrumentation
@ eStopReasonProcessorTrace
@ eStopReasonException
@ eStopReasonSignal
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:436
std::shared_ptr< lldb_private::File > FileSP
Definition: lldb-forward.h:345
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: Type.h:36
std::optional< lldb::LanguageType > GetSingularLanguage()
If the set contains a single language only, return it.
Definition: TypeSystem.cpp:28