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