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