blob: f6027636bd3ccd31aa6f34c42008ffa957efc34d [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;
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +000084static constexpr const char *InitFileWarning =
85 "There is a .lldbinit file in the current directory which is not being "
86 "read.\n"
87 "To silence this warning without sourcing in the local .lldbinit,\n"
88 "add the following to the lldbinit file in your home directory:\n"
89 " settings set target.load-cwd-lldbinit false\n"
90 "To allow lldb to source .lldbinit files in the current working "
91 "directory,\n"
92 "set the value of this variable to true. Only do so if you understand "
93 "and\n"
94 "accept the security risk.";
Stefan Granitzc678ed72018-10-05 16:49:47 +000095
Tatyana Krasnukha8fe53c492018-09-26 18:50:19 +000096static constexpr PropertyDefinition g_properties[] = {
Stefan Granitzc678ed72018-10-05 16:49:47 +000097 {"expand-regex-aliases", OptionValue::eTypeBoolean, NoGlobalSetting,
98 DefaultValueFalse, NoCStrDefault, {},
99 "If true, regular expression alias commands will show the "
100 "expanded command that will be executed. This can be used to "
101 "debug new regular expression alias commands."},
102 {"prompt-on-quit", OptionValue::eTypeBoolean, NoGlobalSetting,
103 DefaultValueTrue, NoCStrDefault, {},
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 "If true, LLDB will prompt you before quitting if there are any live "
105 "processes being debugged. If false, LLDB will quit without asking in any "
106 "case."},
Stefan Granitzc678ed72018-10-05 16:49:47 +0000107 {"stop-command-source-on-error", OptionValue::eTypeBoolean, NoGlobalSetting,
108 DefaultValueTrue, NoCStrDefault, {},
109 "If true, LLDB will stop running a 'command source' "
110 "script upon encountering an error."},
111 {"space-repl-prompts", OptionValue::eTypeBoolean, NoGlobalSetting,
112 DefaultValueFalse, NoCStrDefault, {},
113 "If true, blank lines will be printed between between REPL submissions."},
114 {"echo-commands", OptionValue::eTypeBoolean, NoGlobalSetting,
115 DefaultValueTrue, NoCStrDefault, {},
116 "If true, commands will be echoed before they are evaluated."},
117 {"echo-comment-commands", OptionValue::eTypeBoolean, NoGlobalSetting,
118 DefaultValueTrue, NoCStrDefault, {},
119 "If true, commands will be echoed even if they are pure comment lines."}};
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120
121enum {
122 ePropertyExpandRegexAliases = 0,
123 ePropertyPromptOnQuit = 1,
124 ePropertyStopCmdSourceOnError = 2,
Stefan Granitzc678ed72018-10-05 16:49:47 +0000125 eSpaceReplPrompts = 3,
126 eEchoCommands = 4,
127 eEchoCommentCommands = 5
Greg Clayton754a9362012-08-23 00:22:02 +0000128};
129
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130ConstString &CommandInterpreter::GetStaticBroadcasterClass() {
131 static ConstString class_name("lldb.commandInterpreter");
132 return class_name;
Jim Ingham4bddaeb2012-02-16 06:50:00 +0000133}
134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135CommandInterpreter::CommandInterpreter(Debugger &debugger,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136 bool synchronous_execution)
137 : Broadcaster(debugger.GetBroadcasterManager(),
138 CommandInterpreter::GetStaticBroadcasterClass().AsCString()),
139 Properties(OptionValuePropertiesSP(
140 new OptionValueProperties(ConstString("interpreter")))),
Zachary Turner2c1f46d2015-07-30 20:28:07 +0000141 IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 m_debugger(debugger), m_synchronous_execution(synchronous_execution),
143 m_skip_lldbinit_files(false), m_skip_app_init_files(false),
Jonas Devlieghere2b29b432019-04-26 22:43:16 +0000144 m_command_io_handler_sp(), m_comment_char('#'),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000145 m_batch_command_mode(false), m_truncation_warning(eNoTruncation),
146 m_command_source_depth(0), m_num_errors(0), m_quit_requested(false),
147 m_stopped_for_crash(false) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit");
149 SetEventName(eBroadcastBitResetPrompt, "reset-prompt");
150 SetEventName(eBroadcastBitQuitCommandReceived, "quit");
151 CheckInWithManager();
152 m_collection_sp->Initialize(g_properties);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000153}
154
Kate Stoneb9c1b512016-09-06 20:57:50 +0000155bool CommandInterpreter::GetExpandRegexAliases() const {
156 const uint32_t idx = ePropertyExpandRegexAliases;
157 return m_collection_sp->GetPropertyAtIndexAsBoolean(
158 nullptr, idx, g_properties[idx].default_uint_value != 0);
Greg Clayton754a9362012-08-23 00:22:02 +0000159}
160
Kate Stoneb9c1b512016-09-06 20:57:50 +0000161bool CommandInterpreter::GetPromptOnQuit() const {
162 const uint32_t idx = ePropertyPromptOnQuit;
163 return m_collection_sp->GetPropertyAtIndexAsBoolean(
164 nullptr, idx, g_properties[idx].default_uint_value != 0);
Enrico Granatabcba2b22013-01-17 21:36:19 +0000165}
Greg Clayton754a9362012-08-23 00:22:02 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167void CommandInterpreter::SetPromptOnQuit(bool b) {
168 const uint32_t idx = ePropertyPromptOnQuit;
169 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
Ilia Kacf28be2015-03-23 22:45:13 +0000170}
171
Stefan Granitzc678ed72018-10-05 16:49:47 +0000172bool CommandInterpreter::GetEchoCommands() const {
173 const uint32_t idx = eEchoCommands;
174 return m_collection_sp->GetPropertyAtIndexAsBoolean(
175 nullptr, idx, g_properties[idx].default_uint_value != 0);
176}
177
178void CommandInterpreter::SetEchoCommands(bool b) {
179 const uint32_t idx = eEchoCommands;
180 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
181}
182
183bool CommandInterpreter::GetEchoCommentCommands() const {
184 const uint32_t idx = eEchoCommentCommands;
185 return m_collection_sp->GetPropertyAtIndexAsBoolean(
186 nullptr, idx, g_properties[idx].default_uint_value != 0);
187}
188
189void CommandInterpreter::SetEchoCommentCommands(bool b) {
190 const uint32_t idx = eEchoCommentCommands;
191 m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b);
192}
193
Raphael Isemannc094d232018-07-11 17:18:01 +0000194void CommandInterpreter::AllowExitCodeOnQuit(bool allow) {
195 m_allow_exit_code = allow;
196 if (!allow)
197 m_quit_exit_code.reset();
198}
199
200bool CommandInterpreter::SetQuitExitCode(int exit_code) {
201 if (!m_allow_exit_code)
202 return false;
203 m_quit_exit_code = exit_code;
204 return true;
205}
206
207int CommandInterpreter::GetQuitExitCode(bool &exited) const {
208 exited = m_quit_exit_code.hasValue();
209 if (exited)
210 return *m_quit_exit_code;
211 return 0;
212}
213
Kate Stoneb9c1b512016-09-06 20:57:50 +0000214void CommandInterpreter::ResolveCommand(const char *command_line,
215 CommandReturnObject &result) {
216 std::string command = command_line;
217 if (ResolveCommandImpl(command, result) != nullptr) {
218 result.AppendMessageWithFormat("%s", command.c_str());
219 result.SetStatus(eReturnStatusSuccessFinishResult);
220 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +0000221}
222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223bool CommandInterpreter::GetStopCmdSourceOnError() const {
224 const uint32_t idx = ePropertyStopCmdSourceOnError;
225 return m_collection_sp->GetPropertyAtIndexAsBoolean(
226 nullptr, idx, g_properties[idx].default_uint_value != 0);
Enrico Granata012d4fc2013-06-11 01:26:35 +0000227}
228
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229bool CommandInterpreter::GetSpaceReplPrompts() const {
230 const uint32_t idx = eSpaceReplPrompts;
231 return m_collection_sp->GetPropertyAtIndexAsBoolean(
232 nullptr, idx, g_properties[idx].default_uint_value != 0);
Sean Callanan66810412015-10-19 23:11:07 +0000233}
234
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235void CommandInterpreter::Initialize() {
Pavel Labathf9d16472017-05-15 13:02:37 +0000236 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
237 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000238
Kate Stoneb9c1b512016-09-06 20:57:50 +0000239 CommandReturnObject result;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000240
Kate Stoneb9c1b512016-09-06 20:57:50 +0000241 LoadCommandDictionary();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000242
Kate Stoneb9c1b512016-09-06 20:57:50 +0000243 // An alias arguments vector to reuse - reset it before use...
244 OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector);
245
246 // Set up some initial aliases.
247 CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit", false);
248 if (cmd_obj_sp) {
249 AddAlias("q", cmd_obj_sp);
250 AddAlias("exit", cmd_obj_sp);
251 }
252
253 cmd_obj_sp = GetCommandSPExact("_regexp-attach", false);
254 if (cmd_obj_sp)
255 AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
256
257 cmd_obj_sp = GetCommandSPExact("process detach", false);
258 if (cmd_obj_sp) {
259 AddAlias("detach", cmd_obj_sp);
260 }
261
262 cmd_obj_sp = GetCommandSPExact("process continue", false);
263 if (cmd_obj_sp) {
264 AddAlias("c", cmd_obj_sp);
265 AddAlias("continue", cmd_obj_sp);
266 }
267
268 cmd_obj_sp = GetCommandSPExact("_regexp-break", false);
269 if (cmd_obj_sp)
270 AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
271
272 cmd_obj_sp = GetCommandSPExact("_regexp-tbreak", false);
273 if (cmd_obj_sp)
274 AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
275
276 cmd_obj_sp = GetCommandSPExact("thread step-inst", false);
277 if (cmd_obj_sp) {
278 AddAlias("stepi", cmd_obj_sp);
279 AddAlias("si", cmd_obj_sp);
280 }
281
282 cmd_obj_sp = GetCommandSPExact("thread step-inst-over", false);
283 if (cmd_obj_sp) {
284 AddAlias("nexti", cmd_obj_sp);
285 AddAlias("ni", cmd_obj_sp);
286 }
287
288 cmd_obj_sp = GetCommandSPExact("thread step-in", false);
289 if (cmd_obj_sp) {
290 AddAlias("s", cmd_obj_sp);
291 AddAlias("step", cmd_obj_sp);
292 CommandAlias *sif_alias = AddAlias(
293 "sif", cmd_obj_sp, "--end-linenumber block --step-in-target %1");
294 if (sif_alias) {
295 sif_alias->SetHelp("Step through the current block, stopping if you step "
296 "directly into a function whose name matches the "
297 "TargetFunctionName.");
298 sif_alias->SetSyntax("sif <TargetFunctionName>");
Caroline Ticeca90c472011-05-06 21:37:15 +0000299 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300 }
Caroline Ticeca90c472011-05-06 21:37:15 +0000301
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 cmd_obj_sp = GetCommandSPExact("thread step-over", false);
303 if (cmd_obj_sp) {
304 AddAlias("n", cmd_obj_sp);
305 AddAlias("next", cmd_obj_sp);
306 }
307
308 cmd_obj_sp = GetCommandSPExact("thread step-out", false);
309 if (cmd_obj_sp) {
310 AddAlias("finish", cmd_obj_sp);
311 }
312
313 cmd_obj_sp = GetCommandSPExact("frame select", false);
314 if (cmd_obj_sp) {
315 AddAlias("f", cmd_obj_sp);
316 }
317
318 cmd_obj_sp = GetCommandSPExact("thread select", false);
319 if (cmd_obj_sp) {
320 AddAlias("t", cmd_obj_sp);
321 }
322
323 cmd_obj_sp = GetCommandSPExact("_regexp-jump", false);
324 if (cmd_obj_sp) {
325 AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
326 AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
327 }
328
329 cmd_obj_sp = GetCommandSPExact("_regexp-list", false);
330 if (cmd_obj_sp) {
331 AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
332 AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
333 }
334
335 cmd_obj_sp = GetCommandSPExact("_regexp-env", false);
336 if (cmd_obj_sp)
337 AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
338
339 cmd_obj_sp = GetCommandSPExact("memory read", false);
340 if (cmd_obj_sp)
341 AddAlias("x", cmd_obj_sp);
342
343 cmd_obj_sp = GetCommandSPExact("_regexp-up", false);
344 if (cmd_obj_sp)
345 AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
346
347 cmd_obj_sp = GetCommandSPExact("_regexp-down", false);
348 if (cmd_obj_sp)
349 AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
350
351 cmd_obj_sp = GetCommandSPExact("_regexp-display", false);
352 if (cmd_obj_sp)
353 AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
354
355 cmd_obj_sp = GetCommandSPExact("disassemble", false);
356 if (cmd_obj_sp)
357 AddAlias("dis", cmd_obj_sp);
358
359 cmd_obj_sp = GetCommandSPExact("disassemble", false);
360 if (cmd_obj_sp)
361 AddAlias("di", cmd_obj_sp);
362
363 cmd_obj_sp = GetCommandSPExact("_regexp-undisplay", false);
364 if (cmd_obj_sp)
365 AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
366
367 cmd_obj_sp = GetCommandSPExact("_regexp-bt", false);
368 if (cmd_obj_sp)
369 AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax());
370
371 cmd_obj_sp = GetCommandSPExact("target create", false);
372 if (cmd_obj_sp)
373 AddAlias("file", cmd_obj_sp);
374
375 cmd_obj_sp = GetCommandSPExact("target modules", false);
376 if (cmd_obj_sp)
377 AddAlias("image", cmd_obj_sp);
378
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000379 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000380
381 cmd_obj_sp = GetCommandSPExact("expression", false);
382 if (cmd_obj_sp) {
383 AddAlias("p", cmd_obj_sp, "--")->SetHelpLong("");
384 AddAlias("print", cmd_obj_sp, "--")->SetHelpLong("");
385 AddAlias("call", cmd_obj_sp, "--")->SetHelpLong("");
386 if (auto po = AddAlias("po", cmd_obj_sp, "-O --")) {
387 po->SetHelp("Evaluate an expression on the current thread. Displays any "
388 "returned value with formatting "
389 "controlled by the type's author.");
390 po->SetHelpLong("");
Johnny Chen6d675242012-08-24 18:15:45 +0000391 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000392 AddAlias("parray", cmd_obj_sp, "--element-count %1 --")->SetHelpLong("");
393 AddAlias("poarray", cmd_obj_sp,
394 "--object-description --element-count %1 --")
395 ->SetHelpLong("");
396 }
Johnny Chen6d675242012-08-24 18:15:45 +0000397
Kate Stoneb9c1b512016-09-06 20:57:50 +0000398 cmd_obj_sp = GetCommandSPExact("process kill", false);
399 if (cmd_obj_sp) {
400 AddAlias("kill", cmd_obj_sp);
401 }
Caroline Ticeca90c472011-05-06 21:37:15 +0000402
Kate Stoneb9c1b512016-09-06 20:57:50 +0000403 cmd_obj_sp = GetCommandSPExact("process launch", false);
404 if (cmd_obj_sp) {
Jonas Devlieghere796ac802019-02-11 23:13:08 +0000405 alias_arguments_vector_sp = std::make_shared<OptionArgVector>();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000406#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__)
407 AddAlias("r", cmd_obj_sp, "--");
408 AddAlias("run", cmd_obj_sp, "--");
Jason Molenda85da3122012-07-06 02:46:23 +0000409#else
Kate Stoneb9c1b512016-09-06 20:57:50 +0000410#if defined(__APPLE__)
411 std::string shell_option;
412 shell_option.append("--shell-expand-args");
413 shell_option.append(" true");
414 shell_option.append(" --");
415 AddAlias("r", cmd_obj_sp, "--shell-expand-args true --");
416 AddAlias("run", cmd_obj_sp, "--shell-expand-args true --");
417#else
418 StreamString defaultshell;
419 defaultshell.Printf("--shell=%s --",
420 HostInfo::GetDefaultShell().GetPath().c_str());
Zachary Turnerc1564272016-11-16 21:15:24 +0000421 AddAlias("r", cmd_obj_sp, defaultshell.GetString());
422 AddAlias("run", cmd_obj_sp, defaultshell.GetString());
Jason Molenda85da3122012-07-06 02:46:23 +0000423#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000424#endif
425 }
426
427 cmd_obj_sp = GetCommandSPExact("target symbols add", false);
428 if (cmd_obj_sp) {
429 AddAlias("add-dsym", cmd_obj_sp);
430 }
431
432 cmd_obj_sp = GetCommandSPExact("breakpoint set", false);
433 if (cmd_obj_sp) {
434 AddAlias("rbreak", cmd_obj_sp, "--func-regex %1");
435 }
Jim Ingham285ae0c2018-10-10 00:51:30 +0000436
437 cmd_obj_sp = GetCommandSPExact("frame variable", false);
438 if (cmd_obj_sp) {
Jim Ingham9082c1c2018-10-12 18:46:02 +0000439 AddAlias("v", cmd_obj_sp);
Jim Ingham285ae0c2018-10-10 00:51:30 +0000440 AddAlias("var", cmd_obj_sp);
441 AddAlias("vo", cmd_obj_sp, "--object-description");
442 }
Jonas Devliegheree5f7d602019-05-03 20:37:09 +0000443
444 cmd_obj_sp = GetCommandSPExact("register", false);
445 if (cmd_obj_sp) {
446 AddAlias("re", cmd_obj_sp);
447 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000448}
449
Kate Stoneb9c1b512016-09-06 20:57:50 +0000450void CommandInterpreter::Clear() {
451 m_command_io_handler_sp.reset();
Greg Clayton0c4129f2014-04-25 00:35:14 +0000452}
453
Kate Stoneb9c1b512016-09-06 20:57:50 +0000454const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) {
455 // This function has not yet been implemented.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000456
Kate Stoneb9c1b512016-09-06 20:57:50 +0000457 // Look for any embedded script command
458 // If found,
459 // get interpreter object from the command dictionary,
460 // call execute_one_command on it,
461 // get the results as a string,
462 // substitute that string for current stuff.
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000463
Kate Stoneb9c1b512016-09-06 20:57:50 +0000464 return arg;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000465}
466
Kate Stoneb9c1b512016-09-06 20:57:50 +0000467void CommandInterpreter::LoadCommandDictionary() {
Pavel Labathf9d16472017-05-15 13:02:37 +0000468 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
469 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000470
Kate Stoneb9c1b512016-09-06 20:57:50 +0000471 lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000472
Kate Stoneb9c1b512016-09-06 20:57:50 +0000473 m_command_dict["apropos"] = CommandObjectSP(new CommandObjectApropos(*this));
474 m_command_dict["breakpoint"] =
475 CommandObjectSP(new CommandObjectMultiwordBreakpoint(*this));
476 m_command_dict["bugreport"] =
477 CommandObjectSP(new CommandObjectMultiwordBugreport(*this));
478 m_command_dict["command"] =
479 CommandObjectSP(new CommandObjectMultiwordCommands(*this));
480 m_command_dict["disassemble"] =
481 CommandObjectSP(new CommandObjectDisassemble(*this));
482 m_command_dict["expression"] =
483 CommandObjectSP(new CommandObjectExpression(*this));
484 m_command_dict["frame"] =
485 CommandObjectSP(new CommandObjectMultiwordFrame(*this));
486 m_command_dict["gui"] = CommandObjectSP(new CommandObjectGUI(*this));
487 m_command_dict["help"] = CommandObjectSP(new CommandObjectHelp(*this));
488 m_command_dict["log"] = CommandObjectSP(new CommandObjectLog(*this));
489 m_command_dict["memory"] = CommandObjectSP(new CommandObjectMemory(*this));
490 m_command_dict["platform"] =
491 CommandObjectSP(new CommandObjectPlatform(*this));
492 m_command_dict["plugin"] = CommandObjectSP(new CommandObjectPlugin(*this));
493 m_command_dict["process"] =
494 CommandObjectSP(new CommandObjectMultiwordProcess(*this));
495 m_command_dict["quit"] = CommandObjectSP(new CommandObjectQuit(*this));
496 m_command_dict["register"] =
497 CommandObjectSP(new CommandObjectRegister(*this));
Jonas Devlieghere9e046f02018-11-13 19:18:16 +0000498 m_command_dict["reproducer"] =
499 CommandObjectSP(new CommandObjectReproducer(*this));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000500 m_command_dict["script"] =
501 CommandObjectSP(new CommandObjectScript(*this, script_language));
502 m_command_dict["settings"] =
503 CommandObjectSP(new CommandObjectMultiwordSettings(*this));
504 m_command_dict["source"] =
505 CommandObjectSP(new CommandObjectMultiwordSource(*this));
Davide Italiano24fff242018-04-13 18:02:39 +0000506 m_command_dict["statistics"] = CommandObjectSP(new CommandObjectStats(*this));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000507 m_command_dict["target"] =
508 CommandObjectSP(new CommandObjectMultiwordTarget(*this));
509 m_command_dict["thread"] =
510 CommandObjectSP(new CommandObjectMultiwordThread(*this));
511 m_command_dict["type"] = CommandObjectSP(new CommandObjectType(*this));
512 m_command_dict["version"] = CommandObjectSP(new CommandObjectVersion(*this));
513 m_command_dict["watchpoint"] =
514 CommandObjectSP(new CommandObjectMultiwordWatchpoint(*this));
515 m_command_dict["language"] =
516 CommandObjectSP(new CommandObjectLanguage(*this));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000517
Kate Stoneb9c1b512016-09-06 20:57:50 +0000518 const char *break_regexes[][2] = {
519 {"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$",
520 "breakpoint set --file '%1' --line %2"},
521 {"^/([^/]+)/$", "breakpoint set --source-pattern-regexp '%1'"},
522 {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
523 {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
524 {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$",
525 "breakpoint set --name '%1'"},
526 {"^(-.*)$", "breakpoint set %1"},
527 {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$",
528 "breakpoint set --name '%2' --shlib '%1'"},
529 {"^\\&(.*[^[:space:]])[[:space:]]*$",
530 "breakpoint set --name '%1' --skip-prologue=0"},
531 {"^[\"']?(.*[^[:space:]\"'])[\"']?[[:space:]]*$",
532 "breakpoint set --name '%1'"}};
Kate Stone7428a182016-07-14 22:03:10 +0000533
Kate Stoneb9c1b512016-09-06 20:57:50 +0000534 size_t num_regexes = llvm::array_lengthof(break_regexes);
Jim Inghamca36cd12012-10-05 19:16:31 +0000535
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000536 std::unique_ptr<CommandObjectRegexCommand> break_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000537 new CommandObjectRegexCommand(
538 *this, "_regexp-break",
Raphael Isemann129fe892018-07-30 21:41:13 +0000539 "Set a breakpoint using one of several shorthand formats.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000540 "\n"
541 "_regexp-break <filename>:<linenum>\n"
542 " main.c:12 // Break at line 12 of "
543 "main.c\n\n"
544 "_regexp-break <linenum>\n"
545 " 12 // Break at line 12 of current "
546 "file\n\n"
547 "_regexp-break 0x<address>\n"
548 " 0x1234000 // Break at address "
549 "0x1234000\n\n"
550 "_regexp-break <name>\n"
551 " main // Break in 'main' after the "
552 "prologue\n\n"
553 "_regexp-break &<name>\n"
554 " &main // Break at first instruction "
555 "in 'main'\n\n"
556 "_regexp-break <module>`<name>\n"
557 " libc.so`malloc // Break in 'malloc' from "
558 "'libc.so'\n\n"
559 "_regexp-break /<source-regex>/\n"
560 " /break here/ // Break on source lines in "
561 "current file\n"
562 " // containing text 'break "
563 "here'.\n",
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000564 2,
565 CommandCompletions::eSymbolCompletion |
566 CommandCompletions::eSourceFileCompletion,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000567 false));
Jim Inghamca36cd12012-10-05 19:16:31 +0000568
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000569 if (break_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000570 bool success = true;
571 for (size_t i = 0; i < num_regexes; i++) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000572 success = break_regex_cmd_up->AddRegexCommand(break_regexes[i][0],
Kate Stoneb9c1b512016-09-06 20:57:50 +0000573 break_regexes[i][1]);
574 if (!success)
575 break;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000576 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000577 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000578 break_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
Jim Inghamffba2292011-03-22 02:29:32 +0000579
Kate Stoneb9c1b512016-09-06 20:57:50 +0000580 if (success) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000581 CommandObjectSP break_regex_cmd_sp(break_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000582 m_command_dict[break_regex_cmd_sp->GetCommandName()] = break_regex_cmd_sp;
Jim Inghamca36cd12012-10-05 19:16:31 +0000583 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000584 }
Jim Inghamca36cd12012-10-05 19:16:31 +0000585
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000586 std::unique_ptr<CommandObjectRegexCommand> tbreak_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000587 new CommandObjectRegexCommand(
588 *this, "_regexp-tbreak",
Raphael Isemann129fe892018-07-30 21:41:13 +0000589 "Set a one-shot breakpoint using one of several shorthand formats.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000590 "\n"
591 "_regexp-break <filename>:<linenum>\n"
592 " main.c:12 // Break at line 12 of "
593 "main.c\n\n"
594 "_regexp-break <linenum>\n"
595 " 12 // Break at line 12 of current "
596 "file\n\n"
597 "_regexp-break 0x<address>\n"
598 " 0x1234000 // Break at address "
599 "0x1234000\n\n"
600 "_regexp-break <name>\n"
601 " main // Break in 'main' after the "
602 "prologue\n\n"
603 "_regexp-break &<name>\n"
604 " &main // Break at first instruction "
605 "in 'main'\n\n"
606 "_regexp-break <module>`<name>\n"
607 " libc.so`malloc // Break in 'malloc' from "
608 "'libc.so'\n\n"
609 "_regexp-break /<source-regex>/\n"
610 " /break here/ // Break on source lines in "
611 "current file\n"
612 " // containing text 'break "
613 "here'.\n",
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000614 2,
615 CommandCompletions::eSymbolCompletion |
616 CommandCompletions::eSourceFileCompletion,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000617 false));
618
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000619 if (tbreak_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000620 bool success = true;
621 for (size_t i = 0; i < num_regexes; i++) {
622 // If you add a resultant command string longer than 1024 characters be
623 // sure to increase the size of this buffer.
624 char buffer[1024];
625 int num_printed =
Frederic Riss49c9d8b2018-06-18 04:34:33 +0000626 snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o 1");
Leonard Mosescu17ffd392017-10-05 23:41:28 +0000627 lldbassert(num_printed < 1024);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000628 UNUSED_IF_ASSERT_DISABLED(num_printed);
629 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000630 tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], buffer);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000631 if (!success)
632 break;
Johnny Chen6d675242012-08-24 18:15:45 +0000633 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000634 success =
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000635 tbreak_regex_cmd_up->AddRegexCommand("^$", "breakpoint list --full");
Kate Stone7428a182016-07-14 22:03:10 +0000636
Kate Stoneb9c1b512016-09-06 20:57:50 +0000637 if (success) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000638 CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000639 m_command_dict[tbreak_regex_cmd_sp->GetCommandName()] =
640 tbreak_regex_cmd_sp;
Jim Inghamffba2292011-03-22 02:29:32 +0000641 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000642 }
Kate Stone7428a182016-07-14 22:03:10 +0000643
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000644 std::unique_ptr<CommandObjectRegexCommand> attach_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000645 new CommandObjectRegexCommand(
646 *this, "_regexp-attach", "Attach to process by ID or name.",
647 "_regexp-attach <pid> | <process-name>", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000648 if (attach_regex_cmd_up) {
649 if (attach_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000650 "process attach --pid %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000651 attach_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000652 "^(-.*|.* -.*)$", "process attach %1") && // Any options that are
653 // specified get passed to
654 // 'process attach'
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000655 attach_regex_cmd_up->AddRegexCommand("^(.+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000656 "process attach --name '%1'") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000657 attach_regex_cmd_up->AddRegexCommand("^$", "process attach")) {
658 CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000659 m_command_dict[attach_regex_cmd_sp->GetCommandName()] =
660 attach_regex_cmd_sp;
Jim Inghamffba2292011-03-22 02:29:32 +0000661 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000662 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000663
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000664 std::unique_ptr<CommandObjectRegexCommand> down_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000665 new CommandObjectRegexCommand(*this, "_regexp-down",
666 "Select a newer stack frame. Defaults to "
667 "moving one frame, a numeric argument can "
668 "specify an arbitrary number.",
669 "_regexp-down [<count>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000670 if (down_regex_cmd_up) {
671 if (down_regex_cmd_up->AddRegexCommand("^$", "frame select -r -1") &&
672 down_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000673 "frame select -r -%1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000674 CommandObjectSP down_regex_cmd_sp(down_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000675 m_command_dict[down_regex_cmd_sp->GetCommandName()] = down_regex_cmd_sp;
Jason Molendabc7748b2011-10-22 01:30:52 +0000676 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000677 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000678
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000679 std::unique_ptr<CommandObjectRegexCommand> up_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000680 new CommandObjectRegexCommand(
681 *this, "_regexp-up",
682 "Select an older stack frame. Defaults to moving one "
683 "frame, a numeric argument can specify an arbitrary number.",
684 "_regexp-up [<count>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000685 if (up_regex_cmd_up) {
686 if (up_regex_cmd_up->AddRegexCommand("^$", "frame select -r 1") &&
687 up_regex_cmd_up->AddRegexCommand("^([0-9]+)$", "frame select -r %1")) {
688 CommandObjectSP up_regex_cmd_sp(up_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000689 m_command_dict[up_regex_cmd_sp->GetCommandName()] = up_regex_cmd_sp;
Jason Molendabc7748b2011-10-22 01:30:52 +0000690 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000691 }
Jason Molendabc7748b2011-10-22 01:30:52 +0000692
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000693 std::unique_ptr<CommandObjectRegexCommand> display_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000694 new CommandObjectRegexCommand(
695 *this, "_regexp-display",
696 "Evaluate an expression at every stop (see 'help target stop-hook'.)",
697 "_regexp-display expression", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000698 if (display_regex_cmd_up) {
699 if (display_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000700 "^(.+)$", "target stop-hook add -o \"expr -- %1\"")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000701 CommandObjectSP display_regex_cmd_sp(display_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000702 m_command_dict[display_regex_cmd_sp->GetCommandName()] =
703 display_regex_cmd_sp;
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000704 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000705 }
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000706
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000707 std::unique_ptr<CommandObjectRegexCommand> undisplay_regex_cmd_up(
708 new CommandObjectRegexCommand(*this, "_regexp-undisplay",
709 "Stop displaying expression at every "
710 "stop (specified by stop-hook index.)",
711 "_regexp-undisplay stop-hook-number", 2, 0,
712 false));
713 if (undisplay_regex_cmd_up) {
714 if (undisplay_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000715 "target stop-hook delete %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000716 CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000717 m_command_dict[undisplay_regex_cmd_sp->GetCommandName()] =
718 undisplay_regex_cmd_sp;
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000719 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000720 }
Greg Clayton30c0a1c2012-09-26 22:26:47 +0000721
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000722 std::unique_ptr<CommandObjectRegexCommand> connect_gdb_remote_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000723 new CommandObjectRegexCommand(
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000724 *this, "gdb-remote",
725 "Connect to a process via remote GDB server. "
726 "If no host is specifed, localhost is assumed.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000727 "gdb-remote [<hostname>:]<portnum>", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000728 if (connect_gdb_remote_cmd_up) {
729 if (connect_gdb_remote_cmd_up->AddRegexCommand(
Chris Bieneman51978f52017-04-27 16:13:58 +0000730 "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
731 "process connect --plugin gdb-remote connect://%1:%2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000732 connect_gdb_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000733 "^([[:digit:]]+)$",
734 "process connect --plugin gdb-remote connect://localhost:%1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000735 CommandObjectSP command_sp(connect_gdb_remote_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000736 m_command_dict[command_sp->GetCommandName()] = command_sp;
Jason Molenda4cddfed2012-10-05 05:29:32 +0000737 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000738 }
Jason Molenda4cddfed2012-10-05 05:29:32 +0000739
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000740 std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000741 new CommandObjectRegexCommand(
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000742 *this, "kdp-remote",
743 "Connect to a process via remote KDP server. "
744 "If no UDP port is specified, port 41139 is "
745 "assumed.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000746 "kdp-remote <hostname>[:<portnum>]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000747 if (connect_kdp_remote_cmd_up) {
748 if (connect_kdp_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000749 "^([^:]+:[[:digit:]]+)$",
750 "process connect --plugin kdp-remote udp://%1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000751 connect_kdp_remote_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000752 "^(.+)$", "process connect --plugin kdp-remote udp://%1:41139")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000753 CommandObjectSP command_sp(connect_kdp_remote_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000754 m_command_dict[command_sp->GetCommandName()] = command_sp;
Greg Clayton6bade322013-02-01 23:33:03 +0000755 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000756 }
Greg Clayton6bade322013-02-01 23:33:03 +0000757
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000758 std::unique_ptr<CommandObjectRegexCommand> bt_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000759 new CommandObjectRegexCommand(
760 *this, "_regexp-bt",
761 "Show the current thread's call stack. Any numeric argument "
762 "displays at most that many "
Jim Inghame91ad7d2019-05-02 02:14:08 +0000763 "frames. The argument 'all' displays all threads. Use 'settings"
764 " set frame-format' to customize the printing of individual frames "
765 "and 'settings set thread-format' to customize the thread header.",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000766 "bt [<digit> | all]", 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000767 if (bt_regex_cmd_up) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000768 // accept but don't document "bt -c <number>" -- before bt was a regex
Adrian Prantl05097242018-04-30 16:49:04 +0000769 // command if you wanted to backtrace three frames you would do "bt -c 3"
770 // but the intention is to have this emulate the gdb "bt" command and so
771 // now "bt 3" is the preferred form, in line with gdb.
Stella Stamenova5bac7062019-05-17 18:52:42 +0000772 if (bt_regex_cmd_up->AddRegexCommand("^([[:digit:]]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000773 "thread backtrace -c %1") &&
Stella Stamenova5bac7062019-05-17 18:52:42 +0000774 bt_regex_cmd_up->AddRegexCommand("^-c ([[:digit:]]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000775 "thread backtrace -c %1") &&
Stella Stamenova5bac7062019-05-17 18:52:42 +0000776 bt_regex_cmd_up->AddRegexCommand("^all[[:space:]]*$", "thread backtrace all") &&
777 bt_regex_cmd_up->AddRegexCommand("^[[:space:]]*$", "thread backtrace")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000778 CommandObjectSP command_sp(bt_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000779 m_command_dict[command_sp->GetCommandName()] = command_sp;
Greg Claytonef5651d2013-02-12 18:52:24 +0000780 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000781 }
Greg Claytonef5651d2013-02-12 18:52:24 +0000782
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000783 std::unique_ptr<CommandObjectRegexCommand> list_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000784 new CommandObjectRegexCommand(
785 *this, "_regexp-list",
786 "List relevant source code using one of several shorthand formats.",
787 "\n"
788 "_regexp-list <file>:<line> // List around specific file/line\n"
789 "_regexp-list <line> // List current file around specified "
790 "line\n"
791 "_regexp-list <function-name> // List specified function\n"
792 "_regexp-list 0x<address> // List around specified address\n"
793 "_regexp-list -[<count>] // List previous <count> lines\n"
794 "_regexp-list // List subsequent lines",
795 2, CommandCompletions::eSourceFileCompletion, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000796 if (list_regex_cmd_up) {
797 if (list_regex_cmd_up->AddRegexCommand("^([0-9]+)[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000798 "source list --line %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000799 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000800 "^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]"
801 "]*$",
802 "source list --file '%1' --line %2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000803 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000804 "^\\*?(0x[[:xdigit:]]+)[[:space:]]*$",
805 "source list --address %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000806 list_regex_cmd_up->AddRegexCommand("^-[[:space:]]*$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000807 "source list --reverse") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000808 list_regex_cmd_up->AddRegexCommand(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000809 "^-([[:digit:]]+)[[:space:]]*$",
810 "source list --reverse --count %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000811 list_regex_cmd_up->AddRegexCommand("^(.+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000812 "source list --name \"%1\"") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000813 list_regex_cmd_up->AddRegexCommand("^$", "source list")) {
814 CommandObjectSP list_regex_cmd_sp(list_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000815 m_command_dict[list_regex_cmd_sp->GetCommandName()] = list_regex_cmd_sp;
Richard Mittonf86248d2013-09-12 02:20:34 +0000816 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000817 }
Richard Mittonf86248d2013-09-12 02:20:34 +0000818
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000819 std::unique_ptr<CommandObjectRegexCommand> env_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000820 new CommandObjectRegexCommand(
821 *this, "_regexp-env",
822 "Shorthand for viewing and setting environment variables.",
823 "\n"
824 "_regexp-env // Show enrivonment\n"
825 "_regexp-env <name>=<value> // Set an environment variable",
826 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000827 if (env_regex_cmd_up) {
828 if (env_regex_cmd_up->AddRegexCommand("^$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000829 "settings show target.env-vars") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000830 env_regex_cmd_up->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000831 "settings set target.env-vars %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000832 CommandObjectSP env_regex_cmd_sp(env_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000833 m_command_dict[env_regex_cmd_sp->GetCommandName()] = env_regex_cmd_sp;
834 }
835 }
836
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000837 std::unique_ptr<CommandObjectRegexCommand> jump_regex_cmd_up(
Kate Stoneb9c1b512016-09-06 20:57:50 +0000838 new CommandObjectRegexCommand(
839 *this, "_regexp-jump", "Set the program counter to a new address.",
840 "\n"
841 "_regexp-jump <line>\n"
842 "_regexp-jump +<line-offset> | -<line-offset>\n"
843 "_regexp-jump <file>:<line>\n"
844 "_regexp-jump *<addr>\n",
845 2, 0, false));
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000846 if (jump_regex_cmd_up) {
847 if (jump_regex_cmd_up->AddRegexCommand("^\\*(.*)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000848 "thread jump --addr %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000849 jump_regex_cmd_up->AddRegexCommand("^([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000850 "thread jump --line %1") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000851 jump_regex_cmd_up->AddRegexCommand("^([^:]+):([0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000852 "thread jump --file %1 --line %2") &&
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000853 jump_regex_cmd_up->AddRegexCommand("^([+\\-][0-9]+)$",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000854 "thread jump --by %1")) {
Jonas Devlieghered5b44032019-02-13 06:25:41 +0000855 CommandObjectSP jump_regex_cmd_sp(jump_regex_cmd_up.release());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000856 m_command_dict[jump_regex_cmd_sp->GetCommandName()] = jump_regex_cmd_sp;
857 }
858 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000859}
860
Kate Stoneb9c1b512016-09-06 20:57:50 +0000861int CommandInterpreter::GetCommandNamesMatchingPartialString(
Raphael Isemann7f888292018-09-13 21:26:00 +0000862 const char *cmd_str, bool include_aliases, StringList &matches,
863 StringList &descriptions) {
864 AddNamesMatchingPartialString(m_command_dict, cmd_str, matches,
865 &descriptions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000866
Kate Stoneb9c1b512016-09-06 20:57:50 +0000867 if (include_aliases) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000868 AddNamesMatchingPartialString(m_alias_dict, cmd_str, matches,
869 &descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000870 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000871
Kate Stoneb9c1b512016-09-06 20:57:50 +0000872 return matches.GetSize();
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000873}
874
Raphael Isemann7f888292018-09-13 21:26:00 +0000875CommandObjectSP
876CommandInterpreter::GetCommandSP(llvm::StringRef cmd_str, bool include_aliases,
877 bool exact, StringList *matches,
878 StringList *descriptions) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000879 CommandObjectSP command_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000880
Zachary Turnera4496982016-10-05 21:14:38 +0000881 std::string cmd = cmd_str;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000882
Kate Stoneb9c1b512016-09-06 20:57:50 +0000883 if (HasCommands()) {
Zachary Turnera4496982016-10-05 21:14:38 +0000884 auto pos = m_command_dict.find(cmd);
Greg Claytonb5472782015-01-09 19:08:20 +0000885 if (pos != m_command_dict.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000886 command_sp = pos->second;
887 }
888
889 if (include_aliases && HasAliases()) {
890 auto alias_pos = m_alias_dict.find(cmd);
891 if (alias_pos != m_alias_dict.end())
892 command_sp = alias_pos->second;
893 }
894
895 if (HasUserCommands()) {
Zachary Turnera4496982016-10-05 21:14:38 +0000896 auto pos = m_user_dict.find(cmd);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000897 if (pos != m_user_dict.end())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000898 command_sp = pos->second;
899 }
900
901 if (!exact && !command_sp) {
902 // We will only get into here if we didn't find any exact matches.
903
904 CommandObjectSP user_match_sp, alias_match_sp, real_match_sp;
905
906 StringList local_matches;
907 if (matches == nullptr)
908 matches = &local_matches;
909
910 unsigned int num_cmd_matches = 0;
911 unsigned int num_alias_matches = 0;
912 unsigned int num_user_matches = 0;
913
914 // Look through the command dictionaries one by one, and if we get only one
Adrian Prantl05097242018-04-30 16:49:04 +0000915 // match from any of them in toto, then return that, otherwise return an
916 // empty CommandObjectSP and the list of matches.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000917
918 if (HasCommands()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000919 num_cmd_matches = AddNamesMatchingPartialString(m_command_dict, cmd_str,
920 *matches, descriptions);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000921 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000922
923 if (num_cmd_matches == 1) {
924 cmd.assign(matches->GetStringAtIndex(0));
Zachary Turnera4496982016-10-05 21:14:38 +0000925 auto pos = m_command_dict.find(cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000926 if (pos != m_command_dict.end())
927 real_match_sp = pos->second;
928 }
929
930 if (include_aliases && HasAliases()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000931 num_alias_matches = AddNamesMatchingPartialString(m_alias_dict, cmd_str,
932 *matches, descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000933 }
934
935 if (num_alias_matches == 1) {
936 cmd.assign(matches->GetStringAtIndex(num_cmd_matches));
937 auto alias_pos = m_alias_dict.find(cmd);
938 if (alias_pos != m_alias_dict.end())
939 alias_match_sp = alias_pos->second;
940 }
941
942 if (HasUserCommands()) {
Raphael Isemann7f888292018-09-13 21:26:00 +0000943 num_user_matches = AddNamesMatchingPartialString(m_user_dict, cmd_str,
944 *matches, descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000945 }
946
947 if (num_user_matches == 1) {
948 cmd.assign(
949 matches->GetStringAtIndex(num_cmd_matches + num_alias_matches));
950
Zachary Turnera4496982016-10-05 21:14:38 +0000951 auto pos = m_user_dict.find(cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000952 if (pos != m_user_dict.end())
953 user_match_sp = pos->second;
954 }
955
956 // If we got exactly one match, return that, otherwise return the match
957 // list.
958
959 if (num_user_matches + num_cmd_matches + num_alias_matches == 1) {
960 if (num_cmd_matches)
961 return real_match_sp;
962 else if (num_alias_matches)
963 return alias_match_sp;
964 else
965 return user_match_sp;
966 }
967 } else if (matches && command_sp) {
Zachary Turnera4496982016-10-05 21:14:38 +0000968 matches->AppendString(cmd_str);
Raphael Isemann7f888292018-09-13 21:26:00 +0000969 if (descriptions)
970 descriptions->AppendString(command_sp->GetHelp());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000971 }
972
973 return command_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000974}
975
Zachary Turnera4496982016-10-05 21:14:38 +0000976bool CommandInterpreter::AddCommand(llvm::StringRef name,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000977 const lldb::CommandObjectSP &cmd_sp,
978 bool can_replace) {
979 if (cmd_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +0000980 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
981 "tried to add a CommandObject from a different interpreter");
Kate Stonea487aa42015-01-15 00:52:41 +0000982
Zachary Turnera4496982016-10-05 21:14:38 +0000983 if (name.empty())
984 return false;
985
986 std::string name_sstr(name);
987 auto name_iter = m_command_dict.find(name_sstr);
988 if (name_iter != m_command_dict.end()) {
989 if (!can_replace || !name_iter->second->IsRemovable())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000990 return false;
Zachary Turnera4496982016-10-05 21:14:38 +0000991 name_iter->second = cmd_sp;
992 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000993 m_command_dict[name_sstr] = cmd_sp;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000994 }
Zachary Turnera4496982016-10-05 21:14:38 +0000995 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000996}
997
Zachary Turnera483f572016-10-05 21:14:49 +0000998bool CommandInterpreter::AddUserCommand(llvm::StringRef name,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000999 const lldb::CommandObjectSP &cmd_sp,
1000 bool can_replace) {
1001 if (cmd_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001002 lldbassert((this == &cmd_sp->GetCommandInterpreter()) &&
1003 "tried to add a CommandObject from a different interpreter");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001004
Kate Stoneb9c1b512016-09-06 20:57:50 +00001005 if (!name.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001006 // do not allow replacement of internal commands
Zachary Turnera483f572016-10-05 21:14:49 +00001007 if (CommandExists(name)) {
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001008 if (!can_replace)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001009 return false;
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001010 if (!m_command_dict[name]->IsRemovable())
Greg Clayton5a314712011-10-14 07:41:33 +00001011 return false;
1012 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001013
Zachary Turnera483f572016-10-05 21:14:49 +00001014 if (UserCommandExists(name)) {
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001015 if (!can_replace)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001016 return false;
Jonas Devliegherea6682a42018-12-15 00:15:33 +00001017 if (!m_user_dict[name]->IsRemovable())
Kate Stoneb9c1b512016-09-06 20:57:50 +00001018 return false;
Caroline Tice844d2302010-12-09 22:52:49 +00001019 }
1020
Kate Stoneb9c1b512016-09-06 20:57:50 +00001021 m_user_dict[name] = cmd_sp;
1022 return true;
1023 }
1024 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001025}
1026
Zachary Turnera4496982016-10-05 21:14:38 +00001027CommandObjectSP CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str,
1028 bool include_aliases) const {
1029 Args cmd_words(cmd_str); // Break up the command string into words, in case
Kate Stoneb9c1b512016-09-06 20:57:50 +00001030 // it's a multi-word command.
1031 CommandObjectSP ret_val; // Possibly empty return value.
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001032
Zachary Turnera4496982016-10-05 21:14:38 +00001033 if (cmd_str.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +00001034 return ret_val;
1035
1036 if (cmd_words.GetArgumentCount() == 1)
Zachary Turnera4496982016-10-05 21:14:38 +00001037 return GetCommandSP(cmd_str, include_aliases, true, nullptr);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001038 else {
1039 // We have a multi-word command (seemingly), so we need to do more work.
1040 // First, get the cmd_obj_sp for the first word in the command.
Zachary Turnera4496982016-10-05 21:14:38 +00001041 CommandObjectSP cmd_obj_sp = GetCommandSP(llvm::StringRef(cmd_words.GetArgumentAtIndex(0)),
Kate Stoneb9c1b512016-09-06 20:57:50 +00001042 include_aliases, true, nullptr);
1043 if (cmd_obj_sp.get() != nullptr) {
Adrian Prantl05097242018-04-30 16:49:04 +00001044 // Loop through the rest of the words in the command (everything passed
1045 // in was supposed to be part of a command name), and find the
1046 // appropriate sub-command SP for each command word....
Kate Stoneb9c1b512016-09-06 20:57:50 +00001047 size_t end = cmd_words.GetArgumentCount();
1048 for (size_t j = 1; j < end; ++j) {
1049 if (cmd_obj_sp->IsMultiwordObject()) {
1050 cmd_obj_sp =
1051 cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(j));
1052 if (cmd_obj_sp.get() == nullptr)
1053 // The sub-command name was invalid. Fail and return the empty
1054 // 'ret_val'.
1055 return ret_val;
1056 } else
1057 // We have more words in the command name, but we don't have a
Zachary Turnera4496982016-10-05 21:14:38 +00001058 // multiword object. Fail and return empty 'ret_val'.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001059 return ret_val;
1060 }
1061 // We successfully looped through all the command words and got valid
Zachary Turnera4496982016-10-05 21:14:38 +00001062 // command objects for them. Assign the last object retrieved to
1063 // 'ret_val'.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001064 ret_val = cmd_obj_sp;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001065 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001066 }
1067 return ret_val;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001068}
1069
Raphael Isemann7f888292018-09-13 21:26:00 +00001070CommandObject *
1071CommandInterpreter::GetCommandObject(llvm::StringRef cmd_str,
1072 StringList *matches,
1073 StringList *descriptions) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001074 CommandObject *command_obj =
Raphael Isemann7f888292018-09-13 21:26:00 +00001075 GetCommandSP(cmd_str, false, true, matches, descriptions).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001076
Kate Stoneb9c1b512016-09-06 20:57:50 +00001077 // If we didn't find an exact match to the command string in the commands,
Adrian Prantl05097242018-04-30 16:49:04 +00001078 // look in the aliases.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001079
1080 if (command_obj)
1081 return command_obj;
1082
Raphael Isemann7f888292018-09-13 21:26:00 +00001083 command_obj = GetCommandSP(cmd_str, true, true, matches, descriptions).get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001084
1085 if (command_obj)
1086 return command_obj;
1087
1088 // If there wasn't an exact match then look for an inexact one in just the
1089 // commands
Zachary Turnera4496982016-10-05 21:14:38 +00001090 command_obj = GetCommandSP(cmd_str, false, false, nullptr).get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001091
1092 // Finally, if there wasn't an inexact match among the commands, look for an
Adrian Prantl05097242018-04-30 16:49:04 +00001093 // inexact match in both the commands and aliases.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001094
1095 if (command_obj) {
1096 if (matches)
1097 matches->AppendString(command_obj->GetCommandName());
Raphael Isemann7f888292018-09-13 21:26:00 +00001098 if (descriptions)
1099 descriptions->AppendString(command_obj->GetHelp());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001100 return command_obj;
1101 }
1102
Raphael Isemann7f888292018-09-13 21:26:00 +00001103 return GetCommandSP(cmd_str, true, false, matches, descriptions).get();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001104}
1105
Zachary Turnera483f572016-10-05 21:14:49 +00001106bool CommandInterpreter::CommandExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001107 return m_command_dict.find(cmd) != m_command_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001108}
1109
Zachary Turnera483f572016-10-05 21:14:49 +00001110bool CommandInterpreter::GetAliasFullName(llvm::StringRef cmd,
1111 std::string &full_name) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001112 bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
1113 if (exact_match) {
1114 full_name.assign(cmd);
1115 return exact_match;
1116 } else {
1117 StringList matches;
1118 size_t num_alias_matches;
1119 num_alias_matches =
1120 AddNamesMatchingPartialString(m_alias_dict, cmd, matches);
1121 if (num_alias_matches == 1) {
1122 // Make sure this isn't shadowing a command in the regular command space:
1123 StringList regular_matches;
1124 const bool include_aliases = false;
1125 const bool exact = false;
1126 CommandObjectSP cmd_obj_sp(
1127 GetCommandSP(cmd, include_aliases, exact, &regular_matches));
1128 if (cmd_obj_sp || regular_matches.GetSize() > 0)
1129 return false;
1130 else {
1131 full_name.assign(matches.GetStringAtIndex(0));
1132 return true;
1133 }
1134 } else
1135 return false;
1136 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001137}
1138
Zachary Turnera483f572016-10-05 21:14:49 +00001139bool CommandInterpreter::AliasExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001140 return m_alias_dict.find(cmd) != m_alias_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001141}
1142
Zachary Turnera483f572016-10-05 21:14:49 +00001143bool CommandInterpreter::UserCommandExists(llvm::StringRef cmd) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001144 return m_user_dict.find(cmd) != m_user_dict.end();
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001145}
1146
Kate Stoneb9c1b512016-09-06 20:57:50 +00001147CommandAlias *
Zachary Turnera483f572016-10-05 21:14:49 +00001148CommandInterpreter::AddAlias(llvm::StringRef alias_name,
Kate Stoneb9c1b512016-09-06 20:57:50 +00001149 lldb::CommandObjectSP &command_obj_sp,
Zachary Turnera483f572016-10-05 21:14:49 +00001150 llvm::StringRef args_string) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001151 if (command_obj_sp.get())
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001152 lldbassert((this == &command_obj_sp->GetCommandInterpreter()) &&
1153 "tried to add a CommandObject from a different interpreter");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001154
1155 std::unique_ptr<CommandAlias> command_alias_up(
1156 new CommandAlias(*this, command_obj_sp, args_string, alias_name));
1157
1158 if (command_alias_up && command_alias_up->IsValid()) {
1159 m_alias_dict[alias_name] = CommandObjectSP(command_alias_up.get());
1160 return command_alias_up.release();
1161 }
1162
1163 return nullptr;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001164}
1165
Zachary Turnera483f572016-10-05 21:14:49 +00001166bool CommandInterpreter::RemoveAlias(llvm::StringRef alias_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001167 auto pos = m_alias_dict.find(alias_name);
1168 if (pos != m_alias_dict.end()) {
1169 m_alias_dict.erase(pos);
1170 return true;
1171 }
1172 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001173}
1174
Zachary Turnera483f572016-10-05 21:14:49 +00001175bool CommandInterpreter::RemoveCommand(llvm::StringRef cmd) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001176 auto pos = m_command_dict.find(cmd);
1177 if (pos != m_command_dict.end()) {
1178 if (pos->second->IsRemovable()) {
1179 // Only regular expression objects or python commands are removable
1180 m_command_dict.erase(pos);
1181 return true;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001182 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001183 }
1184 return false;
1185}
Zachary Turnera483f572016-10-05 21:14:49 +00001186bool CommandInterpreter::RemoveUser(llvm::StringRef alias_name) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001187 CommandObject::CommandMap::iterator pos = m_user_dict.find(alias_name);
1188 if (pos != m_user_dict.end()) {
1189 m_user_dict.erase(pos);
1190 return true;
1191 }
1192 return false;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001193}
1194
Kate Stoneb9c1b512016-09-06 20:57:50 +00001195void CommandInterpreter::GetHelp(CommandReturnObject &result,
1196 uint32_t cmd_types) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001197 llvm::StringRef help_prologue(GetDebugger().GetIOHandlerHelpPrologue());
1198 if (!help_prologue.empty()) {
1199 OutputFormattedHelpText(result.GetOutputStream(), llvm::StringRef(),
1200 help_prologue);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001201 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001202
Kate Stoneb9c1b512016-09-06 20:57:50 +00001203 CommandObject::CommandMap::const_iterator pos;
1204 size_t max_len = FindLongestCommandWord(m_command_dict);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001205
Kate Stoneb9c1b512016-09-06 20:57:50 +00001206 if ((cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin) {
1207 result.AppendMessage("Debugger commands:");
1208 result.AppendMessage("");
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001209
Kate Stoneb9c1b512016-09-06 20:57:50 +00001210 for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) {
1211 if (!(cmd_types & eCommandTypesHidden) &&
1212 (pos->first.compare(0, 1, "_") == 0))
1213 continue;
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001214
Zachary Turner0ac5f982016-11-08 04:12:42 +00001215 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1216 pos->second->GetHelp(), max_len);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001217 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001218 result.AppendMessage("");
1219 }
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001220
Kate Stoneb9c1b512016-09-06 20:57:50 +00001221 if (!m_alias_dict.empty() &&
1222 ((cmd_types & eCommandTypesAliases) == eCommandTypesAliases)) {
1223 result.AppendMessageWithFormat(
1224 "Current command abbreviations "
1225 "(type '%shelp command alias' for more info):\n",
1226 GetCommandPrefix());
1227 result.AppendMessage("");
1228 max_len = FindLongestCommandWord(m_alias_dict);
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001229
Kate Stoneb9c1b512016-09-06 20:57:50 +00001230 for (auto alias_pos = m_alias_dict.begin(); alias_pos != m_alias_dict.end();
1231 ++alias_pos) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001232 OutputFormattedHelpText(result.GetOutputStream(), alias_pos->first, "--",
Kate Stoneb9c1b512016-09-06 20:57:50 +00001233 alias_pos->second->GetHelp(), max_len);
Jim Ingham16e0c682011-08-12 23:34:31 +00001234 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001235 result.AppendMessage("");
1236 }
Greg Clayton14a35512011-09-11 00:01:44 +00001237
Kate Stoneb9c1b512016-09-06 20:57:50 +00001238 if (!m_user_dict.empty() &&
1239 ((cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef)) {
1240 result.AppendMessage("Current user-defined commands:");
1241 result.AppendMessage("");
1242 max_len = FindLongestCommandWord(m_user_dict);
1243 for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00001244 OutputFormattedHelpText(result.GetOutputStream(), pos->first, "--",
1245 pos->second->GetHelp(), max_len);
Greg Clayton14a35512011-09-11 00:01:44 +00001246 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001247 result.AppendMessage("");
1248 }
Greg Clayton14a35512011-09-11 00:01:44 +00001249
Kate Stoneb9c1b512016-09-06 20:57:50 +00001250 result.AppendMessageWithFormat(
1251 "For more information on any command, type '%shelp <command-name>'.\n",
1252 GetCommandPrefix());
Greg Clayton44d93782014-01-27 23:43:24 +00001253}
1254
Zachary Turnera01bccd2016-10-05 21:14:56 +00001255CommandObject *CommandInterpreter::GetCommandObjectForCommand(
1256 llvm::StringRef &command_string) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001257 // This function finds the final, lowest-level, alias-resolved command object
Adrian Prantl05097242018-04-30 16:49:04 +00001258 // whose 'Execute' function will eventually be invoked by the given command
1259 // line.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001260
1261 CommandObject *cmd_obj = nullptr;
1262 size_t start = command_string.find_first_not_of(k_white_space);
1263 size_t end = 0;
1264 bool done = false;
1265 while (!done) {
1266 if (start != std::string::npos) {
1267 // Get the next word from command_string.
1268 end = command_string.find_first_of(k_white_space, start);
1269 if (end == std::string::npos)
1270 end = command_string.size();
1271 std::string cmd_word = command_string.substr(start, end - start);
1272
1273 if (cmd_obj == nullptr)
1274 // Since cmd_obj is NULL we are on our first time through this loop.
Zachary Turnera01bccd2016-10-05 21:14:56 +00001275 // Check to see if cmd_word is a valid command or alias.
Zachary Turnera4496982016-10-05 21:14:38 +00001276 cmd_obj = GetCommandObject(cmd_word);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001277 else if (cmd_obj->IsMultiwordObject()) {
1278 // Our current object is a multi-word object; see if the cmd_word is a
1279 // valid sub-command for our object.
1280 CommandObject *sub_cmd_obj =
1281 cmd_obj->GetSubcommandObject(cmd_word.c_str());
1282 if (sub_cmd_obj)
1283 cmd_obj = sub_cmd_obj;
1284 else // cmd_word was not a valid sub-command word, so we are done
1285 done = true;
1286 } else
1287 // We have a cmd_obj and it is not a multi-word object, so we are done.
1288 done = true;
1289
1290 // If we didn't find a valid command object, or our command object is not
Zachary Turnera01bccd2016-10-05 21:14:56 +00001291 // a multi-word object, or we are at the end of the command_string, then
1292 // we are done. Otherwise, find the start of the next word.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001293
1294 if (!cmd_obj || !cmd_obj->IsMultiwordObject() ||
1295 end >= command_string.size())
1296 done = true;
1297 else
1298 start = command_string.find_first_not_of(k_white_space, end);
1299 } else
1300 // Unable to find any more words.
1301 done = true;
1302 }
1303
Zachary Turnera01bccd2016-10-05 21:14:56 +00001304 command_string = command_string.substr(end);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001305 return cmd_obj;
1306}
1307
1308static const char *k_valid_command_chars =
1309 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
1310static void StripLeadingSpaces(std::string &s) {
1311 if (!s.empty()) {
1312 size_t pos = s.find_first_not_of(k_white_space);
1313 if (pos == std::string::npos)
1314 s.clear();
1315 else if (pos == 0)
1316 return;
1317 s.erase(0, pos);
1318 }
1319}
1320
1321static size_t FindArgumentTerminator(const std::string &s) {
1322 const size_t s_len = s.size();
1323 size_t offset = 0;
1324 while (offset < s_len) {
1325 size_t pos = s.find("--", offset);
1326 if (pos == std::string::npos)
1327 break;
1328 if (pos > 0) {
1329 if (isspace(s[pos - 1])) {
Adrian Prantl05097242018-04-30 16:49:04 +00001330 // Check if the string ends "\s--" (where \s is a space character) or
1331 // if we have "\s--\s".
Kate Stoneb9c1b512016-09-06 20:57:50 +00001332 if ((pos + 2 >= s_len) || isspace(s[pos + 2])) {
1333 return pos;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001334 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001335 }
1336 }
1337 offset = pos + 2;
1338 }
1339 return std::string::npos;
1340}
1341
1342static bool ExtractCommand(std::string &command_string, std::string &command,
1343 std::string &suffix, char &quote_char) {
1344 command.clear();
1345 suffix.clear();
1346 StripLeadingSpaces(command_string);
1347
1348 bool result = false;
1349 quote_char = '\0';
1350
1351 if (!command_string.empty()) {
1352 const char first_char = command_string[0];
1353 if (first_char == '\'' || first_char == '"') {
1354 quote_char = first_char;
1355 const size_t end_quote_pos = command_string.find(quote_char, 1);
1356 if (end_quote_pos == std::string::npos) {
1357 command.swap(command_string);
1358 command_string.erase();
1359 } else {
1360 command.assign(command_string, 1, end_quote_pos - 1);
1361 if (end_quote_pos + 1 < command_string.size())
1362 command_string.erase(0, command_string.find_first_not_of(
1363 k_white_space, end_quote_pos + 1));
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001364 else
Kate Stoneb9c1b512016-09-06 20:57:50 +00001365 command_string.erase();
1366 }
1367 } else {
1368 const size_t first_space_pos =
1369 command_string.find_first_of(k_white_space);
1370 if (first_space_pos == std::string::npos) {
1371 command.swap(command_string);
1372 command_string.erase();
1373 } else {
1374 command.assign(command_string, 0, first_space_pos);
1375 command_string.erase(0, command_string.find_first_not_of(
1376 k_white_space, first_space_pos));
1377 }
1378 }
1379 result = true;
1380 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001381
Kate Stoneb9c1b512016-09-06 20:57:50 +00001382 if (!command.empty()) {
1383 // actual commands can't start with '-' or '_'
1384 if (command[0] != '-' && command[0] != '_') {
1385 size_t pos = command.find_first_not_of(k_valid_command_chars);
1386 if (pos > 0 && pos != std::string::npos) {
1387 suffix.assign(command.begin() + pos, command.end());
1388 command.erase(pos);
1389 }
1390 }
1391 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001392
Kate Stoneb9c1b512016-09-06 20:57:50 +00001393 return result;
1394}
1395
1396CommandObject *CommandInterpreter::BuildAliasResult(
Zachary Turnera483f572016-10-05 21:14:49 +00001397 llvm::StringRef alias_name, std::string &raw_input_string,
Kate Stoneb9c1b512016-09-06 20:57:50 +00001398 std::string &alias_result, CommandReturnObject &result) {
1399 CommandObject *alias_cmd_obj = nullptr;
1400 Args cmd_args(raw_input_string);
1401 alias_cmd_obj = GetCommandObject(alias_name);
1402 StreamString result_str;
1403
Zachary Turner5c28c662016-10-03 23:20:36 +00001404 if (!alias_cmd_obj || !alias_cmd_obj->IsAlias()) {
1405 alias_result.clear();
1406 return alias_cmd_obj;
1407 }
1408 std::pair<CommandObjectSP, OptionArgVectorSP> desugared =
1409 ((CommandAlias *)alias_cmd_obj)->Desugar();
1410 OptionArgVectorSP option_arg_vector_sp = desugared.second;
1411 alias_cmd_obj = desugared.first.get();
1412 std::string alias_name_str = alias_name;
1413 if ((cmd_args.GetArgumentCount() == 0) ||
Jonas Devlieghere8d20cfd2018-12-21 22:46:10 +00001414 (alias_name_str != cmd_args.GetArgumentAtIndex(0)))
Zachary Turner5c28c662016-10-03 23:20:36 +00001415 cmd_args.Unshift(alias_name_str);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001416
Zachary Turnera4496982016-10-05 21:14:38 +00001417 result_str.Printf("%s", alias_cmd_obj->GetCommandName().str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001418
Zachary Turner5c28c662016-10-03 23:20:36 +00001419 if (!option_arg_vector_sp.get()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00001420 alias_result = result_str.GetString();
Zachary Turner5c28c662016-10-03 23:20:36 +00001421 return alias_cmd_obj;
1422 }
1423 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001424
Zachary Turner5c28c662016-10-03 23:20:36 +00001425 int value_type;
1426 std::string option;
1427 std::string value;
1428 for (const auto &entry : *option_arg_vector) {
1429 std::tie(option, value_type, value) = entry;
1430 if (option == "<argument>") {
1431 result_str.Printf(" %s", value.c_str());
1432 continue;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001433 }
1434
Zachary Turner5c28c662016-10-03 23:20:36 +00001435 result_str.Printf(" %s", option.c_str());
1436 if (value_type == OptionParser::eNoArgument)
1437 continue;
1438
1439 if (value_type != OptionParser::eOptionalArgument)
1440 result_str.Printf(" ");
1441 int index = GetOptionArgumentPosition(value.c_str());
1442 if (index == 0)
1443 result_str.Printf("%s", value.c_str());
1444 else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
1445
1446 result.AppendErrorWithFormat("Not enough arguments provided; you "
1447 "need at least %d arguments to use "
1448 "this alias.\n",
1449 index);
1450 result.SetStatus(eReturnStatusFailed);
1451 return nullptr;
Zachary Turnerf9fd8cb2016-10-04 01:34:39 +00001452 } else {
1453 size_t strpos = raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
1454 if (strpos != std::string::npos)
1455 raw_input_string = raw_input_string.erase(
1456 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
1457 result_str.Printf("%s", cmd_args.GetArgumentAtIndex(index));
Zachary Turner5c28c662016-10-03 23:20:36 +00001458 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001459 }
Zachary Turner5c28c662016-10-03 23:20:36 +00001460
Zachary Turnerc1564272016-11-16 21:15:24 +00001461 alias_result = result_str.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001462 return alias_cmd_obj;
1463}
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001464
Zachary Turner97206d52017-05-12 04:51:55 +00001465Status CommandInterpreter::PreprocessCommand(std::string &command) {
Adrian Prantl05097242018-04-30 16:49:04 +00001466 // The command preprocessor needs to do things to the command line before any
1467 // parsing of arguments or anything else is done. The only current stuff that
1468 // gets preprocessed is anything enclosed in backtick ('`') characters is
1469 // evaluated as an expression and the result of the expression must be a
1470 // scalar that can be substituted into the command. An example would be:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001471 // (lldb) memory read `$rsp + 20`
Zachary Turner97206d52017-05-12 04:51:55 +00001472 Status error; // Status for any expressions that might not evaluate
Kate Stoneb9c1b512016-09-06 20:57:50 +00001473 size_t start_backtick;
1474 size_t pos = 0;
1475 while ((start_backtick = command.find('`', pos)) != std::string::npos) {
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001476 // Stop if an error was encountered during the previous iteration.
1477 if (error.Fail())
1478 break;
1479
Kate Stoneb9c1b512016-09-06 20:57:50 +00001480 if (start_backtick > 0 && command[start_backtick - 1] == '\\') {
Adrian Prantl05097242018-04-30 16:49:04 +00001481 // The backtick was preceded by a '\' character, remove the slash and
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001482 // don't treat the backtick as the start of an expression.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001483 command.erase(start_backtick - 1, 1);
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001484 // No need to add one to start_backtick since we just deleted a char.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001485 pos = start_backtick;
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001486 continue;
1487 }
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00001488
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001489 const size_t expr_content_start = start_backtick + 1;
1490 const size_t end_backtick = command.find('`', expr_content_start);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001491
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001492 if (end_backtick == std::string::npos) {
1493 // Stop if there's no end backtick.
1494 break;
1495 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001496
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001497 if (end_backtick == expr_content_start) {
1498 // Skip over empty expression. (two backticks in a row)
1499 command.erase(start_backtick, 2);
1500 continue;
1501 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001502
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001503 std::string expr_str(command, expr_content_start,
1504 end_backtick - expr_content_start);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001505
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001506 ExecutionContext exe_ctx(GetExecutionContext());
1507 Target *target = exe_ctx.GetTargetPtr();
1508
1509 // Get a dummy target to allow for calculator mode while processing
1510 // backticks. This also helps break the infinite loop caused when target is
1511 // null.
1512 if (!target)
1513 target = m_debugger.GetDummyTarget();
1514
1515 if (!target)
1516 continue;
1517
1518 ValueObjectSP expr_result_valobj_sp;
1519
1520 EvaluateExpressionOptions options;
1521 options.SetCoerceToId(false);
1522 options.SetUnwindOnError(true);
1523 options.SetIgnoreBreakpoints(true);
1524 options.SetKeepInMemory(false);
1525 options.SetTryAllThreads(true);
1526 options.SetTimeout(llvm::None);
1527
1528 ExpressionResults expr_result =
1529 target->EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(),
1530 expr_result_valobj_sp, options);
1531
1532 if (expr_result == eExpressionCompleted) {
1533 Scalar scalar;
1534 if (expr_result_valobj_sp)
1535 expr_result_valobj_sp =
1536 expr_result_valobj_sp->GetQualifiedRepresentationIfAvailable(
1537 expr_result_valobj_sp->GetDynamicValueType(), true);
1538 if (expr_result_valobj_sp->ResolveValue(scalar)) {
1539 command.erase(start_backtick, end_backtick - start_backtick + 1);
1540 StreamString value_strm;
1541 const bool show_type = false;
1542 scalar.GetValue(&value_strm, show_type);
1543 size_t value_string_size = value_strm.GetSize();
1544 if (value_string_size) {
1545 command.insert(start_backtick, value_strm.GetString());
1546 pos = start_backtick + value_string_size;
1547 continue;
1548 } else {
1549 error.SetErrorStringWithFormat("expression value didn't result "
1550 "in a scalar value for the "
1551 "expression '%s'",
1552 expr_str.c_str());
1553 break;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001554 }
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001555 } else {
1556 error.SetErrorStringWithFormat("expression value didn't result "
1557 "in a scalar value for the "
1558 "expression '%s'",
1559 expr_str.c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001560 break;
Jonas Devlieghere76c6fea2018-12-30 17:56:30 +00001561 }
1562
1563 continue;
1564 }
1565
1566 if (expr_result_valobj_sp)
1567 error = expr_result_valobj_sp->GetError();
1568
1569 if (error.Success()) {
1570 switch (expr_result) {
1571 case eExpressionSetupError:
1572 error.SetErrorStringWithFormat(
1573 "expression setup error for the expression '%s'", expr_str.c_str());
1574 break;
1575 case eExpressionParseError:
1576 error.SetErrorStringWithFormat(
1577 "expression parse error for the expression '%s'", expr_str.c_str());
1578 break;
1579 case eExpressionResultUnavailable:
1580 error.SetErrorStringWithFormat(
1581 "expression error fetching result for the expression '%s'",
1582 expr_str.c_str());
1583 break;
1584 case eExpressionCompleted:
1585 break;
1586 case eExpressionDiscarded:
1587 error.SetErrorStringWithFormat(
1588 "expression discarded for the expression '%s'", expr_str.c_str());
1589 break;
1590 case eExpressionInterrupted:
1591 error.SetErrorStringWithFormat(
1592 "expression interrupted for the expression '%s'", expr_str.c_str());
1593 break;
1594 case eExpressionHitBreakpoint:
1595 error.SetErrorStringWithFormat(
1596 "expression hit breakpoint for the expression '%s'",
1597 expr_str.c_str());
1598 break;
1599 case eExpressionTimedOut:
1600 error.SetErrorStringWithFormat(
1601 "expression timed out for the expression '%s'", expr_str.c_str());
1602 break;
1603 case eExpressionStoppedForDebug:
1604 error.SetErrorStringWithFormat("expression stop at entry point "
1605 "for debugging for the "
1606 "expression '%s'",
1607 expr_str.c_str());
1608 break;
1609 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001610 }
1611 }
1612 return error;
1613}
1614
1615bool CommandInterpreter::HandleCommand(const char *command_line,
1616 LazyBool lazy_add_to_history,
1617 CommandReturnObject &result,
1618 ExecutionContext *override_context,
1619 bool repeat_on_empty_command,
1620 bool no_context_switching)
1621
1622{
1623
1624 std::string command_string(command_line);
1625 std::string original_command_string(command_line);
1626
1627 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS));
Jim Ingham8f7db522016-12-15 00:30:30 +00001628 llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
Sean Callanan237c3ed2016-12-14 21:31:31 +00001629 command_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001630
1631 if (log)
1632 log->Printf("Processing command: %s", command_line);
1633
Pavel Labathf9d16472017-05-15 13:02:37 +00001634 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
1635 Timer scoped_timer(func_cat, "Handling command: %s.", command_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001636
1637 if (!no_context_switching)
1638 UpdateExecutionContext(override_context);
1639
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001640 if (WasInterrupted()) {
1641 result.AppendError("interrupted");
1642 result.SetStatus(eReturnStatusFailed);
1643 return false;
1644 }
1645
Kate Stoneb9c1b512016-09-06 20:57:50 +00001646 bool add_to_history;
1647 if (lazy_add_to_history == eLazyBoolCalculate)
1648 add_to_history = (m_command_source_depth == 0);
1649 else
1650 add_to_history = (lazy_add_to_history == eLazyBoolYes);
1651
1652 bool empty_command = false;
1653 bool comment_command = false;
1654 if (command_string.empty())
1655 empty_command = true;
1656 else {
1657 const char *k_space_characters = "\t\n\v\f\r ";
1658
1659 size_t non_space = command_string.find_first_not_of(k_space_characters);
Adrian Prantl05097242018-04-30 16:49:04 +00001660 // Check for empty line or comment line (lines whose first non-space
1661 // character is the comment character for this interpreter)
Kate Stoneb9c1b512016-09-06 20:57:50 +00001662 if (non_space == std::string::npos)
1663 empty_command = true;
1664 else if (command_string[non_space] == m_comment_char)
1665 comment_command = true;
1666 else if (command_string[non_space] == CommandHistory::g_repeat_char) {
Zachary Turner53877af2016-11-18 23:22:42 +00001667 llvm::StringRef search_str(command_string);
1668 search_str = search_str.drop_front(non_space);
1669 if (auto hist_str = m_command_history.FindString(search_str)) {
1670 add_to_history = false;
1671 command_string = *hist_str;
1672 original_command_string = *hist_str;
1673 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001674 result.AppendErrorWithFormat("Could not find entry: %s in history",
1675 command_string.c_str());
1676 result.SetStatus(eReturnStatusFailed);
1677 return false;
1678 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001679 }
1680 }
1681
1682 if (empty_command) {
1683 if (repeat_on_empty_command) {
1684 if (m_command_history.IsEmpty()) {
1685 result.AppendError("empty command");
1686 result.SetStatus(eReturnStatusFailed);
1687 return false;
1688 } else {
1689 command_line = m_repeat_command.c_str();
1690 command_string = command_line;
1691 original_command_string = command_line;
1692 if (m_repeat_command.empty()) {
1693 result.AppendErrorWithFormat("No auto repeat.\n");
1694 result.SetStatus(eReturnStatusFailed);
1695 return false;
1696 }
1697 }
1698 add_to_history = false;
1699 } else {
1700 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1701 return true;
1702 }
1703 } else if (comment_command) {
1704 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1705 return true;
1706 }
1707
Zachary Turner97206d52017-05-12 04:51:55 +00001708 Status error(PreprocessCommand(command_string));
Kate Stoneb9c1b512016-09-06 20:57:50 +00001709
1710 if (error.Fail()) {
1711 result.AppendError(error.AsCString());
1712 result.SetStatus(eReturnStatusFailed);
1713 return false;
1714 }
1715
1716 // Phase 1.
1717
1718 // Before we do ANY kind of argument processing, we need to figure out what
1719 // the real/final command object is for the specified command. This gets
1720 // complicated by the fact that the user could have specified an alias, and,
1721 // in translating the alias, there may also be command options and/or even
1722 // data (including raw text strings) that need to be found and inserted into
1723 // the command line as part of the translation. So this first step is plain
1724 // look-up and replacement, resulting in:
1725 // 1. the command object whose Execute method will actually be called
1726 // 2. a revised command string, with all substitutions and replacements
1727 // taken care of
1728 // From 1 above, we can determine whether the Execute function wants raw
1729 // input or not.
1730
1731 CommandObject *cmd_obj = ResolveCommandImpl(command_string, result);
1732
1733 // Although the user may have abbreviated the command, the command_string now
Adrian Prantl05097242018-04-30 16:49:04 +00001734 // has the command expanded to the full name. For example, if the input was
1735 // "br s -n main", command_string is now "breakpoint set -n main".
Kate Stoneb9c1b512016-09-06 20:57:50 +00001736 if (log) {
Zachary Turnera4496982016-10-05 21:14:38 +00001737 llvm::StringRef command_name = cmd_obj ? cmd_obj->GetCommandName() : "<not found>";
1738 log->Printf("HandleCommand, cmd_obj : '%s'", command_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00001739 log->Printf("HandleCommand, (revised) command_string: '%s'",
1740 command_string.c_str());
1741 const bool wants_raw_input =
1742 (cmd_obj != NULL) ? cmd_obj->WantsRawCommandString() : false;
1743 log->Printf("HandleCommand, wants_raw_input:'%s'",
1744 wants_raw_input ? "True" : "False");
1745 }
1746
1747 // Phase 2.
1748 // Take care of things like setting up the history command & calling the
Adrian Prantl05097242018-04-30 16:49:04 +00001749 // appropriate Execute method on the CommandObject, with the appropriate
1750 // arguments.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001751
1752 if (cmd_obj != nullptr) {
1753 if (add_to_history) {
1754 Args command_args(command_string);
1755 const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
1756 if (repeat_command != nullptr)
1757 m_repeat_command.assign(repeat_command);
1758 else
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00001759 m_repeat_command.assign(original_command_string);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001760
1761 m_command_history.AppendString(original_command_string);
1762 }
1763
1764 std::string remainder;
Zachary Turnera4496982016-10-05 21:14:38 +00001765 const std::size_t actual_cmd_name_len = cmd_obj->GetCommandName().size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001766 if (actual_cmd_name_len < command_string.length())
1767 remainder = command_string.substr(actual_cmd_name_len);
1768
1769 // Remove any initial spaces
1770 size_t pos = remainder.find_first_not_of(k_white_space);
1771 if (pos != 0 && pos != std::string::npos)
1772 remainder.erase(0, pos);
1773
1774 if (log)
1775 log->Printf(
1776 "HandleCommand, command line after removing command name(s): '%s'",
1777 remainder.c_str());
1778
1779 cmd_obj->Execute(remainder.c_str(), result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001780 }
1781
1782 if (log)
1783 log->Printf("HandleCommand, command %s",
1784 (result.Succeeded() ? "succeeded" : "did not succeed"));
1785
1786 return result.Succeeded();
1787}
1788
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001789int CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001790 int num_command_matches = 0;
1791 bool look_for_subcommand = false;
1792
1793 // For any of the command completions a unique match will be a complete word.
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001794 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001795
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001796 if (request.GetCursorIndex() == -1) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001797 // We got nothing on the command line, so return the list of commands
1798 bool include_aliases = true;
Raphael Isemann7f888292018-09-13 21:26:00 +00001799 StringList new_matches, descriptions;
1800 num_command_matches = GetCommandNamesMatchingPartialString(
1801 "", include_aliases, new_matches, descriptions);
1802 request.AddCompletions(new_matches, descriptions);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001803 } else if (request.GetCursorIndex() == 0) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001804 // The cursor is in the first argument, so just do a lookup in the
1805 // dictionary.
Raphael Isemann7f888292018-09-13 21:26:00 +00001806 StringList new_matches, new_descriptions;
1807 CommandObject *cmd_obj =
1808 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0),
1809 &new_matches, &new_descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001810
1811 if (num_command_matches == 1 && cmd_obj && cmd_obj->IsMultiwordObject() &&
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001812 new_matches.GetStringAtIndex(0) != nullptr &&
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001813 strcmp(request.GetParsedLine().GetArgumentAtIndex(0),
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001814 new_matches.GetStringAtIndex(0)) == 0) {
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001815 if (request.GetParsedLine().GetArgumentCount() == 1) {
1816 request.SetWordComplete(true);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001817 } else {
1818 look_for_subcommand = true;
1819 num_command_matches = 0;
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001820 new_matches.DeleteStringAtIndex(0);
Raphael Isemann7f888292018-09-13 21:26:00 +00001821 new_descriptions.DeleteStringAtIndex(0);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001822 request.GetParsedLine().AppendArgument(llvm::StringRef());
1823 request.SetCursorIndex(request.GetCursorIndex() + 1);
1824 request.SetCursorCharPosition(0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001825 }
1826 }
Raphael Isemann7f888292018-09-13 21:26:00 +00001827 request.AddCompletions(new_matches, new_descriptions);
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001828 num_command_matches = request.GetNumberOfMatches();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001829 }
1830
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001831 if (request.GetCursorIndex() > 0 || look_for_subcommand) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001832 // We are completing further on into a commands arguments, so find the
Adrian Prantl05097242018-04-30 16:49:04 +00001833 // command and tell it to complete the command. First see if there is a
1834 // matching initial command:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001835 CommandObject *command_object =
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001836 GetCommandObject(request.GetParsedLine().GetArgumentAtIndex(0));
Kate Stoneb9c1b512016-09-06 20:57:50 +00001837 if (command_object == nullptr) {
1838 return 0;
1839 } else {
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001840 request.GetParsedLine().Shift();
1841 request.SetCursorIndex(request.GetCursorIndex() - 1);
1842 num_command_matches = command_object->HandleCompletion(request);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001843 }
1844 }
1845
1846 return num_command_matches;
1847}
1848
1849int CommandInterpreter::HandleCompletion(
1850 const char *current_line, const char *cursor, const char *last_char,
Raphael Isemann7f888292018-09-13 21:26:00 +00001851 int match_start_point, int max_return_elements, StringList &matches,
1852 StringList &descriptions) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001853
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001854 llvm::StringRef command_line(current_line, last_char - current_line);
Raphael Isemann7f888292018-09-13 21:26:00 +00001855 CompletionResult result;
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001856 CompletionRequest request(command_line, cursor - current_line,
Raphael Isemann7f888292018-09-13 21:26:00 +00001857 match_start_point, max_return_elements, result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001858 // Don't complete comments, and if the line we are completing is just the
Adrian Prantl05097242018-04-30 16:49:04 +00001859 // history repeat character, substitute the appropriate history line.
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001860 const char *first_arg = request.GetParsedLine().GetArgumentAtIndex(0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001861 if (first_arg) {
1862 if (first_arg[0] == m_comment_char)
1863 return 0;
1864 else if (first_arg[0] == CommandHistory::g_repeat_char) {
Zachary Turner53877af2016-11-18 23:22:42 +00001865 if (auto hist_str = m_command_history.FindString(first_arg)) {
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001866 matches.InsertStringAtIndex(0, *hist_str);
Raphael Isemann7f888292018-09-13 21:26:00 +00001867 descriptions.InsertStringAtIndex(0, "Previous command history event");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001868 return -2;
1869 } else
1870 return 0;
1871 }
1872 }
1873
Kate Stoneb9c1b512016-09-06 20:57:50 +00001874 // Only max_return_elements == -1 is supported at present:
Leonard Mosescu17ffd392017-10-05 23:41:28 +00001875 lldbassert(max_return_elements == -1);
Raphael Isemann2443bbd2018-07-02 21:29:56 +00001876
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001877 int num_command_matches = HandleCompletionMatches(request);
Raphael Isemann7f888292018-09-13 21:26:00 +00001878 result.GetMatches(matches);
1879 result.GetDescriptions(descriptions);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001880
1881 if (num_command_matches <= 0)
1882 return num_command_matches;
1883
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001884 if (request.GetParsedLine().GetArgumentCount() == 0) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001885 // If we got an empty string, insert nothing.
1886 matches.InsertStringAtIndex(0, "");
Raphael Isemann7f888292018-09-13 21:26:00 +00001887 descriptions.InsertStringAtIndex(0, "");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001888 } else {
1889 // Now figure out if there is a common substring, and if so put that in
Adrian Prantl05097242018-04-30 16:49:04 +00001890 // element 0, otherwise put an empty string in element 0.
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001891 std::string command_partial_str = request.GetCursorArgumentPrefix().str();
Kate Stoneb9c1b512016-09-06 20:57:50 +00001892
1893 std::string common_prefix;
1894 matches.LongestCommonPrefix(common_prefix);
1895 const size_t partial_name_len = command_partial_str.size();
1896 common_prefix.erase(0, partial_name_len);
1897
Adrian Prantl05097242018-04-30 16:49:04 +00001898 // If we matched a unique single command, add a space... Only do this if
1899 // the completer told us this was a complete word, however...
Raphael Isemanna2e76c02018-07-13 18:28:14 +00001900 if (num_command_matches == 1 && request.GetWordComplete()) {
1901 char quote_char = request.GetParsedLine()[request.GetCursorIndex()].quote;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001902 common_prefix =
1903 Args::EscapeLLDBCommandArgument(common_prefix, quote_char);
1904 if (quote_char != '\0')
1905 common_prefix.push_back(quote_char);
1906 common_prefix.push_back(' ');
1907 }
Raphael Isemann1a6d7ab2018-07-27 18:42:46 +00001908 matches.InsertStringAtIndex(0, common_prefix.c_str());
Raphael Isemann7f888292018-09-13 21:26:00 +00001909 descriptions.InsertStringAtIndex(0, "");
Kate Stoneb9c1b512016-09-06 20:57:50 +00001910 }
1911 return num_command_matches;
1912}
1913
1914CommandInterpreter::~CommandInterpreter() {}
1915
Zachary Turner514d8cd2016-09-23 18:06:53 +00001916void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001917 EventSP prompt_change_event_sp(
1918 new Event(eBroadcastBitResetPrompt, new EventDataBytes(new_prompt)));
1919 ;
1920 BroadcastEvent(prompt_change_event_sp);
1921 if (m_command_io_handler_sp)
1922 m_command_io_handler_sp->SetPrompt(new_prompt);
1923}
1924
Zachary Turner7a120c82016-11-13 03:05:58 +00001925bool CommandInterpreter::Confirm(llvm::StringRef message, bool default_answer) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001926 // Check AutoConfirm first:
1927 if (m_debugger.GetAutoConfirm())
1928 return default_answer;
1929
1930 IOHandlerConfirm *confirm =
1931 new IOHandlerConfirm(m_debugger, message, default_answer);
1932 IOHandlerSP io_handler_sp(confirm);
1933 m_debugger.RunIOHandler(io_handler_sp);
1934 return confirm->GetResponse();
1935}
1936
Zachary Turnera483f572016-10-05 21:14:49 +00001937const CommandAlias *
1938CommandInterpreter::GetAlias(llvm::StringRef alias_name) const {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001939 OptionArgVectorSP ret_val;
1940
Zachary Turnera483f572016-10-05 21:14:49 +00001941 auto pos = m_alias_dict.find(alias_name);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001942 if (pos != m_alias_dict.end())
1943 return (CommandAlias *)pos->second.get();
1944
1945 return nullptr;
1946}
1947
Zachary Turnera4496982016-10-05 21:14:38 +00001948bool CommandInterpreter::HasCommands() const { return (!m_command_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001949
Zachary Turnera4496982016-10-05 21:14:38 +00001950bool CommandInterpreter::HasAliases() const { return (!m_alias_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001951
Zachary Turnera4496982016-10-05 21:14:38 +00001952bool CommandInterpreter::HasUserCommands() const { return (!m_user_dict.empty()); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001953
Zachary Turnera4496982016-10-05 21:14:38 +00001954bool CommandInterpreter::HasAliasOptions() const { return HasAliases(); }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001955
1956void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj,
1957 const char *alias_name,
1958 Args &cmd_args,
1959 std::string &raw_input_string,
1960 CommandReturnObject &result) {
1961 OptionArgVectorSP option_arg_vector_sp =
1962 GetAlias(alias_name)->GetOptionArguments();
1963
1964 bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
1965
1966 // Make sure that the alias name is the 0th element in cmd_args
1967 std::string alias_name_str = alias_name;
Jonas Devlieghere8d20cfd2018-12-21 22:46:10 +00001968 if (alias_name_str != cmd_args.GetArgumentAtIndex(0))
Zachary Turner5c725f32016-09-19 21:56:59 +00001969 cmd_args.Unshift(alias_name_str);
Kate Stoneb9c1b512016-09-06 20:57:50 +00001970
1971 Args new_args(alias_cmd_obj->GetCommandName());
1972 if (new_args.GetArgumentCount() == 2)
1973 new_args.Shift();
1974
1975 if (option_arg_vector_sp.get()) {
1976 if (wants_raw_input) {
1977 // We have a command that both has command options and takes raw input.
Adrian Prantl05097242018-04-30 16:49:04 +00001978 // Make *sure* it has a " -- " in the right place in the
1979 // raw_input_string.
Kate Stoneb9c1b512016-09-06 20:57:50 +00001980 size_t pos = raw_input_string.find(" -- ");
1981 if (pos == std::string::npos) {
1982 // None found; assume it goes at the beginning of the raw input string
1983 raw_input_string.insert(0, " -- ");
1984 }
1985 }
1986
1987 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
1988 const size_t old_size = cmd_args.GetArgumentCount();
1989 std::vector<bool> used(old_size + 1, false);
1990
1991 used[0] = true;
1992
Zachary Turner5c28c662016-10-03 23:20:36 +00001993 int value_type;
1994 std::string option;
1995 std::string value;
1996 for (const auto &option_entry : *option_arg_vector) {
1997 std::tie(option, value_type, value) = option_entry;
1998 if (option == "<argument>") {
1999 if (!wants_raw_input || (value != "--")) {
2000 // Since we inserted this above, make sure we don't insert it twice
2001 new_args.AppendArgument(value);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002002 }
Zachary Turner5c28c662016-10-03 23:20:36 +00002003 continue;
2004 }
2005
2006 if (value_type != OptionParser::eOptionalArgument)
2007 new_args.AppendArgument(option);
2008
2009 if (value == "<no-argument>")
2010 continue;
2011
2012 int index = GetOptionArgumentPosition(value.c_str());
2013 if (index == 0) {
2014 // value was NOT a positional argument; must be a real value
2015 if (value_type != OptionParser::eOptionalArgument)
2016 new_args.AppendArgument(value);
2017 else {
2018 char buffer[255];
2019 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
2020 value.c_str());
2021 new_args.AppendArgument(llvm::StringRef(buffer));
2022 }
2023
2024 } else if (static_cast<size_t>(index) >= cmd_args.GetArgumentCount()) {
2025 result.AppendErrorWithFormat("Not enough arguments provided; you "
2026 "need at least %d arguments to use "
2027 "this alias.\n",
2028 index);
2029 result.SetStatus(eReturnStatusFailed);
2030 return;
2031 } else {
2032 // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
2033 size_t strpos =
2034 raw_input_string.find(cmd_args.GetArgumentAtIndex(index));
2035 if (strpos != std::string::npos) {
2036 raw_input_string = raw_input_string.erase(
2037 strpos, strlen(cmd_args.GetArgumentAtIndex(index)));
2038 }
2039
2040 if (value_type != OptionParser::eOptionalArgument)
2041 new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index));
2042 else {
2043 char buffer[255];
2044 ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(),
2045 cmd_args.GetArgumentAtIndex(index));
2046 new_args.AppendArgument(buffer);
2047 }
2048 used[index] = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002049 }
2050 }
2051
Zachary Turner97d2c402016-10-05 23:40:23 +00002052 for (auto entry : llvm::enumerate(cmd_args.entries())) {
Zachary Turner4eb84492017-03-13 17:12:12 +00002053 if (!used[entry.index()] && !wants_raw_input)
2054 new_args.AppendArgument(entry.value().ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002055 }
2056
2057 cmd_args.Clear();
2058 cmd_args.SetArguments(new_args.GetArgumentCount(),
2059 new_args.GetConstArgumentVector());
2060 } else {
2061 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2062 // This alias was not created with any options; nothing further needs to be
Adrian Prantl05097242018-04-30 16:49:04 +00002063 // done, unless it is a command that wants raw input, in which case we need
2064 // to clear the rest of the data from cmd_args, since its in the raw input
2065 // string.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002066 if (wants_raw_input) {
2067 cmd_args.Clear();
2068 cmd_args.SetArguments(new_args.GetArgumentCount(),
2069 new_args.GetConstArgumentVector());
2070 }
2071 return;
2072 }
2073
2074 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2075 return;
2076}
2077
2078int CommandInterpreter::GetOptionArgumentPosition(const char *in_string) {
2079 int position = 0; // Any string that isn't an argument position, i.e. '%'
2080 // followed by an integer, gets a position
2081 // of zero.
2082
2083 const char *cptr = in_string;
2084
2085 // Does it start with '%'
2086 if (cptr[0] == '%') {
2087 ++cptr;
2088
2089 // Is the rest of it entirely digits?
2090 if (isdigit(cptr[0])) {
2091 const char *start = cptr;
2092 while (isdigit(cptr[0]))
2093 ++cptr;
2094
Adrian Prantl05097242018-04-30 16:49:04 +00002095 // We've gotten to the end of the digits; are we at the end of the
2096 // string?
Kate Stoneb9c1b512016-09-06 20:57:50 +00002097 if (cptr[0] == '\0')
2098 position = atoi(start);
2099 }
2100 }
2101
2102 return position;
2103}
2104
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +00002105static void GetHomeInitFile(llvm::SmallVectorImpl<char> &init_file,
2106 llvm::StringRef suffix = {}) {
2107 std::string init_file_name = ".lldbinit";
2108 if (!suffix.empty()) {
2109 init_file_name.append("-");
2110 init_file_name.append(suffix.str());
2111 }
2112
2113 llvm::sys::path::home_directory(init_file);
2114 llvm::sys::path::append(init_file, init_file_name);
2115
2116 FileSystem::Instance().Resolve(init_file);
2117}
2118
2119static void GetCwdInitFile(llvm::SmallVectorImpl<char> &init_file) {
2120 llvm::StringRef s = ".lldbinit";
2121 init_file.assign(s.begin(), s.end());
2122 FileSystem::Instance().Resolve(init_file);
2123}
2124
2125static LoadCWDlldbinitFile ShouldLoadCwdInitFile() {
2126 lldb::TargetPropertiesSP properties = Target::GetGlobalProperties();
2127 if (!properties)
2128 return eLoadCWDlldbinitFalse;
2129 return properties->GetLoadCWDlldbinitFile();
2130}
2131
2132void CommandInterpreter::SourceInitFile(FileSpec file,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002133 CommandReturnObject &result) {
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +00002134 assert(!m_skip_lldbinit_files);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002135
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +00002136 if (!FileSystem::Instance().Exists(file)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002137 result.SetStatus(eReturnStatusSuccessFinishNoResult);
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +00002138 return;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002139 }
Jonas Devlieghere2fc6b022019-05-17 22:53:04 +00002140
2141 // Use HandleCommand to 'source' the given file; this will do the actual
2142 // broadcasting of the commands back to any appropriate listener (see
2143 // CommandObjectSource::Execute for more details).
2144 const bool saved_batch = SetBatchCommandMode(true);
2145 ExecutionContext *ctx = nullptr;
2146 CommandInterpreterRunOptions options;
2147 options.SetSilent(true);
2148 options.SetPrintErrors(true);
2149 options.SetStopOnError(false);
2150 options.SetStopOnContinue(true);
2151 HandleCommandsFromFile(file, ctx, options, result);
2152 SetBatchCommandMode(saved_batch);
2153}
2154
2155void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) {
2156 if (m_skip_lldbinit_files) {
2157 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2158 return;
2159 }
2160
2161 llvm::SmallString<128> init_file;
2162 GetCwdInitFile(init_file);
2163 if (!FileSystem::Instance().Exists(init_file)) {
2164 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2165 return;
2166 }
2167
2168 LoadCWDlldbinitFile should_load = ShouldLoadCwdInitFile();
2169
2170 switch (should_load) {
2171 case eLoadCWDlldbinitFalse:
2172 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2173 break;
2174 case eLoadCWDlldbinitTrue:
2175 SourceInitFile(FileSpec(init_file.str()), result);
2176 break;
2177 case eLoadCWDlldbinitWarn: {
2178 llvm::SmallString<128> home_init_file;
2179 GetHomeInitFile(home_init_file);
2180 if (llvm::sys::path::parent_path(init_file) ==
2181 llvm::sys::path::parent_path(home_init_file)) {
2182 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2183 } else {
2184 result.AppendErrorWithFormat(InitFileWarning);
2185 result.SetStatus(eReturnStatusFailed);
2186 }
2187 }
2188 }
2189}
2190
2191/// We will first see if there is an application specific ".lldbinit" file
2192/// whose name is "~/.lldbinit" followed by a "-" and the name of the program.
2193/// If this file doesn't exist, we fall back to just the "~/.lldbinit" file.
2194void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result) {
2195 if (m_skip_lldbinit_files) {
2196 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2197 return;
2198 }
2199
2200 llvm::SmallString<128> init_file;
2201 GetHomeInitFile(init_file);
2202
2203 if (!m_skip_app_init_files) {
2204 llvm::StringRef program_name =
2205 HostInfo::GetProgramFileSpec().GetFilename().GetStringRef();
2206 llvm::SmallString<128> program_init_file;
2207 GetHomeInitFile(program_init_file, program_name);
2208 if (FileSystem::Instance().Exists(program_init_file))
2209 init_file = program_init_file;
2210 }
2211
2212 SourceInitFile(FileSpec(init_file.str()), result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002213}
2214
2215const char *CommandInterpreter::GetCommandPrefix() {
2216 const char *prefix = GetDebugger().GetIOHandlerCommandPrefix();
2217 return prefix == NULL ? "" : prefix;
2218}
2219
2220PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) {
2221 PlatformSP platform_sp;
2222 if (prefer_target_platform) {
2223 ExecutionContext exe_ctx(GetExecutionContext());
2224 Target *target = exe_ctx.GetTargetPtr();
2225 if (target)
2226 platform_sp = target->GetPlatform();
2227 }
2228
2229 if (!platform_sp)
2230 platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
2231 return platform_sp;
2232}
2233
2234void CommandInterpreter::HandleCommands(const StringList &commands,
2235 ExecutionContext *override_context,
2236 CommandInterpreterRunOptions &options,
2237 CommandReturnObject &result) {
2238 size_t num_lines = commands.GetSize();
2239
2240 // If we are going to continue past a "continue" then we need to run the
Adrian Prantl05097242018-04-30 16:49:04 +00002241 // commands synchronously. Make sure you reset this value anywhere you return
2242 // from the function.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002243
2244 bool old_async_execution = m_debugger.GetAsyncExecution();
2245
2246 // If we've been given an execution context, set it at the start, but don't
Adrian Prantl05097242018-04-30 16:49:04 +00002247 // keep resetting it or we will cause series of commands that change the
2248 // context, then do an operation that relies on that context to fail.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002249
2250 if (override_context != nullptr)
2251 UpdateExecutionContext(override_context);
2252
2253 if (!options.GetStopOnContinue()) {
2254 m_debugger.SetAsyncExecution(false);
2255 }
2256
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002257 for (size_t idx = 0; idx < num_lines && !WasInterrupted(); idx++) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002258 const char *cmd = commands.GetStringAtIndex(idx);
2259 if (cmd[0] == '\0')
2260 continue;
2261
2262 if (options.GetEchoCommands()) {
Zachary Turner514d8cd2016-09-23 18:06:53 +00002263 // TODO: Add Stream support.
2264 result.AppendMessageWithFormat("%s %s\n",
2265 m_debugger.GetPrompt().str().c_str(), cmd);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002266 }
2267
2268 CommandReturnObject tmp_result;
2269 // If override_context is not NULL, pass no_context_switching = true for
2270 // HandleCommand() since we updated our context already.
2271
2272 // We might call into a regex or alias command, in which case the
Adrian Prantl05097242018-04-30 16:49:04 +00002273 // add_to_history will get lost. This m_command_source_depth dingus is the
2274 // way we turn off adding to the history in that case, so set it up here.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002275 if (!options.GetAddToHistory())
2276 m_command_source_depth++;
2277 bool success =
2278 HandleCommand(cmd, options.m_add_to_history, tmp_result,
2279 nullptr, /* override_context */
2280 true, /* repeat_on_empty_command */
2281 override_context != nullptr /* no_context_switching */);
2282 if (!options.GetAddToHistory())
2283 m_command_source_depth--;
2284
2285 if (options.GetPrintResults()) {
2286 if (tmp_result.Succeeded())
Zachary Turner03c9f362016-11-14 23:23:31 +00002287 result.AppendMessage(tmp_result.GetOutputData());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002288 }
2289
2290 if (!success || !tmp_result.Succeeded()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002291 llvm::StringRef error_msg = tmp_result.GetErrorData();
2292 if (error_msg.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +00002293 error_msg = "<unknown error>.\n";
2294 if (options.GetStopOnError()) {
2295 result.AppendErrorWithFormat(
2296 "Aborting reading of commands after command #%" PRIu64
2297 ": '%s' failed with %s",
Zachary Turnerc1564272016-11-16 21:15:24 +00002298 (uint64_t)idx, cmd, error_msg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002299 result.SetStatus(eReturnStatusFailed);
2300 m_debugger.SetAsyncExecution(old_async_execution);
2301 return;
2302 } else if (options.GetPrintResults()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002303 result.AppendMessageWithFormat(
2304 "Command #%" PRIu64 " '%s' failed with %s", (uint64_t)idx + 1, cmd,
2305 error_msg.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002306 }
2307 }
2308
2309 if (result.GetImmediateOutputStream())
2310 result.GetImmediateOutputStream()->Flush();
2311
2312 if (result.GetImmediateErrorStream())
2313 result.GetImmediateErrorStream()->Flush();
2314
Adrian Prantl05097242018-04-30 16:49:04 +00002315 // N.B. Can't depend on DidChangeProcessState, because the state coming
2316 // into the command execution could be running (for instance in Breakpoint
2317 // Commands. So we check the return value to see if it is has running in
2318 // it.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002319 if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
2320 (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult)) {
2321 if (options.GetStopOnContinue()) {
2322 // If we caused the target to proceed, and we're going to stop in that
Adrian Prantl05097242018-04-30 16:49:04 +00002323 // case, set the status in our real result before returning. This is
2324 // an error if the continue was not the last command in the set of
2325 // commands to be run.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002326 if (idx != num_lines - 1)
2327 result.AppendErrorWithFormat(
2328 "Aborting reading of commands after command #%" PRIu64
2329 ": '%s' continued the target.\n",
2330 (uint64_t)idx + 1, cmd);
2331 else
2332 result.AppendMessageWithFormat("Command #%" PRIu64
2333 " '%s' continued the target.\n",
2334 (uint64_t)idx + 1, cmd);
2335
2336 result.SetStatus(tmp_result.GetStatus());
2337 m_debugger.SetAsyncExecution(old_async_execution);
2338
2339 return;
2340 }
2341 }
2342
2343 // Also check for "stop on crash here:
2344 bool should_stop = false;
2345 if (tmp_result.GetDidChangeProcessState() && options.GetStopOnCrash()) {
2346 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2347 if (target_sp) {
2348 ProcessSP process_sp(target_sp->GetProcessSP());
2349 if (process_sp) {
2350 for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
2351 StopReason reason = thread_sp->GetStopReason();
2352 if (reason == eStopReasonSignal || reason == eStopReasonException ||
2353 reason == eStopReasonInstrumentation) {
2354 should_stop = true;
2355 break;
2356 }
2357 }
2358 }
2359 }
2360 if (should_stop) {
2361 if (idx != num_lines - 1)
2362 result.AppendErrorWithFormat(
2363 "Aborting reading of commands after command #%" PRIu64
2364 ": '%s' stopped with a signal or exception.\n",
2365 (uint64_t)idx + 1, cmd);
2366 else
2367 result.AppendMessageWithFormat(
2368 "Command #%" PRIu64 " '%s' stopped with a signal or exception.\n",
2369 (uint64_t)idx + 1, cmd);
2370
2371 result.SetStatus(tmp_result.GetStatus());
2372 m_debugger.SetAsyncExecution(old_async_execution);
2373
2374 return;
2375 }
2376 }
2377 }
2378
2379 result.SetStatus(eReturnStatusSuccessFinishResult);
2380 m_debugger.SetAsyncExecution(old_async_execution);
2381
2382 return;
2383}
2384
2385// Make flags that we can pass into the IOHandler so our delegates can do the
2386// right thing
2387enum {
2388 eHandleCommandFlagStopOnContinue = (1u << 0),
2389 eHandleCommandFlagStopOnError = (1u << 1),
2390 eHandleCommandFlagEchoCommand = (1u << 2),
Stefan Granitzc678ed72018-10-05 16:49:47 +00002391 eHandleCommandFlagEchoCommentCommand = (1u << 3),
2392 eHandleCommandFlagPrintResult = (1u << 4),
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002393 eHandleCommandFlagPrintErrors = (1u << 5),
2394 eHandleCommandFlagStopOnCrash = (1u << 6)
Kate Stoneb9c1b512016-09-06 20:57:50 +00002395};
2396
2397void CommandInterpreter::HandleCommandsFromFile(
2398 FileSpec &cmd_file, ExecutionContext *context,
2399 CommandInterpreterRunOptions &options, CommandReturnObject &result) {
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002400 if (!FileSystem::Instance().Exists(cmd_file)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002401 result.AppendErrorWithFormat(
2402 "Error reading commands from file %s - file not found.\n",
2403 cmd_file.GetFilename().AsCString("<Unknown>"));
2404 result.SetStatus(eReturnStatusFailed);
2405 return;
2406 }
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002407
2408 StreamFileSP input_file_sp(new StreamFile());
2409 std::string cmd_file_path = cmd_file.GetPath();
2410 Status error = FileSystem::Instance().Open(input_file_sp->GetFile(), cmd_file,
2411 File::eOpenOptionRead);
2412
2413 if (error.Fail()) {
2414 result.AppendErrorWithFormat(
2415 "error: an error occurred read file '%s': %s\n", cmd_file_path.c_str(),
2416 error.AsCString());
2417 result.SetStatus(eReturnStatusFailed);
2418 return;
2419 }
2420
2421 Debugger &debugger = GetDebugger();
2422
2423 uint32_t flags = 0;
2424
2425 if (options.m_stop_on_continue == eLazyBoolCalculate) {
2426 if (m_command_source_flags.empty()) {
2427 // Stop on continue by default
2428 flags |= eHandleCommandFlagStopOnContinue;
2429 } else if (m_command_source_flags.back() &
2430 eHandleCommandFlagStopOnContinue) {
2431 flags |= eHandleCommandFlagStopOnContinue;
2432 }
2433 } else if (options.m_stop_on_continue == eLazyBoolYes) {
2434 flags |= eHandleCommandFlagStopOnContinue;
2435 }
2436
2437 if (options.m_stop_on_error == eLazyBoolCalculate) {
2438 if (m_command_source_flags.empty()) {
2439 if (GetStopCmdSourceOnError())
2440 flags |= eHandleCommandFlagStopOnError;
2441 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnError) {
2442 flags |= eHandleCommandFlagStopOnError;
2443 }
2444 } else if (options.m_stop_on_error == eLazyBoolYes) {
2445 flags |= eHandleCommandFlagStopOnError;
2446 }
2447
2448 // stop-on-crash can only be set, if it is present in all levels of
2449 // pushed flag sets.
2450 if (options.GetStopOnCrash()) {
2451 if (m_command_source_flags.empty()) {
2452 flags |= eHandleCommandFlagStopOnCrash;
2453 } else if (m_command_source_flags.back() & eHandleCommandFlagStopOnCrash) {
2454 flags |= eHandleCommandFlagStopOnCrash;
2455 }
2456 }
2457
2458 if (options.m_echo_commands == eLazyBoolCalculate) {
2459 if (m_command_source_flags.empty()) {
2460 // Echo command by default
2461 flags |= eHandleCommandFlagEchoCommand;
2462 } else if (m_command_source_flags.back() & eHandleCommandFlagEchoCommand) {
2463 flags |= eHandleCommandFlagEchoCommand;
2464 }
2465 } else if (options.m_echo_commands == eLazyBoolYes) {
2466 flags |= eHandleCommandFlagEchoCommand;
2467 }
2468
2469 // We will only ever ask for this flag, if we echo commands in general.
2470 if (options.m_echo_comment_commands == eLazyBoolCalculate) {
2471 if (m_command_source_flags.empty()) {
2472 // Echo comments by default
2473 flags |= eHandleCommandFlagEchoCommentCommand;
2474 } else if (m_command_source_flags.back() &
2475 eHandleCommandFlagEchoCommentCommand) {
2476 flags |= eHandleCommandFlagEchoCommentCommand;
2477 }
2478 } else if (options.m_echo_comment_commands == eLazyBoolYes) {
2479 flags |= eHandleCommandFlagEchoCommentCommand;
2480 }
2481
2482 if (options.m_print_results == eLazyBoolCalculate) {
2483 if (m_command_source_flags.empty()) {
2484 // Print output by default
2485 flags |= eHandleCommandFlagPrintResult;
2486 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintResult) {
2487 flags |= eHandleCommandFlagPrintResult;
2488 }
2489 } else if (options.m_print_results == eLazyBoolYes) {
2490 flags |= eHandleCommandFlagPrintResult;
2491 }
2492
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002493 if (options.m_print_errors == eLazyBoolCalculate) {
2494 if (m_command_source_flags.empty()) {
2495 // Print output by default
2496 flags |= eHandleCommandFlagPrintErrors;
2497 } else if (m_command_source_flags.back() & eHandleCommandFlagPrintErrors) {
2498 flags |= eHandleCommandFlagPrintErrors;
2499 }
2500 } else if (options.m_print_errors == eLazyBoolYes) {
2501 flags |= eHandleCommandFlagPrintErrors;
2502 }
2503
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002504 if (flags & eHandleCommandFlagPrintResult) {
2505 debugger.GetOutputFile()->Printf("Executing commands in '%s'.\n",
2506 cmd_file_path.c_str());
2507 }
2508
2509 // Used for inheriting the right settings when "command source" might
2510 // have nested "command source" commands
2511 lldb::StreamFileSP empty_stream_sp;
2512 m_command_source_flags.push_back(flags);
2513 IOHandlerSP io_handler_sp(new IOHandlerEditline(
2514 debugger, IOHandler::Type::CommandInterpreter, input_file_sp,
2515 empty_stream_sp, // Pass in an empty stream so we inherit the top
2516 // input reader output stream
2517 empty_stream_sp, // Pass in an empty stream so we inherit the top
2518 // input reader error stream
2519 flags,
2520 nullptr, // Pass in NULL for "editline_name" so no history is saved,
2521 // or written
2522 debugger.GetPrompt(), llvm::StringRef(),
2523 false, // Not multi-line
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002524 debugger.GetUseColor(), 0, *this, nullptr));
Jonas Devlieghere166c2622019-02-07 21:51:20 +00002525 const bool old_async_execution = debugger.GetAsyncExecution();
2526
2527 // Set synchronous execution if we are not stopping on continue
2528 if ((flags & eHandleCommandFlagStopOnContinue) == 0)
2529 debugger.SetAsyncExecution(false);
2530
2531 m_command_source_depth++;
2532
2533 debugger.RunIOHandler(io_handler_sp);
2534 if (!m_command_source_flags.empty())
2535 m_command_source_flags.pop_back();
2536 m_command_source_depth--;
2537 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2538 debugger.SetAsyncExecution(old_async_execution);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002539}
2540
Kate Stoneb9c1b512016-09-06 20:57:50 +00002541bool CommandInterpreter::GetSynchronous() { return m_synchronous_execution; }
2542
2543void CommandInterpreter::SetSynchronous(bool value) {
2544 m_synchronous_execution = value;
2545}
2546
2547void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
Zachary Turner0ac5f982016-11-08 04:12:42 +00002548 llvm::StringRef prefix,
2549 llvm::StringRef help_text) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002550 const uint32_t max_columns = m_debugger.GetTerminalWidth();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002551
Zachary Turner0ac5f982016-11-08 04:12:42 +00002552 size_t line_width_max = max_columns - prefix.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002553 if (line_width_max < 16)
Zachary Turner0ac5f982016-11-08 04:12:42 +00002554 line_width_max = help_text.size() + prefix.size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002555
Zachary Turner0ac5f982016-11-08 04:12:42 +00002556 strm.IndentMore(prefix.size());
2557 bool prefixed_yet = false;
2558 while (!help_text.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002559 // Prefix the first line, indent subsequent lines to line up
Zachary Turner0ac5f982016-11-08 04:12:42 +00002560 if (!prefixed_yet) {
2561 strm << prefix;
2562 prefixed_yet = true;
2563 } else
Kate Stoneb9c1b512016-09-06 20:57:50 +00002564 strm.Indent();
Zachary Turner0ac5f982016-11-08 04:12:42 +00002565
2566 // Never print more than the maximum on one line.
2567 llvm::StringRef this_line = help_text.substr(0, line_width_max);
2568
2569 // Always break on an explicit newline.
2570 std::size_t first_newline = this_line.find_first_of("\n");
2571
2572 // Don't break on space/tab unless the text is too long to fit on one line.
2573 std::size_t last_space = llvm::StringRef::npos;
2574 if (this_line.size() != help_text.size())
2575 last_space = this_line.find_last_of(" \t");
2576
2577 // Break at whichever condition triggered first.
2578 this_line = this_line.substr(0, std::min(first_newline, last_space));
2579 strm.PutCString(this_line);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002580 strm.EOL();
2581
Zachary Turner0ac5f982016-11-08 04:12:42 +00002582 // Remove whitespace / newlines after breaking.
2583 help_text = help_text.drop_front(this_line.size()).ltrim();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002584 }
Zachary Turner0ac5f982016-11-08 04:12:42 +00002585 strm.IndentLess(prefix.size());
Kate Stoneb9c1b512016-09-06 20:57:50 +00002586}
2587
2588void CommandInterpreter::OutputFormattedHelpText(Stream &strm,
Zachary Turner0ac5f982016-11-08 04:12:42 +00002589 llvm::StringRef word_text,
2590 llvm::StringRef separator,
2591 llvm::StringRef help_text,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002592 size_t max_word_len) {
2593 StreamString prefix_stream;
Zachary Turner0ac5f982016-11-08 04:12:42 +00002594 prefix_stream.Printf(" %-*s %*s ", (int)max_word_len, word_text.data(),
2595 (int)separator.size(), separator.data());
Zachary Turnerc1564272016-11-16 21:15:24 +00002596 OutputFormattedHelpText(strm, prefix_stream.GetString(), help_text);
2597}
2598
Zachary Turner0ac5f982016-11-08 04:12:42 +00002599void CommandInterpreter::OutputHelpText(Stream &strm, llvm::StringRef word_text,
2600 llvm::StringRef separator,
2601 llvm::StringRef help_text,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002602 uint32_t max_word_len) {
Zachary Turner0ac5f982016-11-08 04:12:42 +00002603 int indent_size = max_word_len + separator.size() + 2;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002604
2605 strm.IndentMore(indent_size);
2606
2607 StreamString text_strm;
Zachary Turner0ac5f982016-11-08 04:12:42 +00002608 text_strm.Printf("%-*s ", (int)max_word_len, word_text.data());
2609 text_strm << separator << " " << help_text;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002610
2611 const uint32_t max_columns = m_debugger.GetTerminalWidth();
2612
Zachary Turnerc1564272016-11-16 21:15:24 +00002613 llvm::StringRef text = text_strm.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002614
2615 uint32_t chars_left = max_columns;
2616
Davide Italianocf8a8292017-04-14 22:36:08 +00002617 auto nextWordLength = [](llvm::StringRef S) {
Jonas Devliegherec712bac2019-03-28 18:10:14 +00002618 size_t pos = S.find(' ');
Davide Italianocf8a8292017-04-14 22:36:08 +00002619 return pos == llvm::StringRef::npos ? S.size() : pos;
2620 };
2621
Zachary Turnerc1564272016-11-16 21:15:24 +00002622 while (!text.empty()) {
2623 if (text.front() == '\n' ||
Jim Inghama81bd7f2017-07-27 00:18:18 +00002624 (text.front() == ' ' && nextWordLength(text.ltrim(' ')) > chars_left)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002625 strm.EOL();
2626 strm.Indent();
Zachary Turnerc1564272016-11-16 21:15:24 +00002627 chars_left = max_columns - indent_size;
2628 if (text.front() == '\n')
2629 text = text.drop_front();
2630 else
2631 text = text.ltrim(' ');
Kate Stoneb9c1b512016-09-06 20:57:50 +00002632 } else {
Zachary Turnerc1564272016-11-16 21:15:24 +00002633 strm.PutChar(text.front());
2634 --chars_left;
2635 text = text.drop_front();
Kate Stoneb9c1b512016-09-06 20:57:50 +00002636 }
2637 }
2638
2639 strm.EOL();
2640 strm.IndentLess(indent_size);
2641}
2642
2643void CommandInterpreter::FindCommandsForApropos(
Zachary Turner067d1db2016-11-16 21:45:04 +00002644 llvm::StringRef search_word, StringList &commands_found,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002645 StringList &commands_help, CommandObject::CommandMap &command_map) {
2646 CommandObject::CommandMap::const_iterator pos;
2647
2648 for (pos = command_map.begin(); pos != command_map.end(); ++pos) {
Zachary Turner067d1db2016-11-16 21:45:04 +00002649 llvm::StringRef command_name = pos->first;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002650 CommandObject *cmd_obj = pos->second.get();
2651
2652 const bool search_short_help = true;
2653 const bool search_long_help = false;
2654 const bool search_syntax = false;
2655 const bool search_options = false;
Zachary Turner067d1db2016-11-16 21:45:04 +00002656 if (command_name.contains_lower(search_word) ||
Kate Stoneb9c1b512016-09-06 20:57:50 +00002657 cmd_obj->HelpTextContainsWord(search_word, search_short_help,
2658 search_long_help, search_syntax,
2659 search_options)) {
2660 commands_found.AppendString(cmd_obj->GetCommandName());
2661 commands_help.AppendString(cmd_obj->GetHelp());
2662 }
2663
2664 if (cmd_obj->IsMultiwordObject()) {
2665 CommandObjectMultiword *cmd_multiword = cmd_obj->GetAsMultiwordCommand();
2666 FindCommandsForApropos(search_word, commands_found, commands_help,
2667 cmd_multiword->GetSubcommandDictionary());
2668 }
2669 }
2670}
2671
Zachary Turner067d1db2016-11-16 21:45:04 +00002672void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word,
Kate Stoneb9c1b512016-09-06 20:57:50 +00002673 StringList &commands_found,
2674 StringList &commands_help,
2675 bool search_builtin_commands,
2676 bool search_user_commands,
2677 bool search_alias_commands) {
2678 CommandObject::CommandMap::const_iterator pos;
2679
2680 if (search_builtin_commands)
2681 FindCommandsForApropos(search_word, commands_found, commands_help,
2682 m_command_dict);
2683
2684 if (search_user_commands)
2685 FindCommandsForApropos(search_word, commands_found, commands_help,
2686 m_user_dict);
2687
2688 if (search_alias_commands)
2689 FindCommandsForApropos(search_word, commands_found, commands_help,
2690 m_alias_dict);
2691}
2692
2693void CommandInterpreter::UpdateExecutionContext(
2694 ExecutionContext *override_context) {
2695 if (override_context != nullptr) {
2696 m_exe_ctx_ref = *override_context;
2697 } else {
2698 const bool adopt_selected = true;
2699 m_exe_ctx_ref.SetTargetPtr(m_debugger.GetSelectedTarget().get(),
2700 adopt_selected);
2701 }
2702}
2703
2704size_t CommandInterpreter::GetProcessOutput() {
2705 // The process has stuff waiting for stderr; get it and write it out to the
2706 // appropriate place.
2707 char stdio_buffer[1024];
2708 size_t len;
2709 size_t total_bytes = 0;
Zachary Turner97206d52017-05-12 04:51:55 +00002710 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +00002711 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2712 if (target_sp) {
2713 ProcessSP process_sp(target_sp->GetProcessSP());
2714 if (process_sp) {
2715 while ((len = process_sp->GetSTDOUT(stdio_buffer, sizeof(stdio_buffer),
2716 error)) > 0) {
2717 size_t bytes_written = len;
2718 m_debugger.GetOutputFile()->Write(stdio_buffer, bytes_written);
2719 total_bytes += len;
2720 }
2721 while ((len = process_sp->GetSTDERR(stdio_buffer, sizeof(stdio_buffer),
2722 error)) > 0) {
2723 size_t bytes_written = len;
2724 m_debugger.GetErrorFile()->Write(stdio_buffer, bytes_written);
2725 total_bytes += len;
2726 }
2727 }
2728 }
2729 return total_bytes;
2730}
2731
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002732void CommandInterpreter::StartHandlingCommand() {
2733 auto idle_state = CommandHandlingState::eIdle;
2734 if (m_command_state.compare_exchange_strong(
2735 idle_state, CommandHandlingState::eInProgress))
2736 lldbassert(m_iohandler_nesting_level == 0);
2737 else
2738 lldbassert(m_iohandler_nesting_level > 0);
2739 ++m_iohandler_nesting_level;
2740}
2741
2742void CommandInterpreter::FinishHandlingCommand() {
2743 lldbassert(m_iohandler_nesting_level > 0);
2744 if (--m_iohandler_nesting_level == 0) {
2745 auto prev_state = m_command_state.exchange(CommandHandlingState::eIdle);
2746 lldbassert(prev_state != CommandHandlingState::eIdle);
2747 }
2748}
2749
2750bool CommandInterpreter::InterruptCommand() {
2751 auto in_progress = CommandHandlingState::eInProgress;
2752 return m_command_state.compare_exchange_strong(
2753 in_progress, CommandHandlingState::eInterrupted);
2754}
2755
2756bool CommandInterpreter::WasInterrupted() const {
2757 bool was_interrupted =
2758 (m_command_state == CommandHandlingState::eInterrupted);
2759 lldbassert(!was_interrupted || m_iohandler_nesting_level > 0);
2760 return was_interrupted;
2761}
2762
2763void CommandInterpreter::PrintCommandOutput(Stream &stream,
2764 llvm::StringRef str) {
2765 // Split the output into lines and poll for interrupt requests
2766 const char *data = str.data();
2767 size_t size = str.size();
2768 while (size > 0 && !WasInterrupted()) {
2769 size_t chunk_size = 0;
2770 for (; chunk_size < size; ++chunk_size) {
2771 lldbassert(data[chunk_size] != '\0');
2772 if (data[chunk_size] == '\n') {
2773 ++chunk_size;
2774 break;
2775 }
2776 }
2777 chunk_size = stream.Write(data, chunk_size);
2778 lldbassert(size >= chunk_size);
2779 data += chunk_size;
2780 size -= chunk_size;
2781 }
2782 if (size > 0) {
2783 stream.Printf("\n... Interrupted.\n");
2784 }
2785}
2786
Stefan Granitzc678ed72018-10-05 16:49:47 +00002787bool CommandInterpreter::EchoCommandNonInteractive(
2788 llvm::StringRef line, const Flags &io_handler_flags) const {
2789 if (!io_handler_flags.Test(eHandleCommandFlagEchoCommand))
2790 return false;
2791
2792 llvm::StringRef command = line.trim();
2793 if (command.empty())
2794 return true;
2795
2796 if (command.front() == m_comment_char)
2797 return io_handler_flags.Test(eHandleCommandFlagEchoCommentCommand);
2798
2799 return true;
2800}
2801
Kate Stoneb9c1b512016-09-06 20:57:50 +00002802void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler,
2803 std::string &line) {
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002804 // If we were interrupted, bail out...
2805 if (WasInterrupted())
2806 return;
2807
Kate Stoneb9c1b512016-09-06 20:57:50 +00002808 const bool is_interactive = io_handler.GetIsInteractive();
Jonas Devliegherea6682a42018-12-15 00:15:33 +00002809 if (!is_interactive) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002810 // When we are not interactive, don't execute blank lines. This will happen
2811 // sourcing a commands file. We don't want blank lines to repeat the
Adrian Prantl05097242018-04-30 16:49:04 +00002812 // previous command and cause any errors to occur (like redefining an
2813 // alias, get an error and stop parsing the commands file).
Kate Stoneb9c1b512016-09-06 20:57:50 +00002814 if (line.empty())
2815 return;
2816
2817 // When using a non-interactive file handle (like when sourcing commands
Adrian Prantl05097242018-04-30 16:49:04 +00002818 // from a file) we need to echo the command out so we don't just see the
2819 // command output and no command...
Stefan Granitzc678ed72018-10-05 16:49:47 +00002820 if (EchoCommandNonInteractive(line, io_handler.GetFlags()))
Kate Stoneb9c1b512016-09-06 20:57:50 +00002821 io_handler.GetOutputStreamFile()->Printf("%s%s\n", io_handler.GetPrompt(),
2822 line.c_str());
2823 }
2824
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002825 StartHandlingCommand();
2826
Kate Stoneb9c1b512016-09-06 20:57:50 +00002827 lldb_private::CommandReturnObject result;
2828 HandleCommand(line.c_str(), eLazyBoolCalculate, result);
2829
2830 // Now emit the command output text from the command we just executed
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00002831 if ((result.Succeeded() &&
2832 io_handler.GetFlags().Test(eHandleCommandFlagPrintResult)) ||
2833 io_handler.GetFlags().Test(eHandleCommandFlagPrintErrors)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +00002834 // Display any STDOUT/STDERR _prior_ to emitting the command result text
2835 GetProcessOutput();
2836
2837 if (!result.GetImmediateOutputStream()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002838 llvm::StringRef output = result.GetOutputData();
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002839 PrintCommandOutput(*io_handler.GetOutputStreamFile(), output);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002840 }
2841
2842 // Now emit the command error text from the command we just executed
2843 if (!result.GetImmediateErrorStream()) {
Zachary Turnerc1564272016-11-16 21:15:24 +00002844 llvm::StringRef error = result.GetErrorData();
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002845 PrintCommandOutput(*io_handler.GetErrorStreamFile(), error);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002846 }
2847 }
2848
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002849 FinishHandlingCommand();
2850
Kate Stoneb9c1b512016-09-06 20:57:50 +00002851 switch (result.GetStatus()) {
2852 case eReturnStatusInvalid:
2853 case eReturnStatusSuccessFinishNoResult:
2854 case eReturnStatusSuccessFinishResult:
2855 case eReturnStatusStarted:
2856 break;
2857
2858 case eReturnStatusSuccessContinuingNoResult:
2859 case eReturnStatusSuccessContinuingResult:
2860 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnContinue))
2861 io_handler.SetIsDone(true);
2862 break;
2863
2864 case eReturnStatusFailed:
2865 m_num_errors++;
2866 if (io_handler.GetFlags().Test(eHandleCommandFlagStopOnError))
2867 io_handler.SetIsDone(true);
2868 break;
2869
2870 case eReturnStatusQuit:
2871 m_quit_requested = true;
2872 io_handler.SetIsDone(true);
2873 break;
2874 }
2875
2876 // Finally, if we're going to stop on crash, check that here:
2877 if (!m_quit_requested && result.GetDidChangeProcessState() &&
2878 io_handler.GetFlags().Test(eHandleCommandFlagStopOnCrash)) {
2879 bool should_stop = false;
2880 TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget());
2881 if (target_sp) {
2882 ProcessSP process_sp(target_sp->GetProcessSP());
2883 if (process_sp) {
2884 for (ThreadSP thread_sp : process_sp->GetThreadList().Threads()) {
2885 StopReason reason = thread_sp->GetStopReason();
2886 if ((reason == eStopReasonSignal || reason == eStopReasonException ||
2887 reason == eStopReasonInstrumentation) &&
2888 !result.GetAbnormalStopWasExpected()) {
2889 should_stop = true;
2890 break;
2891 }
2892 }
2893 }
2894 }
2895 if (should_stop) {
2896 io_handler.SetIsDone(true);
2897 m_stopped_for_crash = true;
2898 }
2899 }
2900}
2901
2902bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
2903 ExecutionContext exe_ctx(GetExecutionContext());
2904 Process *process = exe_ctx.GetProcessPtr();
2905
Leonard Mosescu17ffd392017-10-05 23:41:28 +00002906 if (InterruptCommand())
2907 return true;
2908
Kate Stoneb9c1b512016-09-06 20:57:50 +00002909 if (process) {
2910 StateType state = process->GetState();
2911 if (StateIsRunningState(state)) {
2912 process->Halt();
2913 return true; // Don't do any updating when we are running
2914 }
2915 }
2916
Jonas Devlieghere2b29b432019-04-26 22:43:16 +00002917 ScriptInterpreter *script_interpreter =
2918 m_debugger.GetScriptInterpreter(false);
Kate Stoneb9c1b512016-09-06 20:57:50 +00002919 if (script_interpreter) {
2920 if (script_interpreter->Interrupt())
2921 return true;
2922 }
2923 return false;
2924}
2925
2926void CommandInterpreter::GetLLDBCommandsFromIOHandler(
2927 const char *prompt, IOHandlerDelegate &delegate, bool asynchronously,
2928 void *baton) {
2929 Debugger &debugger = GetDebugger();
2930 IOHandlerSP io_handler_sp(
2931 new IOHandlerEditline(debugger, IOHandler::Type::CommandList,
2932 "lldb", // Name of input reader for history
Zachary Turner514d8cd2016-09-23 18:06:53 +00002933 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2934 llvm::StringRef(), // Continuation prompt
2935 true, // Get multiple lines
Kate Stoneb9c1b512016-09-06 20:57:50 +00002936 debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002937 0, // Don't show line numbers
2938 delegate, // IOHandlerDelegate
2939 nullptr)); // FileShadowCollector
Kate Stoneb9c1b512016-09-06 20:57:50 +00002940
2941 if (io_handler_sp) {
2942 io_handler_sp->SetUserData(baton);
2943 if (asynchronously)
2944 debugger.PushIOHandler(io_handler_sp);
2945 else
2946 debugger.RunIOHandler(io_handler_sp);
2947 }
2948}
2949
2950void CommandInterpreter::GetPythonCommandsFromIOHandler(
2951 const char *prompt, IOHandlerDelegate &delegate, bool asynchronously,
2952 void *baton) {
2953 Debugger &debugger = GetDebugger();
2954 IOHandlerSP io_handler_sp(
2955 new IOHandlerEditline(debugger, IOHandler::Type::PythonCode,
2956 "lldb-python", // Name of input reader for history
Zachary Turner514d8cd2016-09-23 18:06:53 +00002957 llvm::StringRef::withNullAsEmpty(prompt), // Prompt
2958 llvm::StringRef(), // Continuation prompt
2959 true, // Get multiple lines
Kate Stoneb9c1b512016-09-06 20:57:50 +00002960 debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00002961 0, // Don't show line numbers
2962 delegate, // IOHandlerDelegate
2963 nullptr)); // FileShadowCollector
Kate Stoneb9c1b512016-09-06 20:57:50 +00002964
2965 if (io_handler_sp) {
2966 io_handler_sp->SetUserData(baton);
2967 if (asynchronously)
2968 debugger.PushIOHandler(io_handler_sp);
2969 else
2970 debugger.RunIOHandler(io_handler_sp);
2971 }
2972}
2973
2974bool CommandInterpreter::IsActive() {
2975 return m_debugger.IsTopIOHandler(m_command_io_handler_sp);
2976}
2977
2978lldb::IOHandlerSP
2979CommandInterpreter::GetIOHandler(bool force_create,
2980 CommandInterpreterRunOptions *options) {
Adrian Prantl05097242018-04-30 16:49:04 +00002981 // Always re-create the IOHandlerEditline in case the input changed. The old
2982 // instance might have had a non-interactive input and now it does or vice
2983 // versa.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002984 if (force_create || !m_command_io_handler_sp) {
Adrian Prantl05097242018-04-30 16:49:04 +00002985 // Always re-create the IOHandlerEditline in case the input changed. The
2986 // old instance might have had a non-interactive input and now it does or
2987 // vice versa.
Kate Stoneb9c1b512016-09-06 20:57:50 +00002988 uint32_t flags = 0;
2989
2990 if (options) {
2991 if (options->m_stop_on_continue == eLazyBoolYes)
2992 flags |= eHandleCommandFlagStopOnContinue;
2993 if (options->m_stop_on_error == eLazyBoolYes)
2994 flags |= eHandleCommandFlagStopOnError;
2995 if (options->m_stop_on_crash == eLazyBoolYes)
2996 flags |= eHandleCommandFlagStopOnCrash;
2997 if (options->m_echo_commands != eLazyBoolNo)
2998 flags |= eHandleCommandFlagEchoCommand;
Stefan Granitzc678ed72018-10-05 16:49:47 +00002999 if (options->m_echo_comment_commands != eLazyBoolNo)
3000 flags |= eHandleCommandFlagEchoCommentCommand;
Kate Stoneb9c1b512016-09-06 20:57:50 +00003001 if (options->m_print_results != eLazyBoolNo)
3002 flags |= eHandleCommandFlagPrintResult;
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00003003 if (options->m_print_errors != eLazyBoolNo)
3004 flags |= eHandleCommandFlagPrintErrors;
Kate Stoneb9c1b512016-09-06 20:57:50 +00003005 } else {
Jonas Devliegherec0b48ab2019-05-08 01:23:47 +00003006 flags = eHandleCommandFlagEchoCommand | eHandleCommandFlagPrintResult |
3007 eHandleCommandFlagPrintErrors;
Kate Stoneb9c1b512016-09-06 20:57:50 +00003008 }
3009
Jonas Devlieghere796ac802019-02-11 23:13:08 +00003010 m_command_io_handler_sp = std::make_shared<IOHandlerEditline>(
Kate Stoneb9c1b512016-09-06 20:57:50 +00003011 m_debugger, IOHandler::Type::CommandInterpreter,
3012 m_debugger.GetInputFile(), m_debugger.GetOutputFile(),
3013 m_debugger.GetErrorFile(), flags, "lldb", m_debugger.GetPrompt(),
Zachary Turner514d8cd2016-09-23 18:06:53 +00003014 llvm::StringRef(), // Continuation prompt
Kate Stoneb9c1b512016-09-06 20:57:50 +00003015 false, // Don't enable multiple line input, just single line commands
3016 m_debugger.GetUseColor(),
Jonas Devlieghered77c2e02019-03-02 00:20:26 +00003017 0, // Don't show line numbers
3018 *this, // IOHandlerDelegate
3019 GetDebugger().GetInputRecorder());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003020 }
3021 return m_command_io_handler_sp;
3022}
3023
3024void CommandInterpreter::RunCommandInterpreter(
3025 bool auto_handle_events, bool spawn_thread,
3026 CommandInterpreterRunOptions &options) {
Adrian Prantl05097242018-04-30 16:49:04 +00003027 // Always re-create the command interpreter when we run it in case any file
3028 // handles have changed.
Kate Stoneb9c1b512016-09-06 20:57:50 +00003029 bool force_create = true;
3030 m_debugger.PushIOHandler(GetIOHandler(force_create, &options));
3031 m_stopped_for_crash = false;
3032
3033 if (auto_handle_events)
3034 m_debugger.StartEventHandlerThread();
3035
3036 if (spawn_thread) {
3037 m_debugger.StartIOHandlerThread();
3038 } else {
3039 m_debugger.ExecuteIOHandlers();
3040
3041 if (auto_handle_events)
3042 m_debugger.StopEventHandlerThread();
3043 }
3044}
3045
3046CommandObject *
3047CommandInterpreter::ResolveCommandImpl(std::string &command_line,
3048 CommandReturnObject &result) {
3049 std::string scratch_command(command_line); // working copy so we don't modify
3050 // command_line unless we succeed
3051 CommandObject *cmd_obj = nullptr;
3052 StreamString revised_command_line;
3053 bool wants_raw_input = false;
3054 size_t actual_cmd_name_len = 0;
3055 std::string next_word;
3056 StringList matches;
3057 bool done = false;
3058 while (!done) {
3059 char quote_char = '\0';
3060 std::string suffix;
3061 ExtractCommand(scratch_command, next_word, suffix, quote_char);
3062 if (cmd_obj == nullptr) {
3063 std::string full_name;
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00003064 bool is_alias = GetAliasFullName(next_word, full_name);
Zachary Turnera4496982016-10-05 21:14:38 +00003065 cmd_obj = GetCommandObject(next_word, &matches);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003066 bool is_real_command =
Jonas Devliegherea6682a42018-12-15 00:15:33 +00003067 (!is_alias) || (cmd_obj != nullptr && !cmd_obj->IsAlias());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003068 if (!is_real_command) {
3069 matches.Clear();
3070 std::string alias_result;
Malcolm Parsons771ef6d2016-11-02 20:34:10 +00003071 cmd_obj =
3072 BuildAliasResult(full_name, scratch_command, alias_result, result);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003073 revised_command_line.Printf("%s", alias_result.c_str());
3074 if (cmd_obj) {
3075 wants_raw_input = cmd_obj->WantsRawCommandString();
Zachary Turnera4496982016-10-05 21:14:38 +00003076 actual_cmd_name_len = cmd_obj->GetCommandName().size();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003077 }
3078 } else {
Kate Stoneb9c1b512016-09-06 20:57:50 +00003079 if (cmd_obj) {
Zachary Turnera4496982016-10-05 21:14:38 +00003080 llvm::StringRef cmd_name = cmd_obj->GetCommandName();
3081 actual_cmd_name_len += cmd_name.size();
3082 revised_command_line.Printf("%s", cmd_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003083 wants_raw_input = cmd_obj->WantsRawCommandString();
3084 } else {
3085 revised_command_line.Printf("%s", next_word.c_str());
3086 }
3087 }
3088 } else {
3089 if (cmd_obj->IsMultiwordObject()) {
3090 CommandObject *sub_cmd_obj =
3091 cmd_obj->GetSubcommandObject(next_word.c_str());
3092 if (sub_cmd_obj) {
Adrian Prantl05097242018-04-30 16:49:04 +00003093 // The subcommand's name includes the parent command's name, so
3094 // restart rather than append to the revised_command_line.
Zachary Turnera4496982016-10-05 21:14:38 +00003095 llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName();
3096 actual_cmd_name_len = sub_cmd_name.size() + 1;
Kate Stoneb9c1b512016-09-06 20:57:50 +00003097 revised_command_line.Clear();
Zachary Turnera4496982016-10-05 21:14:38 +00003098 revised_command_line.Printf("%s", sub_cmd_name.str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003099 cmd_obj = sub_cmd_obj;
3100 wants_raw_input = cmd_obj->WantsRawCommandString();
3101 } else {
3102 if (quote_char)
3103 revised_command_line.Printf(" %c%s%s%c", quote_char,
3104 next_word.c_str(), suffix.c_str(),
3105 quote_char);
3106 else
3107 revised_command_line.Printf(" %s%s", next_word.c_str(),
3108 suffix.c_str());
3109 done = true;
3110 }
3111 } else {
3112 if (quote_char)
3113 revised_command_line.Printf(" %c%s%s%c", quote_char,
3114 next_word.c_str(), suffix.c_str(),
3115 quote_char);
3116 else
3117 revised_command_line.Printf(" %s%s", next_word.c_str(),
3118 suffix.c_str());
3119 done = true;
3120 }
3121 }
3122
3123 if (cmd_obj == nullptr) {
3124 const size_t num_matches = matches.GetSize();
3125 if (matches.GetSize() > 1) {
3126 StreamString error_msg;
3127 error_msg.Printf("Ambiguous command '%s'. Possible matches:\n",
3128 next_word.c_str());
3129
3130 for (uint32_t i = 0; i < num_matches; ++i) {
3131 error_msg.Printf("\t%s\n", matches.GetStringAtIndex(i));
3132 }
Zachary Turnerc1564272016-11-16 21:15:24 +00003133 result.AppendRawError(error_msg.GetString());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003134 } else {
3135 // We didn't have only one match, otherwise we wouldn't get here.
Leonard Mosescu17ffd392017-10-05 23:41:28 +00003136 lldbassert(num_matches == 0);
Kate Stoneb9c1b512016-09-06 20:57:50 +00003137 result.AppendErrorWithFormat("'%s' is not a valid command.\n",
3138 next_word.c_str());
3139 }
3140 result.SetStatus(eReturnStatusFailed);
3141 return nullptr;
3142 }
3143
3144 if (cmd_obj->IsMultiwordObject()) {
3145 if (!suffix.empty()) {
3146 result.AppendErrorWithFormat(
3147 "command '%s' did not recognize '%s%s%s' as valid (subcommand "
3148 "might be invalid).\n",
Zachary Turnera4496982016-10-05 21:14:38 +00003149 cmd_obj->GetCommandName().str().c_str(),
Kate Stoneb9c1b512016-09-06 20:57:50 +00003150 next_word.empty() ? "" : next_word.c_str(),
3151 next_word.empty() ? " -- " : " ", suffix.c_str());
3152 result.SetStatus(eReturnStatusFailed);
3153 return nullptr;
3154 }
3155 } else {
3156 // If we found a normal command, we are done
3157 done = true;
3158 if (!suffix.empty()) {
3159 switch (suffix[0]) {
3160 case '/':
3161 // GDB format suffixes
3162 {
3163 Options *command_options = cmd_obj->GetOptions();
3164 if (command_options &&
3165 command_options->SupportsLongOption("gdb-format")) {
3166 std::string gdb_format_option("--gdb-format=");
3167 gdb_format_option += (suffix.c_str() + 1);
3168
Zachary Turnerc1564272016-11-16 21:15:24 +00003169 std::string cmd = revised_command_line.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003170 size_t arg_terminator_idx = FindArgumentTerminator(cmd);
3171 if (arg_terminator_idx != std::string::npos) {
3172 // Insert the gdb format option before the "--" that terminates
3173 // options
3174 gdb_format_option.append(1, ' ');
3175 cmd.insert(arg_terminator_idx, gdb_format_option);
Zachary Turnerc1564272016-11-16 21:15:24 +00003176 revised_command_line.Clear();
3177 revised_command_line.PutCString(cmd);
3178 } else
Kate Stoneb9c1b512016-09-06 20:57:50 +00003179 revised_command_line.Printf(" %s", gdb_format_option.c_str());
3180
3181 if (wants_raw_input &&
3182 FindArgumentTerminator(cmd) == std::string::npos)
3183 revised_command_line.PutCString(" --");
3184 } else {
3185 result.AppendErrorWithFormat(
3186 "the '%s' command doesn't support the --gdb-format option\n",
Zachary Turnera4496982016-10-05 21:14:38 +00003187 cmd_obj->GetCommandName().str().c_str());
Kate Stoneb9c1b512016-09-06 20:57:50 +00003188 result.SetStatus(eReturnStatusFailed);
3189 return nullptr;
3190 }
3191 }
3192 break;
3193
3194 default:
3195 result.AppendErrorWithFormat(
3196 "unknown command shorthand suffix: '%s'\n", suffix.c_str());
3197 result.SetStatus(eReturnStatusFailed);
3198 return nullptr;
3199 }
3200 }
3201 }
3202 if (scratch_command.empty())
3203 done = true;
3204 }
3205
3206 if (!scratch_command.empty())
3207 revised_command_line.Printf(" %s", scratch_command.c_str());
3208
3209 if (cmd_obj != NULL)
Zachary Turnerc1564272016-11-16 21:15:24 +00003210 command_line = revised_command_line.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +00003211
3212 return cmd_obj;
Adrian McCarthy2304b6f2015-04-23 20:00:25 +00003213}