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