1 //===-- CommandInterpreter.cpp ----------------------------------*- C++ -*-===//
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 <memory>
10 #include <stdlib.h>
11 #include <string>
12 #include <vector>
13
14 #include "CommandObjectScript.h"
15 #include "lldb/Interpreter/CommandObjectRegexCommand.h"
16
17 #include "Commands/CommandObjectApropos.h"
18 #include "Commands/CommandObjectBreakpoint.h"
19 #include "Commands/CommandObjectCommands.h"
20 #include "Commands/CommandObjectDisassemble.h"
21 #include "Commands/CommandObjectExpression.h"
22 #include "Commands/CommandObjectFrame.h"
23 #include "Commands/CommandObjectGUI.h"
24 #include "Commands/CommandObjectHelp.h"
25 #include "Commands/CommandObjectLanguage.h"
26 #include "Commands/CommandObjectLog.h"
27 #include "Commands/CommandObjectMemory.h"
28 #include "Commands/CommandObjectPlatform.h"
29 #include "Commands/CommandObjectPlugin.h"
30 #include "Commands/CommandObjectProcess.h"
31 #include "Commands/CommandObjectQuit.h"
32 #include "Commands/CommandObjectRegister.h"
33 #include "Commands/CommandObjectReproducer.h"
34 #include "Commands/CommandObjectSettings.h"
35 #include "Commands/CommandObjectSource.h"
36 #include "Commands/CommandObjectStats.h"
37 #include "Commands/CommandObjectTarget.h"
38 #include "Commands/CommandObjectThread.h"
39 #include "Commands/CommandObjectType.h"
40 #include "Commands/CommandObjectVersion.h"
41 #include "Commands/CommandObjectWatchpoint.h"
42
43 #include "lldb/Core/Debugger.h"
44 #include "lldb/Core/PluginManager.h"
45 #include "lldb/Core/StreamFile.h"
46 #include "lldb/Utility/Log.h"
47 #include "lldb/Utility/State.h"
48 #include "lldb/Utility/Stream.h"
49 #include "lldb/Utility/Timer.h"
50
51 #include "lldb/Host/Config.h"
52 #if LLDB_ENABLE_LIBEDIT
53 #include "lldb/Host/Editline.h"
54 #endif
55 #include "lldb/Host/Host.h"
56 #include "lldb/Host/HostInfo.h"
57
58 #include "lldb/Interpreter/CommandCompletions.h"
59 #include "lldb/Interpreter/CommandInterpreter.h"
60 #include "lldb/Interpreter/CommandReturnObject.h"
61 #include "lldb/Interpreter/OptionValueProperties.h"
62 #include "lldb/Interpreter/Options.h"
63 #include "lldb/Interpreter/Property.h"
64 #include "lldb/Utility/Args.h"
65
66 #include "lldb/Target/Process.h"
67 #include "lldb/Target/StopInfo.h"
68 #include "lldb/Target/TargetList.h"
69 #include "lldb/Target/Thread.h"
70 #include "lldb/Target/UnixSignals.h"
71
72 #include "llvm/ADT/STLExtras.h"
73 #include "llvm/ADT/SmallString.h"
74 #include "llvm/Support/FormatAdapters.h"
75 #include "llvm/Support/Path.h"
76 #include "llvm/Support/PrettyStackTrace.h"
77
78 using namespace lldb;
79 using namespace lldb_private;
80
81 static const char *k_white_space = " \t\v";
82
83 static constexpr const char *InitFileWarning =
84 "There is a .lldbinit file in the current directory which is not being "
85 "read.\n"
86 "To silence this warning without sourcing in the local .lldbinit,\n"
87 "add the following to the lldbinit file in your home directory:\n"
88 " settings set target.load-cwd-lldbinit false\n"
89 "To allow lldb to source .lldbinit files in the current working "
90 "directory,\n"
91 "set the value of this variable to true. Only do so if you understand "
92 "and\n"
93 "accept the security risk.";
94
95 #define LLDB_PROPERTIES_interpreter
96 #include "InterpreterProperties.inc"
97
98 enum {
99 #define LLDB_PROPERTIES_interpreter
100 #include "InterpreterPropertiesEnum.inc"
101 };
102
GetStaticBroadcasterClass()103 ConstString &CommandInterpreter::GetStaticBroadcasterClass() {
104 static ConstString class_name("lldb.commandInterpreter");
105 return class_name;
106 }
107
CommandInterpreter(Debugger & debugger,bool synchronous_execution)108 CommandInterpreter::CommandInterpreter(Debugger &debugger,
109 bool synchronous_execution)
110 : Broadcaster(debugger.GetBroadcasterManager(),
111 CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
112 Properties(OptionValuePropertiesSP(
113 new OptionValueProperties(ConstString("interpreter")))),
114 IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
115 m_debugger(debugger), m_synchronous_execution(true),
116 m_skip_lldbinit_files(false), m_skip_app_init_files(false),
117 m_command_io_handler_sp(), m_comment_char('#'),
118 m_batch_command_mode(false), m_truncation_warning(eNoTruncation),
119 m_command_source_depth(0), m_num_errors(0), m_quit_requested(false),
120 m_stopped_for_crash(false) {
121 SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
122 SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
123 SetEventName(eBroadcastBitQuitCommandReceived, "quit");
124 SetSynchronous(synchronous_execution);
125 CheckInWithManager();
126 m_collection_sp->Initialize(g_interpreter_properties);
127 }
128
GetExpandRegexAliases() const129 bool CommandInterpreter::GetExpandRegexAliases() const {
130 const uint32_t idx = ePropertyExpandRegexAliases;
131 return m_collection_sp->GetPropertyAtIndexAsBoolean(
132 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
133 }
134
GetPromptOnQuit() const135 bool CommandInterpreter::GetPromptOnQuit() const {
136 const uint32_t idx = ePropertyPromptOnQuit;
137 return m_collection_sp->GetPropertyAtIndexAsBoolean(
138 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
139 }
140
SetPromptOnQuit(bool enable)141 void CommandInterpreter::SetPromptOnQuit(bool enable) {
142 const uint32_t idx = ePropertyPromptOnQuit;
143 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
144 }
145
GetEchoCommands() const146 bool CommandInterpreter::GetEchoCommands() const {
147 const uint32_t idx = ePropertyEchoCommands;
148 return m_collection_sp->GetPropertyAtIndexAsBoolean(
149 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
150 }
151
SetEchoCommands(bool enable)152 void CommandInterpreter::SetEchoCommands(bool enable) {
153 const uint32_t idx = ePropertyEchoCommands;
154 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
155 }
156
GetEchoCommentCommands() const157 bool CommandInterpreter::GetEchoCommentCommands() const {
158 const uint32_t idx = ePropertyEchoCommentCommands;
159 return m_collection_sp->GetPropertyAtIndexAsBoolean(
160 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
161 }
162
SetEchoCommentCommands(bool enable)163 void CommandInterpreter::SetEchoCommentCommands(bool enable) {
164 const uint32_t idx = ePropertyEchoCommentCommands;
165 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable);
166 }
167
AllowExitCodeOnQuit(bool allow)168 void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
169 m_allow_exit_code = allow;
170 if (!allow)
171 m_quit_exit_code.reset();
172 }
173
SetQuitExitCode(int exit_code)174 bool CommandInterpreter::SetQuitExitCode(int exit_code) {
175 if (!m_allow_exit_code)
176 return false;
177 m_quit_exit_code = exit_code;
178 return true;
179 }
180
GetQuitExitCode(bool & exited) const181 int CommandInterpreter::GetQuitExitCode(bool &exited) const {
182 exited = m_quit_exit_code.hasValue();
183 if (exited)
184 return *m_quit_exit_code;
185 return 0;
186 }
187
ResolveCommand(const char * command_line,CommandReturnObject & result)188 void CommandInterpreter::ResolveCommand(const char *command_line,
189 CommandReturnObject &result) {
190 std::string command = command_line;
191 if (ResolveCommandImpl(command, result) != nullptr) {
192 result.AppendMessageWithFormat("%s", command.c_str());
193 result.SetStatus(eReturnStatusSuccessFinishResult);
194 }
195 }
196
GetStopCmdSourceOnError() const197 bool CommandInterpreter::GetStopCmdSourceOnError() const {
198 const uint32_t idx = ePropertyStopCmdSourceOnError;
199 return m_collection_sp->GetPropertyAtIndexAsBoolean(
200 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
201 }
202
GetSpaceReplPrompts() const203 bool CommandInterpreter::GetSpaceReplPrompts() const {
204 const uint32_t idx = ePropertySpaceReplPrompts;
205 return m_collection_sp->GetPropertyAtIndexAsBoolean(
206 nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0);
207 }
208
Initialize()209 void CommandInterpreter::Initialize() {
210 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
211 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
212
213 CommandReturnObject result;
214
215 LoadCommandDictionary();
216
217 // An alias arguments vector to reuse - reset it before use...
218 OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
219
220 // Set up some initial aliases.
221 CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit", false);
222 if (cmd_obj_sp) {
223 AddAlias("q", cmd_obj_sp);
224 AddAlias("exit", cmd_obj_sp);
225 }
226
227 cmd_obj_sp = GetCommandSPExact("_regexp-attach", false);
228 if (cmd_obj_sp)
229 AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
230
231 cmd_obj_sp = GetCommandSPExact("process detach", false);
232 if (cmd_obj_sp) {
233 AddAlias("detach", cmd_obj_sp);
234 }
235
236 cmd_obj_sp = GetCommandSPExact("process continue", false);
237 if (cmd_obj_sp) {
238 AddAlias("c", cmd_obj_sp);
239 AddAlias("continue", cmd_obj_sp);
240 }
241
242 cmd_obj_sp = GetCommandSPExact("_regexp-break", false);
243 if (cmd_obj_sp)
244 AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
245
246 cmd_obj_sp = GetCommandSPExact("_regexp-tbreak", false);
247 if (cmd_obj_sp)
248 AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
249
250 cmd_obj_sp = GetCommandSPExact("thread step-inst", false);
251 if (cmd_obj_sp) {
252 AddAlias("stepi", cmd_obj_sp);
253 AddAlias("si", cmd_obj_sp);
254 }
255
256 cmd_obj_sp = GetCommandSPExact("thread step-inst-over", false);
257 if (cmd_obj_sp) {
258 AddAlias("nexti", cmd_obj_sp);
259 AddAlias("ni", cmd_obj_sp);
260 }
261
262 cmd_obj_sp = GetCommandSPExact("thread step-in", false);
263 if (cmd_obj_sp) {
264 AddAlias("s", cmd_obj_sp);
265 AddAlias("step", cmd_obj_sp);
266 CommandAlias *sif_alias = AddAlias(
267 "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
268 if (sif_alias) {
269 sif_alias->SetHelp("Step through the current block, stopping if you step "
270 "directly into a function whose name matches the "
271 "TargetFunctionName.");
272 sif_alias->SetSyntax("sif <TargetFunctionName>");
273 }
274 }
275
276 cmd_obj_sp = GetCommandSPExact("thread step-over", false);
277 if (cmd_obj_sp) {
278 AddAlias("n", cmd_obj_sp);
279 AddAlias("next", cmd_obj_sp);
280 }
281
282 cmd_obj_sp = GetCommandSPExact("thread step-out", false);
283 if (cmd_obj_sp) {
284 AddAlias("finish", cmd_obj_sp);
285 }
286
287 cmd_obj_sp = GetCommandSPExact("frame select", false);
288 if (cmd_obj_sp) {
289 AddAlias("f", cmd_obj_sp);
290 }
291
292 cmd_obj_sp = GetCommandSPExact("thread select", false);
293 if (cmd_obj_sp) {
294 AddAlias("t", cmd_obj_sp);
295 }
296
297 cmd_obj_sp = GetCommandSPExact("_regexp-jump", false);
298 if (cmd_obj_sp) {
299 AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
300 AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
301 }
302
303 cmd_obj_sp = GetCommandSPExact("_regexp-list", false);
304 if (cmd_obj_sp) {
305 AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
306 AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
307 }
308
309 cmd_obj_sp = GetCommandSPExact("_regexp-env", false);
310 if (cmd_obj_sp)
311 AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
312
313 cmd_obj_sp = GetCommandSPExact("memory read", false);
314 if (cmd_obj_sp)
315 AddAlias("x", cmd_obj_sp);
316
317 cmd_obj_sp = GetCommandSPExact("_regexp-up", false);
318 if (cmd_obj_sp)
319 AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
320
321 cmd_obj_sp = GetCommandSPExact("_regexp-down", false);
322 if (cmd_obj_sp)
323 AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
324
325 cmd_obj_sp = GetCommandSPExact("_regexp-display", false);
326 if (cmd_obj_sp)
327 AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
328
329 cmd_obj_sp = GetCommandSPExact("disassemble", false);
330 if (cmd_obj_sp)
331 AddAlias("dis", cmd_obj_sp);
332
333 cmd_obj_sp = GetCommandSPExact("disassemble", false);
334 if (cmd_obj_sp)
335 AddAlias("di", cmd_obj_sp);
336
337 cmd_obj_sp = GetCommandSPExact("_regexp-undisplay", false);
338 if (cmd_obj_sp)
339 AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
340
341 cmd_obj_sp = GetCommandSPExact("_regexp-bt", false);
342 if (cmd_obj_sp)
343 AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
344
345 cmd_obj_sp = GetCommandSPExact("target create", false);
346 if (cmd_obj_sp)
347 AddAlias("file", cmd_obj_sp);
348
349 cmd_obj_sp = GetCommandSPExact("target modules", false);
350 if (cmd_obj_sp)
351 AddAlias("image", cmd_obj_sp);
352
353 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
354
355 cmd_obj_sp = GetCommandSPExact("expression", false);
356 if (cmd_obj_sp) {
357 AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
358 AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
359 AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
360 if (auto po = AddAlias("po", cmd_obj_sp, "-O --")) {
361 po->SetHelp("Evaluate an expression on the current thread. Displays any "
362 "returned value with formatting "
363 "controlled by the type's author.");
364 po->SetHelpLong("");
365 }
366 CommandAlias *parray_alias =
367 AddAlias("parray", cmd_obj_sp, "--element-count %1 --");
368 if (parray_alias) {
369 parray_alias->SetHelp
370 ("parray <COUNT> <EXPRESSION> -- lldb will evaluate EXPRESSION "
371 "to get a typed-pointer-to-an-array in memory, and will display "
372 "COUNT elements of that type from the array.");
373 parray_alias->SetHelpLong("");
374 }
375 CommandAlias *poarray_alias = AddAlias("poarray", cmd_obj_sp,
376 "--object-description --element-count %1 --");
377 if (poarray_alias) {
378 poarray_alias->SetHelp("poarray <COUNT> <EXPRESSION> -- lldb will "
379 "evaluate EXPRESSION to get the address of an array of COUNT "
380 "objects in memory, and will call po on them.");
381 poarray_alias->SetHelpLong("");
382 }
383 }
384
385 cmd_obj_sp = GetCommandSPExact("process kill", false);
386 if (cmd_obj_sp) {
387 AddAlias("kill", cmd_obj_sp);
388 }
389
390 cmd_obj_sp = GetCommandSPExact("process launch", false);
391 if (cmd_obj_sp) {
392 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
393 #if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
394 AddAlias("r", cmd_obj_sp, "--");
395 AddAlias("run", cmd_obj_sp, "--");
396 #else
397 #if defined(__APPLE__)
398 std::string shell_option;
399 shell_option.append("--shell-expand-args");
400 shell_option.append(" true");
401 shell_option.append(" --");
402 AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
403 AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
404 #else
405 StreamString defaultshell;
406 defaultshell.Printf("--shell=%s --",
407 HostInfo::GetDefaultShell().GetPath().c_str());
408 AddAlias("r", cmd_obj_sp, defaultshell.GetString());
409 AddAlias("run", cmd_obj_sp, defaultshell.GetString());
410 #endif
411 #endif
412 }
413
414 cmd_obj_sp = GetCommandSPExact("target symbols add", false);
415 if (cmd_obj_sp) {
416 AddAlias("add-dsym", cmd_obj_sp);
417 }
418
419 cmd_obj_sp = GetCommandSPExact("breakpoint set", false);
420 if (cmd_obj_sp) {
421 AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
422 }
423
424 cmd_obj_sp = GetCommandSPExact("frame variable", false);
425 if (cmd_obj_sp) {
426 AddAlias("v", cmd_obj_sp);
427 AddAlias("var", cmd_obj_sp);
428 AddAlias("vo", cmd_obj_sp, "--object-description");
429 }
430
431 cmd_obj_sp = GetCommandSPExact("register", false);
432 if (cmd_obj_sp) {
433 AddAlias("re", cmd_obj_sp);
434 }
435 }
436
Clear()437 void CommandInterpreter::Clear() {
438 m_command_io_handler_sp.reset();
439 }
440
ProcessEmbeddedScriptCommands(const char * arg)441 const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
442 // This function has not yet been implemented.
443
444 // Look for any embedded script command
445 // If found,
446 // get interpreter object from the command dictionary,
447 // call execute_one_command on it,
448 // get the results as a string,
449 // substitute that string for current stuff.
450
451 return arg;
452 }
453
LoadCommandDictionary()454 void CommandInterpreter::LoadCommandDictionary() {
455 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
456 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
457
458 lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage();
459
460 m_command_dict["apropos"] = CommandObjectSP(new CommandObjectApropos(*this));
461 m_command_dict["breakpoint"] =
462 CommandObjectSP(new CommandObjectMultiwordBreakpoint(*this));
463 m_command_dict["command"] =
464 CommandObjectSP(new CommandObjectMultiwordCommands(*this));
465 m_command_dict["disassemble"] =
466 CommandObjectSP(new CommandObjectDisassemble(*this));
467 m_command_dict["expression"] =
468 CommandObjectSP(new CommandObjectExpression(*this));
469 m_command_dict["frame"] =
470 CommandObjectSP(new CommandObjectMultiwordFrame(*this));
471 m_command_dict["gui"] = CommandObjectSP(new CommandObjectGUI(*this));
472 m_command_dict["help"] = CommandObjectSP(new CommandObjectHelp(*this));
473 m_command_dict["log"] = CommandObjectSP(new CommandObjectLog(*this));
474 m_command_dict["memory"] = CommandObjectSP(new CommandObjectMemory(*this));
475 m_command_dict["platform"] =
476 CommandObjectSP(new CommandObjectPlatform(*this));
477 m_command_dict["plugin"] = CommandObjectSP(new CommandObjectPlugin(*this));
478 m_command_dict["process"] =
479 CommandObjectSP(new CommandObjectMultiwordProcess(*this));
480 m_command_dict["quit"] = CommandObjectSP(new CommandObjectQuit(*this));
481 m_command_dict["register"] =
482 CommandObjectSP(new CommandObjectRegister(*this));
483 m_command_dict["reproducer"] =
484 CommandObjectSP(new CommandObjectReproducer(*this));
485 m_command_dict["script"] =
486 CommandObjectSP(new CommandObjectScript(*this, script_language));
487 m_command_dict["settings"] =
488 CommandObjectSP(new CommandObjectMultiwordSettings(*this));
489 m_command_dict["source"] =
490 CommandObjectSP(new CommandObjectMultiwordSource(*this));
491 m_command_dict["statistics"] = CommandObjectSP(new CommandObjectStats(*this));
492 m_command_dict["target"] =
493 CommandObjectSP(new CommandObjectMultiwordTarget(*this));
494 m_command_dict["thread"] =
495 CommandObjectSP(new CommandObjectMultiwordThread(*this));
496 m_command_dict["type"] = CommandObjectSP(new CommandObjectType(*this));
497 m_command_dict["version"] = CommandObjectSP(new CommandObjectVersion(*this));
498 m_command_dict["watchpoint"] =
499 CommandObjectSP(new CommandObjectMultiwordWatchpoint(*this));
500 m_command_dict["language"] =
501 CommandObjectSP(new CommandObjectLanguage(*this));
502
503 const char *break_regexes[][2] = {
504 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
505 "breakpoint set --file '%1' --line %2"},
506 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
507 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
508 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
509 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
510 "breakpoint set --name '%1'"},
511 {"^(-.*)$", "breakpoint set %1"},
512 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
513 "breakpoint set --name '%2' --shlib '%1'"},
514 {"^\\&(.*[^[:space:]])[[:space:]]*$",
515 "breakpoint set --name '%1' --skip-prologue=0"},
516 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
517 "breakpoint set --name '%1'"}};
518
519 size_t num_regexes = llvm::array_lengthof(break_regexes);
520
521 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
522 new CommandObjectRegexCommand(
523 *this, "_regexp-break",
524 "Set a breakpoint using one of several shorthand formats.",
525 "\n"
526 "_regexp-break <filename>:<linenum>\n"
527 " main.c:12 // Break at line 12 of "
528 "main.c\n\n"
529 "_regexp-break <linenum>\n"
530 " 12 // Break at line 12 of current "
531 "file\n\n"
532 "_regexp-break 0x<address>\n"
533 " 0x1234000 // Break at address "
534 "0x1234000\n\n"
535 "_regexp-break <name>\n"
536 " main // Break in 'main' after the "
537 "prologue\n\n"
538 "_regexp-break &<name>\n"
539 " &main // Break at first instruction "
540 "in 'main'\n\n"
541 "_regexp-break <module>`<name>\n"
542 " libc.so`malloc // Break in 'malloc' from "
543 "'libc.so'\n\n"
544 "_regexp-break /<source-regex>/\n"
545 " /break here/ // Break on source lines in "
546 "current file\n"
547 " // containing text 'break "
548 "here'.\n",
549 2,
550 CommandCompletions::eSymbolCompletion |
551 CommandCompletions::eSourceFileCompletion,
552 false));
553
554 if (break_regex_cmd_up) {
555 bool success = true;
556 for (size_t i = 0; i < num_regexes; i++) {
557 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
558 break_regexes[i][1]);
559 if (!success)
560 break;
561 }
562 success =
563 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
564
565 if (success) {
566 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
567 m_command_dict[break_regex_cmd_sp->GetCommandName()] = break_regex_cmd_sp;
568 }
569 }
570
571 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
572 new CommandObjectRegexCommand(
573 *this, "_regexp-tbreak",
574 "Set a one-shot breakpoint using one of several shorthand formats.",
575 "\n"
576 "_regexp-break <filename>:<linenum>\n"
577 " main.c:12 // Break at line 12 of "
578 "main.c\n\n"
579 "_regexp-break <linenum>\n"
580 " 12 // Break at line 12 of current "
581 "file\n\n"
582 "_regexp-break 0x<address>\n"
583 " 0x1234000 // Break at address "
584 "0x1234000\n\n"
585 "_regexp-break <name>\n"
586 " main // Break in 'main' after the "
587 "prologue\n\n"
588 "_regexp-break &<name>\n"
589 " &main // Break at first instruction "
590 "in 'main'\n\n"
591 "_regexp-break <module>`<name>\n"
592 " libc.so`malloc // Break in 'malloc' from "
593 "'libc.so'\n\n"
594 "_regexp-break /<source-regex>/\n"
595 " /break here/ // Break on source lines in "
596 "current file\n"
597 " // containing text 'break "
598 "here'.\n",
599 2,
600 CommandCompletions::eSymbolCompletion |
601 CommandCompletions::eSourceFileCompletion,
602 false));
603
604 if (tbreak_regex_cmd_up) {
605 bool success = true;
606 for (size_t i = 0; i < num_regexes; i++) {
607 // If you add a resultant command string longer than 1024 characters be
608 // sure to increase the size of this buffer.
609 char buffer[1024];
610 int num_printed =
611 snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o 1");
612 lldbassert(num_printed < 1024);
613 UNUSED_IF_ASSERT_DISABLED(num_printed);
614 success =
615 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], buffer);
616 if (!success)
617 break;
618 }
619 success =
620 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
621
622 if (success) {
623 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
624 m_command_dict[tbreak_regex_cmd_sp->GetCommandName()] =
625 tbreak_regex_cmd_sp;
626 }
627 }
628
629 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
630 new CommandObjectRegexCommand(
631 *this, "_regexp-attach", "Attach to process by ID or name.",
632 "_regexp-attach <pid> | <process-name>", 2, 0, false));
633 if (attach_regex_cmd_up) {
634 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
635 "process attach --pid %1") &&
636 attach_regex_cmd_up->AddRegexCommand(
637 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
638 // specified get passed to
639 // 'process attach'
640 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
641 "process attach --name '%1'") &&
642 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
643 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
644 m_command_dict[attach_regex_cmd_sp->GetCommandName()] =
645 attach_regex_cmd_sp;
646 }
647 }
648
649 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
650 new CommandObjectRegexCommand(*this, "_regexp-down",
651 "Select a newer stack frame. Defaults to "
652 "moving one frame, a numeric argument can "
653 "specify an arbitrary number.",
654 "_regexp-down [<count>]", 2, 0, false));
655 if (down_regex_cmd_up) {
656 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
657 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
658 "frame select -r -%1")) {
659 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
660 m_command_dict[down_regex_cmd_sp->GetCommandName()] = down_regex_cmd_sp;
661 }
662 }
663
664 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
665 new CommandObjectRegexCommand(
666 *this, "_regexp-up",
667 "Select an older stack frame. Defaults to moving one "
668 "frame, a numeric argument can specify an arbitrary number.",
669 "_regexp-up [<count>]", 2, 0, false));
670 if (up_regex_cmd_up) {
671 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
672 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
673 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
674 m_command_dict[up_regex_cmd_sp->GetCommandName()] = up_regex_cmd_sp;
675 }
676 }
677
678 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
679 new CommandObjectRegexCommand(
680 *this, "_regexp-display",
681 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
682 "_regexp-display expression", 2, 0, false));
683 if (display_regex_cmd_up) {
684 if (display_regex_cmd_up->AddRegexCommand(
685 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
686 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
687 m_command_dict[display_regex_cmd_sp->GetCommandName()] =
688 display_regex_cmd_sp;
689 }
690 }
691
692 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
693 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
694 "Stop displaying expression at every "
695 "stop (specified by stop-hook index.)",
696 "_regexp-undisplay stop-hook-number", 2, 0,
697 false));
698 if (undisplay_regex_cmd_up) {
699 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
700 "target stop-hook delete %1")) {
701 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
702 m_command_dict[undisplay_regex_cmd_sp->GetCommandName()] =
703 undisplay_regex_cmd_sp;
704 }
705 }
706
707 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
708 new CommandObjectRegexCommand(
709 *this, "gdb-remote",
710 "Connect to a process via remote GDB server. "
711 "If no host is specifed, localhost is assumed.",
712 "gdb-remote [<hostname>:]<portnum>", 2, 0, false));
713 if (connect_gdb_remote_cmd_up) {
714 if (connect_gdb_remote_cmd_up->AddRegexCommand(
715 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
716 "process connect --plugin gdb-remote connect://%1:%2") &&
717 connect_gdb_remote_cmd_up->AddRegexCommand(
718 "^([[:digit:]]+)$",
719 "process connect --plugin gdb-remote connect://localhost:%1")) {
720 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
721 m_command_dict[command_sp->GetCommandName()] = command_sp;
722 }
723 }
724
725 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
726 new CommandObjectRegexCommand(
727 *this, "kdp-remote",
728 "Connect to a process via remote KDP server. "
729 "If no UDP port is specified, port 41139 is "
730 "assumed.",
731 "kdp-remote <hostname>[:<portnum>]", 2, 0, false));
732 if (connect_kdp_remote_cmd_up) {
733 if (connect_kdp_remote_cmd_up->AddRegexCommand(
734 "^([^:]+:[[:digit:]]+)$",
735 "process connect --plugin kdp-remote udp://%1") &&
736 connect_kdp_remote_cmd_up->AddRegexCommand(
737 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
738 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
739 m_command_dict[command_sp->GetCommandName()] = command_sp;
740 }
741 }
742
743 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
744 new CommandObjectRegexCommand(
745 *this, "_regexp-bt",
746 "Show the current thread's call stack. Any numeric argument "
747 "displays at most that many "
748 "frames. The argument 'all' displays all threads. Use 'settings"
749 " set frame-format' to customize the printing of individual frames "
750 "and 'settings set thread-format' to customize the thread header.",
751 "bt [<digit> | all]", 2, 0, false));
752 if (bt_regex_cmd_up) {
753 // accept but don't document "bt -c <number>" -- before bt was a regex
754 // command if you wanted to backtrace three frames you would do "bt -c 3"
755 // but the intention is to have this emulate the gdb "bt" command and so
756 // now "bt 3" is the preferred form, in line with gdb.
757 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
758 "thread backtrace -c %1") &&
759 bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
760 "thread backtrace -c %1") &&
761 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
762 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
763 CommandObjectSP command_sp(bt_regex_cmd_up.release());
764 m_command_dict[command_sp->GetCommandName()] = command_sp;
765 }
766 }
767
768 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
769 new CommandObjectRegexCommand(
770 *this, "_regexp-list",
771 "List relevant source code using one of several shorthand formats.",
772 "\n"
773 "_regexp-list <file>:<line> // List around specific file/line\n"
774 "_regexp-list <line> // List current file around specified "
775 "line\n"
776 "_regexp-list <function-name> // List specified function\n"
777 "_regexp-list 0x<address> // List around specified address\n"
778 "_regexp-list -[<count>] // List previous <count> lines\n"
779 "_regexp-list // List subsequent lines",
780 2, CommandCompletions::eSourceFileCompletion, false));
781 if (list_regex_cmd_up) {
782 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
783 "source list --line %1") &&
784 list_regex_cmd_up->AddRegexCommand(
785 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
786 "]*$",
787 "source list --file '%1' --line %2") &&
788 list_regex_cmd_up->AddRegexCommand(
789 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
790 "source list --address %1") &&
791 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
792 "source list --reverse") &&
793 list_regex_cmd_up->AddRegexCommand(
794 "^-([[:digit:]]+)[[:space:]]*$",
795 "source list --reverse --count %1") &&
796 list_regex_cmd_up->AddRegexCommand("^(.+)$",
797 "source list --name \"%1\"") &&
798 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
799 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
800 m_command_dict[list_regex_cmd_sp->GetCommandName()] = list_regex_cmd_sp;
801 }
802 }
803
804 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
805 new CommandObjectRegexCommand(
806 *this, "_regexp-env",
807 "Shorthand for viewing and setting environment variables.",
808 "\n"
809 "_regexp-env // Show environment\n"
810 "_regexp-env <name>=<value> // Set an environment variable",
811 2, 0, false));
812 if (env_regex_cmd_up) {
813 if (env_regex_cmd_up->AddRegexCommand("^$",
814 "settings show target.env-vars") &&
815 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
816 "settings set target.env-vars %1")) {
817 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
818 m_command_dict[env_regex_cmd_sp->GetCommandName()] = env_regex_cmd_sp;
819 }
820 }
821
822 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
823 new CommandObjectRegexCommand(
824 *this, "_regexp-jump", "Set the program counter to a new address.",
825 "\n"
826 "_regexp-jump <line>\n"
827 "_regexp-jump +<line-offset> | -<line-offset>\n"
828 "_regexp-jump <file>:<line>\n"
829 "_regexp-jump *<addr>\n",
830 2, 0, false));
831 if (jump_regex_cmd_up) {
832 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
833 "thread jump --addr %1") &&
834 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
835 "thread jump --line %1") &&
836 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
837 "thread jump --file %1 --line %2") &&
838 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
839 "thread jump --by %1")) {
840 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
841 m_command_dict[jump_regex_cmd_sp->GetCommandName()] = jump_regex_cmd_sp;
842 }
843 }
844 }
845
GetCommandNamesMatchingPartialString(const char * cmd_str,bool include_aliases,StringList & matches,StringList & descriptions)846 int CommandInterpreter::GetCommandNamesMatchingPartialString(
847 const char *cmd_str, bool include_aliases, StringList &matches,
848 StringList &descriptions) {
849 AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
850 &descriptions);
851
852 if (include_aliases) {
853 AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
854 &descriptions);
855 }
856
857 return matches.GetSize();
858 }
859
860 CommandObjectSP
GetCommandSP(llvm::StringRef cmd_str,bool include_aliases,bool exact,StringList * matches,StringList * descriptions) const861 CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
862 bool exact, StringList *matches,
863 StringList *descriptions) const {
864 CommandObjectSP command_sp;
865
866 std::string cmd = cmd_str;
867
868 if (HasCommands()) {
869 auto pos = m_command_dict.find(cmd);
870 if (pos != m_command_dict.end())
871 command_sp = pos->second;
872 }
873
874 if (include_aliases && HasAliases()) {
875 auto alias_pos = m_alias_dict.find(cmd);
876 if (alias_pos != m_alias_dict.end())
877 command_sp = alias_pos->second;
878 }
879
880 if (HasUserCommands()) {
881 auto pos = m_user_dict.find(cmd);
882 if (pos != m_user_dict.end())
883 command_sp = pos->second;
884 }
885
886 if (!exact && !command_sp) {
887 // We will only get into here if we didn't find any exact matches.
888
889 CommandObjectSP user_match_sp, alias_match_sp, real_match_sp;
890
891 StringList local_matches;
892 if (matches == nullptr)
893 matches = &local_matches;
894
895 unsigned int num_cmd_matches = 0;
896 unsigned int num_alias_matches = 0;
897 unsigned int num_user_matches = 0;
898
899 // Look through the command dictionaries one by one, and if we get only one
900 // match from any of them in toto, then return that, otherwise return an
901 // empty CommandObjectSP and the list of matches.
902
903 if (HasCommands()) {
904 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
905 *matches, descriptions);
906 }
907
908 if (num_cmd_matches == 1) {
909 cmd.assign(matches->GetStringAtIndex(0));
910 auto pos = m_command_dict.find(cmd);
911 if (pos != m_command_dict.end())
912 real_match_sp = pos->second;
913 }
914
915 if (include_aliases && HasAliases()) {
916 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
917 *matches, descriptions);
918 }
919
920 if (num_alias_matches == 1) {
921 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
922 auto alias_pos = m_alias_dict.find(cmd);
923 if (alias_pos != m_alias_dict.end())
924 alias_match_sp = alias_pos->second;
925 }
926
927 if (HasUserCommands()) {
928 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
929 *matches, descriptions);
930 }
931
932 if (num_user_matches == 1) {
933 cmd.assign(
934 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
935
936 auto pos = m_user_dict.find(cmd);
937 if (pos != m_user_dict.end())
938 user_match_sp = pos->second;
939 }
940
941 // If we got exactly one match, return that, otherwise return the match
942 // list.
943
944 if (num_user_matches + num_cmd_matches + num_alias_matches == 1) {
945 if (num_cmd_matches)
946 return real_match_sp;
947 else if (num_alias_matches)
948 return alias_match_sp;
949 else
950 return user_match_sp;
951 }
952 } else if (matches && command_sp) {
953 matches->AppendString(cmd_str);
954 if (descriptions)
955 descriptions->AppendString(command_sp->GetHelp());
956 }
957
958 return command_sp;
959 }
960
AddCommand(llvm::StringRef name,const lldb::CommandObjectSP & cmd_sp,bool can_replace)961 bool CommandInterpreter::AddCommand(llvm::StringRef name,
962 const lldb::CommandObjectSP &cmd_sp,
963 bool can_replace) {
964 if (cmd_sp.get())
965 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
966 "tried to add a CommandObject from a different interpreter");
967
968 if (name.empty())
969 return false;
970
971 std::string name_sstr(name);
972 auto name_iter = m_command_dict.find(name_sstr);
973 if (name_iter != m_command_dict.end()) {
974 if (!can_replace || !name_iter->second->IsRemovable())
975 return false;
976 name_iter->second = cmd_sp;
977 } else {
978 m_command_dict[name_sstr] = cmd_sp;
979 }
980 return true;
981 }
982
AddUserCommand(llvm::StringRef name,const lldb::CommandObjectSP & cmd_sp,bool can_replace)983 bool CommandInterpreter::AddUserCommand(llvm::StringRef name,
984 const lldb::CommandObjectSP &cmd_sp,
985 bool can_replace) {
986 if (cmd_sp.get())
987 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
988 "tried to add a CommandObject from a different interpreter");
989
990 if (!name.empty()) {
991 // do not allow replacement of internal commands
992 if (CommandExists(name)) {
993 if (!can_replace)
994 return false;
995 if (!m_command_dict[name]->IsRemovable())
996 return false;
997 }
998
999 if (UserCommandExists(name)) {
1000 if (!can_replace)
1001 return false;
1002 if (!m_user_dict[name]->IsRemovable())
1003 return false;
1004 }
1005
1006 m_user_dict[name] = cmd_sp;
1007 return true;
1008 }
1009 return false;
1010 }
1011
GetCommandSPExact(llvm::StringRef cmd_str,bool include_aliases) const1012 CommandObjectSP CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1013 bool include_aliases) const {
1014 Args cmd_words(cmd_str); // Break up the command string into words, in case
1015 // it's a multi-word command.
1016 CommandObjectSP ret_val; // Possibly empty return value.
1017
1018 if (cmd_str.empty())
1019 return ret_val;
1020
1021 if (cmd_words.GetArgumentCount() == 1)
1022 return GetCommandSP(cmd_str, include_aliases, true, nullptr);
1023 else {
1024 // We have a multi-word command (seemingly), so we need to do more work.
1025 // First, get the cmd_obj_sp for the first word in the command.
1026 CommandObjectSP cmd_obj_sp = GetCommandSP(llvm::StringRef(cmd_words.GetArgumentAtIndex(0)),
1027 include_aliases, true, nullptr);
1028 if (cmd_obj_sp.get() != nullptr) {
1029 // Loop through the rest of the words in the command (everything passed
1030 // in was supposed to be part of a command name), and find the
1031 // appropriate sub-command SP for each command word....
1032 size_t end = cmd_words.GetArgumentCount();
1033 for (size_t j = 1; j < end; ++j) {
1034 if (cmd_obj_sp->IsMultiwordObject()) {
1035 cmd_obj_sp =
1036 cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(j));
1037 if (cmd_obj_sp.get() == nullptr)
1038 // The sub-command name was invalid. Fail and return the empty
1039 // 'ret_val'.
1040 return ret_val;
1041 } else
1042 // We have more words in the command name, but we don't have a
1043 // multiword object. Fail and return empty 'ret_val'.
1044 return ret_val;
1045 }
1046 // We successfully looped through all the command words and got valid
1047 // command objects for them. Assign the last object retrieved to
1048 // 'ret_val'.
1049 ret_val = cmd_obj_sp;
1050 }
1051 }
1052 return ret_val;
1053 }
1054
1055 CommandObject *
GetCommandObject(llvm::StringRef cmd_str,StringList * matches,StringList * descriptions) const1056 CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1057 StringList *matches,
1058 StringList *descriptions) const {
1059 CommandObject *command_obj =
1060 GetCommandSP(cmd_str, false, true, matches, descriptions).get();
1061
1062 // If we didn't find an exact match to the command string in the commands,
1063 // look in the aliases.
1064
1065 if (command_obj)
1066 return command_obj;
1067
1068 command_obj = GetCommandSP(cmd_str, true, true, matches, descriptions).get();
1069
1070 if (command_obj)
1071 return command_obj;
1072
1073 // If there wasn't an exact match then look for an inexact one in just the
1074 // commands
1075 command_obj = GetCommandSP(cmd_str, false, false, nullptr).get();
1076
1077 // Finally, if there wasn't an inexact match among the commands, look for an
1078 // inexact match in both the commands and aliases.
1079
1080 if (command_obj) {
1081 if (matches)
1082 matches->AppendString(command_obj->GetCommandName());
1083 if (descriptions)
1084 descriptions->AppendString(command_obj->GetHelp());
1085 return command_obj;
1086 }
1087
1088 return GetCommandSP(cmd_str, true, false, matches, descriptions).get();
1089 }
1090
CommandExists(llvm::StringRef cmd) const1091 bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
1092 return m_command_dict.find(cmd) != m_command_dict.end();
1093 }
1094
GetAliasFullName(llvm::StringRef cmd,std::string & full_name) const1095 bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1096 std::string &full_name) const {
1097 bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
1098 if (exact_match) {
1099 full_name.assign(cmd);
1100 return exact_match;
1101 } else {
1102 StringList matches;
1103 size_t num_alias_matches;
1104 num_alias_matches =
1105 AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1106 if (num_alias_matches == 1) {
1107 // Make sure this isn't shadowing a command in the regular command space:
1108 StringList regular_matches;
1109 const bool include_aliases = false;
1110 const bool exact = false;
1111 CommandObjectSP cmd_obj_sp(
1112 GetCommandSP(cmd, include_aliases, exact, ®ular_matches));
1113 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1114 return false;
1115 else {
1116 full_name.assign(matches.GetStringAtIndex(0));
1117 return true;
1118 }
1119 } else
1120 return false;
1121 }
1122 }
1123
AliasExists(llvm::StringRef cmd) const1124 bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
1125 return m_alias_dict.find(cmd) != m_alias_dict.end();
1126 }
1127
UserCommandExists(llvm::StringRef cmd) const1128 bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
1129 return m_user_dict.find(cmd) != m_user_dict.end();
1130 }
1131
1132 CommandAlias *
AddAlias(llvm::StringRef alias_name,lldb::CommandObjectSP & command_obj_sp,llvm::StringRef args_string)1133 CommandInterpreter::AddAlias(llvm::StringRef alias_name,
1134 lldb::CommandObjectSP &command_obj_sp,
1135 llvm::StringRef args_string) {
1136 if (command_obj_sp.get())
1137 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1138 "tried to add a CommandObject from a different interpreter");
1139
1140 std::unique_ptr<CommandAlias> command_alias_up(
1141 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1142
1143 if (command_alias_up && command_alias_up->IsValid()) {
1144 m_alias_dict[alias_name] = CommandObjectSP(command_alias_up.get());
1145 return command_alias_up.release();
1146 }
1147
1148 return nullptr;
1149 }
1150
RemoveAlias(llvm::StringRef alias_name)1151 bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
1152 auto pos = m_alias_dict.find(alias_name);
1153 if (pos != m_alias_dict.end()) {
1154 m_alias_dict.erase(pos);
1155 return true;
1156 }
1157 return false;
1158 }
1159
RemoveCommand(llvm::StringRef cmd)1160 bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd) {
1161 auto pos = m_command_dict.find(cmd);
1162 if (pos != m_command_dict.end()) {
1163 if (pos->second->IsRemovable()) {
1164 // Only regular expression objects or python commands are removable
1165 m_command_dict.erase(pos);
1166 return true;
1167 }
1168 }
1169 return false;
1170 }
RemoveUser(llvm::StringRef alias_name)1171 bool CommandInterpreter::RemoveUser(llvm::StringRef alias_name) {
1172 CommandObject::CommandMap::iterator pos = m_user_dict.find(alias_name);
1173 if (pos != m_user_dict.end()) {
1174 m_user_dict.erase(pos);
1175 return true;
1176 }
1177 return false;
1178 }
1179
GetHelp(CommandReturnObject & result,uint32_t cmd_types)1180 void CommandInterpreter::GetHelp(CommandReturnObject &result,
1181 uint32_t cmd_types) {
1182 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1183 if (!help_prologue.empty()) {
1184 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1185 help_prologue);
1186 }
1187
1188 CommandObject::CommandMap::const_iterator pos;
1189 size_t max_len = FindLongestCommandWord(m_command_dict);
1190
1191 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1192 result.AppendMessage("Debugger commands:");
1193 result.AppendMessage("");
1194
1195 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1196 if (!(cmd_types & eCommandTypesHidden) &&
1197 (pos->first.compare(0, 1, "_") == 0))
1198 continue;
1199
1200 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1201 pos->second->GetHelp(), max_len);
1202 }
1203 result.AppendMessage("");
1204 }
1205
1206 if (!m_alias_dict.empty() &&
1207 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1208 result.AppendMessageWithFormat(
1209 "Current command abbreviations "
1210 "(type '%shelp command alias' for more info):\n",
1211 GetCommandPrefix());
1212 result.AppendMessage("");
1213 max_len = FindLongestCommandWord(m_alias_dict);
1214
1215 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1216 ++alias_pos) {
1217 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
1218 alias_pos->second->GetHelp(), max_len);
1219 }
1220 result.AppendMessage("");
1221 }
1222
1223 if (!m_user_dict.empty() &&
1224 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1225 result.AppendMessage("Current user-defined commands:");
1226 result.AppendMessage("");
1227 max_len = FindLongestCommandWord(m_user_dict);
1228 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
1229 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1230 pos->second->GetHelp(), max_len);
1231 }
1232 result.AppendMessage("");
1233 }
1234
1235 result.AppendMessageWithFormat(
1236 "For more information on any command, type '%shelp <command-name>'.\n",
1237 GetCommandPrefix());
1238 }
1239
GetCommandObjectForCommand(llvm::StringRef & command_string)1240 CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1241 llvm::StringRef &command_string) {
1242 // This function finds the final, lowest-level, alias-resolved command object
1243 // whose 'Execute' function will eventually be invoked by the given command
1244 // line.
1245
1246 CommandObject *cmd_obj = nullptr;
1247 size_t start = command_string.find_first_not_of(k_white_space);
1248 size_t end = 0;
1249 bool done = false;
1250 while (!done) {
1251 if (start != std::string::npos) {
1252 // Get the next word from command_string.
1253 end = command_string.find_first_of(k_white_space, start);
1254 if (end == std::string::npos)
1255 end = command_string.size();
1256 std::string cmd_word = command_string.substr(start, end - start);
1257
1258 if (cmd_obj == nullptr)
1259 // Since cmd_obj is NULL we are on our first time through this loop.
1260 // Check to see if cmd_word is a valid command or alias.
1261 cmd_obj = GetCommandObject(cmd_word);
1262 else if (cmd_obj->IsMultiwordObject()) {
1263 // Our current object is a multi-word object; see if the cmd_word is a
1264 // valid sub-command for our object.
1265 CommandObject *sub_cmd_obj =
1266 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1267 if (sub_cmd_obj)
1268 cmd_obj = sub_cmd_obj;
1269 else // cmd_word was not a valid sub-command word, so we are done
1270 done = true;
1271 } else
1272 // We have a cmd_obj and it is not a multi-word object, so we are done.
1273 done = true;
1274
1275 // If we didn't find a valid command object, or our command object is not
1276 // a multi-word object, or we are at the end of the command_string, then
1277 // we are done. Otherwise, find the start of the next word.
1278
1279 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1280 end >= command_string.size())
1281 done = true;
1282 else
1283 start = command_string.find_first_not_of(k_white_space, end);
1284 } else
1285 // Unable to find any more words.
1286 done = true;
1287 }
1288
1289 command_string = command_string.substr(end);
1290 return cmd_obj;
1291 }
1292
1293 static const char *k_valid_command_chars =
1294 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
StripLeadingSpaces(std::string & s)1295 static void StripLeadingSpaces(std::string &s) {
1296 if (!s.empty()) {
1297 size_t pos = s.find_first_not_of(k_white_space);
1298 if (pos == std::string::npos)
1299 s.clear();
1300 else if (pos == 0)
1301 return;
1302 s.erase(0, pos);
1303 }
1304 }
1305
FindArgumentTerminator(const std::string & s)1306 static size_t FindArgumentTerminator(const std::string &s) {
1307 const size_t s_len = s.size();
1308 size_t offset = 0;
1309 while (offset < s_len) {
1310 size_t pos = s.find("--", offset);
1311 if (pos == std::string::npos)
1312 break;
1313 if (pos > 0) {
1314 if (isspace(s[pos - 1])) {
1315 // Check if the string ends "\s--" (where \s is a space character) or
1316 // if we have "\s--\s".
1317 if ((pos + 2 >= s_len) || isspace(s[pos + 2])) {
1318 return pos;
1319 }
1320 }
1321 }
1322 offset = pos + 2;
1323 }
1324 return std::string::npos;
1325 }
1326
ExtractCommand(std::string & command_string,std::string & command,std::string & suffix,char & quote_char)1327 static bool ExtractCommand(std::string &command_string, std::string &command,
1328 std::string &suffix, char "e_char) {
1329 command.clear();
1330 suffix.clear();
1331 StripLeadingSpaces(command_string);
1332
1333 bool result = false;
1334 quote_char = '\0';
1335
1336 if (!command_string.empty()) {
1337 const char first_char = command_string[0];
1338 if (first_char == '\'' || first_char == '"') {
1339 quote_char = first_char;
1340 const size_t end_quote_pos = command_string.find(quote_char, 1);
1341 if (end_quote_pos == std::string::npos) {
1342 command.swap(command_string);
1343 command_string.erase();
1344 } else {
1345 command.assign(command_string, 1, end_quote_pos - 1);
1346 if (end_quote_pos + 1 < command_string.size())
1347 command_string.erase(0, command_string.find_first_not_of(
1348 k_white_space, end_quote_pos + 1));
1349 else
1350 command_string.erase();
1351 }
1352 } else {
1353 const size_t first_space_pos =
1354 command_string.find_first_of(k_white_space);
1355 if (first_space_pos == std::string::npos) {
1356 command.swap(command_string);
1357 command_string.erase();
1358 } else {
1359 command.assign(command_string, 0, first_space_pos);
1360 command_string.erase(0, command_string.find_first_not_of(
1361 k_white_space, first_space_pos));
1362 }
1363 }
1364 result = true;
1365 }
1366
1367 if (!command.empty()) {
1368 // actual commands can't start with '-' or '_'
1369 if (command[0] != '-' && command[0] != '_') {
1370 size_t pos = command.find_first_not_of(k_valid_command_chars);
1371 if (pos > 0 && pos != std::string::npos) {
1372 suffix.assign(command.begin() + pos, command.end());
1373 command.erase(pos);
1374 }
1375 }
1376 }
1377
1378 return result;
1379 }
1380
BuildAliasResult(llvm::StringRef alias_name,std::string & raw_input_string,std::string & alias_result,CommandReturnObject & result)1381 CommandObject *CommandInterpreter::BuildAliasResult(
1382 llvm::StringRef alias_name, std::string &raw_input_string,
1383 std::string &alias_result, CommandReturnObject &result) {
1384 CommandObject *alias_cmd_obj = nullptr;
1385 Args cmd_args(raw_input_string);
1386 alias_cmd_obj = GetCommandObject(alias_name);
1387 StreamString result_str;
1388
1389 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1390 alias_result.clear();
1391 return alias_cmd_obj;
1392 }
1393 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1394 ((CommandAlias *)alias_cmd_obj)->Desugar();
1395 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1396 alias_cmd_obj = desugared.first.get();
1397 std::string alias_name_str = alias_name;
1398 if ((cmd_args.GetArgumentCount() == 0) ||
1399 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
1400 cmd_args.Unshift(alias_name_str);
1401
1402 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
1403
1404 if (!option_arg_vector_sp.get()) {
1405 alias_result = result_str.GetString();
1406 return alias_cmd_obj;
1407 }
1408 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1409
1410 int value_type;
1411 std::string option;
1412 std::string value;
1413 for (const auto &entry : *option_arg_vector) {
1414 std::tie(option, value_type, value) = entry;
1415 if (option == "<argument>") {
1416 result_str.Printf(" %s", value.c_str());
1417 continue;
1418 }
1419
1420 result_str.Printf(" %s", option.c_str());
1421 if (value_type == OptionParser::eNoArgument)
1422 continue;
1423
1424 if (value_type != OptionParser::eOptionalArgument)
1425 result_str.Printf(" ");
1426 int index = GetOptionArgumentPosition(value.c_str());
1427 if (index == 0)
1428 result_str.Printf("%s", value.c_str());
1429 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1430
1431 result.AppendErrorWithFormat("Not enough arguments provided; you "
1432 "need at least %d arguments to use "
1433 "this alias.\n",
1434 index);
1435 result.SetStatus(eReturnStatusFailed);
1436 return nullptr;
1437 } else {
1438 size_t strpos = raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
1439 if (strpos != std::string::npos)
1440 raw_input_string = raw_input_string.erase(
1441 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
1442 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
1443 }
1444 }
1445
1446 alias_result = result_str.GetString();
1447 return alias_cmd_obj;
1448 }
1449
PreprocessCommand(std::string & command)1450 Status CommandInterpreter::PreprocessCommand(std::string &command) {
1451 // The command preprocessor needs to do things to the command line before any
1452 // parsing of arguments or anything else is done. The only current stuff that
1453 // gets preprocessed is anything enclosed in backtick ('`') characters is
1454 // evaluated as an expression and the result of the expression must be a
1455 // scalar that can be substituted into the command. An example would be:
1456 // (lldb) memory read `$rsp + 20`
1457 Status error; // Status for any expressions that might not evaluate
1458 size_t start_backtick;
1459 size_t pos = 0;
1460 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
1461 // Stop if an error was encountered during the previous iteration.
1462 if (error.Fail())
1463 break;
1464
1465 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
1466 // The backtick was preceded by a '\' character, remove the slash and
1467 // don't treat the backtick as the start of an expression.
1468 command.erase(start_backtick - 1, 1);
1469 // No need to add one to start_backtick since we just deleted a char.
1470 pos = start_backtick;
1471 continue;
1472 }
1473
1474 const size_t expr_content_start = start_backtick + 1;
1475 const size_t end_backtick = command.find('`', expr_content_start);
1476
1477 if (end_backtick == std::string::npos) {
1478 // Stop if there's no end backtick.
1479 break;
1480 }
1481
1482 if (end_backtick == expr_content_start) {
1483 // Skip over empty expression. (two backticks in a row)
1484 command.erase(start_backtick, 2);
1485 continue;
1486 }
1487
1488 std::string expr_str(command, expr_content_start,
1489 end_backtick - expr_content_start);
1490
1491 ExecutionContext exe_ctx(GetExecutionContext());
1492 Target *target = exe_ctx.GetTargetPtr();
1493
1494 // Get a dummy target to allow for calculator mode while processing
1495 // backticks. This also helps break the infinite loop caused when target is
1496 // null.
1497 if (!target)
1498 target = m_debugger.GetDummyTarget();
1499
1500 if (!target)
1501 continue;
1502
1503 ValueObjectSP expr_result_valobj_sp;
1504
1505 EvaluateExpressionOptions options;
1506 options.SetCoerceToId(false);
1507 options.SetUnwindOnError(true);
1508 options.SetIgnoreBreakpoints(true);
1509 options.SetKeepInMemory(false);
1510 options.SetTryAllThreads(true);
1511 options.SetTimeout(llvm::None);
1512
1513 ExpressionResults expr_result =
1514 target->EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1515 expr_result_valobj_sp, options);
1516
1517 if (expr_result == eExpressionCompleted) {
1518 Scalar scalar;
1519 if (expr_result_valobj_sp)
1520 expr_result_valobj_sp =
1521 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1522 expr_result_valobj_sp->GetDynamicValueType(), true);
1523 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1524 command.erase(start_backtick, end_backtick - start_backtick + 1);
1525 StreamString value_strm;
1526 const bool show_type = false;
1527 scalar.GetValue(&value_strm, show_type);
1528 size_t value_string_size = value_strm.GetSize();
1529 if (value_string_size) {
1530 command.insert(start_backtick, value_strm.GetString());
1531 pos = start_backtick + value_string_size;
1532 continue;
1533 } else {
1534 error.SetErrorStringWithFormat("expression value didn't result "
1535 "in a scalar value for the "
1536 "expression '%s'",
1537 expr_str.c_str());
1538 break;
1539 }
1540 } else {
1541 error.SetErrorStringWithFormat("expression value didn't result "
1542 "in a scalar value for the "
1543 "expression '%s'",
1544 expr_str.c_str());
1545 break;
1546 }
1547
1548 continue;
1549 }
1550
1551 if (expr_result_valobj_sp)
1552 error = expr_result_valobj_sp->GetError();
1553
1554 if (error.Success()) {
1555 switch (expr_result) {
1556 case eExpressionSetupError:
1557 error.SetErrorStringWithFormat(
1558 "expression setup error for the expression '%s'", expr_str.c_str());
1559 break;
1560 case eExpressionParseError:
1561 error.SetErrorStringWithFormat(
1562 "expression parse error for the expression '%s'", expr_str.c_str());
1563 break;
1564 case eExpressionResultUnavailable:
1565 error.SetErrorStringWithFormat(
1566 "expression error fetching result for the expression '%s'",
1567 expr_str.c_str());
1568 break;
1569 case eExpressionCompleted:
1570 break;
1571 case eExpressionDiscarded:
1572 error.SetErrorStringWithFormat(
1573 "expression discarded for the expression '%s'", expr_str.c_str());
1574 break;
1575 case eExpressionInterrupted:
1576 error.SetErrorStringWithFormat(
1577 "expression interrupted for the expression '%s'", expr_str.c_str());
1578 break;
1579 case eExpressionHitBreakpoint:
1580 error.SetErrorStringWithFormat(
1581 "expression hit breakpoint for the expression '%s'",
1582 expr_str.c_str());
1583 break;
1584 case eExpressionTimedOut:
1585 error.SetErrorStringWithFormat(
1586 "expression timed out for the expression '%s'", expr_str.c_str());
1587 break;
1588 case eExpressionStoppedForDebug:
1589 error.SetErrorStringWithFormat("expression stop at entry point "
1590 "for debugging for the "
1591 "expression '%s'",
1592 expr_str.c_str());
1593 break;
1594 }
1595 }
1596 }
1597 return error;
1598 }
1599
HandleCommand(const char * command_line,LazyBool lazy_add_to_history,CommandReturnObject & result,ExecutionContext * override_context,bool repeat_on_empty_command,bool no_context_switching)1600 bool CommandInterpreter::HandleCommand(const char *command_line,
1601 LazyBool lazy_add_to_history,
1602 CommandReturnObject &result,
1603 ExecutionContext *override_context,
1604 bool repeat_on_empty_command,
1605 bool no_context_switching)
1606
1607 {
1608
1609 std::string command_string(command_line);
1610 std::string original_command_string(command_line);
1611
1612 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS));
1613 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
1614 command_line);
1615
1616 LLDB_LOGF(log, "Processing command: %s", command_line);
1617
1618 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
1619 Timer scoped_timer(func_cat, "Handling command: %s.", command_line);
1620
1621 if (!no_context_switching)
1622 UpdateExecutionContext(override_context);
1623
1624 if (WasInterrupted()) {
1625 result.AppendError("interrupted");
1626 result.SetStatus(eReturnStatusFailed);
1627 return false;
1628 }
1629
1630 bool add_to_history;
1631 if (lazy_add_to_history == eLazyBoolCalculate)
1632 add_to_history = (m_command_source_depth == 0);
1633 else
1634 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1635
1636 bool empty_command = false;
1637 bool comment_command = false;
1638 if (command_string.empty())
1639 empty_command = true;
1640 else {
1641 const char *k_space_characters = "\t\n\v\f\r ";
1642
1643 size_t non_space = command_string.find_first_not_of(k_space_characters);
1644 // Check for empty line or comment line (lines whose first non-space
1645 // character is the comment character for this interpreter)
1646 if (non_space == std::string::npos)
1647 empty_command = true;
1648 else if (command_string[non_space] == m_comment_char)
1649 comment_command = true;
1650 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
1651 llvm::StringRef search_str(command_string);
1652 search_str = search_str.drop_front(non_space);
1653 if (auto hist_str = m_command_history.FindString(search_str)) {
1654 add_to_history = false;
1655 command_string = *hist_str;
1656 original_command_string = *hist_str;
1657 } else {
1658 result.AppendErrorWithFormat("Could not find entry: %s in history",
1659 command_string.c_str());
1660 result.SetStatus(eReturnStatusFailed);
1661 return false;
1662 }
1663 }
1664 }
1665
1666 if (empty_command) {
1667 if (repeat_on_empty_command) {
1668 if (m_command_history.IsEmpty()) {
1669 result.AppendError("empty command");
1670 result.SetStatus(eReturnStatusFailed);
1671 return false;
1672 } else {
1673 command_line = m_repeat_command.c_str();
1674 command_string = command_line;
1675 original_command_string = command_line;
1676 if (m_repeat_command.empty()) {
1677 result.AppendErrorWithFormat("No auto repeat.\n");
1678 result.SetStatus(eReturnStatusFailed);
1679 return false;
1680 }
1681 }
1682 add_to_history = false;
1683 } else {
1684 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1685 return true;
1686 }
1687 } else if (comment_command) {
1688 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1689 return true;
1690 }
1691
1692 Status error(PreprocessCommand(command_string));
1693
1694 if (error.Fail()) {
1695 result.AppendError(error.AsCString());
1696 result.SetStatus(eReturnStatusFailed);
1697 return false;
1698 }
1699
1700 // Phase 1.
1701
1702 // Before we do ANY kind of argument processing, we need to figure out what
1703 // the real/final command object is for the specified command. This gets
1704 // complicated by the fact that the user could have specified an alias, and,
1705 // in translating the alias, there may also be command options and/or even
1706 // data (including raw text strings) that need to be found and inserted into
1707 // the command line as part of the translation. So this first step is plain
1708 // look-up and replacement, resulting in:
1709 // 1. the command object whose Execute method will actually be called
1710 // 2. a revised command string, with all substitutions and replacements
1711 // taken care of
1712 // From 1 above, we can determine whether the Execute function wants raw
1713 // input or not.
1714
1715 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1716
1717 // Although the user may have abbreviated the command, the command_string now
1718 // has the command expanded to the full name. For example, if the input was
1719 // "br s -n main", command_string is now "breakpoint set -n main".
1720 if (log) {
1721 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1722 LLDB_LOGF(log, "HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
1723 LLDB_LOGF(log, "HandleCommand, (revised) command_string: '%s'",
1724 command_string.c_str());
1725 const bool wants_raw_input =
1726 (cmd_obj != nullptr) ? cmd_obj->WantsRawCommandString() : false;
1727 LLDB_LOGF(log, "HandleCommand, wants_raw_input:'%s'",
1728 wants_raw_input ? "True" : "False");
1729 }
1730
1731 // Phase 2.
1732 // Take care of things like setting up the history command & calling the
1733 // appropriate Execute method on the CommandObject, with the appropriate
1734 // arguments.
1735
1736 if (cmd_obj != nullptr) {
1737 if (add_to_history) {
1738 Args command_args(command_string);
1739 const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
1740 if (repeat_command != nullptr)
1741 m_repeat_command.assign(repeat_command);
1742 else
1743 m_repeat_command.assign(original_command_string);
1744
1745 m_command_history.AppendString(original_command_string);
1746 }
1747
1748 std::string remainder;
1749 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
1750 if (actual_cmd_name_len < command_string.length())
1751 remainder = command_string.substr(actual_cmd_name_len);
1752
1753 // Remove any initial spaces
1754 size_t pos = remainder.find_first_not_of(k_white_space);
1755 if (pos != 0 && pos != std::string::npos)
1756 remainder.erase(0, pos);
1757
1758 LLDB_LOGF(
1759 log, "HandleCommand, command line after removing command name(s): '%s'",
1760 remainder.c_str());
1761
1762 cmd_obj->Execute(remainder.c_str(), result);
1763 }
1764
1765 LLDB_LOGF(log, "HandleCommand, command %s",
1766 (result.Succeeded() ? "succeeded" : "did not succeed"));
1767
1768 return result.Succeeded();
1769 }
1770
HandleCompletionMatches(CompletionRequest & request)1771 void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
1772 bool look_for_subcommand = false;
1773
1774 // For any of the command completions a unique match will be a complete word.
1775
1776 if (request.GetParsedLine().GetArgumentCount() == 0) {
1777 // We got nothing on the command line, so return the list of commands
1778 bool include_aliases = true;
1779 StringList new_matches, descriptions;
1780 GetCommandNamesMatchingPartialString("", include_aliases, new_matches,
1781 descriptions);
1782 request.AddCompletions(new_matches, descriptions);
1783 } else if (request.GetCursorIndex() == 0) {
1784 // The cursor is in the first argument, so just do a lookup in the
1785 // dictionary.
1786 StringList new_matches, new_descriptions;
1787 CommandObject *cmd_obj =
1788 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
1789 &new_matches, &new_descriptions);
1790
1791 if (new_matches.GetSize() && cmd_obj && cmd_obj->IsMultiwordObject() &&
1792 new_matches.GetStringAtIndex(0) != nullptr &&
1793 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
1794 new_matches.GetStringAtIndex(0)) == 0) {
1795 if (request.GetParsedLine().GetArgumentCount() != 1) {
1796 look_for_subcommand = true;
1797 new_matches.DeleteStringAtIndex(0);
1798 new_descriptions.DeleteStringAtIndex(0);
1799 request.AppendEmptyArgument();
1800 }
1801 }
1802 request.AddCompletions(new_matches, new_descriptions);
1803 }
1804
1805 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
1806 // We are completing further on into a commands arguments, so find the
1807 // command and tell it to complete the command. First see if there is a
1808 // matching initial command:
1809 CommandObject *command_object =
1810 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
1811 if (command_object) {
1812 request.ShiftArguments();
1813 command_object->HandleCompletion(request);
1814 }
1815 }
1816 }
1817
HandleCompletion(CompletionRequest & request)1818 void CommandInterpreter::HandleCompletion(CompletionRequest &request) {
1819
1820 // Don't complete comments, and if the line we are completing is just the
1821 // history repeat character, substitute the appropriate history line.
1822 llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
1823
1824 if (!first_arg.empty()) {
1825 if (first_arg.front() == m_comment_char)
1826 return;
1827 if (first_arg.front() == CommandHistory::g_repeat_char) {
1828 if (auto hist_str = m_command_history.FindString(first_arg))
1829 request.AddCompletion(*hist_str, "Previous command history event",
1830 CompletionMode::RewriteLine);
1831 return;
1832 }
1833 }
1834
1835 HandleCompletionMatches(request);
1836 }
1837
~CommandInterpreter()1838 CommandInterpreter::~CommandInterpreter() {}
1839
UpdatePrompt(llvm::StringRef new_prompt)1840 void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
1841 EventSP prompt_change_event_sp(
1842 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
1843 ;
1844 BroadcastEvent(prompt_change_event_sp);
1845 if (m_command_io_handler_sp)
1846 m_command_io_handler_sp->SetPrompt(new_prompt);
1847 }
1848
Confirm(llvm::StringRef message,bool default_answer)1849 bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
1850 // Check AutoConfirm first:
1851 if (m_debugger.GetAutoConfirm())
1852 return default_answer;
1853
1854 IOHandlerConfirm *confirm =
1855 new IOHandlerConfirm(m_debugger, message, default_answer);
1856 IOHandlerSP io_handler_sp(confirm);
1857 m_debugger.RunIOHandler(io_handler_sp);
1858 return confirm->GetResponse();
1859 }
1860
1861 const CommandAlias *
GetAlias(llvm::StringRef alias_name) const1862 CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
1863 OptionArgVectorSP ret_val;
1864
1865 auto pos = m_alias_dict.find(alias_name);
1866 if (pos != m_alias_dict.end())
1867 return (CommandAlias *)pos->second.get();
1868
1869 return nullptr;
1870 }
1871
HasCommands() const1872 bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
1873
HasAliases() const1874 bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
1875
HasUserCommands() const1876 bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
1877
HasAliasOptions() const1878 bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
1879
BuildAliasCommandArgs(CommandObject * alias_cmd_obj,const char * alias_name,Args & cmd_args,std::string & raw_input_string,CommandReturnObject & result)1880 void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
1881 const char *alias_name,
1882 Args &cmd_args,
1883 std::string &raw_input_string,
1884 CommandReturnObject &result) {
1885 OptionArgVectorSP option_arg_vector_sp =
1886 GetAlias(alias_name)->GetOptionArguments();
1887
1888 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
1889
1890 // Make sure that the alias name is the 0th element in cmd_args
1891 std::string alias_name_str = alias_name;
1892 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
1893 cmd_args.Unshift(alias_name_str);
1894
1895 Args new_args(alias_cmd_obj->GetCommandName());
1896 if (new_args.GetArgumentCount() == 2)
1897 new_args.Shift();
1898
1899 if (option_arg_vector_sp.get()) {
1900 if (wants_raw_input) {
1901 // We have a command that both has command options and takes raw input.
1902 // Make *sure* it has a " -- " in the right place in the
1903 // raw_input_string.
1904 size_t pos = raw_input_string.find(" -- ");
1905 if (pos == std::string::npos) {
1906 // None found; assume it goes at the beginning of the raw input string
1907 raw_input_string.insert(0, " -- ");
1908 }
1909 }
1910
1911 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1912 const size_t old_size = cmd_args.GetArgumentCount();
1913 std::vector<bool> used(old_size + 1, false);
1914
1915 used[0] = true;
1916
1917 int value_type;
1918 std::string option;
1919 std::string value;
1920 for (const auto &option_entry : *option_arg_vector) {
1921 std::tie(option, value_type, value) = option_entry;
1922 if (option == "<argument>") {
1923 if (!wants_raw_input || (value != "--")) {
1924 // Since we inserted this above, make sure we don't insert it twice
1925 new_args.AppendArgument(value);
1926 }
1927 continue;
1928 }
1929
1930 if (value_type != OptionParser::eOptionalArgument)
1931 new_args.AppendArgument(option);
1932
1933 if (value == "<no-argument>")
1934 continue;
1935
1936 int index = GetOptionArgumentPosition(value.c_str());
1937 if (index == 0) {
1938 // value was NOT a positional argument; must be a real value
1939 if (value_type != OptionParser::eOptionalArgument)
1940 new_args.AppendArgument(value);
1941 else {
1942 char buffer[255];
1943 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
1944 value.c_str());
1945 new_args.AppendArgument(llvm::StringRef(buffer));
1946 }
1947
1948 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1949 result.AppendErrorWithFormat("Not enough arguments provided; you "
1950 "need at least %d arguments to use "
1951 "this alias.\n",
1952 index);
1953 result.SetStatus(eReturnStatusFailed);
1954 return;
1955 } else {
1956 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
1957 size_t strpos =
1958 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
1959 if (strpos != std::string::npos) {
1960 raw_input_string = raw_input_string.erase(
1961 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
1962 }
1963
1964 if (value_type != OptionParser::eOptionalArgument)
1965 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
1966 else {
1967 char buffer[255];
1968 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
1969 cmd_args.GetArgumentAtIndex(index));
1970 new_args.AppendArgument(buffer);
1971 }
1972 used[index] = true;
1973 }
1974 }
1975
1976 for (auto entry : llvm::enumerate(cmd_args.entries())) {
1977 if (!used[entry.index()] && !wants_raw_input)
1978 new_args.AppendArgument(entry.value().ref());
1979 }
1980
1981 cmd_args.Clear();
1982 cmd_args.SetArguments(new_args.GetArgumentCount(),
1983 new_args.GetConstArgumentVector());
1984 } else {
1985 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1986 // This alias was not created with any options; nothing further needs to be
1987 // done, unless it is a command that wants raw input, in which case we need
1988 // to clear the rest of the data from cmd_args, since its in the raw input
1989 // string.
1990 if (wants_raw_input) {
1991 cmd_args.Clear();
1992 cmd_args.SetArguments(new_args.GetArgumentCount(),
1993 new_args.GetConstArgumentVector());
1994 }
1995 return;
1996 }
1997
1998 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1999 return;
2000 }
2001
GetOptionArgumentPosition(const char * in_string)2002 int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2003 int position = 0; // Any string that isn't an argument position, i.e. '%'
2004 // followed by an integer, gets a position
2005 // of zero.
2006
2007 const char *cptr = in_string;
2008
2009 // Does it start with '%'
2010 if (cptr[0] == '%') {
2011 ++cptr;
2012
2013 // Is the rest of it entirely digits?
2014 if (isdigit(cptr[0])) {
2015 const char *start = cptr;
2016 while (isdigit(cptr[0]))
2017 ++cptr;
2018
2019 // We've gotten to the end of the digits; are we at the end of the
2020 // string?
2021 if (cptr[0] == '\0')
2022 position = atoi(start);
2023 }
2024 }
2025
2026 return position;
2027 }
2028
GetHomeInitFile(llvm::SmallVectorImpl<char> & init_file,llvm::StringRef suffix={})2029 static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2030 llvm::StringRef suffix = {}) {
2031 std::string init_file_name = ".lldbinit";
2032 if (!suffix.empty()) {
2033 init_file_name.append("-");
2034 init_file_name.append(suffix.str());
2035 }
2036
2037 llvm::sys::path::home_directory(init_file);
2038 llvm::sys::path::append(init_file, init_file_name);
2039
2040 FileSystem::Instance().Resolve(init_file);
2041 }
2042
GetCwdInitFile(llvm::SmallVectorImpl<char> & init_file)2043 static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
2044 llvm::StringRef s = ".lldbinit";
2045 init_file.assign(s.begin(), s.end());
2046 FileSystem::Instance().Resolve(init_file);
2047 }
2048
ShouldLoadCwdInitFile()2049 static LoadCWDlldbinitFile ShouldLoadCwdInitFile() {
2050 lldb::TargetPropertiesSP properties = Target::GetGlobalProperties();
2051 if (!properties)
2052 return eLoadCWDlldbinitFalse;
2053 return properties->GetLoadCWDlldbinitFile();
2054 }
2055
SourceInitFile(FileSpec file,CommandReturnObject & result)2056 void CommandInterpreter::SourceInitFile(FileSpec file,
2057 CommandReturnObject &result) {
2058 assert(!m_skip_lldbinit_files);
2059
2060 if (!FileSystem::Instance().Exists(file)) {
2061 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2062 return;
2063 }
2064
2065 // Use HandleCommand to 'source' the given file; this will do the actual
2066 // broadcasting of the commands back to any appropriate listener (see
2067 // CommandObjectSource::Execute for more details).
2068 const bool saved_batch = SetBatchCommandMode(true);
2069 ExecutionContext *ctx = nullptr;
2070 CommandInterpreterRunOptions options;
2071 options.SetSilent(true);
2072 options.SetPrintErrors(true);
2073 options.SetStopOnError(false);
2074 options.SetStopOnContinue(true);
2075 HandleCommandsFromFile(file, ctx, options, result);
2076 SetBatchCommandMode(saved_batch);
2077 }
2078
SourceInitFileCwd(CommandReturnObject & result)2079 void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
2080 if (m_skip_lldbinit_files) {
2081 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2082 return;
2083 }
2084
2085 llvm::SmallString<128> init_file;
2086 GetCwdInitFile(init_file);
2087 if (!FileSystem::Instance().Exists(init_file)) {
2088 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2089 return;
2090 }
2091
2092 LoadCWDlldbinitFile should_load = ShouldLoadCwdInitFile();
2093
2094 switch (should_load) {
2095 case eLoadCWDlldbinitFalse:
2096 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2097 break;
2098 case eLoadCWDlldbinitTrue:
2099 SourceInitFile(FileSpec(init_file.str()), result);
2100 break;
2101 case eLoadCWDlldbinitWarn: {
2102 llvm::SmallString<128> home_init_file;
2103 GetHomeInitFile(home_init_file);
2104 if (llvm::sys::path::parent_path(init_file) ==
2105 llvm::sys::path::parent_path(home_init_file)) {
2106 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2107 } else {
2108 result.AppendErrorWithFormat(InitFileWarning);
2109 result.SetStatus(eReturnStatusFailed);
2110 }
2111 }
2112 }
2113 }
2114
2115 /// We will first see if there is an application specific ".lldbinit" file
2116 /// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2117 /// If this file doesn't exist, we fall back to just the "~/.lldbinit" file.
SourceInitFileHome(CommandReturnObject & result)2118 void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result) {
2119 if (m_skip_lldbinit_files) {
2120 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2121 return;
2122 }
2123
2124 llvm::SmallString<128> init_file;
2125 GetHomeInitFile(init_file);
2126
2127 if (!m_skip_app_init_files) {
2128 llvm::StringRef program_name =
2129 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2130 llvm::SmallString<128> program_init_file;
2131 GetHomeInitFile(program_init_file, program_name);
2132 if (FileSystem::Instance().Exists(program_init_file))
2133 init_file = program_init_file;
2134 }
2135
2136 SourceInitFile(FileSpec(init_file.str()), result);
2137 }
2138
GetCommandPrefix()2139 const char *CommandInterpreter::GetCommandPrefix() {
2140 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2141 return prefix == nullptr ? "" : prefix;
2142 }
2143
GetPlatform(bool prefer_target_platform)2144 PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2145 PlatformSP platform_sp;
2146 if (prefer_target_platform) {
2147 ExecutionContext exe_ctx(GetExecutionContext());
2148 Target *target = exe_ctx.GetTargetPtr();
2149 if (target)
2150 platform_sp = target->GetPlatform();
2151 }
2152
2153 if (!platform_sp)
2154 platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2155 return platform_sp;
2156 }
2157
DidProcessStopAbnormally() const2158 bool CommandInterpreter::DidProcessStopAbnormally() const {
2159 TargetSP target_sp = m_debugger.GetTargetList().GetSelectedTarget();
2160 if (!target_sp)
2161 return false;
2162
2163 ProcessSP process_sp(target_sp->GetProcessSP());
2164 if (!process_sp)
2165 return false;
2166
2167 if (eStateStopped != process_sp->GetState())
2168 return false;
2169
2170 for (const auto &thread_sp : process_sp->GetThreadList().Threads()) {
2171 StopInfoSP stop_info = thread_sp->GetStopInfo();
2172 if (!stop_info)
2173 return false;
2174
2175 const StopReason reason = stop_info->GetStopReason();
2176 if (reason == eStopReasonException || reason == eStopReasonInstrumentation)
2177 return true;
2178
2179 if (reason == eStopReasonSignal) {
2180 const auto stop_signal = static_cast<int32_t>(stop_info->GetValue());
2181 UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
2182 if (!signals_sp || !signals_sp->SignalIsValid(stop_signal))
2183 // The signal is unknown, treat it as abnormal.
2184 return true;
2185
2186 const auto sigint_num = signals_sp->GetSignalNumberFromName("SIGINT");
2187 const auto sigstop_num = signals_sp->GetSignalNumberFromName("SIGSTOP");
2188 if ((stop_signal != sigint_num) && (stop_signal != sigstop_num))
2189 // The signal very likely implies a crash.
2190 return true;
2191 }
2192 }
2193
2194 return false;
2195 }
2196
HandleCommands(const StringList & commands,ExecutionContext * override_context,CommandInterpreterRunOptions & options,CommandReturnObject & result)2197 void CommandInterpreter::HandleCommands(const StringList &commands,
2198 ExecutionContext *override_context,
2199 CommandInterpreterRunOptions &options,
2200 CommandReturnObject &result) {
2201 size_t num_lines = commands.GetSize();
2202
2203 // If we are going to continue past a "continue" then we need to run the
2204 // commands synchronously. Make sure you reset this value anywhere you return
2205 // from the function.
2206
2207 bool old_async_execution = m_debugger.GetAsyncExecution();
2208
2209 // If we've been given an execution context, set it at the start, but don't
2210 // keep resetting it or we will cause series of commands that change the
2211 // context, then do an operation that relies on that context to fail.
2212
2213 if (override_context != nullptr)
2214 UpdateExecutionContext(override_context);
2215
2216 if (!options.GetStopOnContinue()) {
2217 m_debugger.SetAsyncExecution(false);
2218 }
2219
2220 for (size_t idx = 0; idx < num_lines && !WasInterrupted(); idx++) {
2221 const char *cmd = commands.GetStringAtIndex(idx);
2222 if (cmd[0] == '\0')
2223 continue;
2224
2225 if (options.GetEchoCommands()) {
2226 // TODO: Add Stream support.
2227 result.AppendMessageWithFormat("%s %s\n",
2228 m_debugger.GetPrompt().str().c_str(), cmd);
2229 }
2230
2231 CommandReturnObject tmp_result;
2232 // If override_context is not NULL, pass no_context_switching = true for
2233 // HandleCommand() since we updated our context already.
2234
2235 // We might call into a regex or alias command, in which case the
2236 // add_to_history will get lost. This m_command_source_depth dingus is the
2237 // way we turn off adding to the history in that case, so set it up here.
2238 if (!options.GetAddToHistory())
2239 m_command_source_depth++;
2240 bool success =
2241 HandleCommand(cmd, options.m_add_to_history, tmp_result,
2242 nullptr, /* override_context */
2243 true, /* repeat_on_empty_command */
2244 override_context != nullptr /* no_context_switching */);
2245 if (!options.GetAddToHistory())
2246 m_command_source_depth--;
2247
2248 if (options.GetPrintResults()) {
2249 if (tmp_result.Succeeded())
2250 result.AppendMessage(tmp_result.GetOutputData());
2251 }
2252
2253 if (!success || !tmp_result.Succeeded()) {
2254 llvm::StringRef error_msg = tmp_result.GetErrorData();
2255 if (error_msg.empty())
2256 error_msg = "<unknown error>.\n";
2257 if (options.GetStopOnError()) {
2258 result.AppendErrorWithFormat(
2259 "Aborting reading of commands after command #%" PRIu64
2260 ": '%s' failed with %s",
2261 (uint64_t)idx, cmd, error_msg.str().c_str());
2262 result.SetStatus(eReturnStatusFailed);
2263 m_debugger.SetAsyncExecution(old_async_execution);
2264 return;
2265 } else if (options.GetPrintResults()) {
2266 result.AppendMessageWithFormat(
2267 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2268 error_msg.str().c_str());
2269 }
2270 }
2271
2272 if (result.GetImmediateOutputStream())
2273 result.GetImmediateOutputStream()->Flush();
2274
2275 if (result.GetImmediateErrorStream())
2276 result.GetImmediateErrorStream()->Flush();
2277
2278 // N.B. Can't depend on DidChangeProcessState, because the state coming
2279 // into the command execution could be running (for instance in Breakpoint
2280 // Commands. So we check the return value to see if it is has running in
2281 // it.
2282 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2283 (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2284 if (options.GetStopOnContinue()) {
2285 // If we caused the target to proceed, and we're going to stop in that
2286 // case, set the status in our real result before returning. This is
2287 // an error if the continue was not the last command in the set of
2288 // commands to be run.
2289 if (idx != num_lines - 1)
2290 result.AppendErrorWithFormat(
2291 "Aborting reading of commands after command #%" PRIu64
2292 ": '%s' continued the target.\n",
2293 (uint64_t)idx + 1, cmd);
2294 else
2295 result.AppendMessageWithFormat("Command #%" PRIu64
2296 " '%s' continued the target.\n",
2297 (uint64_t)idx + 1, cmd);
2298
2299 result.SetStatus(tmp_result.GetStatus());
2300 m_debugger.SetAsyncExecution(old_async_execution);
2301
2302 return;
2303 }
2304 }
2305
2306 // Also check for "stop on crash here:
2307 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash() &&
2308 DidProcessStopAbnormally()) {
2309 if (idx != num_lines - 1)
2310 result.AppendErrorWithFormat(
2311 "Aborting reading of commands after command #%" PRIu64
2312 ": '%s' stopped with a signal or exception.\n",
2313 (uint64_t)idx + 1, cmd);
2314 else
2315 result.AppendMessageWithFormat(
2316 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2317 (uint64_t)idx + 1, cmd);
2318
2319 result.SetStatus(tmp_result.GetStatus());
2320 m_debugger.SetAsyncExecution(old_async_execution);
2321
2322 return;
2323 }
2324 }
2325
2326 result.SetStatus(eReturnStatusSuccessFinishResult);
2327 m_debugger.SetAsyncExecution(old_async_execution);
2328
2329 return;
2330 }
2331
2332 // Make flags that we can pass into the IOHandler so our delegates can do the
2333 // right thing
2334 enum {
2335 eHandleCommandFlagStopOnContinue = (1u << 0),
2336 eHandleCommandFlagStopOnError = (1u << 1),
2337 eHandleCommandFlagEchoCommand = (1u << 2),
2338 eHandleCommandFlagEchoCommentCommand = (1u << 3),
2339 eHandleCommandFlagPrintResult = (1u << 4),
2340 eHandleCommandFlagPrintErrors = (1u << 5),
2341 eHandleCommandFlagStopOnCrash = (1u << 6)
2342 };
2343
HandleCommandsFromFile(FileSpec & cmd_file,ExecutionContext * context,CommandInterpreterRunOptions & options,CommandReturnObject & result)2344 void CommandInterpreter::HandleCommandsFromFile(
2345 FileSpec &cmd_file, ExecutionContext *context,
2346 CommandInterpreterRunOptions &options, CommandReturnObject &result) {
2347 if (!FileSystem::Instance().Exists(cmd_file)) {
2348 result.AppendErrorWithFormat(
2349 "Error reading commands from file %s - file not found.\n",
2350 cmd_file.GetFilename().AsCString("<Unknown>"));
2351 result.SetStatus(eReturnStatusFailed);
2352 return;
2353 }
2354
2355 std::string cmd_file_path = cmd_file.GetPath();
2356 auto input_file_up =
2357 FileSystem::Instance().Open(cmd_file, File::eOpenOptionRead);
2358 if (!input_file_up) {
2359 std::string error = llvm::toString(input_file_up.takeError());
2360 result.AppendErrorWithFormatv(
2361 "error: an error occurred read file '{0}': {1}\n", cmd_file_path,
2362 llvm::fmt_consume(input_file_up.takeError()));
2363 result.SetStatus(eReturnStatusFailed);
2364 return;
2365 }
2366 FileSP input_file_sp = FileSP(std::move(input_file_up.get()));
2367
2368 Debugger &debugger = GetDebugger();
2369
2370 uint32_t flags = 0;
2371
2372 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2373 if (m_command_source_flags.empty()) {
2374 // Stop on continue by default
2375 flags |= eHandleCommandFlagStopOnContinue;
2376 } else if (m_command_source_flags.back() &
2377 eHandleCommandFlagStopOnContinue) {
2378 flags |= eHandleCommandFlagStopOnContinue;
2379 }
2380 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2381 flags |= eHandleCommandFlagStopOnContinue;
2382 }
2383
2384 if (options.m_stop_on_error == eLazyBoolCalculate) {
2385 if (m_command_source_flags.empty()) {
2386 if (GetStopCmdSourceOnError())
2387 flags |= eHandleCommandFlagStopOnError;
2388 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2389 flags |= eHandleCommandFlagStopOnError;
2390 }
2391 } else if (options.m_stop_on_error == eLazyBoolYes) {
2392 flags |= eHandleCommandFlagStopOnError;
2393 }
2394
2395 // stop-on-crash can only be set, if it is present in all levels of
2396 // pushed flag sets.
2397 if (options.GetStopOnCrash()) {
2398 if (m_command_source_flags.empty()) {
2399 flags |= eHandleCommandFlagStopOnCrash;
2400 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2401 flags |= eHandleCommandFlagStopOnCrash;
2402 }
2403 }
2404
2405 if (options.m_echo_commands == eLazyBoolCalculate) {
2406 if (m_command_source_flags.empty()) {
2407 // Echo command by default
2408 flags |= eHandleCommandFlagEchoCommand;
2409 } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2410 flags |= eHandleCommandFlagEchoCommand;
2411 }
2412 } else if (options.m_echo_commands == eLazyBoolYes) {
2413 flags |= eHandleCommandFlagEchoCommand;
2414 }
2415
2416 // We will only ever ask for this flag, if we echo commands in general.
2417 if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2418 if (m_command_source_flags.empty()) {
2419 // Echo comments by default
2420 flags |= eHandleCommandFlagEchoCommentCommand;
2421 } else if (m_command_source_flags.back() &
2422 eHandleCommandFlagEchoCommentCommand) {
2423 flags |= eHandleCommandFlagEchoCommentCommand;
2424 }
2425 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2426 flags |= eHandleCommandFlagEchoCommentCommand;
2427 }
2428
2429 if (options.m_print_results == eLazyBoolCalculate) {
2430 if (m_command_source_flags.empty()) {
2431 // Print output by default
2432 flags |= eHandleCommandFlagPrintResult;
2433 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2434 flags |= eHandleCommandFlagPrintResult;
2435 }
2436 } else if (options.m_print_results == eLazyBoolYes) {
2437 flags |= eHandleCommandFlagPrintResult;
2438 }
2439
2440 if (options.m_print_errors == eLazyBoolCalculate) {
2441 if (m_command_source_flags.empty()) {
2442 // Print output by default
2443 flags |= eHandleCommandFlagPrintErrors;
2444 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2445 flags |= eHandleCommandFlagPrintErrors;
2446 }
2447 } else if (options.m_print_errors == eLazyBoolYes) {
2448 flags |= eHandleCommandFlagPrintErrors;
2449 }
2450
2451 if (flags & eHandleCommandFlagPrintResult) {
2452 debugger.GetOutputFile().Printf("Executing commands in '%s'.\n",
2453 cmd_file_path.c_str());
2454 }
2455
2456 // Used for inheriting the right settings when "command source" might
2457 // have nested "command source" commands
2458 lldb::StreamFileSP empty_stream_sp;
2459 m_command_source_flags.push_back(flags);
2460 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2461 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2462 empty_stream_sp, // Pass in an empty stream so we inherit the top
2463 // input reader output stream
2464 empty_stream_sp, // Pass in an empty stream so we inherit the top
2465 // input reader error stream
2466 flags,
2467 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2468 // or written
2469 debugger.GetPrompt(), llvm::StringRef(),
2470 false, // Not multi-line
2471 debugger.GetUseColor(), 0, *this, nullptr));
2472 const bool old_async_execution = debugger.GetAsyncExecution();
2473
2474 // Set synchronous execution if we are not stopping on continue
2475 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2476 debugger.SetAsyncExecution(false);
2477
2478 m_command_source_depth++;
2479
2480 debugger.RunIOHandler(io_handler_sp);
2481 if (!m_command_source_flags.empty())
2482 m_command_source_flags.pop_back();
2483 m_command_source_depth--;
2484 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2485 debugger.SetAsyncExecution(old_async_execution);
2486 }
2487
GetSynchronous()2488 bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2489
SetSynchronous(bool value)2490 void CommandInterpreter::SetSynchronous(bool value) {
2491 // Asynchronous mode is not supported during reproducer replay.
2492 if (repro::Reproducer::Instance().GetLoader())
2493 return;
2494 m_synchronous_execution = value;
2495 }
2496
OutputFormattedHelpText(Stream & strm,llvm::StringRef prefix,llvm::StringRef help_text)2497 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2498 llvm::StringRef prefix,
2499 llvm::StringRef help_text) {
2500 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2501
2502 size_t line_width_max = max_columns - prefix.size();
2503 if (line_width_max < 16)
2504 line_width_max = help_text.size() + prefix.size();
2505
2506 strm.IndentMore(prefix.size());
2507 bool prefixed_yet = false;
2508 while (!help_text.empty()) {
2509 // Prefix the first line, indent subsequent lines to line up
2510 if (!prefixed_yet) {
2511 strm << prefix;
2512 prefixed_yet = true;
2513 } else
2514 strm.Indent();
2515
2516 // Never print more than the maximum on one line.
2517 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2518
2519 // Always break on an explicit newline.
2520 std::size_t first_newline = this_line.find_first_of("\n");
2521
2522 // Don't break on space/tab unless the text is too long to fit on one line.
2523 std::size_t last_space = llvm::StringRef::npos;
2524 if (this_line.size() != help_text.size())
2525 last_space = this_line.find_last_of(" \t");
2526
2527 // Break at whichever condition triggered first.
2528 this_line = this_line.substr(0, std::min(first_newline, last_space));
2529 strm.PutCString(this_line);
2530 strm.EOL();
2531
2532 // Remove whitespace / newlines after breaking.
2533 help_text = help_text.drop_front(this_line.size()).ltrim();
2534 }
2535 strm.IndentLess(prefix.size());
2536 }
2537
OutputFormattedHelpText(Stream & strm,llvm::StringRef word_text,llvm::StringRef separator,llvm::StringRef help_text,size_t max_word_len)2538 void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
2539 llvm::StringRef word_text,
2540 llvm::StringRef separator,
2541 llvm::StringRef help_text,
2542 size_t max_word_len) {
2543 StreamString prefix_stream;
2544 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2545 (int)separator.size(), separator.data());
2546 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2547 }
2548
OutputHelpText(Stream & strm,llvm::StringRef word_text,llvm::StringRef separator,llvm::StringRef help_text,uint32_t max_word_len)2549 void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2550 llvm::StringRef separator,
2551 llvm::StringRef help_text,
2552 uint32_t max_word_len) {
2553 int indent_size = max_word_len + separator.size() + 2;
2554
2555 strm.IndentMore(indent_size);
2556
2557 StreamString text_strm;
2558 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2559 text_strm << separator << " " << help_text;
2560
2561 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2562
2563 llvm::StringRef text = text_strm.GetString();
2564
2565 uint32_t chars_left = max_columns;
2566
2567 auto nextWordLength = [](llvm::StringRef S) {
2568 size_t pos = S.find(' ');
2569 return pos == llvm::StringRef::npos ? S.size() : pos;
2570 };
2571
2572 while (!text.empty()) {
2573 if (text.front() == '\n' ||
2574 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
2575 strm.EOL();
2576 strm.Indent();
2577 chars_left = max_columns - indent_size;
2578 if (text.front() == '\n')
2579 text = text.drop_front();
2580 else
2581 text = text.ltrim(' ');
2582 } else {
2583 strm.PutChar(text.front());
2584 --chars_left;
2585 text = text.drop_front();
2586 }
2587 }
2588
2589 strm.EOL();
2590 strm.IndentLess(indent_size);
2591 }
2592
FindCommandsForApropos(llvm::StringRef search_word,StringList & commands_found,StringList & commands_help,CommandObject::CommandMap & command_map)2593 void CommandInterpreter::FindCommandsForApropos(
2594 llvm::StringRef search_word, StringList &commands_found,
2595 StringList &commands_help, CommandObject::CommandMap &command_map) {
2596 CommandObject::CommandMap::const_iterator pos;
2597
2598 for (pos = command_map.begin(); pos != command_map.end(); ++pos) {
2599 llvm::StringRef command_name = pos->first;
2600 CommandObject *cmd_obj = pos->second.get();
2601
2602 const bool search_short_help = true;
2603 const bool search_long_help = false;
2604 const bool search_syntax = false;
2605 const bool search_options = false;
2606 if (command_name.contains_lower(search_word) ||
2607 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2608 search_long_help, search_syntax,
2609 search_options)) {
2610 commands_found.AppendString(cmd_obj->GetCommandName());
2611 commands_help.AppendString(cmd_obj->GetHelp());
2612 }
2613
2614 if (cmd_obj->IsMultiwordObject()) {
2615 CommandObjectMultiword *cmd_multiword = cmd_obj->GetAsMultiwordCommand();
2616 FindCommandsForApropos(search_word, commands_found, commands_help,
2617 cmd_multiword->GetSubcommandDictionary());
2618 }
2619 }
2620 }
2621
FindCommandsForApropos(llvm::StringRef search_word,StringList & commands_found,StringList & commands_help,bool search_builtin_commands,bool search_user_commands,bool search_alias_commands)2622 void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
2623 StringList &commands_found,
2624 StringList &commands_help,
2625 bool search_builtin_commands,
2626 bool search_user_commands,
2627 bool search_alias_commands) {
2628 CommandObject::CommandMap::const_iterator pos;
2629
2630 if (search_builtin_commands)
2631 FindCommandsForApropos(search_word, commands_found, commands_help,
2632 m_command_dict);
2633
2634 if (search_user_commands)
2635 FindCommandsForApropos(search_word, commands_found, commands_help,
2636 m_user_dict);
2637
2638 if (search_alias_commands)
2639 FindCommandsForApropos(search_word, commands_found, commands_help,
2640 m_alias_dict);
2641 }
2642
UpdateExecutionContext(ExecutionContext * override_context)2643 void CommandInterpreter::UpdateExecutionContext(
2644 ExecutionContext *override_context) {
2645 if (override_context != nullptr) {
2646 m_exe_ctx_ref = *override_context;
2647 } else {
2648 const bool adopt_selected = true;
2649 m_exe_ctx_ref.SetTargetPtr(m_debugger.GetSelectedTarget().get(),
2650 adopt_selected);
2651 }
2652 }
2653
GetProcessOutput()2654 void CommandInterpreter::GetProcessOutput() {
2655 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2656 if (!target_sp)
2657 return;
2658
2659 if (ProcessSP process_sp = target_sp->GetProcessSP())
2660 m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true,
2661 /*flush_stderr*/ true);
2662 }
2663
StartHandlingCommand()2664 void CommandInterpreter::StartHandlingCommand() {
2665 auto idle_state = CommandHandlingState::eIdle;
2666 if (m_command_state.compare_exchange_strong(
2667 idle_state, CommandHandlingState::eInProgress))
2668 lldbassert(m_iohandler_nesting_level == 0);
2669 else
2670 lldbassert(m_iohandler_nesting_level > 0);
2671 ++m_iohandler_nesting_level;
2672 }
2673
FinishHandlingCommand()2674 void CommandInterpreter::FinishHandlingCommand() {
2675 lldbassert(m_iohandler_nesting_level > 0);
2676 if (--m_iohandler_nesting_level == 0) {
2677 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
2678 lldbassert(prev_state != CommandHandlingState::eIdle);
2679 }
2680 }
2681
InterruptCommand()2682 bool CommandInterpreter::InterruptCommand() {
2683 auto in_progress = CommandHandlingState::eInProgress;
2684 return m_command_state.compare_exchange_strong(
2685 in_progress, CommandHandlingState::eInterrupted);
2686 }
2687
WasInterrupted() const2688 bool CommandInterpreter::WasInterrupted() const {
2689 bool was_interrupted =
2690 (m_command_state == CommandHandlingState::eInterrupted);
2691 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
2692 return was_interrupted;
2693 }
2694
PrintCommandOutput(Stream & stream,llvm::StringRef str)2695 void CommandInterpreter::PrintCommandOutput(Stream &stream,
2696 llvm::StringRef str) {
2697 // Split the output into lines and poll for interrupt requests
2698 const char *data = str.data();
2699 size_t size = str.size();
2700 while (size > 0 && !WasInterrupted()) {
2701 size_t chunk_size = 0;
2702 for (; chunk_size < size; ++chunk_size) {
2703 lldbassert(data[chunk_size] != '\0');
2704 if (data[chunk_size] == '\n') {
2705 ++chunk_size;
2706 break;
2707 }
2708 }
2709 chunk_size = stream.Write(data, chunk_size);
2710 lldbassert(size >= chunk_size);
2711 data += chunk_size;
2712 size -= chunk_size;
2713 }
2714 if (size > 0) {
2715 stream.Printf("\n... Interrupted.\n");
2716 }
2717 }
2718
EchoCommandNonInteractive(llvm::StringRef line,const Flags & io_handler_flags) const2719 bool CommandInterpreter::EchoCommandNonInteractive(
2720 llvm::StringRef line, const Flags &io_handler_flags) const {
2721 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
2722 return false;
2723
2724 llvm::StringRef command = line.trim();
2725 if (command.empty())
2726 return true;
2727
2728 if (command.front() == m_comment_char)
2729 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
2730
2731 return true;
2732 }
2733
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)2734 void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
2735 std::string &line) {
2736 // If we were interrupted, bail out...
2737 if (WasInterrupted())
2738 return;
2739
2740 const bool is_interactive = io_handler.GetIsInteractive();
2741 if (!is_interactive) {
2742 // When we are not interactive, don't execute blank lines. This will happen
2743 // sourcing a commands file. We don't want blank lines to repeat the
2744 // previous command and cause any errors to occur (like redefining an
2745 // alias, get an error and stop parsing the commands file).
2746 if (line.empty())
2747 return;
2748
2749 // When using a non-interactive file handle (like when sourcing commands
2750 // from a file) we need to echo the command out so we don't just see the
2751 // command output and no command...
2752 if (EchoCommandNonInteractive(line, io_handler.GetFlags()))
2753 io_handler.GetOutputStreamFileSP()->Printf(
2754 "%s%s\n", io_handler.GetPrompt(), line.c_str());
2755 }
2756
2757 StartHandlingCommand();
2758
2759 lldb_private::CommandReturnObject result;
2760 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
2761
2762 // Now emit the command output text from the command we just executed
2763 if ((result.Succeeded() &&
2764 io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
2765 io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
2766 // Display any STDOUT/STDERR _prior_ to emitting the command result text
2767 GetProcessOutput();
2768
2769 if (!result.GetImmediateOutputStream()) {
2770 llvm::StringRef output = result.GetOutputData();
2771 PrintCommandOutput(*io_handler.GetOutputStreamFileSP(), output);
2772 }
2773
2774 // Now emit the command error text from the command we just executed
2775 if (!result.GetImmediateErrorStream()) {
2776 llvm::StringRef error = result.GetErrorData();
2777 PrintCommandOutput(*io_handler.GetErrorStreamFileSP(), error);
2778 }
2779 }
2780
2781 FinishHandlingCommand();
2782
2783 switch (result.GetStatus()) {
2784 case eReturnStatusInvalid:
2785 case eReturnStatusSuccessFinishNoResult:
2786 case eReturnStatusSuccessFinishResult:
2787 case eReturnStatusStarted:
2788 break;
2789
2790 case eReturnStatusSuccessContinuingNoResult:
2791 case eReturnStatusSuccessContinuingResult:
2792 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
2793 io_handler.SetIsDone(true);
2794 break;
2795
2796 case eReturnStatusFailed:
2797 m_num_errors++;
2798 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError))
2799 io_handler.SetIsDone(true);
2800 break;
2801
2802 case eReturnStatusQuit:
2803 m_quit_requested = true;
2804 io_handler.SetIsDone(true);
2805 break;
2806 }
2807
2808 // Finally, if we're going to stop on crash, check that here:
2809 if (!m_quit_requested && result.GetDidChangeProcessState() &&
2810 io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash) &&
2811 DidProcessStopAbnormally()) {
2812 io_handler.SetIsDone(true);
2813 m_stopped_for_crash = true;
2814 }
2815 }
2816
IOHandlerInterrupt(IOHandler & io_handler)2817 bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
2818 ExecutionContext exe_ctx(GetExecutionContext());
2819 Process *process = exe_ctx.GetProcessPtr();
2820
2821 if (InterruptCommand())
2822 return true;
2823
2824 if (process) {
2825 StateType state = process->GetState();
2826 if (StateIsRunningState(state)) {
2827 process->Halt();
2828 return true; // Don't do any updating when we are running
2829 }
2830 }
2831
2832 ScriptInterpreter *script_interpreter =
2833 m_debugger.GetScriptInterpreter(false);
2834 if (script_interpreter) {
2835 if (script_interpreter->Interrupt())
2836 return true;
2837 }
2838 return false;
2839 }
2840
GetLLDBCommandsFromIOHandler(const char * prompt,IOHandlerDelegate & delegate,void * baton)2841 void CommandInterpreter::GetLLDBCommandsFromIOHandler(
2842 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
2843 Debugger &debugger = GetDebugger();
2844 IOHandlerSP io_handler_sp(
2845 new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
2846 "lldb", // Name of input reader for history
2847 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2848 llvm::StringRef(), // Continuation prompt
2849 true, // Get multiple lines
2850 debugger.GetUseColor(),
2851 0, // Don't show line numbers
2852 delegate, // IOHandlerDelegate
2853 nullptr)); // FileShadowCollector
2854
2855 if (io_handler_sp) {
2856 io_handler_sp->SetUserData(baton);
2857 debugger.PushIOHandler(io_handler_sp);
2858 }
2859 }
2860
GetPythonCommandsFromIOHandler(const char * prompt,IOHandlerDelegate & delegate,void * baton)2861 void CommandInterpreter::GetPythonCommandsFromIOHandler(
2862 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
2863 Debugger &debugger = GetDebugger();
2864 IOHandlerSP io_handler_sp(
2865 new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
2866 "lldb-python", // Name of input reader for history
2867 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2868 llvm::StringRef(), // Continuation prompt
2869 true, // Get multiple lines
2870 debugger.GetUseColor(),
2871 0, // Don't show line numbers
2872 delegate, // IOHandlerDelegate
2873 nullptr)); // FileShadowCollector
2874
2875 if (io_handler_sp) {
2876 io_handler_sp->SetUserData(baton);
2877 debugger.PushIOHandler(io_handler_sp);
2878 }
2879 }
2880
IsActive()2881 bool CommandInterpreter::IsActive() {
2882 return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
2883 }
2884
2885 lldb::IOHandlerSP
GetIOHandler(bool force_create,CommandInterpreterRunOptions * options)2886 CommandInterpreter::GetIOHandler(bool force_create,
2887 CommandInterpreterRunOptions *options) {
2888 // Always re-create the IOHandlerEditline in case the input changed. The old
2889 // instance might have had a non-interactive input and now it does or vice
2890 // versa.
2891 if (force_create || !m_command_io_handler_sp) {
2892 // Always re-create the IOHandlerEditline in case the input changed. The
2893 // old instance might have had a non-interactive input and now it does or
2894 // vice versa.
2895 uint32_t flags = 0;
2896
2897 if (options) {
2898 if (options->m_stop_on_continue == eLazyBoolYes)
2899 flags |= eHandleCommandFlagStopOnContinue;
2900 if (options->m_stop_on_error == eLazyBoolYes)
2901 flags |= eHandleCommandFlagStopOnError;
2902 if (options->m_stop_on_crash == eLazyBoolYes)
2903 flags |= eHandleCommandFlagStopOnCrash;
2904 if (options->m_echo_commands != eLazyBoolNo)
2905 flags |= eHandleCommandFlagEchoCommand;
2906 if (options->m_echo_comment_commands != eLazyBoolNo)
2907 flags |= eHandleCommandFlagEchoCommentCommand;
2908 if (options->m_print_results != eLazyBoolNo)
2909 flags |= eHandleCommandFlagPrintResult;
2910 if (options->m_print_errors != eLazyBoolNo)
2911 flags |= eHandleCommandFlagPrintErrors;
2912 } else {
2913 flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
2914 eHandleCommandFlagPrintErrors;
2915 }
2916
2917 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
2918 m_debugger, IOHandler::Type::CommandInterpreter,
2919 m_debugger.GetInputFileSP(), m_debugger.GetOutputStreamSP(),
2920 m_debugger.GetErrorStreamSP(), flags, "lldb", m_debugger.GetPrompt(),
2921 llvm::StringRef(), // Continuation prompt
2922 false, // Don't enable multiple line input, just single line commands
2923 m_debugger.GetUseColor(),
2924 0, // Don't show line numbers
2925 *this, // IOHandlerDelegate
2926 GetDebugger().GetInputRecorder());
2927 }
2928 return m_command_io_handler_sp;
2929 }
2930
RunCommandInterpreter(bool auto_handle_events,bool spawn_thread,CommandInterpreterRunOptions & options)2931 void CommandInterpreter::RunCommandInterpreter(
2932 bool auto_handle_events, bool spawn_thread,
2933 CommandInterpreterRunOptions &options) {
2934 // Always re-create the command interpreter when we run it in case any file
2935 // handles have changed.
2936 bool force_create = true;
2937 m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
2938 m_stopped_for_crash = false;
2939
2940 if (auto_handle_events)
2941 m_debugger.StartEventHandlerThread();
2942
2943 if (spawn_thread) {
2944 m_debugger.StartIOHandlerThread();
2945 } else {
2946 m_debugger.ExecuteIOHandlers();
2947
2948 if (auto_handle_events)
2949 m_debugger.StopEventHandlerThread();
2950 }
2951 }
2952
2953 CommandObject *
ResolveCommandImpl(std::string & command_line,CommandReturnObject & result)2954 CommandInterpreter::ResolveCommandImpl(std::string &command_line,
2955 CommandReturnObject &result) {
2956 std::string scratch_command(command_line); // working copy so we don't modify
2957 // command_line unless we succeed
2958 CommandObject *cmd_obj = nullptr;
2959 StreamString revised_command_line;
2960 bool wants_raw_input = false;
2961 size_t actual_cmd_name_len = 0;
2962 std::string next_word;
2963 StringList matches;
2964 bool done = false;
2965 while (!done) {
2966 char quote_char = '\0';
2967 std::string suffix;
2968 ExtractCommand(scratch_command, next_word, suffix, quote_char);
2969 if (cmd_obj == nullptr) {
2970 std::string full_name;
2971 bool is_alias = GetAliasFullName(next_word, full_name);
2972 cmd_obj = GetCommandObject(next_word, &matches);
2973 bool is_real_command =
2974 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
2975 if (!is_real_command) {
2976 matches.Clear();
2977 std::string alias_result;
2978 cmd_obj =
2979 BuildAliasResult(full_name, scratch_command, alias_result, result);
2980 revised_command_line.Printf("%s", alias_result.c_str());
2981 if (cmd_obj) {
2982 wants_raw_input = cmd_obj->WantsRawCommandString();
2983 actual_cmd_name_len = cmd_obj->GetCommandName().size();
2984 }
2985 } else {
2986 if (cmd_obj) {
2987 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
2988 actual_cmd_name_len += cmd_name.size();
2989 revised_command_line.Printf("%s", cmd_name.str().c_str());
2990 wants_raw_input = cmd_obj->WantsRawCommandString();
2991 } else {
2992 revised_command_line.Printf("%s", next_word.c_str());
2993 }
2994 }
2995 } else {
2996 if (cmd_obj->IsMultiwordObject()) {
2997 CommandObject *sub_cmd_obj =
2998 cmd_obj->GetSubcommandObject(next_word.c_str());
2999 if (sub_cmd_obj) {
3000 // The subcommand's name includes the parent command's name, so
3001 // restart rather than append to the revised_command_line.
3002 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3003 actual_cmd_name_len = sub_cmd_name.size() + 1;
3004 revised_command_line.Clear();
3005 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
3006 cmd_obj = sub_cmd_obj;
3007 wants_raw_input = cmd_obj->WantsRawCommandString();
3008 } else {
3009 if (quote_char)
3010 revised_command_line.Printf(" %c%s%s%c", quote_char,
3011 next_word.c_str(), suffix.c_str(),
3012 quote_char);
3013 else
3014 revised_command_line.Printf(" %s%s", next_word.c_str(),
3015 suffix.c_str());
3016 done = true;
3017 }
3018 } else {
3019 if (quote_char)
3020 revised_command_line.Printf(" %c%s%s%c", quote_char,
3021 next_word.c_str(), suffix.c_str(),
3022 quote_char);
3023 else
3024 revised_command_line.Printf(" %s%s", next_word.c_str(),
3025 suffix.c_str());
3026 done = true;
3027 }
3028 }
3029
3030 if (cmd_obj == nullptr) {
3031 const size_t num_matches = matches.GetSize();
3032 if (matches.GetSize() > 1) {
3033 StreamString error_msg;
3034 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3035 next_word.c_str());
3036
3037 for (uint32_t i = 0; i < num_matches; ++i) {
3038 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3039 }
3040 result.AppendRawError(error_msg.GetString());
3041 } else {
3042 // We didn't have only one match, otherwise we wouldn't get here.
3043 lldbassert(num_matches == 0);
3044 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3045 next_word.c_str());
3046 }
3047 result.SetStatus(eReturnStatusFailed);
3048 return nullptr;
3049 }
3050
3051 if (cmd_obj->IsMultiwordObject()) {
3052 if (!suffix.empty()) {
3053 result.AppendErrorWithFormat(
3054 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3055 "might be invalid).\n",
3056 cmd_obj->GetCommandName().str().c_str(),
3057 next_word.empty() ? "" : next_word.c_str(),
3058 next_word.empty() ? " -- " : " ", suffix.c_str());
3059 result.SetStatus(eReturnStatusFailed);
3060 return nullptr;
3061 }
3062 } else {
3063 // If we found a normal command, we are done
3064 done = true;
3065 if (!suffix.empty()) {
3066 switch (suffix[0]) {
3067 case '/':
3068 // GDB format suffixes
3069 {
3070 Options *command_options = cmd_obj->GetOptions();
3071 if (command_options &&
3072 command_options->SupportsLongOption("gdb-format")) {
3073 std::string gdb_format_option("--gdb-format=");
3074 gdb_format_option += (suffix.c_str() + 1);
3075
3076 std::string cmd = revised_command_line.GetString();
3077 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3078 if (arg_terminator_idx != std::string::npos) {
3079 // Insert the gdb format option before the "--" that terminates
3080 // options
3081 gdb_format_option.append(1, ' ');
3082 cmd.insert(arg_terminator_idx, gdb_format_option);
3083 revised_command_line.Clear();
3084 revised_command_line.PutCString(cmd);
3085 } else
3086 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3087
3088 if (wants_raw_input &&
3089 FindArgumentTerminator(cmd) == std::string::npos)
3090 revised_command_line.PutCString(" --");
3091 } else {
3092 result.AppendErrorWithFormat(
3093 "the '%s' command doesn't support the --gdb-format option\n",
3094 cmd_obj->GetCommandName().str().c_str());
3095 result.SetStatus(eReturnStatusFailed);
3096 return nullptr;
3097 }
3098 }
3099 break;
3100
3101 default:
3102 result.AppendErrorWithFormat(
3103 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3104 result.SetStatus(eReturnStatusFailed);
3105 return nullptr;
3106 }
3107 }
3108 }
3109 if (scratch_command.empty())
3110 done = true;
3111 }
3112
3113 if (!scratch_command.empty())
3114 revised_command_line.Printf(" %s", scratch_command.c_str());
3115
3116 if (cmd_obj != nullptr)
3117 command_line = revised_command_line.GetString();
3118
3119 return cmd_obj;
3120 }
3121