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