LLDB mainline
CommandInterpreter.cpp
Go to the documentation of this file.
1//===-- CommandInterpreter.cpp --------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include <cstdlib>
10#include <limits>
11#include <memory>
12#include <optional>
13#include <string>
14#include <vector>
15
46
47#include "lldb/Core/Debugger.h"
51#include "lldb/Utility/Log.h"
52#include "lldb/Utility/State.h"
53#include "lldb/Utility/Stream.h"
54#include "lldb/Utility/Timer.h"
55
56#include "lldb/Host/Config.h"
57#if LLDB_ENABLE_LIBEDIT
58#include "lldb/Host/Editline.h"
59#endif
60#include "lldb/Host/File.h"
61#include "lldb/Host/FileCache.h"
62#include "lldb/Host/Host.h"
63#include "lldb/Host/HostInfo.h"
64
71#include "lldb/Utility/Args.h"
72
74#include "lldb/Target/Process.h"
77#include "lldb/Target/Thread.h"
79
80#include "llvm/ADT/STLExtras.h"
81#include "llvm/ADT/ScopeExit.h"
82#include "llvm/ADT/SmallString.h"
83#include "llvm/Support/FormatAdapters.h"
84#include "llvm/Support/Path.h"
85#include "llvm/Support/PrettyStackTrace.h"
86#include "llvm/Support/ScopedPrinter.h"
87
88#if defined(__APPLE__)
89#include <TargetConditionals.h>
90#endif
91
92using namespace lldb;
93using namespace lldb_private;
94
95static const char *k_white_space = " \t\v";
96
97static constexpr const char *InitFileWarning =
98 "There is a .lldbinit file in the current directory which is not being "
99 "read.\n"
100 "To silence this warning without sourcing in the local .lldbinit,\n"
101 "add the following to the lldbinit file in your home directory:\n"
102 " settings set target.load-cwd-lldbinit false\n"
103 "To allow lldb to source .lldbinit files in the current working "
104 "directory,\n"
105 "set the value of this variable to true. Only do so if you understand "
106 "and\n"
107 "accept the security risk.";
108
109const char *CommandInterpreter::g_no_argument = "<no-argument>";
110const char *CommandInterpreter::g_need_argument = "<need-argument>";
111const char *CommandInterpreter::g_argument = "<argument>";
112
113
114#define LLDB_PROPERTIES_interpreter
115#include "InterpreterProperties.inc"
116
117enum {
118#define LLDB_PROPERTIES_interpreter
119#include "InterpreterPropertiesEnum.inc"
120};
121
123 static ConstString class_name("lldb.commandInterpreter");
124 return class_name;
125}
126
128 bool synchronous_execution)
129 : Broadcaster(debugger.GetBroadcasterManager(),
130 CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
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) {
1163 result.SetErrorString("user command exists and force replace not set");
1164 return result;
1165 }
1166 if (cmd_sp->IsMultiwordObject()) {
1167 if (!m_user_mw_dict[std::string(name)]->IsRemovable()) {
1168 result.SetErrorString(
1169 "can't replace explicitly non-removable multi-word command");
1170 return result;
1171 }
1172 } else {
1173 if (!m_user_dict[std::string(name)]->IsRemovable()) {
1174 result.SetErrorString("can't replace explicitly non-removable command");
1175 return result;
1176 }
1177 }
1178 }
1179
1180 cmd_sp->SetIsUserCommand(true);
1181
1182 if (cmd_sp->IsMultiwordObject())
1183 m_user_mw_dict[std::string(name)] = cmd_sp;
1184 else
1185 m_user_dict[std::string(name)] = cmd_sp;
1186 return result;
1187}
1188
1191 bool include_aliases) const {
1192 // Break up the command string into words, in case it's a multi-word command.
1193 Args cmd_words(cmd_str);
1194
1195 if (cmd_str.empty())
1196 return {};
1197
1198 if (cmd_words.GetArgumentCount() == 1)
1199 return GetCommandSP(cmd_str, include_aliases, true);
1200
1201 // We have a multi-word command (seemingly), so we need to do more work.
1202 // First, get the cmd_obj_sp for the first word in the command.
1203 CommandObjectSP cmd_obj_sp =
1204 GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true);
1205 if (!cmd_obj_sp)
1206 return {};
1207
1208 // Loop through the rest of the words in the command (everything passed in
1209 // was supposed to be part of a command name), and find the appropriate
1210 // sub-command SP for each command word....
1211 size_t end = cmd_words.GetArgumentCount();
1212 for (size_t i = 1; i < end; ++i) {
1213 if (!cmd_obj_sp->IsMultiwordObject()) {
1214 // We have more words in the command name, but we don't have a
1215 // multiword object. Fail and return.
1216 return {};
1217 }
1218
1219 cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i));
1220 if (!cmd_obj_sp) {
1221 // The sub-command name was invalid. Fail and return.
1222 return {};
1223 }
1224 }
1225
1226 // We successfully looped through all the command words and got valid
1227 // command objects for them.
1228 return cmd_obj_sp;
1229}
1230
1233 StringList *matches,
1234 StringList *descriptions) const {
1235 // Try to find a match among commands and aliases. Allowing inexact matches,
1236 // but perferring exact matches.
1237 return GetCommandSP(cmd_str, /*include_aliases=*/true, /*exact=*/false,
1238 matches, descriptions)
1239 .get();
1240}
1241
1243 llvm::StringRef cmd, StringList *matches, StringList *descriptions) const {
1244 std::string cmd_str(cmd);
1245 auto find_exact = [&](const CommandObject::CommandMap &map) {
1246 auto found_elem = map.find(std::string(cmd));
1247 if (found_elem == map.end())
1248 return (CommandObject *)nullptr;
1249 CommandObject *exact_cmd = found_elem->second.get();
1250 if (exact_cmd) {
1251 if (matches)
1252 matches->AppendString(exact_cmd->GetCommandName());
1253 if (descriptions)
1254 descriptions->AppendString(exact_cmd->GetHelp());
1255 return exact_cmd;
1256 }
1257 return (CommandObject *)nullptr;
1258 };
1259
1260 CommandObject *exact_cmd = find_exact(GetUserCommands());
1261 if (exact_cmd)
1262 return exact_cmd;
1263
1264 exact_cmd = find_exact(GetUserMultiwordCommands());
1265 if (exact_cmd)
1266 return exact_cmd;
1267
1268 // We didn't have an exact command, so now look for partial matches.
1269 StringList tmp_list;
1270 StringList *matches_ptr = matches ? matches : &tmp_list;
1271 AddNamesMatchingPartialString(GetUserCommands(), cmd_str, *matches_ptr);
1273 cmd_str, *matches_ptr);
1274
1275 return {};
1276}
1277
1278bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1279 return m_command_dict.find(std::string(cmd)) != m_command_dict.end();
1280}
1281
1283 std::string &full_name) const {
1284 bool exact_match =
1285 (m_alias_dict.find(std::string(cmd)) != m_alias_dict.end());
1286 if (exact_match) {
1287 full_name.assign(std::string(cmd));
1288 return exact_match;
1289 } else {
1290 StringList matches;
1291 size_t num_alias_matches;
1292 num_alias_matches =
1294 if (num_alias_matches == 1) {
1295 // Make sure this isn't shadowing a command in the regular command space:
1296 StringList regular_matches;
1297 const bool include_aliases = false;
1298 const bool exact = false;
1299 CommandObjectSP cmd_obj_sp(
1300 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1301 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1302 return false;
1303 else {
1304 full_name.assign(matches.GetStringAtIndex(0));
1305 return true;
1306 }
1307 } else
1308 return false;
1309 }
1310}
1311
1312bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1313 return m_alias_dict.find(std::string(cmd)) != m_alias_dict.end();
1314}
1315
1316bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1317 return m_user_dict.find(std::string(cmd)) != m_user_dict.end();
1318}
1319
1320bool CommandInterpreter::UserMultiwordCommandExists(llvm::StringRef cmd) const {
1321 return m_user_mw_dict.find(std::string(cmd)) != m_user_mw_dict.end();
1322}
1323
1325CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1326 lldb::CommandObjectSP &command_obj_sp,
1327 llvm::StringRef args_string) {
1328 if (command_obj_sp.get())
1329 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1330 "tried to add a CommandObject from a different interpreter");
1331
1332 std::unique_ptr<CommandAlias> command_alias_up(
1333 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1334
1335 if (command_alias_up && command_alias_up->IsValid()) {
1336 m_alias_dict[std::string(alias_name)] =
1337 CommandObjectSP(command_alias_up.get());
1338 return command_alias_up.release();
1339 }
1340
1341 return nullptr;
1342}
1343
1344bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1345 auto pos = m_alias_dict.find(std::string(alias_name));
1346 if (pos != m_alias_dict.end()) {
1347 m_alias_dict.erase(pos);
1348 return true;
1349 }
1350 return false;
1351}
1352
1353bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd, bool force) {
1354 auto pos = m_command_dict.find(std::string(cmd));
1355 if (pos != m_command_dict.end()) {
1356 if (force || pos->second->IsRemovable()) {
1357 // Only regular expression objects or python commands are removable under
1358 // normal circumstances.
1359 m_command_dict.erase(pos);
1360 return true;
1361 }
1362 }
1363 return false;
1364}
1365
1366bool CommandInterpreter::RemoveUser(llvm::StringRef user_name) {
1367 CommandObject::CommandMap::iterator pos =
1368 m_user_dict.find(std::string(user_name));
1369 if (pos != m_user_dict.end()) {
1370 m_user_dict.erase(pos);
1371 return true;
1372 }
1373 return false;
1374}
1375
1376bool CommandInterpreter::RemoveUserMultiword(llvm::StringRef multi_name) {
1377 CommandObject::CommandMap::iterator pos =
1378 m_user_mw_dict.find(std::string(multi_name));
1379 if (pos != m_user_mw_dict.end()) {
1380 m_user_mw_dict.erase(pos);
1381 return true;
1382 }
1383 return false;
1384}
1385
1387 uint32_t cmd_types) {
1388 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1389 if (!help_prologue.empty()) {
1390 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1391 help_prologue);
1392 }
1393
1394 CommandObject::CommandMap::const_iterator pos;
1395 size_t max_len = FindLongestCommandWord(m_command_dict);
1396
1397 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1398 result.AppendMessage("Debugger commands:");
1399 result.AppendMessage("");
1400
1401 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1402 if (!(cmd_types & eCommandTypesHidden) &&
1403 (pos->first.compare(0, 1, "_") == 0))
1404 continue;
1405
1406 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1407 pos->second->GetHelp(), max_len);
1408 }
1409 result.AppendMessage("");
1410 }
1411
1412 if (!m_alias_dict.empty() &&
1413 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1415 "Current command abbreviations "
1416 "(type '%shelp command alias' for more info):\n",
1418 result.AppendMessage("");
1420
1421 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1422 ++alias_pos) {
1423 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1424 alias_pos->second->GetHelp(), max_len);
1425 }
1426 result.AppendMessage("");
1427 }
1428
1429 if (!m_user_dict.empty() &&
1430 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1431 result.AppendMessage("Current user-defined commands:");
1432 result.AppendMessage("");
1434 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1435 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1436 pos->second->GetHelp(), max_len);
1437 }
1438 result.AppendMessage("");
1439 }
1440
1441 if (!m_user_mw_dict.empty() &&
1442 ((cmd_types & eCommandTypesUserMW) == eCommandTypesUserMW)) {
1443 result.AppendMessage("Current user-defined container commands:");
1444 result.AppendMessage("");
1446 for (pos = m_user_mw_dict.begin(); pos != m_user_mw_dict.end(); ++pos) {
1447 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1448 pos->second->GetHelp(), max_len);
1449 }
1450 result.AppendMessage("");
1451 }
1452
1454 "For more information on any command, type '%shelp <command-name>'.\n",
1456}
1457
1459 llvm::StringRef &command_string) {
1460 // This function finds the final, lowest-level, alias-resolved command object
1461 // whose 'Execute' function will eventually be invoked by the given command
1462 // line.
1463
1464 CommandObject *cmd_obj = nullptr;
1465 size_t start = command_string.find_first_not_of(k_white_space);
1466 size_t end = 0;
1467 bool done = false;
1468 while (!done) {
1469 if (start != std::string::npos) {
1470 // Get the next word from command_string.
1471 end = command_string.find_first_of(k_white_space, start);
1472 if (end == std::string::npos)
1473 end = command_string.size();
1474 std::string cmd_word =
1475 std::string(command_string.substr(start, end - start));
1476
1477 if (cmd_obj == nullptr)
1478 // Since cmd_obj is NULL we are on our first time through this loop.
1479 // Check to see if cmd_word is a valid command or alias.
1480 cmd_obj = GetCommandObject(cmd_word);
1481 else if (cmd_obj->IsMultiwordObject()) {
1482 // Our current object is a multi-word object; see if the cmd_word is a
1483 // valid sub-command for our object.
1484 CommandObject *sub_cmd_obj =
1485 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1486 if (sub_cmd_obj)
1487 cmd_obj = sub_cmd_obj;
1488 else // cmd_word was not a valid sub-command word, so we are done
1489 done = true;
1490 } else
1491 // We have a cmd_obj and it is not a multi-word object, so we are done.
1492 done = true;
1493
1494 // If we didn't find a valid command object, or our command object is not
1495 // a multi-word object, or we are at the end of the command_string, then
1496 // we are done. Otherwise, find the start of the next word.
1497
1498 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1499 end >= command_string.size())
1500 done = true;
1501 else
1502 start = command_string.find_first_not_of(k_white_space, end);
1503 } else
1504 // Unable to find any more words.
1505 done = true;
1506 }
1507
1508 command_string = command_string.substr(end);
1509 return cmd_obj;
1510}
1511
1512static const char *k_valid_command_chars =
1513 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1514static void StripLeadingSpaces(std::string &s) {
1515 if (!s.empty()) {
1516 size_t pos = s.find_first_not_of(k_white_space);
1517 if (pos == std::string::npos)
1518 s.clear();
1519 else if (pos == 0)
1520 return;
1521 s.erase(0, pos);
1522 }
1523}
1524
1525static size_t FindArgumentTerminator(const std::string &s) {
1526 const size_t s_len = s.size();
1527 size_t offset = 0;
1528 while (offset < s_len) {
1529 size_t pos = s.find("--", offset);
1530 if (pos == std::string::npos)
1531 break;
1532 if (pos > 0) {
1533 if (llvm::isSpace(s[pos - 1])) {
1534 // Check if the string ends "\s--" (where \s is a space character) or
1535 // if we have "\s--\s".
1536 if ((pos + 2 >= s_len) || llvm::isSpace(s[pos + 2])) {
1537 return pos;
1538 }
1539 }
1540 }
1541 offset = pos + 2;
1542 }
1543 return std::string::npos;
1544}
1545
1546static bool ExtractCommand(std::string &command_string, std::string &command,
1547 std::string &suffix, char &quote_char) {
1548 command.clear();
1549 suffix.clear();
1550 StripLeadingSpaces(command_string);
1551
1552 bool result = false;
1553 quote_char = '\0';
1554
1555 if (!command_string.empty()) {
1556 const char first_char = command_string[0];
1557 if (first_char == '\'' || first_char == '"') {
1558 quote_char = first_char;
1559 const size_t end_quote_pos = command_string.find(quote_char, 1);
1560 if (end_quote_pos == std::string::npos) {
1561 command.swap(command_string);
1562 command_string.erase();
1563 } else {
1564 command.assign(command_string, 1, end_quote_pos - 1);
1565 if (end_quote_pos + 1 < command_string.size())
1566 command_string.erase(0, command_string.find_first_not_of(
1567 k_white_space, end_quote_pos + 1));
1568 else
1569 command_string.erase();
1570 }
1571 } else {
1572 const size_t first_space_pos =
1573 command_string.find_first_of(k_white_space);
1574 if (first_space_pos == std::string::npos) {
1575 command.swap(command_string);
1576 command_string.erase();
1577 } else {
1578 command.assign(command_string, 0, first_space_pos);
1579 command_string.erase(0, command_string.find_first_not_of(
1580 k_white_space, first_space_pos));
1581 }
1582 }
1583 result = true;
1584 }
1585
1586 if (!command.empty()) {
1587 // actual commands can't start with '-' or '_'
1588 if (command[0] != '-' && command[0] != '_') {
1589 size_t pos = command.find_first_not_of(k_valid_command_chars);
1590 if (pos > 0 && pos != std::string::npos) {
1591 suffix.assign(command.begin() + pos, command.end());
1592 command.erase(pos);
1593 }
1594 }
1595 }
1596
1597 return result;
1598}
1599
1601 llvm::StringRef alias_name, std::string &raw_input_string,
1602 std::string &alias_result, CommandReturnObject &result) {
1603 CommandObject *alias_cmd_obj = nullptr;
1604 Args cmd_args(raw_input_string);
1605 alias_cmd_obj = GetCommandObject(alias_name);
1606 StreamString result_str;
1607
1608 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1609 alias_result.clear();
1610 return alias_cmd_obj;
1611 }
1612 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1613 ((CommandAlias *)alias_cmd_obj)->Desugar();
1614 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1615 alias_cmd_obj = desugared.first.get();
1616 std::string alias_name_str = std::string(alias_name);
1617 if ((cmd_args.GetArgumentCount() == 0) ||
1618 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1619 cmd_args.Unshift(alias_name_str);
1620
1621 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1622
1623 if (!option_arg_vector_sp.get()) {
1624 alias_result = std::string(result_str.GetString());
1625 return alias_cmd_obj;
1626 }
1627 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1628
1629 int value_type;
1630 std::string option;
1631 std::string value;
1632 for (const auto &entry : *option_arg_vector) {
1633 std::tie(option, value_type, value) = entry;
1634 if (option == g_argument) {
1635 result_str.Printf(" %s", value.c_str());
1636 continue;
1637 }
1638
1639 result_str.Printf(" %s", option.c_str());
1640 if (value_type == OptionParser::eNoArgument)
1641 continue;
1642
1643 if (value_type != OptionParser::eOptionalArgument)
1644 result_str.Printf(" ");
1645 int index = GetOptionArgumentPosition(value.c_str());
1646 if (index == 0)
1647 result_str.Printf("%s", value.c_str());
1648 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1649
1650 result.AppendErrorWithFormat("Not enough arguments provided; you "
1651 "need at least %d arguments to use "
1652 "this alias.\n",
1653 index);
1654 return nullptr;
1655 } else {
1656 const Args::ArgEntry &entry = cmd_args[index];
1657 size_t strpos = raw_input_string.find(entry.c_str());
1658 const char quote_char = entry.GetQuoteChar();
1659 if (strpos != std::string::npos) {
1660 const size_t start_fudge = quote_char == '\0' ? 0 : 1;
1661 const size_t len_fudge = quote_char == '\0' ? 0 : 2;
1662
1663 // Make sure we aren't going outside the bounds of the cmd string:
1664 if (strpos < start_fudge) {
1665 result.AppendError("Unmatched quote at command beginning.");
1666 return nullptr;
1667 }
1668 llvm::StringRef arg_text = entry.ref();
1669 if (strpos - start_fudge + arg_text.size() + len_fudge >
1670 raw_input_string.size()) {
1671 result.AppendError("Unmatched quote at command end.");
1672 return nullptr;
1673 }
1674 raw_input_string = raw_input_string.erase(
1675 strpos - start_fudge,
1676 strlen(cmd_args.GetArgumentAtIndex(index)) + len_fudge);
1677 }
1678 if (quote_char == '\0')
1679 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1680 else
1681 result_str.Printf("%c%s%c", quote_char, entry.c_str(), quote_char);
1682 }
1683 }
1684
1685 alias_result = std::string(result_str.GetString());
1686 return alias_cmd_obj;
1687}
1688
1690 // The command preprocessor needs to do things to the command line before any
1691 // parsing of arguments or anything else is done. The only current stuff that
1692 // gets preprocessed is anything enclosed in backtick ('`') characters is
1693 // evaluated as an expression and the result of the expression must be a
1694 // scalar that can be substituted into the command. An example would be:
1695 // (lldb) memory read `$rsp + 20`
1696 Status error; // Status for any expressions that might not evaluate
1697 size_t start_backtick;
1698 size_t pos = 0;
1699 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1700 // Stop if an error was encountered during the previous iteration.
1701 if (error.Fail())
1702 break;
1703
1704 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1705 // The backtick was preceded by a '\' character, remove the slash and
1706 // don't treat the backtick as the start of an expression.
1707 command.erase(start_backtick - 1, 1);
1708 // No need to add one to start_backtick since we just deleted a char.
1709 pos = start_backtick;
1710 continue;
1711 }
1712
1713 const size_t expr_content_start = start_backtick + 1;
1714 const size_t end_backtick = command.find('`', expr_content_start);
1715
1716 if (end_backtick == std::string::npos) {
1717 // Stop if there's no end backtick.
1718 break;
1719 }
1720
1721 if (end_backtick == expr_content_start) {
1722 // Skip over empty expression. (two backticks in a row)
1723 command.erase(start_backtick, 2);
1724 continue;
1725 }
1726
1727 std::string expr_str(command, expr_content_start,
1728 end_backtick - expr_content_start);
1729 error = PreprocessToken(expr_str);
1730 // We always stop at the first error:
1731 if (error.Fail())
1732 break;
1733
1734 command.erase(start_backtick, end_backtick - start_backtick + 1);
1735 command.insert(start_backtick, std::string(expr_str));
1736 pos = start_backtick + expr_str.size();
1737 }
1738 return error;
1739}
1740
1741Status
1743 Status error;
1745
1746 // Get a dummy target to allow for calculator mode while processing
1747 // backticks. This also helps break the infinite loop caused when target is
1748 // null.
1749 Target *exe_target = exe_ctx.GetTargetPtr();
1750 Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget();
1751
1752 ValueObjectSP expr_result_valobj_sp;
1753
1755 options.SetCoerceToId(false);
1756 options.SetUnwindOnError(true);
1757 options.SetIgnoreBreakpoints(true);
1758 options.SetKeepInMemory(false);
1759 options.SetTryAllThreads(true);
1760 options.SetTimeout(std::nullopt);
1761
1762 ExpressionResults expr_result =
1763 target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1764 expr_result_valobj_sp, options);
1765
1766 if (expr_result == eExpressionCompleted) {
1767 Scalar scalar;
1768 if (expr_result_valobj_sp)
1769 expr_result_valobj_sp =
1770 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1771 expr_result_valobj_sp->GetDynamicValueType(), true);
1772 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1773
1774 StreamString value_strm;
1775 const bool show_type = false;
1776 scalar.GetValue(value_strm, show_type);
1777 size_t value_string_size = value_strm.GetSize();
1778 if (value_string_size) {
1779 expr_str = value_strm.GetData();
1780 } else {
1781 error.SetErrorStringWithFormat("expression value didn't result "
1782 "in a scalar value for the "
1783 "expression '%s'",
1784 expr_str.c_str());
1785 }
1786 } else {
1787 error.SetErrorStringWithFormat("expression value didn't result "
1788 "in a scalar value for the "
1789 "expression '%s'",
1790 expr_str.c_str());
1791 }
1792 return error;
1793 }
1794
1795 // If we have an error from the expression evaluation it will be in the
1796 // ValueObject error, which won't be success and we will just report it.
1797 // But if for some reason we didn't get a value object at all, then we will
1798 // make up some helpful errors from the expression result.
1799 if (expr_result_valobj_sp)
1800 error = expr_result_valobj_sp->GetError();
1801
1802 if (error.Success()) {
1803 switch (expr_result) {
1805 error.SetErrorStringWithFormat(
1806 "expression setup error for the expression '%s'", expr_str.c_str());
1807 break;
1809 error.SetErrorStringWithFormat(
1810 "expression parse error for the expression '%s'", expr_str.c_str());
1811 break;
1813 error.SetErrorStringWithFormat(
1814 "expression error fetching result for the expression '%s'",
1815 expr_str.c_str());
1816 break;
1818 break;
1820 error.SetErrorStringWithFormat(
1821 "expression discarded for the expression '%s'", expr_str.c_str());
1822 break;
1824 error.SetErrorStringWithFormat(
1825 "expression interrupted for the expression '%s'", expr_str.c_str());
1826 break;
1828 error.SetErrorStringWithFormat(
1829 "expression hit breakpoint for the expression '%s'",
1830 expr_str.c_str());
1831 break;
1833 error.SetErrorStringWithFormat(
1834 "expression timed out for the expression '%s'", expr_str.c_str());
1835 break;
1837 error.SetErrorStringWithFormat("expression stop at entry point "
1838 "for debugging for the "
1839 "expression '%s'",
1840 expr_str.c_str());
1841 break;
1843 error.SetErrorStringWithFormat(
1844 "expression thread vanished for the expression '%s'",
1845 expr_str.c_str());
1846 break;
1847 }
1848 }
1849 return error;
1850}
1851
1852bool CommandInterpreter::HandleCommand(const char *command_line,
1853 LazyBool lazy_add_to_history,
1854 const ExecutionContext &override_context,
1855 CommandReturnObject &result) {
1856
1857 OverrideExecutionContext(override_context);
1858 bool status = HandleCommand(command_line, lazy_add_to_history, result);
1860 return status;
1861}
1862
1863bool CommandInterpreter::HandleCommand(const char *command_line,
1864 LazyBool lazy_add_to_history,
1865 CommandReturnObject &result,
1866 bool force_repeat_command) {
1867 std::string command_string(command_line);
1868 std::string original_command_string(command_line);
1869
1871 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1872 command_line);
1873
1874 LLDB_LOGF(log, "Processing command: %s", command_line);
1875 LLDB_SCOPED_TIMERF("Processing command: %s.", command_line);
1876
1877 if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted initiating command")) {
1878 result.AppendError("... Interrupted");
1879 return false;
1880 }
1881
1882 bool add_to_history;
1883 if (lazy_add_to_history == eLazyBoolCalculate)
1884 add_to_history = (m_command_source_depth == 0);
1885 else
1886 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1887
1888 m_transcript_stream << "(lldb) " << command_line << '\n';
1889
1890 bool empty_command = false;
1891 bool comment_command = false;
1892 if (command_string.empty())
1893 empty_command = true;
1894 else {
1895 const char *k_space_characters = "\t\n\v\f\r ";
1896
1897 size_t non_space = command_string.find_first_not_of(k_space_characters);
1898 // Check for empty line or comment line (lines whose first non-space
1899 // character is the comment character for this interpreter)
1900 if (non_space == std::string::npos)
1901 empty_command = true;
1902 else if (command_string[non_space] == m_comment_char)
1903 comment_command = true;
1904 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1905 llvm::StringRef search_str(command_string);
1906 search_str = search_str.drop_front(non_space);
1907 if (auto hist_str = m_command_history.FindString(search_str)) {
1908 add_to_history = false;
1909 command_string = std::string(*hist_str);
1910 original_command_string = std::string(*hist_str);
1911 } else {
1912 result.AppendErrorWithFormat("Could not find entry: %s in history",
1913 command_string.c_str());
1914 return false;
1915 }
1916 }
1917 }
1918
1919 if (empty_command) {
1920 if (!GetRepeatPreviousCommand()) {
1922 return true;
1923 }
1924
1925 if (m_command_history.IsEmpty()) {
1926 result.AppendError("empty command");
1927 return false;
1928 }
1929
1930 command_line = m_repeat_command.c_str();
1931 command_string = command_line;
1932 original_command_string = command_line;
1933 if (m_repeat_command.empty()) {
1934 result.AppendError("No auto repeat.");
1935 return false;
1936 }
1937
1938 add_to_history = false;
1939 } else if (comment_command) {
1941 return true;
1942 }
1943
1944 // Phase 1.
1945
1946 // Before we do ANY kind of argument processing, we need to figure out what
1947 // the real/final command object is for the specified command. This gets
1948 // complicated by the fact that the user could have specified an alias, and,
1949 // in translating the alias, there may also be command options and/or even
1950 // data (including raw text strings) that need to be found and inserted into
1951 // the command line as part of the translation. So this first step is plain
1952 // look-up and replacement, resulting in:
1953 // 1. the command object whose Execute method will actually be called
1954 // 2. a revised command string, with all substitutions and replacements
1955 // taken care of
1956 // From 1 above, we can determine whether the Execute function wants raw
1957 // input or not.
1958
1959 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1960
1961 // We have to preprocess the whole command string for Raw commands, since we
1962 // don't know the structure of the command. For parsed commands, we only
1963 // treat backticks as quote characters specially.
1964 // FIXME: We probably want to have raw commands do their own preprocessing.
1965 // For instance, I don't think people expect substitution in expr expressions.
1966 if (cmd_obj && cmd_obj->WantsRawCommandString()) {
1967 Status error(PreprocessCommand(command_string));
1968
1969 if (error.Fail()) {
1970 result.AppendError(error.AsCString());
1971 return false;
1972 }
1973 }
1974
1975 // Although the user may have abbreviated the command, the command_string now
1976 // has the command expanded to the full name. For example, if the input was
1977 // "br s -n main", command_string is now "breakpoint set -n main".
1978 if (log) {
1979 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1980 LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
1981 LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
1982 command_string.c_str());
1983 const bool wants_raw_input =
1984 (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
1985 LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
1986 wants_raw_input ? "True" : "False");
1987 }
1988
1989 // Phase 2.
1990 // Take care of things like setting up the history command & calling the
1991 // appropriate Execute method on the CommandObject, with the appropriate
1992 // arguments.
1993
1994 if (cmd_obj != nullptr) {
1995 bool generate_repeat_command = add_to_history;
1996 // If we got here when empty_command was true, then this command is a
1997 // stored "repeat command" which we should give a chance to produce it's
1998 // repeat command, even though we don't add repeat commands to the history.
1999 generate_repeat_command |= empty_command;
2000 // For `command regex`, the regex command (ex `bt`) is added to history, but
2001 // the resolved command (ex `thread backtrace`) is _not_ added to history.
2002 // However, the resolved command must be given the opportunity to provide a
2003 // repeat command. `force_repeat_command` supports this case.
2004 generate_repeat_command |= force_repeat_command;
2005 if (generate_repeat_command) {
2006 Args command_args(command_string);
2007 std::optional<std::string> repeat_command =
2008 cmd_obj->GetRepeatCommand(command_args, 0);
2009 if (repeat_command) {
2010 LLDB_LOGF(log, "Repeat command: %s", repeat_command->data());
2011 m_repeat_command.assign(*repeat_command);
2012 } else {
2013 m_repeat_command.assign(original_command_string);
2014 }
2015 }
2016
2017 if (add_to_history)
2018 m_command_history.AppendString(original_command_string);
2019
2020 std::string remainder;
2021 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
2022 if (actual_cmd_name_len < command_string.length())
2023 remainder = command_string.substr(actual_cmd_name_len);
2024
2025 // Remove any initial spaces
2026 size_t pos = remainder.find_first_not_of(k_white_space);
2027 if (pos != 0 && pos != std::string::npos)
2028 remainder.erase(0, pos);
2029
2030 LLDB_LOGF(
2031 log, "HandleCommand, command line after removing command name(s): '%s'",
2032 remainder.c_str());
2033
2034 cmd_obj->Execute(remainder.c_str(), result);
2035 }
2036
2037 LLDB_LOGF(log, "HandleCommand, command %s",
2038 (result.Succeeded() ? "succeeded" : "did not succeed"));
2039
2042
2043 return result.Succeeded();
2044}
2045
2047 bool look_for_subcommand = false;
2048
2049 // For any of the command completions a unique match will be a complete word.
2050
2051 if (request.GetParsedLine().GetArgumentCount() == 0) {
2052 // We got nothing on the command line, so return the list of commands
2053 bool include_aliases = true;
2054 StringList new_matches, descriptions;
2055 GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
2056 descriptions);
2057 request.AddCompletions(new_matches, descriptions);
2058 } else if (request.GetCursorIndex() == 0) {
2059 // The cursor is in the first argument, so just do a lookup in the
2060 // dictionary.
2061 StringList new_matches, new_descriptions;
2062 CommandObject *cmd_obj =
2064 &new_matches, &new_descriptions);
2065
2066 if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
2067 new_matches.GetStringAtIndex(0) != nullptr &&
2068 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
2069 new_matches.GetStringAtIndex(0)) == 0) {
2070 if (request.GetParsedLine().GetArgumentCount() != 1) {
2071 look_for_subcommand = true;
2072 new_matches.DeleteStringAtIndex(0);
2073 new_descriptions.DeleteStringAtIndex(0);
2074 request.AppendEmptyArgument();
2075 }
2076 }
2077 request.AddCompletions(new_matches, new_descriptions);
2078 }
2079
2080 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
2081 // We are completing further on into a commands arguments, so find the
2082 // command and tell it to complete the command. First see if there is a
2083 // matching initial command:
2084 CommandObject *command_object =
2086 if (command_object) {
2087 request.ShiftArguments();
2088 command_object->HandleCompletion(request);
2089 }
2090 }
2091}
2092
2094
2095 // Don't complete comments, and if the line we are completing is just the
2096 // history repeat character, substitute the appropriate history line.
2097 llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
2098
2099 if (!first_arg.empty()) {
2100 if (first_arg.front() == m_comment_char)
2101 return;
2102 if (first_arg.front() == CommandHistory::g_repeat_char) {
2103 if (auto hist_str = m_command_history.FindString(first_arg))
2104 request.AddCompletion(*hist_str, "Previous command history event",
2106 return;
2107 }
2108 }
2109
2110 HandleCompletionMatches(request);
2111}
2112
2113std::optional<std::string>
2115 if (line.empty())
2116 return std::nullopt;
2117 const size_t s = m_command_history.GetSize();
2118 for (int i = s - 1; i >= 0; --i) {
2119 llvm::StringRef entry = m_command_history.GetStringAtIndex(i);
2120 if (entry.consume_front(line))
2121 return entry.str();
2122 }
2123 return std::nullopt;
2124}
2125
2126void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
2127 EventSP prompt_change_event_sp(
2128 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
2129 ;
2130 BroadcastEvent(prompt_change_event_sp);
2132 m_command_io_handler_sp->SetPrompt(new_prompt);
2133}
2134
2135bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
2136 // Check AutoConfirm first:
2138 return default_answer;
2139
2140 IOHandlerConfirm *confirm =
2141 new IOHandlerConfirm(m_debugger, message, default_answer);
2142 IOHandlerSP io_handler_sp(confirm);
2143 m_debugger.RunIOHandlerSync(io_handler_sp);
2144 return confirm->GetResponse();
2145}
2146
2147const CommandAlias *
2148CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
2149 OptionArgVectorSP ret_val;
2150
2151 auto pos = m_alias_dict.find(std::string(alias_name));
2152 if (pos != m_alias_dict.end())
2153 return (CommandAlias *)pos->second.get();
2154
2155 return nullptr;
2156}
2157
2158bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
2159
2160bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
2161
2162bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
2163
2165 return (!m_user_mw_dict.empty());
2166}
2167
2169
2171 const char *alias_name,
2172 Args &cmd_args,
2173 std::string &raw_input_string,
2174 CommandReturnObject &result) {
2175 OptionArgVectorSP option_arg_vector_sp =
2176 GetAlias(alias_name)->GetOptionArguments();
2177
2178 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
2179
2180 // Make sure that the alias name is the 0th element in cmd_args
2181 std::string alias_name_str = alias_name;
2182 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
2183 cmd_args.Unshift(alias_name_str);
2184
2185 Args new_args(alias_cmd_obj->GetCommandName());
2186 if (new_args.GetArgumentCount() == 2)
2187 new_args.Shift();
2188
2189 if (option_arg_vector_sp.get()) {
2190 if (wants_raw_input) {
2191 // We have a command that both has command options and takes raw input.
2192 // Make *sure* it has a " -- " in the right place in the
2193 // raw_input_string.
2194 size_t pos = raw_input_string.find(" -- ");
2195 if (pos == std::string::npos) {
2196 // None found; assume it goes at the beginning of the raw input string
2197 raw_input_string.insert(0, " -- ");
2198 }
2199 }
2200
2201 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
2202 const size_t old_size = cmd_args.GetArgumentCount();
2203 std::vector<bool> used(old_size + 1, false);
2204
2205 used[0] = true;
2206
2207 int value_type;
2208 std::string option;
2209 std::string value;
2210 for (const auto &option_entry : *option_arg_vector) {
2211 std::tie(option, value_type, value) = option_entry;
2212 if (option == g_argument) {
2213 if (!wants_raw_input || (value != "--")) {
2214 // Since we inserted this above, make sure we don't insert it twice
2215 new_args.AppendArgument(value);
2216 }
2217 continue;
2218 }
2219
2220 if (value_type != OptionParser::eOptionalArgument)
2221 new_args.AppendArgument(option);
2222
2223 if (value == g_no_argument)
2224 continue;
2225
2226 int index = GetOptionArgumentPosition(value.c_str());
2227 if (index == 0) {
2228 // value was NOT a positional argument; must be a real value
2229 if (value_type != OptionParser::eOptionalArgument)
2230 new_args.AppendArgument(value);
2231 else {
2232 new_args.AppendArgument(option + value);
2233 }
2234
2235 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2236 result.AppendErrorWithFormat("Not enough arguments provided; you "
2237 "need at least %d arguments to use "
2238 "this alias.\n",
2239 index);
2240 return;
2241 } else {
2242 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2243 size_t strpos =
2244 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2245 if (strpos != std::string::npos) {
2246 raw_input_string = raw_input_string.erase(
2247 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2248 }
2249
2250 if (value_type != OptionParser::eOptionalArgument)
2251 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2252 else {
2253 new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index));
2254 }
2255 used[index] = true;
2256 }
2257 }
2258
2259 for (auto entry : llvm::enumerate(cmd_args.entries())) {
2260 if (!used[entry.index()] && !wants_raw_input)
2261 new_args.AppendArgument(entry.value().ref());
2262 }
2263
2264 cmd_args.Clear();
2265 cmd_args.SetArguments(new_args.GetArgumentCount(),
2266 new_args.GetConstArgumentVector());
2267 } else {
2269 // This alias was not created with any options; nothing further needs to be
2270 // done, unless it is a command that wants raw input, in which case we need
2271 // to clear the rest of the data from cmd_args, since its in the raw input
2272 // string.
2273 if (wants_raw_input) {
2274 cmd_args.Clear();
2275 cmd_args.SetArguments(new_args.GetArgumentCount(),
2276 new_args.GetConstArgumentVector());
2277 }
2278 return;
2279 }
2280
2282}
2283
2285 int position = 0; // Any string that isn't an argument position, i.e. '%'
2286 // followed by an integer, gets a position
2287 // of zero.
2288
2289 const char *cptr = in_string;
2290
2291 // Does it start with '%'
2292 if (cptr[0] == '%') {
2293 ++cptr;
2294
2295 // Is the rest of it entirely digits?
2296 if (isdigit(cptr[0])) {
2297 const char *start = cptr;
2298 while (isdigit(cptr[0]))
2299 ++cptr;
2300
2301 // We've gotten to the end of the digits; are we at the end of the
2302 // string?
2303 if (cptr[0] == '\0')
2304 position = atoi(start);
2305 }
2306 }
2307
2308 return position;
2309}
2310
2312 llvm::StringRef suffix = {}) {
2313 std::string init_file_name = ".lldbinit";
2314 if (!suffix.empty()) {
2315 init_file_name.append("-");
2316 init_file_name.append(suffix.str());
2317 }
2318
2320 llvm::sys::path::append(init_file, init_file_name);
2321
2322 FileSystem::Instance().Resolve(init_file);
2323}
2324
2326 LanguageType language) {
2327 if (language == eLanguageTypeUnknown) {
2329 if (auto main_repl_language = repl_languages.GetSingularLanguage())
2330 language = *main_repl_language;
2331 else
2332 return;
2333 }
2334
2335 std::string init_file_name =
2336 (llvm::Twine(".lldbinit-") +
2337 llvm::Twine(Language::GetNameForLanguageType(language)) +
2338 llvm::Twine("-repl"))
2339 .str();
2341 llvm::sys::path::append(init_file, init_file_name);
2342 FileSystem::Instance().Resolve(init_file);
2343}
2344
2346 llvm::StringRef s = ".lldbinit";
2347 init_file.assign(s.begin(), s.end());
2348 FileSystem::Instance().Resolve(init_file);
2349}
2350
2352 CommandReturnObject &result) {
2353 assert(!m_skip_lldbinit_files);
2354
2355 if (!FileSystem::Instance().Exists(file)) {
2357 return;
2358 }
2359
2360 // Use HandleCommand to 'source' the given file; this will do the actual
2361 // broadcasting of the commands back to any appropriate listener (see
2362 // CommandObjectSource::Execute for more details).
2363 const bool saved_batch = SetBatchCommandMode(true);
2365 options.SetSilent(true);
2366 options.SetPrintErrors(true);
2367 options.SetStopOnError(false);
2368 options.SetStopOnContinue(true);
2369 HandleCommandsFromFile(file, options, result);
2370 SetBatchCommandMode(saved_batch);
2371}
2372
2376 return;
2377 }
2378
2379 llvm::SmallString<128> init_file;
2380 GetCwdInitFile(init_file);
2381 if (!FileSystem::Instance().Exists(init_file)) {
2383 return;
2384 }
2385
2386 LoadCWDlldbinitFile should_load =
2388
2389 switch (should_load) {
2392 break;
2394 SourceInitFile(FileSpec(init_file.str()), result);
2395 break;
2396 case eLoadCWDlldbinitWarn: {
2397 llvm::SmallString<128> home_init_file;
2398 GetHomeInitFile(home_init_file);
2399 if (llvm::sys::path::parent_path(init_file) ==
2400 llvm::sys::path::parent_path(home_init_file)) {
2402 } else {
2404 }
2405 }
2406 }
2407}
2408
2409/// We will first see if there is an application specific ".lldbinit" file
2410/// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2411/// If this file doesn't exist, we fall back to the REPL init file or the
2412/// default home init file in "~/.lldbinit".
2414 bool is_repl) {
2417 return;
2418 }
2419
2420 llvm::SmallString<128> init_file;
2421
2422 if (is_repl)
2423 GetHomeREPLInitFile(init_file, GetDebugger().GetREPLLanguage());
2424
2425 if (init_file.empty())
2426 GetHomeInitFile(init_file);
2427
2428 if (!m_skip_app_init_files) {
2429 llvm::StringRef program_name =
2430 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2431 llvm::SmallString<128> program_init_file;
2432 GetHomeInitFile(program_init_file, program_name);
2433 if (FileSystem::Instance().Exists(program_init_file))
2434 init_file = program_init_file;
2435 }
2436
2437 SourceInitFile(FileSpec(init_file.str()), result);
2438}
2439
2441#ifdef LLDB_GLOBAL_INIT_DIRECTORY
2442 if (!m_skip_lldbinit_files) {
2443 FileSpec init_file(LLDB_GLOBAL_INIT_DIRECTORY);
2444 if (init_file)
2445 init_file.MakeAbsolute(HostInfo::GetShlibDir());
2446
2447 init_file.AppendPathComponent("lldbinit");
2448 SourceInitFile(init_file, result);
2449 return;
2450 }
2451#endif
2453}
2454
2456 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2457 return prefix == nullptr ? "" : prefix;
2458}
2459
2460PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2461 PlatformSP platform_sp;
2462 if (prefer_target_platform) {
2464 Target *target = exe_ctx.GetTargetPtr();
2465 if (target)
2466 platform_sp = target->GetPlatform();
2467 }
2468
2469 if (!platform_sp)
2471 return platform_sp;
2472}
2473
2475 auto exe_ctx = GetExecutionContext();
2476 TargetSP target_sp = exe_ctx.GetTargetSP();
2477 if (!target_sp)
2478 return false;
2479
2480 ProcessSP process_sp(target_sp->GetProcessSP());
2481 if (!process_sp)
2482 return false;
2483
2484 if (eStateStopped != process_sp->GetState())
2485 return false;
2486
2487 for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2488 StopInfoSP stop_info = thread_sp->GetStopInfo();
2489 if (!stop_info) {
2490 // If there's no stop_info, keep iterating through the other threads;
2491 // it's enough that any thread has got a stop_info that indicates
2492 // an abnormal stop, to consider the process to be stopped abnormally.
2493 continue;
2494 }
2495
2496 const StopReason reason = stop_info->GetStopReason();
2497 if (reason == eStopReasonException ||
2498 reason == eStopReasonInstrumentation ||
2499 reason == eStopReasonProcessorTrace)
2500 return true;
2501
2502 if (reason == eStopReasonSignal) {
2503 const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2504 UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2505 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2506 // The signal is unknown, treat it as abnormal.
2507 return true;
2508
2509 const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2510 const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2511 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2512 // The signal very likely implies a crash.
2513 return true;
2514 }
2515 }
2516
2517 return false;
2518}
2519
2520void
2522 const ExecutionContext &override_context,
2523 const CommandInterpreterRunOptions &options,
2524 CommandReturnObject &result) {
2525
2526 OverrideExecutionContext(override_context);
2527 HandleCommands(commands, options, result);
2529}
2530
2532 const CommandInterpreterRunOptions &options,
2533 CommandReturnObject &result) {
2534 size_t num_lines = commands.GetSize();
2535
2536 // If we are going to continue past a "continue" then we need to run the
2537 // commands synchronously. Make sure you reset this value anywhere you return
2538 // from the function.
2539
2540 bool old_async_execution = m_debugger.GetAsyncExecution();
2541
2542 if (!options.GetStopOnContinue()) {
2544 }
2545
2546 for (size_t idx = 0; idx < num_lines; idx++) {
2547 const char *cmd = commands.GetStringAtIndex(idx);
2548 if (cmd[0] == '\0')
2549 continue;
2550
2551 if (options.GetEchoCommands()) {
2552 // TODO: Add Stream support.
2553 result.AppendMessageWithFormat("%s %s\n",
2554 m_debugger.GetPrompt().str().c_str(), cmd);
2555 }
2556
2558 tmp_result.SetInteractive(result.GetInteractive());
2559 tmp_result.SetSuppressImmediateOutput(true);
2560
2561 // We might call into a regex or alias command, in which case the
2562 // add_to_history will get lost. This m_command_source_depth dingus is the
2563 // way we turn off adding to the history in that case, so set it up here.
2564 if (!options.GetAddToHistory())
2566 bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result);
2567 if (!options.GetAddToHistory())
2569
2570 if (options.GetPrintResults()) {
2571 if (tmp_result.Succeeded())
2572 result.AppendMessage(tmp_result.GetOutputData());
2573 }
2574
2575 if (!success || !tmp_result.Succeeded()) {
2576 llvm::StringRef error_msg = tmp_result.GetErrorData();
2577 if (error_msg.empty())
2578 error_msg = "<unknown error>.\n";
2579 if (options.GetStopOnError()) {
2580 result.AppendErrorWithFormat(
2581 "Aborting reading of commands after command #%" PRIu64
2582 ": '%s' failed with %s",
2583 (uint64_t)idx, cmd, error_msg.str().c_str());
2584 m_debugger.SetAsyncExecution(old_async_execution);
2585 return;
2586 } else if (options.GetPrintResults()) {
2588 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2589 error_msg.str().c_str());
2590 }
2591 }
2592
2593 if (result.GetImmediateOutputStream())
2594 result.GetImmediateOutputStream()->Flush();
2595
2596 if (result.GetImmediateErrorStream())
2597 result.GetImmediateErrorStream()->Flush();
2598
2599 // N.B. Can't depend on DidChangeProcessState, because the state coming
2600 // into the command execution could be running (for instance in Breakpoint
2601 // Commands. So we check the return value to see if it is has running in
2602 // it.
2603 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2605 if (options.GetStopOnContinue()) {
2606 // If we caused the target to proceed, and we're going to stop in that
2607 // case, set the status in our real result before returning. This is
2608 // an error if the continue was not the last command in the set of
2609 // commands to be run.
2610 if (idx != num_lines - 1)
2611 result.AppendErrorWithFormat(
2612 "Aborting reading of commands after command #%" PRIu64
2613 ": '%s' continued the target.\n",
2614 (uint64_t)idx + 1, cmd);
2615 else
2616 result.AppendMessageWithFormat("Command #%" PRIu64
2617 " '%s' continued the target.\n",
2618 (uint64_t)idx + 1, cmd);
2619
2620 result.SetStatus(tmp_result.GetStatus());
2621 m_debugger.SetAsyncExecution(old_async_execution);
2622
2623 return;
2624 }
2625 }
2626
2627 // Also check for "stop on crash here:
2628 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2630 if (idx != num_lines - 1)
2631 result.AppendErrorWithFormat(
2632 "Aborting reading of commands after command #%" PRIu64
2633 ": '%s' stopped with a signal or exception.\n",
2634 (uint64_t)idx + 1, cmd);
2635 else
2637 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2638 (uint64_t)idx + 1, cmd);
2639
2640 result.SetStatus(tmp_result.GetStatus());
2641 m_debugger.SetAsyncExecution(old_async_execution);
2642
2643 return;
2644 }
2645 }
2646
2648 m_debugger.SetAsyncExecution(old_async_execution);
2649}
2650
2651// Make flags that we can pass into the IOHandler so our delegates can do the
2652// right thing
2653enum {
2662
2664 FileSpec &cmd_file, const ExecutionContext &context,
2665 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2666 OverrideExecutionContext(context);
2667 HandleCommandsFromFile(cmd_file, options, result);
2669}
2670
2672 const CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2673 if (!FileSystem::Instance().Exists(cmd_file)) {
2674 result.AppendErrorWithFormat(
2675 "Error reading commands from file %s - file not found.\n",
2676 cmd_file.GetFilename().AsCString("<Unknown>"));
2677 return;
2678 }
2679
2680 std::string cmd_file_path = cmd_file.GetPath();
2681 auto input_file_up =
2683 if (!input_file_up) {
2684 std::string error = llvm::toString(input_file_up.takeError());
2686 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2687 llvm::fmt_consume(input_file_up.takeError()));
2688 return;
2689 }
2690 FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2691
2692 Debugger &debugger = GetDebugger();
2693
2694 uint32_t flags = 0;
2695
2696 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2697 if (m_command_source_flags.empty()) {
2698 // Stop on continue by default
2700 } else if (m_command_source_flags.back() &
2703 }
2704 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2706 }
2707
2708 if (options.m_stop_on_error == eLazyBoolCalculate) {
2709 if (m_command_source_flags.empty()) {
2714 }
2715 } else if (options.m_stop_on_error == eLazyBoolYes) {
2717 }
2718
2719 // stop-on-crash can only be set, if it is present in all levels of
2720 // pushed flag sets.
2721 if (options.GetStopOnCrash()) {
2722 if (m_command_source_flags.empty()) {
2726 }
2727 }
2728
2729 if (options.m_echo_commands == eLazyBoolCalculate) {
2730 if (m_command_source_flags.empty()) {
2731 // Echo command by default
2735 }
2736 } else if (options.m_echo_commands == eLazyBoolYes) {
2738 }
2739
2740 // We will only ever ask for this flag, if we echo commands in general.
2742 if (m_command_source_flags.empty()) {
2743 // Echo comments by default
2745 } else if (m_command_source_flags.back() &
2748 }
2749 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2751 }
2752
2753 if (options.m_print_results == eLazyBoolCalculate) {
2754 if (m_command_source_flags.empty()) {
2755 // Print output by default
2759 }
2760 } else if (options.m_print_results == eLazyBoolYes) {
2762 }
2763
2764 if (options.m_print_errors == eLazyBoolCalculate) {
2765 if (m_command_source_flags.empty()) {
2766 // Print output by default
2770 }
2771 } else if (options.m_print_errors == eLazyBoolYes) {
2773 }
2774
2775 if (flags & eHandleCommandFlagPrintResult) {
2776 debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2777 cmd_file_path.c_str());
2778 }
2779
2780 // Used for inheriting the right settings when "command source" might
2781 // have nested "command source" commands
2782 lldb::StreamFileSP empty_stream_sp;
2783 m_command_source_flags.push_back(flags);
2784 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2785 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2786 empty_stream_sp, // Pass in an empty stream so we inherit the top
2787 // input reader output stream
2788 empty_stream_sp, // Pass in an empty stream so we inherit the top
2789 // input reader error stream
2790 flags,
2791 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2792 // or written
2793 debugger.GetPrompt(), llvm::StringRef(),
2794 false, // Not multi-line
2795 debugger.GetUseColor(), 0, *this));
2796 const bool old_async_execution = debugger.GetAsyncExecution();
2797
2798 // Set synchronous execution if we are not stopping on continue
2799 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2800 debugger.SetAsyncExecution(false);
2801
2804
2805 debugger.RunIOHandlerSync(io_handler_sp);
2806 if (!m_command_source_flags.empty())
2807 m_command_source_flags.pop_back();
2808
2809 m_command_source_dirs.pop_back();
2811
2813 debugger.SetAsyncExecution(old_async_execution);
2814}
2815
2817
2820}
2821
2823 llvm::StringRef prefix,
2824 llvm::StringRef help_text) {
2825 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2826
2827 size_t line_width_max = max_columns - prefix.size();
2828 if (line_width_max < 16)
2829 line_width_max = help_text.size() + prefix.size();
2830
2831 strm.IndentMore(prefix.size());
2832 bool prefixed_yet = false;
2833 // Even if we have no help text we still want to emit the command name.
2834 if (help_text.empty())
2835 help_text = "No help text";
2836 while (!help_text.empty()) {
2837 // Prefix the first line, indent subsequent lines to line up
2838 if (!prefixed_yet) {
2839 strm << prefix;
2840 prefixed_yet = true;
2841 } else
2842 strm.Indent();
2843
2844 // Never print more than the maximum on one line.
2845 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2846
2847 // Always break on an explicit newline.
2848 std::size_t first_newline = this_line.find_first_of("\n");
2849
2850 // Don't break on space/tab unless the text is too long to fit on one line.
2851 std::size_t last_space = llvm::StringRef::npos;
2852 if (this_line.size() != help_text.size())
2853 last_space = this_line.find_last_of(" \t");
2854
2855 // Break at whichever condition triggered first.
2856 this_line = this_line.substr(0, std::min(first_newline, last_space));
2857 strm.PutCString(this_line);
2858 strm.EOL();
2859
2860 // Remove whitespace / newlines after breaking.
2861 help_text = help_text.drop_front(this_line.size()).ltrim();
2862 }
2863 strm.IndentLess(prefix.size());
2864}
2865
2867 llvm::StringRef word_text,
2868 llvm::StringRef separator,
2869 llvm::StringRef help_text,
2870 size_t max_word_len) {
2871 StreamString prefix_stream;
2872 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2873 (int)separator.size(), separator.data());
2874 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2875}
2876
2877void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2878 llvm::StringRef separator,
2879 llvm::StringRef help_text,
2880 uint32_t max_word_len) {
2881 int indent_size = max_word_len + separator.size() + 2;
2882
2883 strm.IndentMore(indent_size);
2884
2885 StreamString text_strm;
2886 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2887 text_strm << separator << " " << help_text;
2888
2889 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2890
2891 llvm::StringRef text = text_strm.GetString();
2892
2893 uint32_t chars_left = max_columns;
2894
2895 auto nextWordLength = [](llvm::StringRef S) {
2896 size_t pos = S.find(' ');
2897 return pos == llvm::StringRef::npos ? S.size() : pos;
2898 };
2899
2900 while (!text.empty()) {
2901 if (text.front() == '\n' ||
2902 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2903 strm.EOL();
2904 strm.Indent();
2905 chars_left = max_columns - indent_size;
2906 if (text.front() == '\n')
2907 text = text.drop_front();
2908 else
2909 text = text.ltrim(' ');
2910 } else {
2911 strm.PutChar(text.front());
2912 --chars_left;
2913 text = text.drop_front();
2914 }
2915 }
2916
2917 strm.EOL();
2918 strm.IndentLess(indent_size);
2919}
2920
2922 llvm::StringRef search_word, StringList &commands_found,
2923 StringList &commands_help, const CommandObject::CommandMap &command_map) {
2924 for (const auto &pair : command_map) {
2925 llvm::StringRef command_name = pair.first;
2926 CommandObject *cmd_obj = pair.second.get();
2927
2928 const bool search_short_help = true;
2929 const bool search_long_help = false;
2930 const bool search_syntax = false;
2931 const bool search_options = false;
2932 if (command_name.contains_insensitive(search_word) ||
2933 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2934 search_long_help, search_syntax,
2935 search_options)) {
2936 commands_found.AppendString(command_name);
2937 commands_help.AppendString(cmd_obj->GetHelp());
2938 }
2939
2940 if (auto *multiword_cmd = cmd_obj->GetAsMultiwordCommand()) {
2941 StringList subcommands_found;
2942 FindCommandsForApropos(search_word, subcommands_found, commands_help,
2943 multiword_cmd->GetSubcommandDictionary());
2944 for (const auto &subcommand_name : subcommands_found) {
2945 std::string qualified_name =
2946 (command_name + " " + subcommand_name).str();
2947 commands_found.AppendString(qualified_name);
2948 }
2949 }
2950 }
2951}
2952
2953void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
2954 StringList &commands_found,
2955 StringList &commands_help,
2956 bool search_builtin_commands,
2957 bool search_user_commands,
2958 bool search_alias_commands,
2959 bool search_user_mw_commands) {
2960 CommandObject::CommandMap::const_iterator pos;
2961
2962 if (search_builtin_commands)
2963 FindCommandsForApropos(search_word, commands_found, commands_help,
2965
2966 if (search_user_commands)
2967 FindCommandsForApropos(search_word, commands_found, commands_help,
2968 m_user_dict);
2969
2970 if (search_user_mw_commands)
2971 FindCommandsForApropos(search_word, commands_found, commands_help,
2973
2974 if (search_alias_commands)
2975 FindCommandsForApropos(search_word, commands_found, commands_help,
2976 m_alias_dict);
2977}
2978
2980 return !m_overriden_exe_contexts.empty()
2983}
2984
2986 const ExecutionContext &override_context) {
2987 m_overriden_exe_contexts.push(override_context);
2988}
2989
2991 if (!m_overriden_exe_contexts.empty())
2993}
2994
2996 if (ProcessSP process_sp = GetExecutionContext().GetProcessSP())
2997 m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
2998 /*flush_stderr*/ true);
2999}
3000
3002 auto idle_state = CommandHandlingState::eIdle;
3003 if (m_command_state.compare_exchange_strong(
3006 else
3009}
3010
3013 if (--m_iohandler_nesting_level == 0) {
3014 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
3016 }
3017}
3018
3020 auto in_progress = CommandHandlingState::eInProgress;
3021 return m_command_state.compare_exchange_strong(
3023}
3024
3027 return false;
3028
3029 bool was_interrupted =
3031 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
3032 return was_interrupted;
3033}
3034
3036 llvm::StringRef str,
3037 bool is_stdout) {
3038
3039 lldb::StreamFileSP stream = is_stdout ? io_handler.GetOutputStreamFileSP()
3040 : io_handler.GetErrorStreamFileSP();
3041 // Split the output into lines and poll for interrupt requests
3042 bool had_output = !str.empty();
3043 while (!str.empty()) {
3044 llvm::StringRef line;
3045 std::tie(line, str) = str.split('\n');
3046 {
3047 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3048 stream->Write(line.data(), line.size());
3049 stream->Write("\n", 1);
3050 }
3051 }
3052
3053 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3054 if (had_output && INTERRUPT_REQUESTED(GetDebugger(),
3055 "Interrupted dumping command output"))
3056 stream->Printf("\n... Interrupted.\n");
3057 stream->Flush();
3058}
3059
3061 llvm::StringRef line, const Flags &io_handler_flags) const {
3062 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
3063 return false;
3064
3065 llvm::StringRef command = line.trim();
3066 if (command.empty())
3067 return true;
3068
3069 if (command.front() == m_comment_char)
3070 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
3071
3072 return true;
3073}
3074
3076 std::string &line) {
3077 // If we were interrupted, bail out...
3078 if (WasInterrupted())
3079 return;
3080
3081 const bool is_interactive = io_handler.GetIsInteractive();
3082 if (!is_interactive) {
3083 // When we are not interactive, don't execute blank lines. This will happen
3084 // sourcing a commands file. We don't want blank lines to repeat the
3085 // previous command and cause any errors to occur (like redefining an
3086 // alias, get an error and stop parsing the commands file).
3087 if (line.empty())
3088 return;
3089
3090 // When using a non-interactive file handle (like when sourcing commands
3091 // from a file) we need to echo the command out so we don't just see the
3092 // command output and no command...
3093 if (EchoCommandNonInteractive(line, io_handler.GetFlags())) {
3094 std::lock_guard<std::recursive_mutex> guard(io_handler.GetOutputMutex());
3095 io_handler.GetOutputStreamFileSP()->Printf(
3096 "%s%s\n", io_handler.GetPrompt(), line.c_str());
3097 }
3098 }
3099
3101
3103 bool pushed_exe_ctx = false;
3104 if (exe_ctx.HasTargetScope()) {
3105 OverrideExecutionContext(exe_ctx);
3106 pushed_exe_ctx = true;
3107 }
3108 auto finalize = llvm::make_scope_exit([this, pushed_exe_ctx]() {
3109 if (pushed_exe_ctx)
3111 });
3112
3114 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
3115
3116 // Now emit the command output text from the command we just executed
3117 if ((result.Succeeded() &&
3120 // Display any STDOUT/STDERR _prior_ to emitting the command result text
3122
3123 if (!result.GetImmediateOutputStream()) {
3124 llvm::StringRef output = result.GetOutputData();
3125 PrintCommandOutput(io_handler, output, true);
3126 }
3127
3128 // Now emit the command error text from the command we just executed
3129 if (!result.GetImmediateErrorStream()) {
3130 llvm::StringRef error = result.GetErrorData();
3131 PrintCommandOutput(io_handler, error, false);
3132 }
3133 }
3134
3136
3137 switch (result.GetStatus()) {
3142 break;
3143
3147 io_handler.SetIsDone(true);
3148 break;
3149
3152 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError)) {
3154 io_handler.SetIsDone(true);
3155 }
3156 break;
3157
3158 case eReturnStatusQuit:
3160 io_handler.SetIsDone(true);
3161 break;
3162 }
3163
3164 // Finally, if we're going to stop on crash, check that here:
3166 result.GetDidChangeProcessState() &&
3169 io_handler.SetIsDone(true);
3171 }
3172}
3173
3176 Process *process = exe_ctx.GetProcessPtr();
3177
3178 if (InterruptCommand())
3179 return true;
3180
3181 if (process) {
3182 StateType state = process->GetState();
3183 if (StateIsRunningState(state)) {
3184 process->Halt();
3185 return true; // Don't do any updating when we are running
3186 }
3187 }
3188
3189 ScriptInterpreter *script_interpreter =
3191 if (script_interpreter) {
3192 if (script_interpreter->Interrupt())
3193 return true;
3194 }
3195 return false;
3196}
3197
3199 CommandReturnObject &result, std::optional<std::string> output_file) {
3200 if (output_file == std::nullopt || output_file->empty()) {
3201 std::string now = llvm::to_string(std::chrono::system_clock::now());
3202 std::replace(now.begin(), now.end(), ' ', '_');
3203 const std::string file_name = "lldb_session_" + now + ".log";
3204
3205 FileSpec save_location = GetSaveSessionDirectory();
3206
3207 if (!save_location)
3208 save_location = HostInfo::GetGlobalTempDir();
3209
3210 FileSystem::Instance().Resolve(save_location);
3211 save_location.AppendPathComponent(file_name);
3212 output_file = save_location.GetPath();
3213 }
3214
3215 auto error_out = [&](llvm::StringRef error_message, std::string description) {
3216 LLDB_LOG(GetLog(LLDBLog::Commands), "{0} ({1}:{2})", error_message,
3217 output_file, description);
3219 "Failed to save session's transcripts to {0}!", *output_file);
3220 return false;
3221 };
3222
3226
3227 auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags);
3228
3229 if (!opened_file)
3230 return error_out("Unable to create file",
3231 llvm::toString(opened_file.takeError()));
3232
3233 FileUP file = std::move(opened_file.get());
3234
3235 size_t byte_size = m_transcript_stream.GetSize();
3236
3237 Status error = file->Write(m_transcript_stream.GetData(), byte_size);
3238
3239 if (error.Fail() || byte_size != m_transcript_stream.GetSize())
3240 return error_out("Unable to write to destination file",
3241 "Bytes written do not match transcript size.");
3242
3244 result.AppendMessageWithFormat("Session's transcripts saved to %s\n",
3245 output_file->c_str());
3246
3248 const FileSpec file_spec;
3249 error = file->GetFileSpec(const_cast<FileSpec &>(file_spec));
3250 if (error.Success()) {
3251 if (llvm::Error e = Host::OpenFileInExternalEditor(
3252 m_debugger.GetExternalEditor(), file_spec, 1))
3253 result.AppendError(llvm::toString(std::move(e)));
3254 }
3255 }
3256
3257 return true;
3258}
3259
3261 return (GetIOHandler() ? GetIOHandler()->GetIsInteractive() : false);
3262}
3263
3265 if (m_command_source_dirs.empty())
3266 return {};
3267 return m_command_source_dirs.back();
3268}
3269
3271 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3272 Debugger &debugger = GetDebugger();
3273 IOHandlerSP io_handler_sp(
3275 "lldb", // Name of input reader for history
3276 llvm::StringRef(prompt), // Prompt
3277 llvm::StringRef(), // Continuation prompt
3278 true, // Get multiple lines
3279 debugger.GetUseColor(),
3280 0, // Don't show line numbers
3281 delegate)); // IOHandlerDelegate
3282
3283 if (io_handler_sp) {
3284 io_handler_sp->SetUserData(baton);
3285 debugger.RunIOHandlerAsync(io_handler_sp);
3286 }
3287}
3288
3290 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
3291 Debugger &debugger = GetDebugger();
3292 IOHandlerSP io_handler_sp(
3294 "lldb-python", // Name of input reader for history
3295 llvm::StringRef(prompt), // Prompt
3296 llvm::StringRef(), // Continuation prompt
3297 true, // Get multiple lines
3298 debugger.GetUseColor(),
3299 0, // Don't show line numbers
3300 delegate)); // IOHandlerDelegate
3301
3302 if (io_handler_sp) {
3303 io_handler_sp->SetUserData(baton);
3304 debugger.RunIOHandlerAsync(io_handler_sp);
3305 }
3306}
3307
3310}
3311
3315 // Always re-create the IOHandlerEditline in case the input changed. The old
3316 // instance might have had a non-interactive input and now it does or vice
3317 // versa.
3318 if (force_create || !m_command_io_handler_sp) {
3319 // Always re-create the IOHandlerEditline in case the input changed. The
3320 // old instance might have had a non-interactive input and now it does or
3321 // vice versa.
3322 uint32_t flags = 0;
3323
3324 if (options) {
3325 if (options->m_stop_on_continue == eLazyBoolYes)
3327 if (options->m_stop_on_error == eLazyBoolYes)
3329 if (options->m_stop_on_crash == eLazyBoolYes)
3331 if (options->m_echo_commands != eLazyBoolNo)
3333 if (options->m_echo_comment_commands != eLazyBoolNo)
3335 if (options->m_print_results != eLazyBoolNo)
3337 if (options->m_print_errors != eLazyBoolNo)
3339 } else {
3342 }
3343
3344 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
3347 m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
3348 llvm::StringRef(), // Continuation prompt
3349 false, // Don't enable multiple line input, just single line commands
3351 0, // Don't show line numbers
3352 *this); // IOHandlerDelegate
3353 }
3355}
3356
3359 // Always re-create the command interpreter when we run it in case any file
3360 // handles have changed.
3361 bool force_create = true;
3362 m_debugger.RunIOHandlerAsync(GetIOHandler(force_create, &options));
3364
3365 if (options.GetAutoHandleEvents())
3367
3368 if (options.GetSpawnThread()) {
3370 } else {
3371 // If the current thread is not managed by a host thread, we won't detect
3372 // that this IS the CommandInterpreter IOHandler thread, so make it so:
3373 HostThread new_io_handler_thread(Host::GetCurrentThread());
3374 HostThread old_io_handler_thread =
3375 m_debugger.SetIOHandlerThread(new_io_handler_thread);
3377 m_debugger.SetIOHandlerThread(old_io_handler_thread);
3378
3379 if (options.GetAutoHandleEvents())
3381 }
3382
3383 return m_result;
3384}
3385
3388 CommandReturnObject &result) {
3389 std::string scratch_command(command_line); // working copy so we don't modify
3390 // command_line unless we succeed
3391 CommandObject *cmd_obj = nullptr;
3392 StreamString revised_command_line;
3393 bool wants_raw_input = false;
3394 std::string next_word;
3395 StringList matches;
3396 bool done = false;
3397 while (!done) {
3398 char quote_char = '\0';
3399 std::string suffix;
3400 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3401 if (cmd_obj == nullptr) {
3402 std::string full_name;
3403 bool is_alias = GetAliasFullName(next_word, full_name);
3404 cmd_obj = GetCommandObject(next_word, &matches);
3405 bool is_real_command =
3406 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
3407 if (!is_real_command) {
3408 matches.Clear();
3409 std::string alias_result;
3410 cmd_obj =
3411 BuildAliasResult(full_name, scratch_command, alias_result, result);
3412 revised_command_line.Printf("%s", alias_result.c_str());
3413 if (cmd_obj) {
3414 wants_raw_input = cmd_obj->WantsRawCommandString();
3415 }
3416 } else {
3417 if (cmd_obj) {
3418 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3419 revised_command_line.Printf("%s", cmd_name.str().c_str());
3420 wants_raw_input = cmd_obj->WantsRawCommandString();
3421 } else {
3422 revised_command_line.Printf("%s", next_word.c_str());
3423 }
3424 }
3425 } else {
3426 if (cmd_obj->IsMultiwordObject()) {
3427 CommandObject *sub_cmd_obj =
3428 cmd_obj->GetSubcommandObject(next_word.c_str());
3429 if (sub_cmd_obj) {
3430 // The subcommand's name includes the parent command's name, so
3431 // restart rather than append to the revised_command_line.
3432 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3433 revised_command_line.Clear();
3434 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3435 cmd_obj = sub_cmd_obj;
3436 wants_raw_input = cmd_obj->WantsRawCommandString();
3437 } else {
3438 if (quote_char)
3439 revised_command_line.Printf(" %c%s%s%c", quote_char,
3440 next_word.c_str(), suffix.c_str(),
3441 quote_char);
3442 else
3443 revised_command_line.Printf(" %s%s", next_word.c_str(),
3444 suffix.c_str());
3445 done = true;
3446 }
3447 } else {
3448 if (quote_char)
3449 revised_command_line.Printf(" %c%s%s%c", quote_char,
3450 next_word.c_str(), suffix.c_str(),
3451 quote_char);
3452 else
3453 revised_command_line.Printf(" %s%s", next_word.c_str(),
3454 suffix.c_str());
3455 done = true;
3456 }
3457 }
3458
3459 if (cmd_obj == nullptr) {
3460 const size_t num_matches = matches.GetSize();
3461 if (matches.GetSize() > 1) {
3462 StreamString error_msg;
3463 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3464 next_word.c_str());
3465
3466 for (uint32_t i = 0; i < num_matches; ++i) {
3467 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3468 }
3469 result.AppendRawError(error_msg.GetString());
3470 } else {
3471 // We didn't have only one match, otherwise we wouldn't get here.
3472 lldbassert(num_matches == 0);
3473 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3474 next_word.c_str());
3475 }
3476 return nullptr;
3477 }
3478
3479 if (cmd_obj->IsMultiwordObject()) {
3480 if (!suffix.empty()) {
3481 result.AppendErrorWithFormat(
3482 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3483 "might be invalid).\n",
3484 cmd_obj->GetCommandName().str().c_str(),
3485 next_word.empty() ? "" : next_word.c_str(),
3486 next_word.empty() ? " -- " : " ", suffix.c_str());
3487 return nullptr;
3488 }
3489 } else {
3490 // If we found a normal command, we are done
3491 done = true;
3492 if (!suffix.empty()) {
3493 switch (suffix[0]) {
3494 case '/':
3495 // GDB format suffixes
3496 {
3497 Options *command_options = cmd_obj->GetOptions();
3498 if (command_options &&
3499 command_options->SupportsLongOption("gdb-format")) {
3500 std::string gdb_format_option("--gdb-format=");
3501 gdb_format_option += (suffix.c_str() + 1);
3502
3503 std::string cmd = std::string(revised_command_line.GetString());
3504 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3505 if (arg_terminator_idx != std::string::npos) {
3506 // Insert the gdb format option before the "--" that terminates
3507 // options
3508 gdb_format_option.append(1, ' ');
3509 cmd.insert(arg_terminator_idx, gdb_format_option);
3510 revised_command_line.Clear();
3511 revised_command_line.PutCString(cmd);
3512 } else
3513 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3514
3515 if (wants_raw_input &&
3516 FindArgumentTerminator(cmd) == std::string::npos)
3517 revised_command_line.PutCString(" --");
3518 } else {
3519 result.AppendErrorWithFormat(
3520 "the '%s' command doesn't support the --gdb-format option\n",
3521 cmd_obj->GetCommandName().str().c_str());
3522 return nullptr;
3523 }
3524 }
3525 break;
3526
3527 default:
3528 result.AppendErrorWithFormat(
3529 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3530 return nullptr;
3531 }
3532 }
3533 }
3534 if (scratch_command.empty())
3535 done = true;
3536 }
3537
3538 if (!scratch_command.empty())
3539 revised_command_line.Printf(" %s", scratch_command.c_str());
3540
3541 if (cmd_obj != nullptr)
3542 command_line = std::string(revised_command_line.GetString());
3543
3544 return cmd_obj;
3545}
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:449
#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:243
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.
bool RemoveAlias(llvm::StringRef alias_name)
void SetSaveSessionDirectory(llvm::StringRef path)
void SourceInitFile(FileSpec file, CommandReturnObject &result)
CommandAlias * AddAlias(llvm::StringRef alias_name, lldb::CommandObjectSP &command_obj_sp, llvm::StringRef args_string=llvm::StringRef())
int GetCommandNamesMatchingPartialString(const char *cmd_cstr, bool include_aliases, StringList &matches, StringList &descriptions)
void FindCommandsForApropos(llvm::StringRef word, StringList &commands_found, StringList &commands_help, bool search_builtin_commands, bool search_user_commands, bool search_alias_commands, bool search_user_mw_commands)
CommandObject * GetCommandObject(llvm::StringRef cmd, StringList *matches=nullptr, StringList *descriptions=nullptr) const
std::atomic< CommandHandlingState > m_command_state
Status PreprocessCommand(std::string &command)
CommandObject::CommandMap m_alias_dict
CommandObject * ResolveCommandImpl(std::string &command_line, CommandReturnObject &result)
CommandObject::CommandMap m_command_dict
void HandleCompletion(CompletionRequest &request)
CommandInterpreterRunResult m_result
void ResolveCommand(const char *command_line, CommandReturnObject &result)
bool SetQuitExitCode(int exit_code)
Sets the exit code for the quit command.
CommandInterpreterRunResult RunCommandInterpreter(CommandInterpreterRunOptions &options)
bool HandleCommand(const char *command_line, LazyBool add_to_history, const ExecutionContext &override_context, CommandReturnObject &result)
CommandObject::CommandMap m_user_dict
ExecutionContext GetExecutionContext() const
const CommandObject::CommandMap & GetUserCommands() const
CommandObject * GetUserCommandObject(llvm::StringRef cmd, StringList *matches=nullptr, StringList *descriptions=nullptr) const
void SourceInitFileGlobal(CommandReturnObject &result)
bool GetAliasFullName(llvm::StringRef cmd, std::string &full_name) const
CommandObjectMultiword * VerifyUserMultiwordCmdPath(Args &path, bool leaf_is_command, Status &result)
Look up the command pointed to by path encoded in the arguments of the incoming command object.
void HandleCompletionMatches(CompletionRequest &request)
Status AddUserCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, bool can_replace)
bool AddCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, bool can_replace)
void PrintCommandOutput(IOHandler &io_handler, llvm::StringRef str, bool is_stdout)
bool AliasExists(llvm::StringRef cmd) const
Determine whether an alias command with this name exists.
int GetOptionArgumentPosition(const char *in_string)
Picks the number out of a string of the form "%NNN", otherwise return 0.
void GetHelp(CommandReturnObject &result, uint32_t types=eCommandTypesAllThem)
bool CommandExists(llvm::StringRef cmd) const
Determine whether a root level, built-in command with this name exists.
static ConstString & GetStaticBroadcasterClass()
bool SaveTranscript(CommandReturnObject &result, std::optional< std::string > output_file=std::nullopt)
Save the current debugger session transcript to a file on disk.
int GetQuitExitCode(bool &exited) const
Returns the exit code that the user has specified when running the 'quit' command.
lldb::PlatformSP GetPlatform(bool prefer_target_platform)
void GetPythonCommandsFromIOHandler(const char *prompt, IOHandlerDelegate &delegate, void *baton=nullptr)
lldb::CommandObjectSP GetCommandSPExact(llvm::StringRef cmd, bool include_aliases=false) const
CommandInterpreter(Debugger &debugger, bool synchronous_execution)
const CommandAlias * GetAlias(llvm::StringRef alias_name) const
bool RemoveUser(llvm::StringRef alias_name)
void GetLLDBCommandsFromIOHandler(const char *prompt, IOHandlerDelegate &delegate, void *baton=nullptr)
lldb::CommandObjectSP GetCommandSP(llvm::StringRef cmd, bool include_aliases=true, bool exact=true, StringList *matches=nullptr, StringList *descriptions=nullptr) const
void OutputHelpText(Stream &stream, llvm::StringRef command_word, llvm::StringRef separator, llvm::StringRef help_text, uint32_t max_word_len)
CommandObject * GetCommandObjectForCommand(llvm::StringRef &command_line)
Status PreprocessToken(std::string &token)
bool RemoveUserMultiword(llvm::StringRef multiword_name)
bool UserCommandExists(llvm::StringRef cmd) const
Determine whether a root-level user command with this name exists.
lldb::IOHandlerSP GetIOHandler(bool force_create=false, CommandInterpreterRunOptions *options=nullptr)
const CommandObject::CommandMap & GetUserMultiwordCommands() const
void BuildAliasCommandArgs(CommandObject *alias_cmd_obj, const char *alias_name, Args &cmd_args, std::string &raw_input_string, CommandReturnObject &result)
std::vector< uint32_t > m_command_source_flags
CommandObject * BuildAliasResult(llvm::StringRef alias_name, std::string &raw_input_string, std::string &alias_result, CommandReturnObject &result)
void OverrideExecutionContext(const ExecutionContext &override_context)
const char * ProcessEmbeddedScriptCommands(const char *arg)
void AllowExitCodeOnQuit(bool allow)
Specify if the command interpreter should allow that the user can specify a custom exit code when cal...
CommandObject::CommandMap m_user_mw_dict
void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context, const CommandInterpreterRunOptions &options, CommandReturnObject &result)
Execute a list of commands from a file.
void SourceInitFileCwd(CommandReturnObject &result)
std::vector< FileSpec > m_command_source_dirs
A stack of directory paths.
void HandleCommands(const StringList &commands, const ExecutionContext &context, const CommandInterpreterRunOptions &options, CommandReturnObject &result)
Execute a list of commands in sequence.
bool RemoveCommand(llvm::StringRef cmd, bool force=false)
Remove a command if it is removable (python or regex command).
Implements dwim-print, a printing command that chooses the most direct, efficient,...
lldb::CommandObjectSP GetSubcommandSPExact(llvm::StringRef sub_cmd) override
CommandObjectMultiword * GetAsMultiwordCommand() override
virtual bool WantsRawCommandString()=0
llvm::StringRef GetCommandName() const
bool HelpTextContainsWord(llvm::StringRef search_word, bool search_short_help=true, bool search_long_help=true, bool search_syntax=true, bool search_options=true)
virtual bool IsMultiwordObject()
virtual 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.
A uniqued constant string class.
Definition: ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:182
A class to manage flag bits.
Definition: Debugger.h:79
ExecutionContext GetSelectedExecutionContext()
Definition: Debugger.cpp:1039
bool StartEventHandlerThread()
Manually start the global event handler thread.
Definition: Debugger.cpp:1935
void StopEventHandlerThread()
Manually stop the debugger's default event handler.
Definition: Debugger.cpp:1975
void SetAsyncExecution(bool async)
Definition: Debugger.cpp:955
HostThread SetIOHandlerThread(HostThread &new_thread)
Definition: Debugger.cpp:2087
lldb::FileSP GetInputFileSP()
Definition: Debugger.h:141
bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp)
Definition: Debugger.cpp:1129
bool IsIOHandlerThreadCurrentThread() const
Definition: Debugger.cpp:2123
uint64_t GetTerminalWidth() const
Definition: Debugger.cpp:366
const char * GetIOHandlerCommandPrefix()
Definition: Debugger.cpp:1151
bool GetUseColor() const
Definition: Debugger.cpp:402
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, bool cancel_top_handler=true)
Run the given IO handler and return immediately.
Definition: Debugger.cpp:1163
lldb::StreamFileSP GetErrorStreamSP()
Definition: Debugger.h:145
bool GetAutoConfirm() const
Definition: Debugger.cpp:272
PlatformList & GetPlatformList()
Definition: Debugger.h:207
Target & GetDummyTarget()
Definition: Debugger.h:491
void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp)
Run the given IO handler and block until it's complete.
Definition: Debugger.cpp:1095
lldb::StreamFileSP GetOutputStreamSP()
Definition: Debugger.h:143
ScriptInterpreter * GetScriptInterpreter(bool can_create=true, std::optional< lldb::ScriptLanguage > language={})
Definition: Debugger.cpp:1632
llvm::StringRef GetExternalEditor() const
Definition: Debugger.cpp:391
File & GetOutputFile()
Definition: Debugger.h:149
llvm::StringRef GetPrompt() const
Definition: Debugger.cpp:305
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:1702
void SetUnwindOnError(bool unwind=false)
Definition: Target.h:332
void SetKeepInMemory(bool keep=true)
Definition: Target.h:342
void SetCoerceToId(bool coerce=true)
Definition: Target.h:328
void SetTryAllThreads(bool try_others=true)
Definition: Target.h:365
void SetTimeout(const Timeout< std::micro > &timeout)
Definition: Target.h:353
void SetIgnoreBreakpoints(bool ignore=false)
Definition: Target.h:336
"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:57
void AppendPathComponent(llvm::StringRef component)
Definition: FileSpec.cpp:450
const ConstString & GetFilename() const
Filename string const get accessor.
Definition: FileSpec.h:245
void MakeAbsolute(const FileSpec &dir)
Make the FileSpec absolute by treating it relative to dir.
Definition: FileSpec.cpp:533
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:370
FileSpec CopyByRemovingLastPathComponent() const
Definition: FileSpec.cpp:427
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:401
static const char * GetNameForLanguageType(lldb::LanguageType language)
Definition: Language.cpp:235
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:1032
A plug-in interface definition class for debugging a process.
Definition: Process.h:339
lldb::StateType GetState()
Get accessor for the current process state.
Definition: Process.cpp:1298
Status Halt(bool clear_thread_plans=false, bool use_run_lock=true)
Halts a running process.
Definition: Process.cpp:3143
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 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:130
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:107
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:63
size_t PutChar(char ch)
Definition: Stream.cpp:104
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:128
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:171
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition: Stream.cpp:168
void AppendString(const std::string &s)
Definition: StringList.cpp:43
const char * GetStringAtIndex(size_t idx) const
Definition: StringList.cpp:86
size_t GetSize() const
Definition: StringList.cpp:74
void DeleteStringAtIndex(size_t id)
Definition: StringList.cpp:147
LoadCWDlldbinitFile GetLoadCWDlldbinitFile() const
Definition: Target.cpp:4732
static TargetProperties & GetGlobalProperties()
Definition: Target.cpp:3057
lldb::PlatformSP GetPlatform()
Definition: Target.h:1431
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:2657
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:375
std::shared_ptr< lldb_private::IOHandler > IOHandlerSP
Definition: lldb-forward.h:349
std::shared_ptr< lldb_private::CommandObject > CommandObjectSP
Definition: lldb-forward.h:321
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:467
std::unique_ptr< lldb_private::File > FileUP
Definition: lldb-forward.h:340
@ 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:463
std::shared_ptr< lldb_private::Platform > PlatformSP
Definition: lldb-forward.h:376
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:377
std::shared_ptr< lldb_private::Event > EventSP
Definition: lldb-forward.h:333
@ eReturnStatusStarted
@ eReturnStatusSuccessContinuingResult
@ eReturnStatusFailed
@ eReturnStatusSuccessContinuingNoResult
@ eReturnStatusQuit
@ eReturnStatusSuccessFinishResult
@ eReturnStatusInvalid
@ eReturnStatusSuccessFinishNoResult
std::shared_ptr< lldb_private::StreamFile > StreamFileSP
Definition: lldb-forward.h:417
std::shared_ptr< lldb_private::StopInfo > StopInfoSP
Definition: lldb-forward.h:415
StopReason
Thread stop reasons.
@ eStopReasonInstrumentation
@ eStopReasonProcessorTrace
@ eStopReasonException
@ eStopReasonSignal
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:432
std::shared_ptr< lldb_private::File > FileSP
Definition: lldb-forward.h:341
const char * c_str() const
Definition: Args.h:49
llvm::StringRef ref() const
Definition: Args.h:48
char GetQuoteChar() const
Definition: Args.h:53
A SmallBitVector that represents a set of source languages (lldb::LanguageType).
Definition: TypeSystem.h:51
std::optional< lldb::LanguageType > GetSingularLanguage()
If the set contains a single language only, return it.
Definition: TypeSystem.cpp:28