blob: ae4ba9aac30fa96ad8c76bb12868097da35b6145 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- CommandInterpreter.cpp ----------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Chris Lattner30fdc8d2010-06-08 16:52:24 +00006//
7//===----------------------------------------------------------------------===//
8
Jonas Devlieghere796ac802019-02-11 23:13:08 +00009#include <memory>
Kate Stoneb9c1b512016-09-06 20:57:50 +000010#include <stdlib.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000011#include <string>
Caroline Tice4ab31c92010-10-12 21:57:09 +000012#include <vector>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000013
Greg Clayton4a33d312011-06-23 17:59:56 +000014#include "CommandObjectScript.h"
Peter Collingbourne08405b62011-06-23 20:37:26 +000015#include "lldb/Interpreter/CommandObjectRegexCommand.h"
Greg Clayton4a33d312011-06-23 17:59:56 +000016
James Y Knight2ad48212018-05-22 22:53:50 +000017#include "Commands/CommandObjectApropos.h"
18#include "Commands/CommandObjectBreakpoint.h"
19#include "Commands/CommandObjectBugreport.h"
20#include "Commands/CommandObjectCommands.h"
21#include "Commands/CommandObjectDisassemble.h"
22#include "Commands/CommandObjectExpression.h"
23#include "Commands/CommandObjectFrame.h"
24#include "Commands/CommandObjectGUI.h"
25#include "Commands/CommandObjectHelp.h"
26#include "Commands/CommandObjectLanguage.h"
27#include "Commands/CommandObjectLog.h"
28#include "Commands/CommandObjectMemory.h"
29#include "Commands/CommandObjectPlatform.h"
30#include "Commands/CommandObjectPlugin.h"
31#include "Commands/CommandObjectProcess.h"
32#include "Commands/CommandObjectQuit.h"
33#include "Commands/CommandObjectRegister.h"
Jonas Devlieghere9e046f02018-11-13 19:18:16 +000034#include "Commands/CommandObjectReproducer.h"
James Y Knight2ad48212018-05-22 22:53:50 +000035#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/CommandObjectType.h"
41#include "Commands/CommandObjectVersion.h"
42#include "Commands/CommandObjectWatchpoint.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000043
Chris Lattner30fdc8d2010-06-08 16:52:24 +000044#include "lldb/Core/Debugger.h"
Zachary Turner2c1f46d2015-07-30 20:28:07 +000045#include "lldb/Core/PluginManager.h"
Greg Clayton44d93782014-01-27 23:43:24 +000046#include "lldb/Core/StreamFile.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000047#include "lldb/Utility/Log.h"
Pavel Labathd821c992018-08-07 11:07:21 +000048#include "lldb/Utility/State.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000049#include "lldb/Utility/Stream.h"
Pavel Labath38d06322017-06-29 14:32:17 +000050#include "lldb/Utility/Timer.h"
Enrico Granatab5887262012-10-29 21:18:03 +000051
Todd Fialacacde7d2014-09-27 16:54:22 +000052#ifndef LLDB_DISABLE_LIBEDIT
Greg Clayton44d93782014-01-27 23:43:24 +000053#include "lldb/Host/Editline.h"
Todd Fialacacde7d2014-09-27 16:54:22 +000054#endif
Greg Clayton7fb56d02011-02-01 01:31:41 +000055#include "lldb/Host/Host.h"
Zachary Turnera21fee02014-08-21 21:49:24 +000056#include "lldb/Host/HostInfo.h"
Enrico Granatab5887262012-10-29 21:18:03 +000057
Greg Clayton7d2ef162013-03-29 17:03:23 +000058#include "lldb/Interpreter/CommandCompletions.h"
Enrico Granatab5887262012-10-29 21:18:03 +000059#include "lldb/Interpreter/CommandInterpreter.h"
Greg Clayton7d2ef162013-03-29 17:03:23 +000060#include "lldb/Interpreter/CommandReturnObject.h"
Zachary Turner633a29c2015-03-04 01:58:01 +000061#include "lldb/Interpreter/OptionValueProperties.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000062#include "lldb/Interpreter/Options.h"
Zachary Turner633a29c2015-03-04 01:58:01 +000063#include "lldb/Interpreter/Property.h"
Pavel Labath145d95c2018-04-17 18:53:35 +000064#include "lldb/Utility/Args.h"
Enrico Granatab5887262012-10-29 21:18:03 +000065
Chris Lattner30fdc8d2010-06-08 16:52:24 +000066#include "lldb/Target/Process.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067#include "lldb/Target/TargetList.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000068#include "lldb/Target/Thread.h"
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069
Saleem Abdulrasool28606952014-06-27 05:17:41 +000070#include "llvm/ADT/STLExtras.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000071#include "llvm/ADT/SmallString.h"
Zachary Turnera21fee02014-08-21 21:49:24 +000072#include "llvm/Support/Path.h"
Sean Callanan237c3ed2016-12-14 21:31:31 +000073#include "llvm/Support/PrettyStackTrace.h"
Saleem Abdulrasool28606952014-06-27 05:17:41 +000074
Chris Lattner30fdc8d2010-06-08 16:52:24 +000075using namespace lldb;
76using namespace lldb_private;
77
Adrian McCarthy2304b6f2015-04-23 20:00:25 +000078static const char *k_white_space = " \t\v";
Greg Clayton754a9362012-08-23 00:22:02 +000079
Stefan Granitzc678ed72018-10-05 16:49:47 +000080static constexpr bool NoGlobalSetting = true;
81static constexpr uintptr_t DefaultValueTrue = true;
82static constexpr uintptr_t DefaultValueFalse = false;
83static constexpr const char *NoCStrDefault = nullptr;
84
Tatyana Krasnukha8fe53c492018-09-26 18:50:19 +000085static constexpr PropertyDefinition g_properties[] = {
Stefan Granitzc678ed72018-10-05 16:49:47 +000086 {"expand-regex-aliases", OptionValue::eTypeBoolean, NoGlobalSetting,
87 DefaultValueFalse, NoCStrDefault, {},
88 "If true, regular expression alias commands will show the "
89 "expanded command that will be executed. This can be used to "
90 "debug new regular expression alias commands."},
91 {"prompt-on-quit", OptionValue::eTypeBoolean, NoGlobalSetting,
92 DefaultValueTrue, NoCStrDefault, {},
Kate Stoneb9c1b512016-09-06 20:57:50 +000093 "If true, LLDB will prompt you before quitting if there are any live "
94 "processes being debugged. If false, LLDB will quit without asking in any "
95 "case."},
Stefan Granitzc678ed72018-10-05 16:49:47 +000096 {"stop-command-source-on-error", OptionValue::eTypeBoolean, NoGlobalSetting,
97 DefaultValueTrue, NoCStrDefault, {},
98 "If true, LLDB will stop running a 'command source' "
99 "script upon encountering an error."},
100 {"space-repl-prompts", OptionValue::eTypeBoolean, NoGlobalSetting,
101 DefaultValueFalse, NoCStrDefault, {},
102 "If true, blank lines will be printed between between REPL submissions."},
103 {"echo-commands", OptionValue::eTypeBoolean, NoGlobalSetting,
104 DefaultValueTrue, NoCStrDefault, {},
105 "If true, commands will be echoed before they are evaluated."},
106 {"echo-comment-commands", OptionValue::eTypeBoolean, NoGlobalSetting,
107 DefaultValueTrue, NoCStrDefault, {},
108 "If true, commands will be echoed even if they are pure comment lines."}};
Kate Stoneb9c1b512016-09-06 20:57:50 +0000109
110enum {
111 ePropertyExpandRegexAliases = 0,
112 ePropertyPromptOnQuit = 1,
113 ePropertyStopCmdSourceOnError = 2,
Stefan Granitzc678ed72018-10-05 16:49:47 +0000114 eSpaceReplPrompts = 3,
115 eEchoCommands = 4,
116 eEchoCommentCommands = 5
Greg Clayton754a9362012-08-23 00:22:02 +0000117};
118
Kate Stoneb9c1b512016-09-06 20:57:50 +0000119ConstString &CommandInterpreter::GetStaticBroadcasterClass() {
120 static ConstString class_name("lldb.commandInterpreter");
121 return class_name;
Jim Ingham4bddaeb2012-02-16 06:50:00 +0000122}
123
Kate Stoneb9c1b512016-09-06 20:57:50 +0000124CommandInterpreter::CommandInterpreter(Debugger &debugger,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125 bool synchronous_execution)
126 : Broadcaster(debugger.GetBroadcasterManager(),
127 CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
128 Properties(OptionValuePropertiesSP(
129 new OptionValueProperties(ConstString("interpreter")))),
Zachary Turner2c1f46d2015-07-30 20:28:07 +0000130 IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000131 m_debugger(debugger), m_synchronous_execution(synchronous_execution),
132 m_skip_lldbinit_files(false), m_skip_app_init_files(false),
Jonas Devlieghere2b29b432019-04-26 22:43:16 +0000133 m_command_io_handler_sp(), m_comment_char('#'),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134 m_batch_command_mode(false), m_truncation_warning(eNoTruncation),
135 m_command_source_depth(0), m_num_errors(0), m_quit_requested(false),
136 m_stopped_for_crash(false) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000137 SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
138 SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
139 SetEventName(eBroadcastBitQuitCommandReceived, "quit");
140 CheckInWithManager();
141 m_collection_sp->Initialize(g_properties);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000142}
143
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144bool CommandInterpreter::GetExpandRegexAliases() const {
145 const uint32_t idx = ePropertyExpandRegexAliases;
146 return m_collection_sp->GetPropertyAtIndexAsBoolean(
147 nullptr, idx, g_properties[idx].default_uint_value != 0);
Greg Clayton754a9362012-08-23 00:22:02 +0000148}
149
Kate Stoneb9c1b512016-09-06 20:57:50 +0000150bool CommandInterpreter::GetPromptOnQuit() const {
151 const uint32_t idx = ePropertyPromptOnQuit;
152 return m_collection_sp->GetPropertyAtIndexAsBoolean(
153 nullptr, idx, g_properties[idx].default_uint_value != 0);
Enrico Granatabcba2b22013-01-17 21:36:19 +0000154}
Greg Clayton754a9362012-08-23 00:22:02 +0000155
Kate Stoneb9c1b512016-09-06 20:57:50 +0000156void CommandInterpreter::SetPromptOnQuit(bool b) {
157 const uint32_t idx = ePropertyPromptOnQuit;
158 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
Ilia Kacf28be2015-03-23 22:45:13 +0000159}
160
Stefan Granitzc678ed72018-10-05 16:49:47 +0000161bool CommandInterpreter::GetEchoCommands() const {
162 const uint32_t idx = eEchoCommands;
163 return m_collection_sp->GetPropertyAtIndexAsBoolean(
164 nullptr, idx, g_properties[idx].default_uint_value != 0);
165}
166
167void CommandInterpreter::SetEchoCommands(bool b) {
168 const uint32_t idx = eEchoCommands;
169 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
170}
171
172bool CommandInterpreter::GetEchoCommentCommands() const {
173 const uint32_t idx = eEchoCommentCommands;
174 return m_collection_sp->GetPropertyAtIndexAsBoolean(
175 nullptr, idx, g_properties[idx].default_uint_value != 0);
176}
177
178void CommandInterpreter::SetEchoCommentCommands(bool b) {
179 const uint32_t idx = eEchoCommentCommands;
180 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
181}
182
Raphael Isemannc094d232018-07-11 17:18:01 +0000183void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
184 m_allow_exit_code = allow;
185 if (!allow)
186 m_quit_exit_code.reset();
187}
188
189bool CommandInterpreter::SetQuitExitCode(int exit_code) {
190 if (!m_allow_exit_code)
191 return false;
192 m_quit_exit_code = exit_code;
193 return true;
194}
195
196int CommandInterpreter::GetQuitExitCode(bool &exited) const {
197 exited = m_quit_exit_code.hasValue();
198 if (exited)
199 return *m_quit_exit_code;
200 return 0;
201}
202
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203void CommandInterpreter::ResolveCommand(const char *command_line,
204 CommandReturnObject &result) {
205 std::string command = command_line;
206 if (ResolveCommandImpl(command, result) != nullptr) {
207 result.AppendMessageWithFormat("%s", command.c_str());
208 result.SetStatus(eReturnStatusSuccessFinishResult);
209 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +0000210}
211
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212bool CommandInterpreter::GetStopCmdSourceOnError() const {
213 const uint32_t idx = ePropertyStopCmdSourceOnError;
214 return m_collection_sp->GetPropertyAtIndexAsBoolean(
215 nullptr, idx, g_properties[idx].default_uint_value != 0);
Enrico Granata012d4fc2013-06-11 01:26:35 +0000216}
217
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218bool CommandInterpreter::GetSpaceReplPrompts() const {
219 const uint32_t idx = eSpaceReplPrompts;
220 return m_collection_sp->GetPropertyAtIndexAsBoolean(
221 nullptr, idx, g_properties[idx].default_uint_value != 0);
Sean Callanan66810412015-10-19 23:11:07 +0000222}
223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224void CommandInterpreter::Initialize() {
Pavel Labathf9d16472017-05-15 13:02:37 +0000225 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
226 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000227
Kate Stoneb9c1b512016-09-06 20:57:50 +0000228 CommandReturnObject result;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000229
Kate Stoneb9c1b512016-09-06 20:57:50 +0000230 LoadCommandDictionary();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000231
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232 // An alias arguments vector to reuse - reset it before use...
233 OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
234
235 // Set up some initial aliases.
236 CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit", false);
237 if (cmd_obj_sp) {
238 AddAlias("q", cmd_obj_sp);
239 AddAlias("exit", cmd_obj_sp);
240 }
241
242 cmd_obj_sp = GetCommandSPExact("_regexp-attach", false);
243 if (cmd_obj_sp)
244 AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
245
246 cmd_obj_sp = GetCommandSPExact("process detach", false);
247 if (cmd_obj_sp) {
248 AddAlias("detach", cmd_obj_sp);
249 }
250
251 cmd_obj_sp = GetCommandSPExact("process continue", false);
252 if (cmd_obj_sp) {
253 AddAlias("c", cmd_obj_sp);
254 AddAlias("continue", cmd_obj_sp);
255 }
256
257 cmd_obj_sp = GetCommandSPExact("_regexp-break", false);
258 if (cmd_obj_sp)
259 AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
260
261 cmd_obj_sp = GetCommandSPExact("_regexp-tbreak", false);
262 if (cmd_obj_sp)
263 AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
264
265 cmd_obj_sp = GetCommandSPExact("thread step-inst", false);
266 if (cmd_obj_sp) {
267 AddAlias("stepi", cmd_obj_sp);
268 AddAlias("si", cmd_obj_sp);
269 }
270
271 cmd_obj_sp = GetCommandSPExact("thread step-inst-over", false);
272 if (cmd_obj_sp) {
273 AddAlias("nexti", cmd_obj_sp);
274 AddAlias("ni", cmd_obj_sp);
275 }
276
277 cmd_obj_sp = GetCommandSPExact("thread step-in", false);
278 if (cmd_obj_sp) {
279 AddAlias("s", cmd_obj_sp);
280 AddAlias("step", cmd_obj_sp);
281 CommandAlias *sif_alias = AddAlias(
282 "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
283 if (sif_alias) {
284 sif_alias->SetHelp("Step through the current block, stopping if you step "
285 "directly into a function whose name matches the "
286 "TargetFunctionName.");
287 sif_alias->SetSyntax("sif <TargetFunctionName>");
Caroline Ticeca90c472011-05-06 21:37:15 +0000288 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000289 }
Caroline Ticeca90c472011-05-06 21:37:15 +0000290
Kate Stoneb9c1b512016-09-06 20:57:50 +0000291 cmd_obj_sp = GetCommandSPExact("thread step-over", false);
292 if (cmd_obj_sp) {
293 AddAlias("n", cmd_obj_sp);
294 AddAlias("next", cmd_obj_sp);
295 }
296
297 cmd_obj_sp = GetCommandSPExact("thread step-out", false);
298 if (cmd_obj_sp) {
299 AddAlias("finish", cmd_obj_sp);
300 }
301
302 cmd_obj_sp = GetCommandSPExact("frame select", false);
303 if (cmd_obj_sp) {
304 AddAlias("f", cmd_obj_sp);
305 }
306
307 cmd_obj_sp = GetCommandSPExact("thread select", false);
308 if (cmd_obj_sp) {
309 AddAlias("t", cmd_obj_sp);
310 }
311
312 cmd_obj_sp = GetCommandSPExact("_regexp-jump", false);
313 if (cmd_obj_sp) {
314 AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
315 AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
316 }
317
318 cmd_obj_sp = GetCommandSPExact("_regexp-list", false);
319 if (cmd_obj_sp) {
320 AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
321 AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
322 }
323
324 cmd_obj_sp = GetCommandSPExact("_regexp-env", false);
325 if (cmd_obj_sp)
326 AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
327
328 cmd_obj_sp = GetCommandSPExact("memory read", false);
329 if (cmd_obj_sp)
330 AddAlias("x", cmd_obj_sp);
331
332 cmd_obj_sp = GetCommandSPExact("_regexp-up", false);
333 if (cmd_obj_sp)
334 AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
335
336 cmd_obj_sp = GetCommandSPExact("_regexp-down", false);
337 if (cmd_obj_sp)
338 AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
339
340 cmd_obj_sp = GetCommandSPExact("_regexp-display", false);
341 if (cmd_obj_sp)
342 AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
343
344 cmd_obj_sp = GetCommandSPExact("disassemble", false);
345 if (cmd_obj_sp)
346 AddAlias("dis", cmd_obj_sp);
347
348 cmd_obj_sp = GetCommandSPExact("disassemble", false);
349 if (cmd_obj_sp)
350 AddAlias("di", cmd_obj_sp);
351
352 cmd_obj_sp = GetCommandSPExact("_regexp-undisplay", false);
353 if (cmd_obj_sp)
354 AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
355
356 cmd_obj_sp = GetCommandSPExact("_regexp-bt", false);
357 if (cmd_obj_sp)
358 AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
359
360 cmd_obj_sp = GetCommandSPExact("target create", false);
361 if (cmd_obj_sp)
362 AddAlias("file", cmd_obj_sp);
363
364 cmd_obj_sp = GetCommandSPExact("target modules", false);
365 if (cmd_obj_sp)
366 AddAlias("image", cmd_obj_sp);
367
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000368 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000369
370 cmd_obj_sp = GetCommandSPExact("expression", false);
371 if (cmd_obj_sp) {
372 AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
373 AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
374 AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
375 if (auto po = AddAlias("po", cmd_obj_sp, "-O --")) {
376 po->SetHelp("Evaluate an expression on the current thread. Displays any "
377 "returned value with formatting "
378 "controlled by the type's author.");
379 po->SetHelpLong("");
Johnny Chen6d675242012-08-24 18:15:45 +0000380 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000381 AddAlias("parray", cmd_obj_sp, "--element-count %1 --")->SetHelpLong("");
382 AddAlias("poarray", cmd_obj_sp,
383 "--object-description --element-count %1 --")
384 ->SetHelpLong("");
385 }
Johnny Chen6d675242012-08-24 18:15:45 +0000386
Kate Stoneb9c1b512016-09-06 20:57:50 +0000387 cmd_obj_sp = GetCommandSPExact("process kill", false);
388 if (cmd_obj_sp) {
389 AddAlias("kill", cmd_obj_sp);
390 }
Caroline Ticeca90c472011-05-06 21:37:15 +0000391
Kate Stoneb9c1b512016-09-06 20:57:50 +0000392 cmd_obj_sp = GetCommandSPExact("process launch", false);
393 if (cmd_obj_sp) {
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000394 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000395#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
396 AddAlias("r", cmd_obj_sp, "--");
397 AddAlias("run", cmd_obj_sp, "--");
Jason Molenda85da3122012-07-06 02:46:23 +0000398#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000399#if defined(__APPLE__)
400 std::string shell_option;
401 shell_option.append("--shell-expand-args");
402 shell_option.append(" true");
403 shell_option.append(" --");
404 AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
405 AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
406#else
407 StreamString defaultshell;
408 defaultshell.Printf("--shell=%s --",
409 HostInfo::GetDefaultShell().GetPath().c_str());
Zachary Turnerc1564272016-11-16 21:15:24 +0000410 AddAlias("r", cmd_obj_sp, defaultshell.GetString());
411 AddAlias("run", cmd_obj_sp, defaultshell.GetString());
Jason Molenda85da3122012-07-06 02:46:23 +0000412#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000413#endif
414 }
415
416 cmd_obj_sp = GetCommandSPExact("target symbols add", false);
417 if (cmd_obj_sp) {
418 AddAlias("add-dsym", cmd_obj_sp);
419 }
420
421 cmd_obj_sp = GetCommandSPExact("breakpoint set", false);
422 if (cmd_obj_sp) {
423 AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
424 }
Jim Ingham285ae0c2018-10-10 00:51:30 +0000425
426 cmd_obj_sp = GetCommandSPExact("frame variable", false);
427 if (cmd_obj_sp) {
Jim Ingham9082c1c2018-10-12 18:46:02 +0000428 AddAlias("v", cmd_obj_sp);
Jim Ingham285ae0c2018-10-10 00:51:30 +0000429 AddAlias("var", cmd_obj_sp);
430 AddAlias("vo", cmd_obj_sp, "--object-description");
431 }
Jonas Devliegheree5f7d602019-05-03 20:37:09 +0000432
433 cmd_obj_sp = GetCommandSPExact("register", false);
434 if (cmd_obj_sp) {
435 AddAlias("re", cmd_obj_sp);
436 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000437}
438
Kate Stoneb9c1b512016-09-06 20:57:50 +0000439void CommandInterpreter::Clear() {
440 m_command_io_handler_sp.reset();
Greg Clayton0c4129f2014-04-25 00:35:14 +0000441}
442
Kate Stoneb9c1b512016-09-06 20:57:50 +0000443const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
444 // This function has not yet been implemented.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000445
Kate Stoneb9c1b512016-09-06 20:57:50 +0000446 // Look for any embedded script command
447 // If found,
448 // get interpreter object from the command dictionary,
449 // call execute_one_command on it,
450 // get the results as a string,
451 // substitute that string for current stuff.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000452
Kate Stoneb9c1b512016-09-06 20:57:50 +0000453 return arg;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000454}
455
Kate Stoneb9c1b512016-09-06 20:57:50 +0000456void CommandInterpreter::LoadCommandDictionary() {
Pavel Labathf9d16472017-05-15 13:02:37 +0000457 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
458 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000459
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000461
Kate Stoneb9c1b512016-09-06 20:57:50 +0000462 m_command_dict["apropos"] = CommandObjectSP(new CommandObjectApropos(*this));
463 m_command_dict["breakpoint"] =
464 CommandObjectSP(new CommandObjectMultiwordBreakpoint(*this));
465 m_command_dict["bugreport"] =
466 CommandObjectSP(new CommandObjectMultiwordBugreport(*this));
467 m_command_dict["command"] =
468 CommandObjectSP(new CommandObjectMultiwordCommands(*this));
469 m_command_dict["disassemble"] =
470 CommandObjectSP(new CommandObjectDisassemble(*this));
471 m_command_dict["expression"] =
472 CommandObjectSP(new CommandObjectExpression(*this));
473 m_command_dict["frame"] =
474 CommandObjectSP(new CommandObjectMultiwordFrame(*this));
475 m_command_dict["gui"] = CommandObjectSP(new CommandObjectGUI(*this));
476 m_command_dict["help"] = CommandObjectSP(new CommandObjectHelp(*this));
477 m_command_dict["log"] = CommandObjectSP(new CommandObjectLog(*this));
478 m_command_dict["memory"] = CommandObjectSP(new CommandObjectMemory(*this));
479 m_command_dict["platform"] =
480 CommandObjectSP(new CommandObjectPlatform(*this));
481 m_command_dict["plugin"] = CommandObjectSP(new CommandObjectPlugin(*this));
482 m_command_dict["process"] =
483 CommandObjectSP(new CommandObjectMultiwordProcess(*this));
484 m_command_dict["quit"] = CommandObjectSP(new CommandObjectQuit(*this));
485 m_command_dict["register"] =
486 CommandObjectSP(new CommandObjectRegister(*this));
Jonas Devlieghere9e046f02018-11-13 19:18:16 +0000487 m_command_dict["reproducer"] =
488 CommandObjectSP(new CommandObjectReproducer(*this));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000489 m_command_dict["script"] =
490 CommandObjectSP(new CommandObjectScript(*this, script_language));
491 m_command_dict["settings"] =
492 CommandObjectSP(new CommandObjectMultiwordSettings(*this));
493 m_command_dict["source"] =
494 CommandObjectSP(new CommandObjectMultiwordSource(*this));
Davide Italiano24fff242018-04-13 18:02:39 +0000495 m_command_dict["statistics"] = CommandObjectSP(new CommandObjectStats(*this));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000496 m_command_dict["target"] =
497 CommandObjectSP(new CommandObjectMultiwordTarget(*this));
498 m_command_dict["thread"] =
499 CommandObjectSP(new CommandObjectMultiwordThread(*this));
500 m_command_dict["type"] = CommandObjectSP(new CommandObjectType(*this));
501 m_command_dict["version"] = CommandObjectSP(new CommandObjectVersion(*this));
502 m_command_dict["watchpoint"] =
503 CommandObjectSP(new CommandObjectMultiwordWatchpoint(*this));
504 m_command_dict["language"] =
505 CommandObjectSP(new CommandObjectLanguage(*this));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000506
Kate Stoneb9c1b512016-09-06 20:57:50 +0000507 const char *break_regexes[][2] = {
508 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
509 "breakpoint set --file '%1' --line %2"},
510 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
511 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
512 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
513 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
514 "breakpoint set --name '%1'"},
515 {"^(-.*)$", "breakpoint set %1"},
516 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
517 "breakpoint set --name '%2' --shlib '%1'"},
518 {"^\\&(.*[^[:space:]])[[:space:]]*$",
519 "breakpoint set --name '%1' --skip-prologue=0"},
520 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
521 "breakpoint set --name '%1'"}};
Kate Stone7428a182016-07-14 22:03:10 +0000522
Kate Stoneb9c1b512016-09-06 20:57:50 +0000523 size_t num_regexes = llvm::array_lengthof(break_regexes);
Jim Inghamca36cd12012-10-05 19:16:31 +0000524
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000525 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000526 new CommandObjectRegexCommand(
527 *this, "_regexp-break",
Raphael Isemann129fe892018-07-30 21:41:13 +0000528 "Set a breakpoint using one of several shorthand formats.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000529 "\n"
530 "_regexp-break <filename>:<linenum>\n"
531 " main.c:12 // Break at line 12 of "
532 "main.c\n\n"
533 "_regexp-break <linenum>\n"
534 " 12 // Break at line 12 of current "
535 "file\n\n"
536 "_regexp-break 0x<address>\n"
537 " 0x1234000 // Break at address "
538 "0x1234000\n\n"
539 "_regexp-break <name>\n"
540 " main // Break in 'main' after the "
541 "prologue\n\n"
542 "_regexp-break &<name>\n"
543 " &main // Break at first instruction "
544 "in 'main'\n\n"
545 "_regexp-break <module>`<name>\n"
546 " libc.so`malloc // Break in 'malloc' from "
547 "'libc.so'\n\n"
548 "_regexp-break /<source-regex>/\n"
549 " /break here/ // Break on source lines in "
550 "current file\n"
551 " // containing text 'break "
552 "here'.\n",
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000553 2,
554 CommandCompletions::eSymbolCompletion |
555 CommandCompletions::eSourceFileCompletion,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000556 false));
Jim Inghamca36cd12012-10-05 19:16:31 +0000557
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000558 if (break_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000559 bool success = true;
560 for (size_t i = 0; i < num_regexes; i++) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000561 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
Kate Stoneb9c1b512016-09-06 20:57:50 +0000562 break_regexes[i][1]);
563 if (!success)
564 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000565 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000566 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000567 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
Jim Inghamffba2292011-03-22 02:29:32 +0000568
Kate Stoneb9c1b512016-09-06 20:57:50 +0000569 if (success) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000570 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000571 m_command_dict[break_regex_cmd_sp->GetCommandName()] = break_regex_cmd_sp;
Jim Inghamca36cd12012-10-05 19:16:31 +0000572 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000573 }
Jim Inghamca36cd12012-10-05 19:16:31 +0000574
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000575 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000576 new CommandObjectRegexCommand(
577 *this, "_regexp-tbreak",
Raphael Isemann129fe892018-07-30 21:41:13 +0000578 "Set a one-shot breakpoint using one of several shorthand formats.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000579 "\n"
580 "_regexp-break <filename>:<linenum>\n"
581 " main.c:12 // Break at line 12 of "
582 "main.c\n\n"
583 "_regexp-break <linenum>\n"
584 " 12 // Break at line 12 of current "
585 "file\n\n"
586 "_regexp-break 0x<address>\n"
587 " 0x1234000 // Break at address "
588 "0x1234000\n\n"
589 "_regexp-break <name>\n"
590 " main // Break in 'main' after the "
591 "prologue\n\n"
592 "_regexp-break &<name>\n"
593 " &main // Break at first instruction "
594 "in 'main'\n\n"
595 "_regexp-break <module>`<name>\n"
596 " libc.so`malloc // Break in 'malloc' from "
597 "'libc.so'\n\n"
598 "_regexp-break /<source-regex>/\n"
599 " /break here/ // Break on source lines in "
600 "current file\n"
601 " // containing text 'break "
602 "here'.\n",
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000603 2,
604 CommandCompletions::eSymbolCompletion |
605 CommandCompletions::eSourceFileCompletion,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000606 false));
607
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000608 if (tbreak_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000609 bool success = true;
610 for (size_t i = 0; i < num_regexes; i++) {
611 // If you add a resultant command string longer than 1024 characters be
612 // sure to increase the size of this buffer.
613 char buffer[1024];
614 int num_printed =
Frederic Riss49c9d8b2018-06-18 04:34:33 +0000615 snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o 1");
Leonard Mosescu17ffd392017-10-05 23:41:28 +0000616 lldbassert(num_printed < 1024);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000617 UNUSED_IF_ASSERT_DISABLED(num_printed);
618 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000619 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], buffer);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000620 if (!success)
621 break;
Johnny Chen6d675242012-08-24 18:15:45 +0000622 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000623 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000624 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
Kate Stone7428a182016-07-14 22:03:10 +0000625
Kate Stoneb9c1b512016-09-06 20:57:50 +0000626 if (success) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000627 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000628 m_command_dict[tbreak_regex_cmd_sp->GetCommandName()] =
629 tbreak_regex_cmd_sp;
Jim Inghamffba2292011-03-22 02:29:32 +0000630 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000631 }
Kate Stone7428a182016-07-14 22:03:10 +0000632
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000633 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000634 new CommandObjectRegexCommand(
635 *this, "_regexp-attach", "Attach to process by ID or name.",
636 "_regexp-attach <pid> | <process-name>", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000637 if (attach_regex_cmd_up) {
638 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000639 "process attach --pid %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000640 attach_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000641 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
642 // specified get passed to
643 // 'process attach'
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000644 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000645 "process attach --name '%1'") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000646 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
647 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000648 m_command_dict[attach_regex_cmd_sp->GetCommandName()] =
649 attach_regex_cmd_sp;
Jim Inghamffba2292011-03-22 02:29:32 +0000650 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000651 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000652
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000653 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000654 new CommandObjectRegexCommand(*this, "_regexp-down",
655 "Select a newer stack frame. Defaults to "
656 "moving one frame, a numeric argument can "
657 "specify an arbitrary number.",
658 "_regexp-down [<count>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000659 if (down_regex_cmd_up) {
660 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
661 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000662 "frame select -r -%1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000663 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000664 m_command_dict[down_regex_cmd_sp->GetCommandName()] = down_regex_cmd_sp;
Jason Molendabc7748b2011-10-22 01:30:52 +0000665 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000666 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000667
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000668 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000669 new CommandObjectRegexCommand(
670 *this, "_regexp-up",
671 "Select an older stack frame. Defaults to moving one "
672 "frame, a numeric argument can specify an arbitrary number.",
673 "_regexp-up [<count>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000674 if (up_regex_cmd_up) {
675 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
676 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
677 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000678 m_command_dict[up_regex_cmd_sp->GetCommandName()] = up_regex_cmd_sp;
Jason Molendabc7748b2011-10-22 01:30:52 +0000679 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000680 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000681
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000682 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000683 new CommandObjectRegexCommand(
684 *this, "_regexp-display",
685 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
686 "_regexp-display expression", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000687 if (display_regex_cmd_up) {
688 if (display_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000689 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000690 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000691 m_command_dict[display_regex_cmd_sp->GetCommandName()] =
692 display_regex_cmd_sp;
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000693 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000694 }
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000695
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000696 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
697 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
698 "Stop displaying expression at every "
699 "stop (specified by stop-hook index.)",
700 "_regexp-undisplay stop-hook-number", 2, 0,
701 false));
702 if (undisplay_regex_cmd_up) {
703 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000704 "target stop-hook delete %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000705 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000706 m_command_dict[undisplay_regex_cmd_sp->GetCommandName()] =
707 undisplay_regex_cmd_sp;
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000708 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000709 }
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000710
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000711 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000712 new CommandObjectRegexCommand(
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000713 *this, "gdb-remote",
714 "Connect to a process via remote GDB server. "
715 "If no host is specifed, localhost is assumed.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000716 "gdb-remote [<hostname>:]<portnum>", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000717 if (connect_gdb_remote_cmd_up) {
718 if (connect_gdb_remote_cmd_up->AddRegexCommand(
Chris Bieneman51978f52017-04-27 16:13:58 +0000719 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
720 "process connect --plugin gdb-remote connect://%1:%2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000721 connect_gdb_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000722 "^([[:digit:]]+)$",
723 "process connect --plugin gdb-remote connect://localhost:%1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000724 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000725 m_command_dict[command_sp->GetCommandName()] = command_sp;
Jason Molenda4cddfed2012-10-05 05:29:32 +0000726 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000727 }
Jason Molenda4cddfed2012-10-05 05:29:32 +0000728
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000729 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000730 new CommandObjectRegexCommand(
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000731 *this, "kdp-remote",
732 "Connect to a process via remote KDP server. "
733 "If no UDP port is specified, port 41139 is "
734 "assumed.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000735 "kdp-remote <hostname>[:<portnum>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000736 if (connect_kdp_remote_cmd_up) {
737 if (connect_kdp_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000738 "^([^:]+:[[:digit:]]+)$",
739 "process connect --plugin kdp-remote udp://%1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000740 connect_kdp_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000741 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000742 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000743 m_command_dict[command_sp->GetCommandName()] = command_sp;
Greg Clayton6bade322013-02-01 23:33:03 +0000744 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000745 }
Greg Clayton6bade322013-02-01 23:33:03 +0000746
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000747 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000748 new CommandObjectRegexCommand(
749 *this, "_regexp-bt",
750 "Show the current thread's call stack. Any numeric argument "
751 "displays at most that many "
Jim Inghame91ad7d2019-05-02 02:14:08 +0000752 "frames. The argument 'all' displays all threads. Use 'settings"
753 " set frame-format' to customize the printing of individual frames "
754 "and 'settings set thread-format' to customize the thread header.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000755 "bt [<digit> | all]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000756 if (bt_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000757 // accept but don't document "bt -c <number>" -- before bt was a regex
Adrian Prantl05097242018-04-30 16:49:04 +0000758 // command if you wanted to backtrace three frames you would do "bt -c 3"
759 // but the intention is to have this emulate the gdb "bt" command and so
760 // now "bt 3" is the preferred form, in line with gdb.
Stella Stamenova5bac7062019-05-17 18:52:42 +0000761 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000762 "thread backtrace -c %1") &&
Stella Stamenova5bac7062019-05-17 18:52:42 +0000763 bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000764 "thread backtrace -c %1") &&
Stella Stamenova5bac7062019-05-17 18:52:42 +0000765 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
766 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000767 CommandObjectSP command_sp(bt_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000768 m_command_dict[command_sp->GetCommandName()] = command_sp;
Greg Claytonef5651d2013-02-12 18:52:24 +0000769 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000770 }
Greg Claytonef5651d2013-02-12 18:52:24 +0000771
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000772 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000773 new CommandObjectRegexCommand(
774 *this, "_regexp-list",
775 "List relevant source code using one of several shorthand formats.",
776 "\n"
777 "_regexp-list <file>:<line> // List around specific file/line\n"
778 "_regexp-list <line> // List current file around specified "
779 "line\n"
780 "_regexp-list <function-name> // List specified function\n"
781 "_regexp-list 0x<address> // List around specified address\n"
782 "_regexp-list -[<count>] // List previous <count> lines\n"
783 "_regexp-list // List subsequent lines",
784 2, CommandCompletions::eSourceFileCompletion, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000785 if (list_regex_cmd_up) {
786 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000787 "source list --line %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000788 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000789 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
790 "]*$",
791 "source list --file '%1' --line %2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000792 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000793 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
794 "source list --address %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000795 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000796 "source list --reverse") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000797 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000798 "^-([[:digit:]]+)[[:space:]]*$",
799 "source list --reverse --count %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000800 list_regex_cmd_up->AddRegexCommand("^(.+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000801 "source list --name \"%1\"") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000802 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
803 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000804 m_command_dict[list_regex_cmd_sp->GetCommandName()] = list_regex_cmd_sp;
Richard Mittonf86248d2013-09-12 02:20:34 +0000805 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000806 }
Richard Mittonf86248d2013-09-12 02:20:34 +0000807
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000808 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000809 new CommandObjectRegexCommand(
810 *this, "_regexp-env",
811 "Shorthand for viewing and setting environment variables.",
812 "\n"
813 "_regexp-env // Show enrivonment\n"
814 "_regexp-env <name>=<value> // Set an environment variable",
815 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000816 if (env_regex_cmd_up) {
817 if (env_regex_cmd_up->AddRegexCommand("^$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000818 "settings show target.env-vars") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000819 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000820 "settings set target.env-vars %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000821 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000822 m_command_dict[env_regex_cmd_sp->GetCommandName()] = env_regex_cmd_sp;
823 }
824 }
825
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000826 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000827 new CommandObjectRegexCommand(
828 *this, "_regexp-jump", "Set the program counter to a new address.",
829 "\n"
830 "_regexp-jump <line>\n"
831 "_regexp-jump +<line-offset> | -<line-offset>\n"
832 "_regexp-jump <file>:<line>\n"
833 "_regexp-jump *<addr>\n",
834 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000835 if (jump_regex_cmd_up) {
836 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000837 "thread jump --addr %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000838 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000839 "thread jump --line %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000840 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000841 "thread jump --file %1 --line %2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000842 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000843 "thread jump --by %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000844 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000845 m_command_dict[jump_regex_cmd_sp->GetCommandName()] = jump_regex_cmd_sp;
846 }
847 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000848}
849
Kate Stoneb9c1b512016-09-06 20:57:50 +0000850int CommandInterpreter::GetCommandNamesMatchingPartialString(
Raphael Isemann7f888292018-09-13 21:26:00 +0000851 const char *cmd_str, bool include_aliases, StringList &matches,
852 StringList &descriptions) {
853 AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
854 &descriptions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000855
Kate Stoneb9c1b512016-09-06 20:57:50 +0000856 if (include_aliases) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000857 AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
858 &descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000859 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000860
Kate Stoneb9c1b512016-09-06 20:57:50 +0000861 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000862}
863
Raphael Isemann7f888292018-09-13 21:26:00 +0000864CommandObjectSP
865CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
866 bool exact, StringList *matches,
867 StringList *descriptions) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000868 CommandObjectSP command_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000869
Zachary Turnera4496982016-10-05 21:14:38 +0000870 std::string cmd = cmd_str;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000871
Kate Stoneb9c1b512016-09-06 20:57:50 +0000872 if (HasCommands()) {
Zachary Turnera4496982016-10-05 21:14:38 +0000873 auto pos = m_command_dict.find(cmd);
Greg Claytonb5472782015-01-09 19:08:20 +0000874 if (pos != m_command_dict.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000875 command_sp = pos->second;
876 }
877
878 if (include_aliases && HasAliases()) {
879 auto alias_pos = m_alias_dict.find(cmd);
880 if (alias_pos != m_alias_dict.end())
881 command_sp = alias_pos->second;
882 }
883
884 if (HasUserCommands()) {
Zachary Turnera4496982016-10-05 21:14:38 +0000885 auto pos = m_user_dict.find(cmd);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000886 if (pos != m_user_dict.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000887 command_sp = pos->second;
888 }
889
890 if (!exact && !command_sp) {
891 // We will only get into here if we didn't find any exact matches.
892
893 CommandObjectSP user_match_sp, alias_match_sp, real_match_sp;
894
895 StringList local_matches;
896 if (matches == nullptr)
897 matches = &local_matches;
898
899 unsigned int num_cmd_matches = 0;
900 unsigned int num_alias_matches = 0;
901 unsigned int num_user_matches = 0;
902
903 // Look through the command dictionaries one by one, and if we get only one
Adrian Prantl05097242018-04-30 16:49:04 +0000904 // match from any of them in toto, then return that, otherwise return an
905 // empty CommandObjectSP and the list of matches.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000906
907 if (HasCommands()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000908 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
909 *matches, descriptions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000910 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000911
912 if (num_cmd_matches == 1) {
913 cmd.assign(matches->GetStringAtIndex(0));
Zachary Turnera4496982016-10-05 21:14:38 +0000914 auto pos = m_command_dict.find(cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000915 if (pos != m_command_dict.end())
916 real_match_sp = pos->second;
917 }
918
919 if (include_aliases && HasAliases()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000920 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
921 *matches, descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000922 }
923
924 if (num_alias_matches == 1) {
925 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
926 auto alias_pos = m_alias_dict.find(cmd);
927 if (alias_pos != m_alias_dict.end())
928 alias_match_sp = alias_pos->second;
929 }
930
931 if (HasUserCommands()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000932 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
933 *matches, descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000934 }
935
936 if (num_user_matches == 1) {
937 cmd.assign(
938 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
939
Zachary Turnera4496982016-10-05 21:14:38 +0000940 auto pos = m_user_dict.find(cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000941 if (pos != m_user_dict.end())
942 user_match_sp = pos->second;
943 }
944
945 // If we got exactly one match, return that, otherwise return the match
946 // list.
947
948 if (num_user_matches + num_cmd_matches + num_alias_matches == 1) {
949 if (num_cmd_matches)
950 return real_match_sp;
951 else if (num_alias_matches)
952 return alias_match_sp;
953 else
954 return user_match_sp;
955 }
956 } else if (matches && command_sp) {
Zachary Turnera4496982016-10-05 21:14:38 +0000957 matches->AppendString(cmd_str);
Raphael Isemann7f888292018-09-13 21:26:00 +0000958 if (descriptions)
959 descriptions->AppendString(command_sp->GetHelp());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000960 }
961
962 return command_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000963}
964
Zachary Turnera4496982016-10-05 21:14:38 +0000965bool CommandInterpreter::AddCommand(llvm::StringRef name,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000966 const lldb::CommandObjectSP &cmd_sp,
967 bool can_replace) {
968 if (cmd_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +0000969 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
970 "tried to add a CommandObject from a different interpreter");
Kate Stonea487aa42015-01-15 00:52:41 +0000971
Zachary Turnera4496982016-10-05 21:14:38 +0000972 if (name.empty())
973 return false;
974
975 std::string name_sstr(name);
976 auto name_iter = m_command_dict.find(name_sstr);
977 if (name_iter != m_command_dict.end()) {
978 if (!can_replace || !name_iter->second->IsRemovable())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000979 return false;
Zachary Turnera4496982016-10-05 21:14:38 +0000980 name_iter->second = cmd_sp;
981 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000982 m_command_dict[name_sstr] = cmd_sp;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000983 }
Zachary Turnera4496982016-10-05 21:14:38 +0000984 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000985}
986
Zachary Turnera483f572016-10-05 21:14:49 +0000987bool CommandInterpreter::AddUserCommand(llvm::StringRef name,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000988 const lldb::CommandObjectSP &cmd_sp,
989 bool can_replace) {
990 if (cmd_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +0000991 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
992 "tried to add a CommandObject from a different interpreter");
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000993
Kate Stoneb9c1b512016-09-06 20:57:50 +0000994 if (!name.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000995 // do not allow replacement of internal commands
Zachary Turnera483f572016-10-05 21:14:49 +0000996 if (CommandExists(name)) {
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000997 if (!can_replace)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000998 return false;
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000999 if (!m_command_dict[name]->IsRemovable())
Greg Clayton5a314712011-10-14 07:41:33 +00001000 return false;
1001 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001002
Zachary Turnera483f572016-10-05 21:14:49 +00001003 if (UserCommandExists(name)) {
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001004 if (!can_replace)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001005 return false;
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001006 if (!m_user_dict[name]->IsRemovable())
Kate Stoneb9c1b512016-09-06 20:57:50 +00001007 return false;
Caroline Tice844d2302010-12-09 22:52:49 +00001008 }
1009
Kate Stoneb9c1b512016-09-06 20:57:50 +00001010 m_user_dict[name] = cmd_sp;
1011 return true;
1012 }
1013 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001014}
1015
Zachary Turnera4496982016-10-05 21:14:38 +00001016CommandObjectSP CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1017 bool include_aliases) const {
1018 Args cmd_words(cmd_str); // Break up the command string into words, in case
Kate Stoneb9c1b512016-09-06 20:57:50 +00001019 // it's a multi-word command.
1020 CommandObjectSP ret_val; // Possibly empty return value.
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001021
Zachary Turnera4496982016-10-05 21:14:38 +00001022 if (cmd_str.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +00001023 return ret_val;
1024
1025 if (cmd_words.GetArgumentCount() == 1)
Zachary Turnera4496982016-10-05 21:14:38 +00001026 return GetCommandSP(cmd_str, include_aliases, true, nullptr);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001027 else {
1028 // We have a multi-word command (seemingly), so we need to do more work.
1029 // First, get the cmd_obj_sp for the first word in the command.
Zachary Turnera4496982016-10-05 21:14:38 +00001030 CommandObjectSP cmd_obj_sp = GetCommandSP(llvm::StringRef(cmd_words.GetArgumentAtIndex(0)),
Kate Stoneb9c1b512016-09-06 20:57:50 +00001031 include_aliases, true, nullptr);
1032 if (cmd_obj_sp.get() != nullptr) {
Adrian Prantl05097242018-04-30 16:49:04 +00001033 // Loop through the rest of the words in the command (everything passed
1034 // in was supposed to be part of a command name), and find the
1035 // appropriate sub-command SP for each command word....
Kate Stoneb9c1b512016-09-06 20:57:50 +00001036 size_t end = cmd_words.GetArgumentCount();
1037 for (size_t j = 1; j < end; ++j) {
1038 if (cmd_obj_sp->IsMultiwordObject()) {
1039 cmd_obj_sp =
1040 cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(j));
1041 if (cmd_obj_sp.get() == nullptr)
1042 // The sub-command name was invalid. Fail and return the empty
1043 // 'ret_val'.
1044 return ret_val;
1045 } else
1046 // We have more words in the command name, but we don't have a
Zachary Turnera4496982016-10-05 21:14:38 +00001047 // multiword object. Fail and return empty 'ret_val'.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001048 return ret_val;
1049 }
1050 // We successfully looped through all the command words and got valid
Zachary Turnera4496982016-10-05 21:14:38 +00001051 // command objects for them. Assign the last object retrieved to
1052 // 'ret_val'.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001053 ret_val = cmd_obj_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001054 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001055 }
1056 return ret_val;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001057}
1058
Raphael Isemann7f888292018-09-13 21:26:00 +00001059CommandObject *
1060CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1061 StringList *matches,
1062 StringList *descriptions) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001063 CommandObject *command_obj =
Raphael Isemann7f888292018-09-13 21:26:00 +00001064 GetCommandSP(cmd_str, false, true, matches, descriptions).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001065
Kate Stoneb9c1b512016-09-06 20:57:50 +00001066 // If we didn't find an exact match to the command string in the commands,
Adrian Prantl05097242018-04-30 16:49:04 +00001067 // look in the aliases.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001068
1069 if (command_obj)
1070 return command_obj;
1071
Raphael Isemann7f888292018-09-13 21:26:00 +00001072 command_obj = GetCommandSP(cmd_str, true, true, matches, descriptions).get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001073
1074 if (command_obj)
1075 return command_obj;
1076
1077 // If there wasn't an exact match then look for an inexact one in just the
1078 // commands
Zachary Turnera4496982016-10-05 21:14:38 +00001079 command_obj = GetCommandSP(cmd_str, false, false, nullptr).get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001080
1081 // Finally, if there wasn't an inexact match among the commands, look for an
Adrian Prantl05097242018-04-30 16:49:04 +00001082 // inexact match in both the commands and aliases.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001083
1084 if (command_obj) {
1085 if (matches)
1086 matches->AppendString(command_obj->GetCommandName());
Raphael Isemann7f888292018-09-13 21:26:00 +00001087 if (descriptions)
1088 descriptions->AppendString(command_obj->GetHelp());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001089 return command_obj;
1090 }
1091
Raphael Isemann7f888292018-09-13 21:26:00 +00001092 return GetCommandSP(cmd_str, true, false, matches, descriptions).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001093}
1094
Zachary Turnera483f572016-10-05 21:14:49 +00001095bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001096 return m_command_dict.find(cmd) != m_command_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001097}
1098
Zachary Turnera483f572016-10-05 21:14:49 +00001099bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1100 std::string &full_name) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001101 bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
1102 if (exact_match) {
1103 full_name.assign(cmd);
1104 return exact_match;
1105 } else {
1106 StringList matches;
1107 size_t num_alias_matches;
1108 num_alias_matches =
1109 AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1110 if (num_alias_matches == 1) {
1111 // Make sure this isn't shadowing a command in the regular command space:
1112 StringList regular_matches;
1113 const bool include_aliases = false;
1114 const bool exact = false;
1115 CommandObjectSP cmd_obj_sp(
1116 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1117 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1118 return false;
1119 else {
1120 full_name.assign(matches.GetStringAtIndex(0));
1121 return true;
1122 }
1123 } else
1124 return false;
1125 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001126}
1127
Zachary Turnera483f572016-10-05 21:14:49 +00001128bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001129 return m_alias_dict.find(cmd) != m_alias_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001130}
1131
Zachary Turnera483f572016-10-05 21:14:49 +00001132bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001133 return m_user_dict.find(cmd) != m_user_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001134}
1135
Kate Stoneb9c1b512016-09-06 20:57:50 +00001136CommandAlias *
Zachary Turnera483f572016-10-05 21:14:49 +00001137CommandInterpreter::AddAlias(llvm::StringRef alias_name,
Kate Stoneb9c1b512016-09-06 20:57:50 +00001138 lldb::CommandObjectSP &command_obj_sp,
Zachary Turnera483f572016-10-05 21:14:49 +00001139 llvm::StringRef args_string) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001140 if (command_obj_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001141 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1142 "tried to add a CommandObject from a different interpreter");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001143
1144 std::unique_ptr<CommandAlias> command_alias_up(
1145 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1146
1147 if (command_alias_up && command_alias_up->IsValid()) {
1148 m_alias_dict[alias_name] = CommandObjectSP(command_alias_up.get());
1149 return command_alias_up.release();
1150 }
1151
1152 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001153}
1154
Zachary Turnera483f572016-10-05 21:14:49 +00001155bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001156 auto pos = m_alias_dict.find(alias_name);
1157 if (pos != m_alias_dict.end()) {
1158 m_alias_dict.erase(pos);
1159 return true;
1160 }
1161 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001162}
1163
Zachary Turnera483f572016-10-05 21:14:49 +00001164bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001165 auto pos = m_command_dict.find(cmd);
1166 if (pos != m_command_dict.end()) {
1167 if (pos->second->IsRemovable()) {
1168 // Only regular expression objects or python commands are removable
1169 m_command_dict.erase(pos);
1170 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001171 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001172 }
1173 return false;
1174}
Zachary Turnera483f572016-10-05 21:14:49 +00001175bool CommandInterpreter::RemoveUser(llvm::StringRef alias_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001176 CommandObject::CommandMap::iterator pos = m_user_dict.find(alias_name);
1177 if (pos != m_user_dict.end()) {
1178 m_user_dict.erase(pos);
1179 return true;
1180 }
1181 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001182}
1183
Kate Stoneb9c1b512016-09-06 20:57:50 +00001184void CommandInterpreter::GetHelp(CommandReturnObject &result,
1185 uint32_t cmd_types) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001186 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1187 if (!help_prologue.empty()) {
1188 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1189 help_prologue);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001190 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001191
Kate Stoneb9c1b512016-09-06 20:57:50 +00001192 CommandObject::CommandMap::const_iterator pos;
1193 size_t max_len = FindLongestCommandWord(m_command_dict);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001194
Kate Stoneb9c1b512016-09-06 20:57:50 +00001195 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1196 result.AppendMessage("Debugger commands:");
1197 result.AppendMessage("");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001198
Kate Stoneb9c1b512016-09-06 20:57:50 +00001199 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1200 if (!(cmd_types & eCommandTypesHidden) &&
1201 (pos->first.compare(0, 1, "_") == 0))
1202 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001203
Zachary Turner0ac5f982016-11-08 04:12:42 +00001204 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1205 pos->second->GetHelp(), max_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001206 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001207 result.AppendMessage("");
1208 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001209
Kate Stoneb9c1b512016-09-06 20:57:50 +00001210 if (!m_alias_dict.empty() &&
1211 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1212 result.AppendMessageWithFormat(
1213 "Current command abbreviations "
1214 "(type '%shelp command alias' for more info):\n",
1215 GetCommandPrefix());
1216 result.AppendMessage("");
1217 max_len = FindLongestCommandWord(m_alias_dict);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001218
Kate Stoneb9c1b512016-09-06 20:57:50 +00001219 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1220 ++alias_pos) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001221 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
Kate Stoneb9c1b512016-09-06 20:57:50 +00001222 alias_pos->second->GetHelp(), max_len);
Jim Ingham16e0c682011-08-12 23:34:31 +00001223 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001224 result.AppendMessage("");
1225 }
Greg Clayton14a35512011-09-11 00:01:44 +00001226
Kate Stoneb9c1b512016-09-06 20:57:50 +00001227 if (!m_user_dict.empty() &&
1228 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1229 result.AppendMessage("Current user-defined commands:");
1230 result.AppendMessage("");
1231 max_len = FindLongestCommandWord(m_user_dict);
1232 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001233 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1234 pos->second->GetHelp(), max_len);
Greg Clayton14a35512011-09-11 00:01:44 +00001235 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001236 result.AppendMessage("");
1237 }
Greg Clayton14a35512011-09-11 00:01:44 +00001238
Kate Stoneb9c1b512016-09-06 20:57:50 +00001239 result.AppendMessageWithFormat(
1240 "For more information on any command, type '%shelp <command-name>'.\n",
1241 GetCommandPrefix());
Greg Clayton44d93782014-01-27 23:43:24 +00001242}
1243
Zachary Turnera01bccd2016-10-05 21:14:56 +00001244CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1245 llvm::StringRef &command_string) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001246 // This function finds the final, lowest-level, alias-resolved command object
Adrian Prantl05097242018-04-30 16:49:04 +00001247 // whose 'Execute' function will eventually be invoked by the given command
1248 // line.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001249
1250 CommandObject *cmd_obj = nullptr;
1251 size_t start = command_string.find_first_not_of(k_white_space);
1252 size_t end = 0;
1253 bool done = false;
1254 while (!done) {
1255 if (start != std::string::npos) {
1256 // Get the next word from command_string.
1257 end = command_string.find_first_of(k_white_space, start);
1258 if (end == std::string::npos)
1259 end = command_string.size();
1260 std::string cmd_word = command_string.substr(start, end - start);
1261
1262 if (cmd_obj == nullptr)
1263 // Since cmd_obj is NULL we are on our first time through this loop.
Zachary Turnera01bccd2016-10-05 21:14:56 +00001264 // Check to see if cmd_word is a valid command or alias.
Zachary Turnera4496982016-10-05 21:14:38 +00001265 cmd_obj = GetCommandObject(cmd_word);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001266 else if (cmd_obj->IsMultiwordObject()) {
1267 // Our current object is a multi-word object; see if the cmd_word is a
1268 // valid sub-command for our object.
1269 CommandObject *sub_cmd_obj =
1270 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1271 if (sub_cmd_obj)
1272 cmd_obj = sub_cmd_obj;
1273 else // cmd_word was not a valid sub-command word, so we are done
1274 done = true;
1275 } else
1276 // We have a cmd_obj and it is not a multi-word object, so we are done.
1277 done = true;
1278
1279 // If we didn't find a valid command object, or our command object is not
Zachary Turnera01bccd2016-10-05 21:14:56 +00001280 // a multi-word object, or we are at the end of the command_string, then
1281 // we are done. Otherwise, find the start of the next word.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001282
1283 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1284 end >= command_string.size())
1285 done = true;
1286 else
1287 start = command_string.find_first_not_of(k_white_space, end);
1288 } else
1289 // Unable to find any more words.
1290 done = true;
1291 }
1292
Zachary Turnera01bccd2016-10-05 21:14:56 +00001293 command_string = command_string.substr(end);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001294 return cmd_obj;
1295}
1296
1297static const char *k_valid_command_chars =
1298 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1299static void StripLeadingSpaces(std::string &s) {
1300 if (!s.empty()) {
1301 size_t pos = s.find_first_not_of(k_white_space);
1302 if (pos == std::string::npos)
1303 s.clear();
1304 else if (pos == 0)
1305 return;
1306 s.erase(0, pos);
1307 }
1308}
1309
1310static size_t FindArgumentTerminator(const std::string &s) {
1311 const size_t s_len = s.size();
1312 size_t offset = 0;
1313 while (offset < s_len) {
1314 size_t pos = s.find("--", offset);
1315 if (pos == std::string::npos)
1316 break;
1317 if (pos > 0) {
1318 if (isspace(s[pos - 1])) {
Adrian Prantl05097242018-04-30 16:49:04 +00001319 // Check if the string ends "\s--" (where \s is a space character) or
1320 // if we have "\s--\s".
Kate Stoneb9c1b512016-09-06 20:57:50 +00001321 if ((pos + 2 >= s_len) || isspace(s[pos + 2])) {
1322 return pos;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001323 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001324 }
1325 }
1326 offset = pos + 2;
1327 }
1328 return std::string::npos;
1329}
1330
1331static bool ExtractCommand(std::string &command_string, std::string &command,
1332 std::string &suffix, char &quote_char) {
1333 command.clear();
1334 suffix.clear();
1335 StripLeadingSpaces(command_string);
1336
1337 bool result = false;
1338 quote_char = '\0';
1339
1340 if (!command_string.empty()) {
1341 const char first_char = command_string[0];
1342 if (first_char == '\'' || first_char == '"') {
1343 quote_char = first_char;
1344 const size_t end_quote_pos = command_string.find(quote_char, 1);
1345 if (end_quote_pos == std::string::npos) {
1346 command.swap(command_string);
1347 command_string.erase();
1348 } else {
1349 command.assign(command_string, 1, end_quote_pos - 1);
1350 if (end_quote_pos + 1 < command_string.size())
1351 command_string.erase(0, command_string.find_first_not_of(
1352 k_white_space, end_quote_pos + 1));
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001353 else
Kate Stoneb9c1b512016-09-06 20:57:50 +00001354 command_string.erase();
1355 }
1356 } else {
1357 const size_t first_space_pos =
1358 command_string.find_first_of(k_white_space);
1359 if (first_space_pos == std::string::npos) {
1360 command.swap(command_string);
1361 command_string.erase();
1362 } else {
1363 command.assign(command_string, 0, first_space_pos);
1364 command_string.erase(0, command_string.find_first_not_of(
1365 k_white_space, first_space_pos));
1366 }
1367 }
1368 result = true;
1369 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001370
Kate Stoneb9c1b512016-09-06 20:57:50 +00001371 if (!command.empty()) {
1372 // actual commands can't start with '-' or '_'
1373 if (command[0] != '-' && command[0] != '_') {
1374 size_t pos = command.find_first_not_of(k_valid_command_chars);
1375 if (pos > 0 && pos != std::string::npos) {
1376 suffix.assign(command.begin() + pos, command.end());
1377 command.erase(pos);
1378 }
1379 }
1380 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001381
Kate Stoneb9c1b512016-09-06 20:57:50 +00001382 return result;
1383}
1384
1385CommandObject *CommandInterpreter::BuildAliasResult(
Zachary Turnera483f572016-10-05 21:14:49 +00001386 llvm::StringRef alias_name, std::string &raw_input_string,
Kate Stoneb9c1b512016-09-06 20:57:50 +00001387 std::string &alias_result, CommandReturnObject &result) {
1388 CommandObject *alias_cmd_obj = nullptr;
1389 Args cmd_args(raw_input_string);
1390 alias_cmd_obj = GetCommandObject(alias_name);
1391 StreamString result_str;
1392
Zachary Turner5c28c662016-10-03 23:20:36 +00001393 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1394 alias_result.clear();
1395 return alias_cmd_obj;
1396 }
1397 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1398 ((CommandAlias *)alias_cmd_obj)->Desugar();
1399 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1400 alias_cmd_obj = desugared.first.get();
1401 std::string alias_name_str = alias_name;
1402 if ((cmd_args.GetArgumentCount() == 0) ||
Jonas Devlieghere8d20cfd2018-12-21 22:46:10 +00001403 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
Zachary Turner5c28c662016-10-03 23:20:36 +00001404 cmd_args.Unshift(alias_name_str);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001405
Zachary Turnera4496982016-10-05 21:14:38 +00001406 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001407
Zachary Turner5c28c662016-10-03 23:20:36 +00001408 if (!option_arg_vector_sp.get()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00001409 alias_result = result_str.GetString();
Zachary Turner5c28c662016-10-03 23:20:36 +00001410 return alias_cmd_obj;
1411 }
1412 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001413
Zachary Turner5c28c662016-10-03 23:20:36 +00001414 int value_type;
1415 std::string option;
1416 std::string value;
1417 for (const auto &entry : *option_arg_vector) {
1418 std::tie(option, value_type, value) = entry;
1419 if (option == "<argument>") {
1420 result_str.Printf(" %s", value.c_str());
1421 continue;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001422 }
1423
Zachary Turner5c28c662016-10-03 23:20:36 +00001424 result_str.Printf(" %s", option.c_str());
1425 if (value_type == OptionParser::eNoArgument)
1426 continue;
1427
1428 if (value_type != OptionParser::eOptionalArgument)
1429 result_str.Printf(" ");
1430 int index = GetOptionArgumentPosition(value.c_str());
1431 if (index == 0)
1432 result_str.Printf("%s", value.c_str());
1433 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1434
1435 result.AppendErrorWithFormat("Not enough arguments provided; you "
1436 "need at least %d arguments to use "
1437 "this alias.\n",
1438 index);
1439 result.SetStatus(eReturnStatusFailed);
1440 return nullptr;
Zachary Turnerf9fd8cb2016-10-04 01:34:39 +00001441 } else {
1442 size_t strpos = raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
1443 if (strpos != std::string::npos)
1444 raw_input_string = raw_input_string.erase(
1445 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
1446 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
Zachary Turner5c28c662016-10-03 23:20:36 +00001447 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001448 }
Zachary Turner5c28c662016-10-03 23:20:36 +00001449
Zachary Turnerc1564272016-11-16 21:15:24 +00001450 alias_result = result_str.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001451 return alias_cmd_obj;
1452}
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001453
Zachary Turner97206d52017-05-12 04:51:55 +00001454Status CommandInterpreter::PreprocessCommand(std::string &command) {
Adrian Prantl05097242018-04-30 16:49:04 +00001455 // The command preprocessor needs to do things to the command line before any
1456 // parsing of arguments or anything else is done. The only current stuff that
1457 // gets preprocessed is anything enclosed in backtick ('`') characters is
1458 // evaluated as an expression and the result of the expression must be a
1459 // scalar that can be substituted into the command. An example would be:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001460 // (lldb) memory read `$rsp + 20`
Zachary Turner97206d52017-05-12 04:51:55 +00001461 Status error; // Status for any expressions that might not evaluate
Kate Stoneb9c1b512016-09-06 20:57:50 +00001462 size_t start_backtick;
1463 size_t pos = 0;
1464 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001465 // Stop if an error was encountered during the previous iteration.
1466 if (error.Fail())
1467 break;
1468
Kate Stoneb9c1b512016-09-06 20:57:50 +00001469 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
Adrian Prantl05097242018-04-30 16:49:04 +00001470 // The backtick was preceded by a '\' character, remove the slash and
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001471 // don't treat the backtick as the start of an expression.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001472 command.erase(start_backtick - 1, 1);
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001473 // No need to add one to start_backtick since we just deleted a char.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001474 pos = start_backtick;
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001475 continue;
1476 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001477
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001478 const size_t expr_content_start = start_backtick + 1;
1479 const size_t end_backtick = command.find('`', expr_content_start);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001480
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001481 if (end_backtick == std::string::npos) {
1482 // Stop if there's no end backtick.
1483 break;
1484 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001485
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001486 if (end_backtick == expr_content_start) {
1487 // Skip over empty expression. (two backticks in a row)
1488 command.erase(start_backtick, 2);
1489 continue;
1490 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001491
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001492 std::string expr_str(command, expr_content_start,
1493 end_backtick - expr_content_start);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001494
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001495 ExecutionContext exe_ctx(GetExecutionContext());
1496 Target *target = exe_ctx.GetTargetPtr();
1497
1498 // Get a dummy target to allow for calculator mode while processing
1499 // backticks. This also helps break the infinite loop caused when target is
1500 // null.
1501 if (!target)
1502 target = m_debugger.GetDummyTarget();
1503
1504 if (!target)
1505 continue;
1506
1507 ValueObjectSP expr_result_valobj_sp;
1508
1509 EvaluateExpressionOptions options;
1510 options.SetCoerceToId(false);
1511 options.SetUnwindOnError(true);
1512 options.SetIgnoreBreakpoints(true);
1513 options.SetKeepInMemory(false);
1514 options.SetTryAllThreads(true);
1515 options.SetTimeout(llvm::None);
1516
1517 ExpressionResults expr_result =
1518 target->EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1519 expr_result_valobj_sp, options);
1520
1521 if (expr_result == eExpressionCompleted) {
1522 Scalar scalar;
1523 if (expr_result_valobj_sp)
1524 expr_result_valobj_sp =
1525 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1526 expr_result_valobj_sp->GetDynamicValueType(), true);
1527 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1528 command.erase(start_backtick, end_backtick - start_backtick + 1);
1529 StreamString value_strm;
1530 const bool show_type = false;
1531 scalar.GetValue(&value_strm, show_type);
1532 size_t value_string_size = value_strm.GetSize();
1533 if (value_string_size) {
1534 command.insert(start_backtick, value_strm.GetString());
1535 pos = start_backtick + value_string_size;
1536 continue;
1537 } else {
1538 error.SetErrorStringWithFormat("expression value didn't result "
1539 "in a scalar value for the "
1540 "expression '%s'",
1541 expr_str.c_str());
1542 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001543 }
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001544 } else {
1545 error.SetErrorStringWithFormat("expression value didn't result "
1546 "in a scalar value for the "
1547 "expression '%s'",
1548 expr_str.c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001549 break;
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001550 }
1551
1552 continue;
1553 }
1554
1555 if (expr_result_valobj_sp)
1556 error = expr_result_valobj_sp->GetError();
1557
1558 if (error.Success()) {
1559 switch (expr_result) {
1560 case eExpressionSetupError:
1561 error.SetErrorStringWithFormat(
1562 "expression setup error for the expression '%s'", expr_str.c_str());
1563 break;
1564 case eExpressionParseError:
1565 error.SetErrorStringWithFormat(
1566 "expression parse error for the expression '%s'", expr_str.c_str());
1567 break;
1568 case eExpressionResultUnavailable:
1569 error.SetErrorStringWithFormat(
1570 "expression error fetching result for the expression '%s'",
1571 expr_str.c_str());
1572 break;
1573 case eExpressionCompleted:
1574 break;
1575 case eExpressionDiscarded:
1576 error.SetErrorStringWithFormat(
1577 "expression discarded for the expression '%s'", expr_str.c_str());
1578 break;
1579 case eExpressionInterrupted:
1580 error.SetErrorStringWithFormat(
1581 "expression interrupted for the expression '%s'", expr_str.c_str());
1582 break;
1583 case eExpressionHitBreakpoint:
1584 error.SetErrorStringWithFormat(
1585 "expression hit breakpoint for the expression '%s'",
1586 expr_str.c_str());
1587 break;
1588 case eExpressionTimedOut:
1589 error.SetErrorStringWithFormat(
1590 "expression timed out for the expression '%s'", expr_str.c_str());
1591 break;
1592 case eExpressionStoppedForDebug:
1593 error.SetErrorStringWithFormat("expression stop at entry point "
1594 "for debugging for the "
1595 "expression '%s'",
1596 expr_str.c_str());
1597 break;
1598 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001599 }
1600 }
1601 return error;
1602}
1603
1604bool CommandInterpreter::HandleCommand(const char *command_line,
1605 LazyBool lazy_add_to_history,
1606 CommandReturnObject &result,
1607 ExecutionContext *override_context,
1608 bool repeat_on_empty_command,
1609 bool no_context_switching)
1610
1611{
1612
1613 std::string command_string(command_line);
1614 std::string original_command_string(command_line);
1615
1616 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS));
Jim Ingham8f7db522016-12-15 00:30:30 +00001617 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
Sean Callanan237c3ed2016-12-14 21:31:31 +00001618 command_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001619
1620 if (log)
1621 log->Printf("Processing command: %s", command_line);
1622
Pavel Labathf9d16472017-05-15 13:02:37 +00001623 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
1624 Timer scoped_timer(func_cat, "Handling command: %s.", command_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001625
1626 if (!no_context_switching)
1627 UpdateExecutionContext(override_context);
1628
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001629 if (WasInterrupted()) {
1630 result.AppendError("interrupted");
1631 result.SetStatus(eReturnStatusFailed);
1632 return false;
1633 }
1634
Kate Stoneb9c1b512016-09-06 20:57:50 +00001635 bool add_to_history;
1636 if (lazy_add_to_history == eLazyBoolCalculate)
1637 add_to_history = (m_command_source_depth == 0);
1638 else
1639 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1640
1641 bool empty_command = false;
1642 bool comment_command = false;
1643 if (command_string.empty())
1644 empty_command = true;
1645 else {
1646 const char *k_space_characters = "\t\n\v\f\r ";
1647
1648 size_t non_space = command_string.find_first_not_of(k_space_characters);
Adrian Prantl05097242018-04-30 16:49:04 +00001649 // Check for empty line or comment line (lines whose first non-space
1650 // character is the comment character for this interpreter)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001651 if (non_space == std::string::npos)
1652 empty_command = true;
1653 else if (command_string[non_space] == m_comment_char)
1654 comment_command = true;
1655 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
Zachary Turner53877af2016-11-18 23:22:42 +00001656 llvm::StringRef search_str(command_string);
1657 search_str = search_str.drop_front(non_space);
1658 if (auto hist_str = m_command_history.FindString(search_str)) {
1659 add_to_history = false;
1660 command_string = *hist_str;
1661 original_command_string = *hist_str;
1662 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001663 result.AppendErrorWithFormat("Could not find entry: %s in history",
1664 command_string.c_str());
1665 result.SetStatus(eReturnStatusFailed);
1666 return false;
1667 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001668 }
1669 }
1670
1671 if (empty_command) {
1672 if (repeat_on_empty_command) {
1673 if (m_command_history.IsEmpty()) {
1674 result.AppendError("empty command");
1675 result.SetStatus(eReturnStatusFailed);
1676 return false;
1677 } else {
1678 command_line = m_repeat_command.c_str();
1679 command_string = command_line;
1680 original_command_string = command_line;
1681 if (m_repeat_command.empty()) {
1682 result.AppendErrorWithFormat("No auto repeat.\n");
1683 result.SetStatus(eReturnStatusFailed);
1684 return false;
1685 }
1686 }
1687 add_to_history = false;
1688 } else {
1689 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1690 return true;
1691 }
1692 } else if (comment_command) {
1693 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1694 return true;
1695 }
1696
Zachary Turner97206d52017-05-12 04:51:55 +00001697 Status error(PreprocessCommand(command_string));
Kate Stoneb9c1b512016-09-06 20:57:50 +00001698
1699 if (error.Fail()) {
1700 result.AppendError(error.AsCString());
1701 result.SetStatus(eReturnStatusFailed);
1702 return false;
1703 }
1704
1705 // Phase 1.
1706
1707 // Before we do ANY kind of argument processing, we need to figure out what
1708 // the real/final command object is for the specified command. This gets
1709 // complicated by the fact that the user could have specified an alias, and,
1710 // in translating the alias, there may also be command options and/or even
1711 // data (including raw text strings) that need to be found and inserted into
1712 // the command line as part of the translation. So this first step is plain
1713 // look-up and replacement, resulting in:
1714 // 1. the command object whose Execute method will actually be called
1715 // 2. a revised command string, with all substitutions and replacements
1716 // taken care of
1717 // From 1 above, we can determine whether the Execute function wants raw
1718 // input or not.
1719
1720 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1721
1722 // Although the user may have abbreviated the command, the command_string now
Adrian Prantl05097242018-04-30 16:49:04 +00001723 // has the command expanded to the full name. For example, if the input was
1724 // "br s -n main", command_string is now "breakpoint set -n main".
Kate Stoneb9c1b512016-09-06 20:57:50 +00001725 if (log) {
Zachary Turnera4496982016-10-05 21:14:38 +00001726 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1727 log->Printf("HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001728 log->Printf("HandleCommand, (revised) command_string: '%s'",
1729 command_string.c_str());
1730 const bool wants_raw_input =
1731 (cmd_obj != NULL) ? cmd_obj->WantsRawCommandString() : false;
1732 log->Printf("HandleCommand, wants_raw_input:'%s'",
1733 wants_raw_input ? "True" : "False");
1734 }
1735
1736 // Phase 2.
1737 // Take care of things like setting up the history command & calling the
Adrian Prantl05097242018-04-30 16:49:04 +00001738 // appropriate Execute method on the CommandObject, with the appropriate
1739 // arguments.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001740
1741 if (cmd_obj != nullptr) {
1742 if (add_to_history) {
1743 Args command_args(command_string);
1744 const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
1745 if (repeat_command != nullptr)
1746 m_repeat_command.assign(repeat_command);
1747 else
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00001748 m_repeat_command.assign(original_command_string);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001749
1750 m_command_history.AppendString(original_command_string);
1751 }
1752
1753 std::string remainder;
Zachary Turnera4496982016-10-05 21:14:38 +00001754 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001755 if (actual_cmd_name_len < command_string.length())
1756 remainder = command_string.substr(actual_cmd_name_len);
1757
1758 // Remove any initial spaces
1759 size_t pos = remainder.find_first_not_of(k_white_space);
1760 if (pos != 0 && pos != std::string::npos)
1761 remainder.erase(0, pos);
1762
1763 if (log)
1764 log->Printf(
1765 "HandleCommand, command line after removing command name(s): '%s'",
1766 remainder.c_str());
1767
1768 cmd_obj->Execute(remainder.c_str(), result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001769 }
1770
1771 if (log)
1772 log->Printf("HandleCommand, command %s",
1773 (result.Succeeded() ? "succeeded" : "did not succeed"));
1774
1775 return result.Succeeded();
1776}
1777
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001778int CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001779 int num_command_matches = 0;
1780 bool look_for_subcommand = false;
1781
1782 // For any of the command completions a unique match will be a complete word.
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001783 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001784
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001785 if (request.GetCursorIndex() == -1) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001786 // We got nothing on the command line, so return the list of commands
1787 bool include_aliases = true;
Raphael Isemann7f888292018-09-13 21:26:00 +00001788 StringList new_matches, descriptions;
1789 num_command_matches = GetCommandNamesMatchingPartialString(
1790 "", include_aliases, new_matches, descriptions);
1791 request.AddCompletions(new_matches, descriptions);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001792 } else if (request.GetCursorIndex() == 0) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001793 // The cursor is in the first argument, so just do a lookup in the
1794 // dictionary.
Raphael Isemann7f888292018-09-13 21:26:00 +00001795 StringList new_matches, new_descriptions;
1796 CommandObject *cmd_obj =
1797 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
1798 &new_matches, &new_descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001799
1800 if (num_command_matches == 1 && cmd_obj && cmd_obj->IsMultiwordObject() &&
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001801 new_matches.GetStringAtIndex(0) != nullptr &&
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001802 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001803 new_matches.GetStringAtIndex(0)) == 0) {
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001804 if (request.GetParsedLine().GetArgumentCount() == 1) {
1805 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001806 } else {
1807 look_for_subcommand = true;
1808 num_command_matches = 0;
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001809 new_matches.DeleteStringAtIndex(0);
Raphael Isemann7f888292018-09-13 21:26:00 +00001810 new_descriptions.DeleteStringAtIndex(0);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001811 request.GetParsedLine().AppendArgument(llvm::StringRef());
1812 request.SetCursorIndex(request.GetCursorIndex() + 1);
1813 request.SetCursorCharPosition(0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001814 }
1815 }
Raphael Isemann7f888292018-09-13 21:26:00 +00001816 request.AddCompletions(new_matches, new_descriptions);
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001817 num_command_matches = request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001818 }
1819
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001820 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001821 // We are completing further on into a commands arguments, so find the
Adrian Prantl05097242018-04-30 16:49:04 +00001822 // command and tell it to complete the command. First see if there is a
1823 // matching initial command:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001824 CommandObject *command_object =
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001825 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
Kate Stoneb9c1b512016-09-06 20:57:50 +00001826 if (command_object == nullptr) {
1827 return 0;
1828 } else {
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001829 request.GetParsedLine().Shift();
1830 request.SetCursorIndex(request.GetCursorIndex() - 1);
1831 num_command_matches = command_object->HandleCompletion(request);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001832 }
1833 }
1834
1835 return num_command_matches;
1836}
1837
1838int CommandInterpreter::HandleCompletion(
1839 const char *current_line, const char *cursor, const char *last_char,
Raphael Isemann7f888292018-09-13 21:26:00 +00001840 int match_start_point, int max_return_elements, StringList &matches,
1841 StringList &descriptions) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001842
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001843 llvm::StringRef command_line(current_line, last_char - current_line);
Raphael Isemann7f888292018-09-13 21:26:00 +00001844 CompletionResult result;
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001845 CompletionRequest request(command_line, cursor - current_line,
Raphael Isemann7f888292018-09-13 21:26:00 +00001846 match_start_point, max_return_elements, result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001847 // Don't complete comments, and if the line we are completing is just the
Adrian Prantl05097242018-04-30 16:49:04 +00001848 // history repeat character, substitute the appropriate history line.
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001849 const char *first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001850 if (first_arg) {
1851 if (first_arg[0] == m_comment_char)
1852 return 0;
1853 else if (first_arg[0] == CommandHistory::g_repeat_char) {
Zachary Turner53877af2016-11-18 23:22:42 +00001854 if (auto hist_str = m_command_history.FindString(first_arg)) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001855 matches.InsertStringAtIndex(0, *hist_str);
Raphael Isemann7f888292018-09-13 21:26:00 +00001856 descriptions.InsertStringAtIndex(0, "Previous command history event");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001857 return -2;
1858 } else
1859 return 0;
1860 }
1861 }
1862
Kate Stoneb9c1b512016-09-06 20:57:50 +00001863 // Only max_return_elements == -1 is supported at present:
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001864 lldbassert(max_return_elements == -1);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001865
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001866 int num_command_matches = HandleCompletionMatches(request);
Raphael Isemann7f888292018-09-13 21:26:00 +00001867 result.GetMatches(matches);
1868 result.GetDescriptions(descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001869
1870 if (num_command_matches <= 0)
1871 return num_command_matches;
1872
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001873 if (request.GetParsedLine().GetArgumentCount() == 0) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001874 // If we got an empty string, insert nothing.
1875 matches.InsertStringAtIndex(0, "");
Raphael Isemann7f888292018-09-13 21:26:00 +00001876 descriptions.InsertStringAtIndex(0, "");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001877 } else {
1878 // Now figure out if there is a common substring, and if so put that in
Adrian Prantl05097242018-04-30 16:49:04 +00001879 // element 0, otherwise put an empty string in element 0.
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001880 std::string command_partial_str = request.GetCursorArgumentPrefix().str();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001881
1882 std::string common_prefix;
1883 matches.LongestCommonPrefix(common_prefix);
1884 const size_t partial_name_len = command_partial_str.size();
1885 common_prefix.erase(0, partial_name_len);
1886
Adrian Prantl05097242018-04-30 16:49:04 +00001887 // If we matched a unique single command, add a space... Only do this if
1888 // the completer told us this was a complete word, however...
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001889 if (num_command_matches == 1 && request.GetWordComplete()) {
1890 char quote_char = request.GetParsedLine()[request.GetCursorIndex()].quote;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001891 common_prefix =
1892 Args::EscapeLLDBCommandArgument(common_prefix, quote_char);
1893 if (quote_char != '\0')
1894 common_prefix.push_back(quote_char);
1895 common_prefix.push_back(' ');
1896 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001897 matches.InsertStringAtIndex(0, common_prefix.c_str());
Raphael Isemann7f888292018-09-13 21:26:00 +00001898 descriptions.InsertStringAtIndex(0, "");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001899 }
1900 return num_command_matches;
1901}
1902
1903CommandInterpreter::~CommandInterpreter() {}
1904
Zachary Turner514d8cd2016-09-23 18:06:53 +00001905void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001906 EventSP prompt_change_event_sp(
1907 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
1908 ;
1909 BroadcastEvent(prompt_change_event_sp);
1910 if (m_command_io_handler_sp)
1911 m_command_io_handler_sp->SetPrompt(new_prompt);
1912}
1913
Zachary Turner7a120c82016-11-13 03:05:58 +00001914bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001915 // Check AutoConfirm first:
1916 if (m_debugger.GetAutoConfirm())
1917 return default_answer;
1918
1919 IOHandlerConfirm *confirm =
1920 new IOHandlerConfirm(m_debugger, message, default_answer);
1921 IOHandlerSP io_handler_sp(confirm);
1922 m_debugger.RunIOHandler(io_handler_sp);
1923 return confirm->GetResponse();
1924}
1925
Zachary Turnera483f572016-10-05 21:14:49 +00001926const CommandAlias *
1927CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001928 OptionArgVectorSP ret_val;
1929
Zachary Turnera483f572016-10-05 21:14:49 +00001930 auto pos = m_alias_dict.find(alias_name);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001931 if (pos != m_alias_dict.end())
1932 return (CommandAlias *)pos->second.get();
1933
1934 return nullptr;
1935}
1936
Zachary Turnera4496982016-10-05 21:14:38 +00001937bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001938
Zachary Turnera4496982016-10-05 21:14:38 +00001939bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001940
Zachary Turnera4496982016-10-05 21:14:38 +00001941bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001942
Zachary Turnera4496982016-10-05 21:14:38 +00001943bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001944
1945void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
1946 const char *alias_name,
1947 Args &cmd_args,
1948 std::string &raw_input_string,
1949 CommandReturnObject &result) {
1950 OptionArgVectorSP option_arg_vector_sp =
1951 GetAlias(alias_name)->GetOptionArguments();
1952
1953 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
1954
1955 // Make sure that the alias name is the 0th element in cmd_args
1956 std::string alias_name_str = alias_name;
Jonas Devlieghere8d20cfd2018-12-21 22:46:10 +00001957 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
Zachary Turner5c725f32016-09-19 21:56:59 +00001958 cmd_args.Unshift(alias_name_str);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001959
1960 Args new_args(alias_cmd_obj->GetCommandName());
1961 if (new_args.GetArgumentCount() == 2)
1962 new_args.Shift();
1963
1964 if (option_arg_vector_sp.get()) {
1965 if (wants_raw_input) {
1966 // We have a command that both has command options and takes raw input.
Adrian Prantl05097242018-04-30 16:49:04 +00001967 // Make *sure* it has a " -- " in the right place in the
1968 // raw_input_string.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001969 size_t pos = raw_input_string.find(" -- ");
1970 if (pos == std::string::npos) {
1971 // None found; assume it goes at the beginning of the raw input string
1972 raw_input_string.insert(0, " -- ");
1973 }
1974 }
1975
1976 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1977 const size_t old_size = cmd_args.GetArgumentCount();
1978 std::vector<bool> used(old_size + 1, false);
1979
1980 used[0] = true;
1981
Zachary Turner5c28c662016-10-03 23:20:36 +00001982 int value_type;
1983 std::string option;
1984 std::string value;
1985 for (const auto &option_entry : *option_arg_vector) {
1986 std::tie(option, value_type, value) = option_entry;
1987 if (option == "<argument>") {
1988 if (!wants_raw_input || (value != "--")) {
1989 // Since we inserted this above, make sure we don't insert it twice
1990 new_args.AppendArgument(value);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001991 }
Zachary Turner5c28c662016-10-03 23:20:36 +00001992 continue;
1993 }
1994
1995 if (value_type != OptionParser::eOptionalArgument)
1996 new_args.AppendArgument(option);
1997
1998 if (value == "<no-argument>")
1999 continue;
2000
2001 int index = GetOptionArgumentPosition(value.c_str());
2002 if (index == 0) {
2003 // value was NOT a positional argument; must be a real value
2004 if (value_type != OptionParser::eOptionalArgument)
2005 new_args.AppendArgument(value);
2006 else {
2007 char buffer[255];
2008 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
2009 value.c_str());
2010 new_args.AppendArgument(llvm::StringRef(buffer));
2011 }
2012
2013 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2014 result.AppendErrorWithFormat("Not enough arguments provided; you "
2015 "need at least %d arguments to use "
2016 "this alias.\n",
2017 index);
2018 result.SetStatus(eReturnStatusFailed);
2019 return;
2020 } else {
2021 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2022 size_t strpos =
2023 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2024 if (strpos != std::string::npos) {
2025 raw_input_string = raw_input_string.erase(
2026 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2027 }
2028
2029 if (value_type != OptionParser::eOptionalArgument)
2030 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2031 else {
2032 char buffer[255];
2033 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
2034 cmd_args.GetArgumentAtIndex(index));
2035 new_args.AppendArgument(buffer);
2036 }
2037 used[index] = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002038 }
2039 }
2040
Zachary Turner97d2c402016-10-05 23:40:23 +00002041 for (auto entry : llvm::enumerate(cmd_args.entries())) {
Zachary Turner4eb84492017-03-13 17:12:12 +00002042 if (!used[entry.index()] && !wants_raw_input)
2043 new_args.AppendArgument(entry.value().ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002044 }
2045
2046 cmd_args.Clear();
2047 cmd_args.SetArguments(new_args.GetArgumentCount(),
2048 new_args.GetConstArgumentVector());
2049 } else {
2050 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2051 // This alias was not created with any options; nothing further needs to be
Adrian Prantl05097242018-04-30 16:49:04 +00002052 // done, unless it is a command that wants raw input, in which case we need
2053 // to clear the rest of the data from cmd_args, since its in the raw input
2054 // string.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002055 if (wants_raw_input) {
2056 cmd_args.Clear();
2057 cmd_args.SetArguments(new_args.GetArgumentCount(),
2058 new_args.GetConstArgumentVector());
2059 }
2060 return;
2061 }
2062
2063 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2064 return;
2065}
2066
2067int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2068 int position = 0; // Any string that isn't an argument position, i.e. '%'
2069 // followed by an integer, gets a position
2070 // of zero.
2071
2072 const char *cptr = in_string;
2073
2074 // Does it start with '%'
2075 if (cptr[0] == '%') {
2076 ++cptr;
2077
2078 // Is the rest of it entirely digits?
2079 if (isdigit(cptr[0])) {
2080 const char *start = cptr;
2081 while (isdigit(cptr[0]))
2082 ++cptr;
2083
Adrian Prantl05097242018-04-30 16:49:04 +00002084 // We've gotten to the end of the digits; are we at the end of the
2085 // string?
Kate Stoneb9c1b512016-09-06 20:57:50 +00002086 if (cptr[0] == '\0')
2087 position = atoi(start);
2088 }
2089 }
2090
2091 return position;
2092}
2093
2094void CommandInterpreter::SourceInitFile(bool in_cwd,
2095 CommandReturnObject &result) {
2096 FileSpec init_file;
2097 if (in_cwd) {
Jonas Devlieghere2edcad72019-05-06 20:45:31 +00002098 lldb::TargetPropertiesSP properties = Target::GetGlobalProperties();
2099 if (properties) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002100 // In the current working directory we don't load any program specific
2101 // .lldbinit files, we only look for a ".lldbinit" file.
2102 if (m_skip_lldbinit_files)
2103 return;
2104
Jonas Devlieghere2edcad72019-05-06 20:45:31 +00002105 LoadCWDlldbinitFile should_load = properties->GetLoadCWDlldbinitFile();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002106 if (should_load == eLoadCWDlldbinitWarn) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002107 FileSpec dot_lldb(".lldbinit");
2108 FileSystem::Instance().Resolve(dot_lldb);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002109 llvm::SmallString<64> home_dir_path;
2110 llvm::sys::path::home_directory(home_dir_path);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002111 FileSpec homedir_dot_lldb(home_dir_path.c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002112 homedir_dot_lldb.AppendPathComponent(".lldbinit");
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002113 FileSystem::Instance().Resolve(homedir_dot_lldb);
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +00002114 if (FileSystem::Instance().Exists(dot_lldb) &&
Kate Stoneb9c1b512016-09-06 20:57:50 +00002115 dot_lldb.GetDirectory() != homedir_dot_lldb.GetDirectory()) {
2116 result.AppendErrorWithFormat(
2117 "There is a .lldbinit file in the current directory which is not "
2118 "being read.\n"
2119 "To silence this warning without sourcing in the local "
2120 ".lldbinit,\n"
2121 "add the following to the lldbinit file in your home directory:\n"
2122 " settings set target.load-cwd-lldbinit false\n"
2123 "To allow lldb to source .lldbinit files in the current working "
2124 "directory,\n"
2125 "set the value of this variable to true. Only do so if you "
2126 "understand and\n"
2127 "accept the security risk.");
2128 result.SetStatus(eReturnStatusFailed);
2129 return;
2130 }
2131 } else if (should_load == eLoadCWDlldbinitTrue) {
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002132 init_file.SetFile("./.lldbinit", FileSpec::Style::native);
2133 FileSystem::Instance().Resolve(init_file);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002134 }
2135 }
2136 } else {
Adrian Prantl05097242018-04-30 16:49:04 +00002137 // If we aren't looking in the current working directory we are looking in
2138 // the home directory. We will first see if there is an application
2139 // specific ".lldbinit" file whose name is "~/.lldbinit" followed by a "-"
2140 // and the name of the program. If this file doesn't exist, we fall back to
2141 // just the "~/.lldbinit" file. We also obey any requests to not load the
2142 // init files.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002143 llvm::SmallString<64> home_dir_path;
2144 llvm::sys::path::home_directory(home_dir_path);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002145 FileSpec profilePath(home_dir_path.c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002146 profilePath.AppendPathComponent(".lldbinit");
2147 std::string init_file_path = profilePath.GetPath();
2148
Jonas Devliegherea6682a42018-12-15 00:15:33 +00002149 if (!m_skip_app_init_files) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002150 FileSpec program_file_spec(HostInfo::GetProgramFileSpec());
2151 const char *program_name = program_file_spec.GetFilename().AsCString();
2152
2153 if (program_name) {
2154 char program_init_file_name[PATH_MAX];
2155 ::snprintf(program_init_file_name, sizeof(program_init_file_name),
2156 "%s-%s", init_file_path.c_str(), program_name);
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002157 init_file.SetFile(program_init_file_name, FileSpec::Style::native);
2158 FileSystem::Instance().Resolve(init_file);
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +00002159 if (!FileSystem::Instance().Exists(init_file))
Kate Stoneb9c1b512016-09-06 20:57:50 +00002160 init_file.Clear();
2161 }
2162 }
2163
2164 if (!init_file && !m_skip_lldbinit_files)
Jonas Devlieghere8f3be7a2018-11-01 21:05:36 +00002165 init_file.SetFile(init_file_path, FileSpec::Style::native);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002166 }
2167
2168 // If the file exists, tell HandleCommand to 'source' it; this will do the
Adrian Prantl05097242018-04-30 16:49:04 +00002169 // actual broadcasting of the commands back to any appropriate listener (see
Kate Stoneb9c1b512016-09-06 20:57:50 +00002170 // CommandObjectSource::Execute for more details).
2171
Jonas Devliegheredbd7fab2018-11-01 17:09:25 +00002172 if (FileSystem::Instance().Exists(init_file)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002173 const bool saved_batch = SetBatchCommandMode(true);
2174 CommandInterpreterRunOptions options;
2175 options.SetSilent(true);
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002176 options.SetPrintErrors(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002177 options.SetStopOnError(false);
2178 options.SetStopOnContinue(true);
2179
2180 HandleCommandsFromFile(init_file,
2181 nullptr, // Execution context
2182 options, result);
2183 SetBatchCommandMode(saved_batch);
2184 } else {
2185 // nothing to be done if the file doesn't exist
2186 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2187 }
2188}
2189
2190const char *CommandInterpreter::GetCommandPrefix() {
2191 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2192 return prefix == NULL ? "" : prefix;
2193}
2194
2195PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2196 PlatformSP platform_sp;
2197 if (prefer_target_platform) {
2198 ExecutionContext exe_ctx(GetExecutionContext());
2199 Target *target = exe_ctx.GetTargetPtr();
2200 if (target)
2201 platform_sp = target->GetPlatform();
2202 }
2203
2204 if (!platform_sp)
2205 platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2206 return platform_sp;
2207}
2208
2209void CommandInterpreter::HandleCommands(const StringList &commands,
2210 ExecutionContext *override_context,
2211 CommandInterpreterRunOptions &options,
2212 CommandReturnObject &result) {
2213 size_t num_lines = commands.GetSize();
2214
2215 // If we are going to continue past a "continue" then we need to run the
Adrian Prantl05097242018-04-30 16:49:04 +00002216 // commands synchronously. Make sure you reset this value anywhere you return
2217 // from the function.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002218
2219 bool old_async_execution = m_debugger.GetAsyncExecution();
2220
2221 // If we've been given an execution context, set it at the start, but don't
Adrian Prantl05097242018-04-30 16:49:04 +00002222 // keep resetting it or we will cause series of commands that change the
2223 // context, then do an operation that relies on that context to fail.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002224
2225 if (override_context != nullptr)
2226 UpdateExecutionContext(override_context);
2227
2228 if (!options.GetStopOnContinue()) {
2229 m_debugger.SetAsyncExecution(false);
2230 }
2231
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002232 for (size_t idx = 0; idx < num_lines && !WasInterrupted(); idx++) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002233 const char *cmd = commands.GetStringAtIndex(idx);
2234 if (cmd[0] == '\0')
2235 continue;
2236
2237 if (options.GetEchoCommands()) {
Zachary Turner514d8cd2016-09-23 18:06:53 +00002238 // TODO: Add Stream support.
2239 result.AppendMessageWithFormat("%s %s\n",
2240 m_debugger.GetPrompt().str().c_str(), cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002241 }
2242
2243 CommandReturnObject tmp_result;
2244 // If override_context is not NULL, pass no_context_switching = true for
2245 // HandleCommand() since we updated our context already.
2246
2247 // We might call into a regex or alias command, in which case the
Adrian Prantl05097242018-04-30 16:49:04 +00002248 // add_to_history will get lost. This m_command_source_depth dingus is the
2249 // way we turn off adding to the history in that case, so set it up here.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002250 if (!options.GetAddToHistory())
2251 m_command_source_depth++;
2252 bool success =
2253 HandleCommand(cmd, options.m_add_to_history, tmp_result,
2254 nullptr, /* override_context */
2255 true, /* repeat_on_empty_command */
2256 override_context != nullptr /* no_context_switching */);
2257 if (!options.GetAddToHistory())
2258 m_command_source_depth--;
2259
2260 if (options.GetPrintResults()) {
2261 if (tmp_result.Succeeded())
Zachary Turner03c9f362016-11-14 23:23:31 +00002262 result.AppendMessage(tmp_result.GetOutputData());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002263 }
2264
2265 if (!success || !tmp_result.Succeeded()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002266 llvm::StringRef error_msg = tmp_result.GetErrorData();
2267 if (error_msg.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +00002268 error_msg = "<unknown error>.\n";
2269 if (options.GetStopOnError()) {
2270 result.AppendErrorWithFormat(
2271 "Aborting reading of commands after command #%" PRIu64
2272 ": '%s' failed with %s",
Zachary Turnerc1564272016-11-16 21:15:24 +00002273 (uint64_t)idx, cmd, error_msg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002274 result.SetStatus(eReturnStatusFailed);
2275 m_debugger.SetAsyncExecution(old_async_execution);
2276 return;
2277 } else if (options.GetPrintResults()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002278 result.AppendMessageWithFormat(
2279 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2280 error_msg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002281 }
2282 }
2283
2284 if (result.GetImmediateOutputStream())
2285 result.GetImmediateOutputStream()->Flush();
2286
2287 if (result.GetImmediateErrorStream())
2288 result.GetImmediateErrorStream()->Flush();
2289
Adrian Prantl05097242018-04-30 16:49:04 +00002290 // N.B. Can't depend on DidChangeProcessState, because the state coming
2291 // into the command execution could be running (for instance in Breakpoint
2292 // Commands. So we check the return value to see if it is has running in
2293 // it.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002294 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2295 (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2296 if (options.GetStopOnContinue()) {
2297 // If we caused the target to proceed, and we're going to stop in that
Adrian Prantl05097242018-04-30 16:49:04 +00002298 // case, set the status in our real result before returning. This is
2299 // an error if the continue was not the last command in the set of
2300 // commands to be run.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002301 if (idx != num_lines - 1)
2302 result.AppendErrorWithFormat(
2303 "Aborting reading of commands after command #%" PRIu64
2304 ": '%s' continued the target.\n",
2305 (uint64_t)idx + 1, cmd);
2306 else
2307 result.AppendMessageWithFormat("Command #%" PRIu64
2308 " '%s' continued the target.\n",
2309 (uint64_t)idx + 1, cmd);
2310
2311 result.SetStatus(tmp_result.GetStatus());
2312 m_debugger.SetAsyncExecution(old_async_execution);
2313
2314 return;
2315 }
2316 }
2317
2318 // Also check for "stop on crash here:
2319 bool should_stop = false;
2320 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash()) {
2321 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2322 if (target_sp) {
2323 ProcessSP process_sp(target_sp->GetProcessSP());
2324 if (process_sp) {
2325 for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
2326 StopReason reason = thread_sp->GetStopReason();
2327 if (reason == eStopReasonSignal || reason == eStopReasonException ||
2328 reason == eStopReasonInstrumentation) {
2329 should_stop = true;
2330 break;
2331 }
2332 }
2333 }
2334 }
2335 if (should_stop) {
2336 if (idx != num_lines - 1)
2337 result.AppendErrorWithFormat(
2338 "Aborting reading of commands after command #%" PRIu64
2339 ": '%s' stopped with a signal or exception.\n",
2340 (uint64_t)idx + 1, cmd);
2341 else
2342 result.AppendMessageWithFormat(
2343 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2344 (uint64_t)idx + 1, cmd);
2345
2346 result.SetStatus(tmp_result.GetStatus());
2347 m_debugger.SetAsyncExecution(old_async_execution);
2348
2349 return;
2350 }
2351 }
2352 }
2353
2354 result.SetStatus(eReturnStatusSuccessFinishResult);
2355 m_debugger.SetAsyncExecution(old_async_execution);
2356
2357 return;
2358}
2359
2360// Make flags that we can pass into the IOHandler so our delegates can do the
2361// right thing
2362enum {
2363 eHandleCommandFlagStopOnContinue = (1u << 0),
2364 eHandleCommandFlagStopOnError = (1u << 1),
2365 eHandleCommandFlagEchoCommand = (1u << 2),
Stefan Granitzc678ed72018-10-05 16:49:47 +00002366 eHandleCommandFlagEchoCommentCommand = (1u << 3),
2367 eHandleCommandFlagPrintResult = (1u << 4),
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002368 eHandleCommandFlagPrintErrors = (1u << 5),
2369 eHandleCommandFlagStopOnCrash = (1u << 6)
Kate Stoneb9c1b512016-09-06 20:57:50 +00002370};
2371
2372void CommandInterpreter::HandleCommandsFromFile(
2373 FileSpec &cmd_file, ExecutionContext *context,
2374 CommandInterpreterRunOptions &options, CommandReturnObject &result) {
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002375 if (!FileSystem::Instance().Exists(cmd_file)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002376 result.AppendErrorWithFormat(
2377 "Error reading commands from file %s - file not found.\n",
2378 cmd_file.GetFilename().AsCString("<Unknown>"));
2379 result.SetStatus(eReturnStatusFailed);
2380 return;
2381 }
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002382
2383 StreamFileSP input_file_sp(new StreamFile());
2384 std::string cmd_file_path = cmd_file.GetPath();
2385 Status error = FileSystem::Instance().Open(input_file_sp->GetFile(), cmd_file,
2386 File::eOpenOptionRead);
2387
2388 if (error.Fail()) {
2389 result.AppendErrorWithFormat(
2390 "error: an error occurred read file '%s': %s\n", cmd_file_path.c_str(),
2391 error.AsCString());
2392 result.SetStatus(eReturnStatusFailed);
2393 return;
2394 }
2395
2396 Debugger &debugger = GetDebugger();
2397
2398 uint32_t flags = 0;
2399
2400 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2401 if (m_command_source_flags.empty()) {
2402 // Stop on continue by default
2403 flags |= eHandleCommandFlagStopOnContinue;
2404 } else if (m_command_source_flags.back() &
2405 eHandleCommandFlagStopOnContinue) {
2406 flags |= eHandleCommandFlagStopOnContinue;
2407 }
2408 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2409 flags |= eHandleCommandFlagStopOnContinue;
2410 }
2411
2412 if (options.m_stop_on_error == eLazyBoolCalculate) {
2413 if (m_command_source_flags.empty()) {
2414 if (GetStopCmdSourceOnError())
2415 flags |= eHandleCommandFlagStopOnError;
2416 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2417 flags |= eHandleCommandFlagStopOnError;
2418 }
2419 } else if (options.m_stop_on_error == eLazyBoolYes) {
2420 flags |= eHandleCommandFlagStopOnError;
2421 }
2422
2423 // stop-on-crash can only be set, if it is present in all levels of
2424 // pushed flag sets.
2425 if (options.GetStopOnCrash()) {
2426 if (m_command_source_flags.empty()) {
2427 flags |= eHandleCommandFlagStopOnCrash;
2428 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2429 flags |= eHandleCommandFlagStopOnCrash;
2430 }
2431 }
2432
2433 if (options.m_echo_commands == eLazyBoolCalculate) {
2434 if (m_command_source_flags.empty()) {
2435 // Echo command by default
2436 flags |= eHandleCommandFlagEchoCommand;
2437 } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2438 flags |= eHandleCommandFlagEchoCommand;
2439 }
2440 } else if (options.m_echo_commands == eLazyBoolYes) {
2441 flags |= eHandleCommandFlagEchoCommand;
2442 }
2443
2444 // We will only ever ask for this flag, if we echo commands in general.
2445 if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2446 if (m_command_source_flags.empty()) {
2447 // Echo comments by default
2448 flags |= eHandleCommandFlagEchoCommentCommand;
2449 } else if (m_command_source_flags.back() &
2450 eHandleCommandFlagEchoCommentCommand) {
2451 flags |= eHandleCommandFlagEchoCommentCommand;
2452 }
2453 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2454 flags |= eHandleCommandFlagEchoCommentCommand;
2455 }
2456
2457 if (options.m_print_results == eLazyBoolCalculate) {
2458 if (m_command_source_flags.empty()) {
2459 // Print output by default
2460 flags |= eHandleCommandFlagPrintResult;
2461 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2462 flags |= eHandleCommandFlagPrintResult;
2463 }
2464 } else if (options.m_print_results == eLazyBoolYes) {
2465 flags |= eHandleCommandFlagPrintResult;
2466 }
2467
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002468 if (options.m_print_errors == eLazyBoolCalculate) {
2469 if (m_command_source_flags.empty()) {
2470 // Print output by default
2471 flags |= eHandleCommandFlagPrintErrors;
2472 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2473 flags |= eHandleCommandFlagPrintErrors;
2474 }
2475 } else if (options.m_print_errors == eLazyBoolYes) {
2476 flags |= eHandleCommandFlagPrintErrors;
2477 }
2478
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002479 if (flags & eHandleCommandFlagPrintResult) {
2480 debugger.GetOutputFile()->Printf("Executing commands in '%s'.\n",
2481 cmd_file_path.c_str());
2482 }
2483
2484 // Used for inheriting the right settings when "command source" might
2485 // have nested "command source" commands
2486 lldb::StreamFileSP empty_stream_sp;
2487 m_command_source_flags.push_back(flags);
2488 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2489 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2490 empty_stream_sp, // Pass in an empty stream so we inherit the top
2491 // input reader output stream
2492 empty_stream_sp, // Pass in an empty stream so we inherit the top
2493 // input reader error stream
2494 flags,
2495 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2496 // or written
2497 debugger.GetPrompt(), llvm::StringRef(),
2498 false, // Not multi-line
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002499 debugger.GetUseColor(), 0, *this, nullptr));
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002500 const bool old_async_execution = debugger.GetAsyncExecution();
2501
2502 // Set synchronous execution if we are not stopping on continue
2503 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2504 debugger.SetAsyncExecution(false);
2505
2506 m_command_source_depth++;
2507
2508 debugger.RunIOHandler(io_handler_sp);
2509 if (!m_command_source_flags.empty())
2510 m_command_source_flags.pop_back();
2511 m_command_source_depth--;
2512 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2513 debugger.SetAsyncExecution(old_async_execution);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002514}
2515
Kate Stoneb9c1b512016-09-06 20:57:50 +00002516bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2517
2518void CommandInterpreter::SetSynchronous(bool value) {
2519 m_synchronous_execution = value;
2520}
2521
2522void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
Zachary Turner0ac5f982016-11-08 04:12:42 +00002523 llvm::StringRef prefix,
2524 llvm::StringRef help_text) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002525 const uint32_t max_columns = m_debugger.GetTerminalWidth();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002526
Zachary Turner0ac5f982016-11-08 04:12:42 +00002527 size_t line_width_max = max_columns - prefix.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002528 if (line_width_max < 16)
Zachary Turner0ac5f982016-11-08 04:12:42 +00002529 line_width_max = help_text.size() + prefix.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002530
Zachary Turner0ac5f982016-11-08 04:12:42 +00002531 strm.IndentMore(prefix.size());
2532 bool prefixed_yet = false;
2533 while (!help_text.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002534 // Prefix the first line, indent subsequent lines to line up
Zachary Turner0ac5f982016-11-08 04:12:42 +00002535 if (!prefixed_yet) {
2536 strm << prefix;
2537 prefixed_yet = true;
2538 } else
Kate Stoneb9c1b512016-09-06 20:57:50 +00002539 strm.Indent();
Zachary Turner0ac5f982016-11-08 04:12:42 +00002540
2541 // Never print more than the maximum on one line.
2542 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2543
2544 // Always break on an explicit newline.
2545 std::size_t first_newline = this_line.find_first_of("\n");
2546
2547 // Don't break on space/tab unless the text is too long to fit on one line.
2548 std::size_t last_space = llvm::StringRef::npos;
2549 if (this_line.size() != help_text.size())
2550 last_space = this_line.find_last_of(" \t");
2551
2552 // Break at whichever condition triggered first.
2553 this_line = this_line.substr(0, std::min(first_newline, last_space));
2554 strm.PutCString(this_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002555 strm.EOL();
2556
Zachary Turner0ac5f982016-11-08 04:12:42 +00002557 // Remove whitespace / newlines after breaking.
2558 help_text = help_text.drop_front(this_line.size()).ltrim();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002559 }
Zachary Turner0ac5f982016-11-08 04:12:42 +00002560 strm.IndentLess(prefix.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002561}
2562
2563void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
Zachary Turner0ac5f982016-11-08 04:12:42 +00002564 llvm::StringRef word_text,
2565 llvm::StringRef separator,
2566 llvm::StringRef help_text,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002567 size_t max_word_len) {
2568 StreamString prefix_stream;
Zachary Turner0ac5f982016-11-08 04:12:42 +00002569 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2570 (int)separator.size(), separator.data());
Zachary Turnerc1564272016-11-16 21:15:24 +00002571 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2572}
2573
Zachary Turner0ac5f982016-11-08 04:12:42 +00002574void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2575 llvm::StringRef separator,
2576 llvm::StringRef help_text,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002577 uint32_t max_word_len) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00002578 int indent_size = max_word_len + separator.size() + 2;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002579
2580 strm.IndentMore(indent_size);
2581
2582 StreamString text_strm;
Zachary Turner0ac5f982016-11-08 04:12:42 +00002583 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2584 text_strm << separator << " " << help_text;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002585
2586 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2587
Zachary Turnerc1564272016-11-16 21:15:24 +00002588 llvm::StringRef text = text_strm.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002589
2590 uint32_t chars_left = max_columns;
2591
Davide Italianocf8a8292017-04-14 22:36:08 +00002592 auto nextWordLength = [](llvm::StringRef S) {
Jonas Devliegherec712bac2019-03-28 18:10:14 +00002593 size_t pos = S.find(' ');
Davide Italianocf8a8292017-04-14 22:36:08 +00002594 return pos == llvm::StringRef::npos ? S.size() : pos;
2595 };
2596
Zachary Turnerc1564272016-11-16 21:15:24 +00002597 while (!text.empty()) {
2598 if (text.front() == '\n' ||
Jim Inghama81bd7f2017-07-27 00:18:18 +00002599 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002600 strm.EOL();
2601 strm.Indent();
Zachary Turnerc1564272016-11-16 21:15:24 +00002602 chars_left = max_columns - indent_size;
2603 if (text.front() == '\n')
2604 text = text.drop_front();
2605 else
2606 text = text.ltrim(' ');
Kate Stoneb9c1b512016-09-06 20:57:50 +00002607 } else {
Zachary Turnerc1564272016-11-16 21:15:24 +00002608 strm.PutChar(text.front());
2609 --chars_left;
2610 text = text.drop_front();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002611 }
2612 }
2613
2614 strm.EOL();
2615 strm.IndentLess(indent_size);
2616}
2617
2618void CommandInterpreter::FindCommandsForApropos(
Zachary Turner067d1db2016-11-16 21:45:04 +00002619 llvm::StringRef search_word, StringList &commands_found,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002620 StringList &commands_help, CommandObject::CommandMap &command_map) {
2621 CommandObject::CommandMap::const_iterator pos;
2622
2623 for (pos = command_map.begin(); pos != command_map.end(); ++pos) {
Zachary Turner067d1db2016-11-16 21:45:04 +00002624 llvm::StringRef command_name = pos->first;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002625 CommandObject *cmd_obj = pos->second.get();
2626
2627 const bool search_short_help = true;
2628 const bool search_long_help = false;
2629 const bool search_syntax = false;
2630 const bool search_options = false;
Zachary Turner067d1db2016-11-16 21:45:04 +00002631 if (command_name.contains_lower(search_word) ||
Kate Stoneb9c1b512016-09-06 20:57:50 +00002632 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2633 search_long_help, search_syntax,
2634 search_options)) {
2635 commands_found.AppendString(cmd_obj->GetCommandName());
2636 commands_help.AppendString(cmd_obj->GetHelp());
2637 }
2638
2639 if (cmd_obj->IsMultiwordObject()) {
2640 CommandObjectMultiword *cmd_multiword = cmd_obj->GetAsMultiwordCommand();
2641 FindCommandsForApropos(search_word, commands_found, commands_help,
2642 cmd_multiword->GetSubcommandDictionary());
2643 }
2644 }
2645}
2646
Zachary Turner067d1db2016-11-16 21:45:04 +00002647void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002648 StringList &commands_found,
2649 StringList &commands_help,
2650 bool search_builtin_commands,
2651 bool search_user_commands,
2652 bool search_alias_commands) {
2653 CommandObject::CommandMap::const_iterator pos;
2654
2655 if (search_builtin_commands)
2656 FindCommandsForApropos(search_word, commands_found, commands_help,
2657 m_command_dict);
2658
2659 if (search_user_commands)
2660 FindCommandsForApropos(search_word, commands_found, commands_help,
2661 m_user_dict);
2662
2663 if (search_alias_commands)
2664 FindCommandsForApropos(search_word, commands_found, commands_help,
2665 m_alias_dict);
2666}
2667
2668void CommandInterpreter::UpdateExecutionContext(
2669 ExecutionContext *override_context) {
2670 if (override_context != nullptr) {
2671 m_exe_ctx_ref = *override_context;
2672 } else {
2673 const bool adopt_selected = true;
2674 m_exe_ctx_ref.SetTargetPtr(m_debugger.GetSelectedTarget().get(),
2675 adopt_selected);
2676 }
2677}
2678
2679size_t CommandInterpreter::GetProcessOutput() {
2680 // The process has stuff waiting for stderr; get it and write it out to the
2681 // appropriate place.
2682 char stdio_buffer[1024];
2683 size_t len;
2684 size_t total_bytes = 0;
Zachary Turner97206d52017-05-12 04:51:55 +00002685 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002686 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2687 if (target_sp) {
2688 ProcessSP process_sp(target_sp->GetProcessSP());
2689 if (process_sp) {
2690 while ((len = process_sp->GetSTDOUT(stdio_buffer, sizeof(stdio_buffer),
2691 error)) > 0) {
2692 size_t bytes_written = len;
2693 m_debugger.GetOutputFile()->Write(stdio_buffer, bytes_written);
2694 total_bytes += len;
2695 }
2696 while ((len = process_sp->GetSTDERR(stdio_buffer, sizeof(stdio_buffer),
2697 error)) > 0) {
2698 size_t bytes_written = len;
2699 m_debugger.GetErrorFile()->Write(stdio_buffer, bytes_written);
2700 total_bytes += len;
2701 }
2702 }
2703 }
2704 return total_bytes;
2705}
2706
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002707void CommandInterpreter::StartHandlingCommand() {
2708 auto idle_state = CommandHandlingState::eIdle;
2709 if (m_command_state.compare_exchange_strong(
2710 idle_state, CommandHandlingState::eInProgress))
2711 lldbassert(m_iohandler_nesting_level == 0);
2712 else
2713 lldbassert(m_iohandler_nesting_level > 0);
2714 ++m_iohandler_nesting_level;
2715}
2716
2717void CommandInterpreter::FinishHandlingCommand() {
2718 lldbassert(m_iohandler_nesting_level > 0);
2719 if (--m_iohandler_nesting_level == 0) {
2720 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
2721 lldbassert(prev_state != CommandHandlingState::eIdle);
2722 }
2723}
2724
2725bool CommandInterpreter::InterruptCommand() {
2726 auto in_progress = CommandHandlingState::eInProgress;
2727 return m_command_state.compare_exchange_strong(
2728 in_progress, CommandHandlingState::eInterrupted);
2729}
2730
2731bool CommandInterpreter::WasInterrupted() const {
2732 bool was_interrupted =
2733 (m_command_state == CommandHandlingState::eInterrupted);
2734 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
2735 return was_interrupted;
2736}
2737
2738void CommandInterpreter::PrintCommandOutput(Stream &stream,
2739 llvm::StringRef str) {
2740 // Split the output into lines and poll for interrupt requests
2741 const char *data = str.data();
2742 size_t size = str.size();
2743 while (size > 0 && !WasInterrupted()) {
2744 size_t chunk_size = 0;
2745 for (; chunk_size < size; ++chunk_size) {
2746 lldbassert(data[chunk_size] != '\0');
2747 if (data[chunk_size] == '\n') {
2748 ++chunk_size;
2749 break;
2750 }
2751 }
2752 chunk_size = stream.Write(data, chunk_size);
2753 lldbassert(size >= chunk_size);
2754 data += chunk_size;
2755 size -= chunk_size;
2756 }
2757 if (size > 0) {
2758 stream.Printf("\n... Interrupted.\n");
2759 }
2760}
2761
Stefan Granitzc678ed72018-10-05 16:49:47 +00002762bool CommandInterpreter::EchoCommandNonInteractive(
2763 llvm::StringRef line, const Flags &io_handler_flags) const {
2764 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
2765 return false;
2766
2767 llvm::StringRef command = line.trim();
2768 if (command.empty())
2769 return true;
2770
2771 if (command.front() == m_comment_char)
2772 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
2773
2774 return true;
2775}
2776
Kate Stoneb9c1b512016-09-06 20:57:50 +00002777void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
2778 std::string &line) {
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002779 // If we were interrupted, bail out...
2780 if (WasInterrupted())
2781 return;
2782
Kate Stoneb9c1b512016-09-06 20:57:50 +00002783 const bool is_interactive = io_handler.GetIsInteractive();
Jonas Devliegherea6682a42018-12-15 00:15:33 +00002784 if (!is_interactive) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002785 // When we are not interactive, don't execute blank lines. This will happen
2786 // sourcing a commands file. We don't want blank lines to repeat the
Adrian Prantl05097242018-04-30 16:49:04 +00002787 // previous command and cause any errors to occur (like redefining an
2788 // alias, get an error and stop parsing the commands file).
Kate Stoneb9c1b512016-09-06 20:57:50 +00002789 if (line.empty())
2790 return;
2791
2792 // When using a non-interactive file handle (like when sourcing commands
Adrian Prantl05097242018-04-30 16:49:04 +00002793 // from a file) we need to echo the command out so we don't just see the
2794 // command output and no command...
Stefan Granitzc678ed72018-10-05 16:49:47 +00002795 if (EchoCommandNonInteractive(line, io_handler.GetFlags()))
Kate Stoneb9c1b512016-09-06 20:57:50 +00002796 io_handler.GetOutputStreamFile()->Printf("%s%s\n", io_handler.GetPrompt(),
2797 line.c_str());
2798 }
2799
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002800 StartHandlingCommand();
2801
Kate Stoneb9c1b512016-09-06 20:57:50 +00002802 lldb_private::CommandReturnObject result;
2803 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
2804
2805 // Now emit the command output text from the command we just executed
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002806 if ((result.Succeeded() &&
2807 io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
2808 io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002809 // Display any STDOUT/STDERR _prior_ to emitting the command result text
2810 GetProcessOutput();
2811
2812 if (!result.GetImmediateOutputStream()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002813 llvm::StringRef output = result.GetOutputData();
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002814 PrintCommandOutput(*io_handler.GetOutputStreamFile(), output);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002815 }
2816
2817 // Now emit the command error text from the command we just executed
2818 if (!result.GetImmediateErrorStream()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002819 llvm::StringRef error = result.GetErrorData();
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002820 PrintCommandOutput(*io_handler.GetErrorStreamFile(), error);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002821 }
2822 }
2823
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002824 FinishHandlingCommand();
2825
Kate Stoneb9c1b512016-09-06 20:57:50 +00002826 switch (result.GetStatus()) {
2827 case eReturnStatusInvalid:
2828 case eReturnStatusSuccessFinishNoResult:
2829 case eReturnStatusSuccessFinishResult:
2830 case eReturnStatusStarted:
2831 break;
2832
2833 case eReturnStatusSuccessContinuingNoResult:
2834 case eReturnStatusSuccessContinuingResult:
2835 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
2836 io_handler.SetIsDone(true);
2837 break;
2838
2839 case eReturnStatusFailed:
2840 m_num_errors++;
2841 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError))
2842 io_handler.SetIsDone(true);
2843 break;
2844
2845 case eReturnStatusQuit:
2846 m_quit_requested = true;
2847 io_handler.SetIsDone(true);
2848 break;
2849 }
2850
2851 // Finally, if we're going to stop on crash, check that here:
2852 if (!m_quit_requested && result.GetDidChangeProcessState() &&
2853 io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash)) {
2854 bool should_stop = false;
2855 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2856 if (target_sp) {
2857 ProcessSP process_sp(target_sp->GetProcessSP());
2858 if (process_sp) {
2859 for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
2860 StopReason reason = thread_sp->GetStopReason();
2861 if ((reason == eStopReasonSignal || reason == eStopReasonException ||
2862 reason == eStopReasonInstrumentation) &&
2863 !result.GetAbnormalStopWasExpected()) {
2864 should_stop = true;
2865 break;
2866 }
2867 }
2868 }
2869 }
2870 if (should_stop) {
2871 io_handler.SetIsDone(true);
2872 m_stopped_for_crash = true;
2873 }
2874 }
2875}
2876
2877bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
2878 ExecutionContext exe_ctx(GetExecutionContext());
2879 Process *process = exe_ctx.GetProcessPtr();
2880
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002881 if (InterruptCommand())
2882 return true;
2883
Kate Stoneb9c1b512016-09-06 20:57:50 +00002884 if (process) {
2885 StateType state = process->GetState();
2886 if (StateIsRunningState(state)) {
2887 process->Halt();
2888 return true; // Don't do any updating when we are running
2889 }
2890 }
2891
Jonas Devlieghere2b29b432019-04-26 22:43:16 +00002892 ScriptInterpreter *script_interpreter =
2893 m_debugger.GetScriptInterpreter(false);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002894 if (script_interpreter) {
2895 if (script_interpreter->Interrupt())
2896 return true;
2897 }
2898 return false;
2899}
2900
2901void CommandInterpreter::GetLLDBCommandsFromIOHandler(
2902 const char *prompt, IOHandlerDelegate &delegate, bool asynchronously,
2903 void *baton) {
2904 Debugger &debugger = GetDebugger();
2905 IOHandlerSP io_handler_sp(
2906 new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
2907 "lldb", // Name of input reader for history
Zachary Turner514d8cd2016-09-23 18:06:53 +00002908 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2909 llvm::StringRef(), // Continuation prompt
2910 true, // Get multiple lines
Kate Stoneb9c1b512016-09-06 20:57:50 +00002911 debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002912 0, // Don't show line numbers
2913 delegate, // IOHandlerDelegate
2914 nullptr)); // FileShadowCollector
Kate Stoneb9c1b512016-09-06 20:57:50 +00002915
2916 if (io_handler_sp) {
2917 io_handler_sp->SetUserData(baton);
2918 if (asynchronously)
2919 debugger.PushIOHandler(io_handler_sp);
2920 else
2921 debugger.RunIOHandler(io_handler_sp);
2922 }
2923}
2924
2925void CommandInterpreter::GetPythonCommandsFromIOHandler(
2926 const char *prompt, IOHandlerDelegate &delegate, bool asynchronously,
2927 void *baton) {
2928 Debugger &debugger = GetDebugger();
2929 IOHandlerSP io_handler_sp(
2930 new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
2931 "lldb-python", // Name of input reader for history
Zachary Turner514d8cd2016-09-23 18:06:53 +00002932 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2933 llvm::StringRef(), // Continuation prompt
2934 true, // Get multiple lines
Kate Stoneb9c1b512016-09-06 20:57:50 +00002935 debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002936 0, // Don't show line numbers
2937 delegate, // IOHandlerDelegate
2938 nullptr)); // FileShadowCollector
Kate Stoneb9c1b512016-09-06 20:57:50 +00002939
2940 if (io_handler_sp) {
2941 io_handler_sp->SetUserData(baton);
2942 if (asynchronously)
2943 debugger.PushIOHandler(io_handler_sp);
2944 else
2945 debugger.RunIOHandler(io_handler_sp);
2946 }
2947}
2948
2949bool CommandInterpreter::IsActive() {
2950 return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
2951}
2952
2953lldb::IOHandlerSP
2954CommandInterpreter::GetIOHandler(bool force_create,
2955 CommandInterpreterRunOptions *options) {
Adrian Prantl05097242018-04-30 16:49:04 +00002956 // Always re-create the IOHandlerEditline in case the input changed. The old
2957 // instance might have had a non-interactive input and now it does or vice
2958 // versa.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002959 if (force_create || !m_command_io_handler_sp) {
Adrian Prantl05097242018-04-30 16:49:04 +00002960 // Always re-create the IOHandlerEditline in case the input changed. The
2961 // old instance might have had a non-interactive input and now it does or
2962 // vice versa.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002963 uint32_t flags = 0;
2964
2965 if (options) {
2966 if (options->m_stop_on_continue == eLazyBoolYes)
2967 flags |= eHandleCommandFlagStopOnContinue;
2968 if (options->m_stop_on_error == eLazyBoolYes)
2969 flags |= eHandleCommandFlagStopOnError;
2970 if (options->m_stop_on_crash == eLazyBoolYes)
2971 flags |= eHandleCommandFlagStopOnCrash;
2972 if (options->m_echo_commands != eLazyBoolNo)
2973 flags |= eHandleCommandFlagEchoCommand;
Stefan Granitzc678ed72018-10-05 16:49:47 +00002974 if (options->m_echo_comment_commands != eLazyBoolNo)
2975 flags |= eHandleCommandFlagEchoCommentCommand;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002976 if (options->m_print_results != eLazyBoolNo)
2977 flags |= eHandleCommandFlagPrintResult;
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002978 if (options->m_print_errors != eLazyBoolNo)
2979 flags |= eHandleCommandFlagPrintErrors;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002980 } else {
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002981 flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
2982 eHandleCommandFlagPrintErrors;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002983 }
2984
Jonas Devlieghere796ac802019-02-11 23:13:08 +00002985 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
Kate Stoneb9c1b512016-09-06 20:57:50 +00002986 m_debugger, IOHandler::Type::CommandInterpreter,
2987 m_debugger.GetInputFile(), m_debugger.GetOutputFile(),
2988 m_debugger.GetErrorFile(), flags, "lldb", m_debugger.GetPrompt(),
Zachary Turner514d8cd2016-09-23 18:06:53 +00002989 llvm::StringRef(), // Continuation prompt
Kate Stoneb9c1b512016-09-06 20:57:50 +00002990 false, // Don't enable multiple line input, just single line commands
2991 m_debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002992 0, // Don't show line numbers
2993 *this, // IOHandlerDelegate
2994 GetDebugger().GetInputRecorder());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002995 }
2996 return m_command_io_handler_sp;
2997}
2998
2999void CommandInterpreter::RunCommandInterpreter(
3000 bool auto_handle_events, bool spawn_thread,
3001 CommandInterpreterRunOptions &options) {
Adrian Prantl05097242018-04-30 16:49:04 +00003002 // Always re-create the command interpreter when we run it in case any file
3003 // handles have changed.
Kate Stoneb9c1b512016-09-06 20:57:50 +00003004 bool force_create = true;
3005 m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
3006 m_stopped_for_crash = false;
3007
3008 if (auto_handle_events)
3009 m_debugger.StartEventHandlerThread();
3010
3011 if (spawn_thread) {
3012 m_debugger.StartIOHandlerThread();
3013 } else {
3014 m_debugger.ExecuteIOHandlers();
3015
3016 if (auto_handle_events)
3017 m_debugger.StopEventHandlerThread();
3018 }
3019}
3020
3021CommandObject *
3022CommandInterpreter::ResolveCommandImpl(std::string &command_line,
3023 CommandReturnObject &result) {
3024 std::string scratch_command(command_line); // working copy so we don't modify
3025 // command_line unless we succeed
3026 CommandObject *cmd_obj = nullptr;
3027 StreamString revised_command_line;
3028 bool wants_raw_input = false;
3029 size_t actual_cmd_name_len = 0;
3030 std::string next_word;
3031 StringList matches;
3032 bool done = false;
3033 while (!done) {
3034 char quote_char = '\0';
3035 std::string suffix;
3036 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3037 if (cmd_obj == nullptr) {
3038 std::string full_name;
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00003039 bool is_alias = GetAliasFullName(next_word, full_name);
Zachary Turnera4496982016-10-05 21:14:38 +00003040 cmd_obj = GetCommandObject(next_word, &matches);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003041 bool is_real_command =
Jonas Devliegherea6682a42018-12-15 00:15:33 +00003042 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003043 if (!is_real_command) {
3044 matches.Clear();
3045 std::string alias_result;
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00003046 cmd_obj =
3047 BuildAliasResult(full_name, scratch_command, alias_result, result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003048 revised_command_line.Printf("%s", alias_result.c_str());
3049 if (cmd_obj) {
3050 wants_raw_input = cmd_obj->WantsRawCommandString();
Zachary Turnera4496982016-10-05 21:14:38 +00003051 actual_cmd_name_len = cmd_obj->GetCommandName().size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003052 }
3053 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +00003054 if (cmd_obj) {
Zachary Turnera4496982016-10-05 21:14:38 +00003055 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3056 actual_cmd_name_len += cmd_name.size();
3057 revised_command_line.Printf("%s", cmd_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003058 wants_raw_input = cmd_obj->WantsRawCommandString();
3059 } else {
3060 revised_command_line.Printf("%s", next_word.c_str());
3061 }
3062 }
3063 } else {
3064 if (cmd_obj->IsMultiwordObject()) {
3065 CommandObject *sub_cmd_obj =
3066 cmd_obj->GetSubcommandObject(next_word.c_str());
3067 if (sub_cmd_obj) {
Adrian Prantl05097242018-04-30 16:49:04 +00003068 // The subcommand's name includes the parent command's name, so
3069 // restart rather than append to the revised_command_line.
Zachary Turnera4496982016-10-05 21:14:38 +00003070 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3071 actual_cmd_name_len = sub_cmd_name.size() + 1;
Kate Stoneb9c1b512016-09-06 20:57:50 +00003072 revised_command_line.Clear();
Zachary Turnera4496982016-10-05 21:14:38 +00003073 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003074 cmd_obj = sub_cmd_obj;
3075 wants_raw_input = cmd_obj->WantsRawCommandString();
3076 } else {
3077 if (quote_char)
3078 revised_command_line.Printf(" %c%s%s%c", quote_char,
3079 next_word.c_str(), suffix.c_str(),
3080 quote_char);
3081 else
3082 revised_command_line.Printf(" %s%s", next_word.c_str(),
3083 suffix.c_str());
3084 done = true;
3085 }
3086 } else {
3087 if (quote_char)
3088 revised_command_line.Printf(" %c%s%s%c", quote_char,
3089 next_word.c_str(), suffix.c_str(),
3090 quote_char);
3091 else
3092 revised_command_line.Printf(" %s%s", next_word.c_str(),
3093 suffix.c_str());
3094 done = true;
3095 }
3096 }
3097
3098 if (cmd_obj == nullptr) {
3099 const size_t num_matches = matches.GetSize();
3100 if (matches.GetSize() > 1) {
3101 StreamString error_msg;
3102 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3103 next_word.c_str());
3104
3105 for (uint32_t i = 0; i < num_matches; ++i) {
3106 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3107 }
Zachary Turnerc1564272016-11-16 21:15:24 +00003108 result.AppendRawError(error_msg.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003109 } else {
3110 // We didn't have only one match, otherwise we wouldn't get here.
Leonard Mosescu17ffd392017-10-05 23:41:28 +00003111 lldbassert(num_matches == 0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003112 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3113 next_word.c_str());
3114 }
3115 result.SetStatus(eReturnStatusFailed);
3116 return nullptr;
3117 }
3118
3119 if (cmd_obj->IsMultiwordObject()) {
3120 if (!suffix.empty()) {
3121 result.AppendErrorWithFormat(
3122 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3123 "might be invalid).\n",
Zachary Turnera4496982016-10-05 21:14:38 +00003124 cmd_obj->GetCommandName().str().c_str(),
Kate Stoneb9c1b512016-09-06 20:57:50 +00003125 next_word.empty() ? "" : next_word.c_str(),
3126 next_word.empty() ? " -- " : " ", suffix.c_str());
3127 result.SetStatus(eReturnStatusFailed);
3128 return nullptr;
3129 }
3130 } else {
3131 // If we found a normal command, we are done
3132 done = true;
3133 if (!suffix.empty()) {
3134 switch (suffix[0]) {
3135 case '/':
3136 // GDB format suffixes
3137 {
3138 Options *command_options = cmd_obj->GetOptions();
3139 if (command_options &&
3140 command_options->SupportsLongOption("gdb-format")) {
3141 std::string gdb_format_option("--gdb-format=");
3142 gdb_format_option += (suffix.c_str() + 1);
3143
Zachary Turnerc1564272016-11-16 21:15:24 +00003144 std::string cmd = revised_command_line.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003145 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3146 if (arg_terminator_idx != std::string::npos) {
3147 // Insert the gdb format option before the "--" that terminates
3148 // options
3149 gdb_format_option.append(1, ' ');
3150 cmd.insert(arg_terminator_idx, gdb_format_option);
Zachary Turnerc1564272016-11-16 21:15:24 +00003151 revised_command_line.Clear();
3152 revised_command_line.PutCString(cmd);
3153 } else
Kate Stoneb9c1b512016-09-06 20:57:50 +00003154 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3155
3156 if (wants_raw_input &&
3157 FindArgumentTerminator(cmd) == std::string::npos)
3158 revised_command_line.PutCString(" --");
3159 } else {
3160 result.AppendErrorWithFormat(
3161 "the '%s' command doesn't support the --gdb-format option\n",
Zachary Turnera4496982016-10-05 21:14:38 +00003162 cmd_obj->GetCommandName().str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003163 result.SetStatus(eReturnStatusFailed);
3164 return nullptr;
3165 }
3166 }
3167 break;
3168
3169 default:
3170 result.AppendErrorWithFormat(
3171 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3172 result.SetStatus(eReturnStatusFailed);
3173 return nullptr;
3174 }
3175 }
3176 }
3177 if (scratch_command.empty())
3178 done = true;
3179 }
3180
3181 if (!scratch_command.empty())
3182 revised_command_line.Printf(" %s", scratch_command.c_str());
3183
3184 if (cmd_obj != NULL)
Zachary Turnerc1564272016-11-16 21:15:24 +00003185 command_line = revised_command_line.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003186
3187 return cmd_obj;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00003188}