1 //===-- CommandObjectSettings.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 "CommandObjectSettings.h"
10
11 #include "llvm/ADT/StringRef.h"
12
13 #include "lldb/Host/OptionParser.h"
14 #include "lldb/Interpreter/CommandCompletions.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandReturnObject.h"
17 #include "lldb/Interpreter/OptionValueProperties.h"
18
19 using namespace lldb;
20 using namespace lldb_private;
21
22 // CommandObjectSettingsSet
23 #define LLDB_OPTIONS_settings_set
24 #include "CommandOptions.inc"
25
26 class CommandObjectSettingsSet : public CommandObjectRaw {
27 public:
CommandObjectSettingsSet(CommandInterpreter & interpreter)28 CommandObjectSettingsSet(CommandInterpreter &interpreter)
29 : CommandObjectRaw(interpreter, "settings set",
30 "Set the value of the specified debugger setting."),
31 m_options() {
32 CommandArgumentEntry arg1;
33 CommandArgumentEntry arg2;
34 CommandArgumentData var_name_arg;
35 CommandArgumentData value_arg;
36
37 // Define the first (and only) variant of this arg.
38 var_name_arg.arg_type = eArgTypeSettingVariableName;
39 var_name_arg.arg_repetition = eArgRepeatPlain;
40
41 // There is only one variant this argument could be; put it into the
42 // argument entry.
43 arg1.push_back(var_name_arg);
44
45 // Define the first (and only) variant of this arg.
46 value_arg.arg_type = eArgTypeValue;
47 value_arg.arg_repetition = eArgRepeatPlain;
48
49 // There is only one variant this argument could be; put it into the
50 // argument entry.
51 arg2.push_back(value_arg);
52
53 // Push the data for the first argument into the m_arguments vector.
54 m_arguments.push_back(arg1);
55 m_arguments.push_back(arg2);
56
57 SetHelpLong(
58 "\nWhen setting a dictionary or array variable, you can set multiple entries \
59 at once by giving the values to the set command. For example:"
60 R"(
61
62 (lldb) settings set target.run-args value1 value2 value3
63 (lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345
64
65 (lldb) settings show target.run-args
66 [0]: 'value1'
67 [1]: 'value2'
68 [3]: 'value3'
69 (lldb) settings show target.env-vars
70 'MYPATH=~/.:/usr/bin'
71 'SOME_ENV_VAR=12345'
72
73 )"
74 "Warning: The 'set' command re-sets the entire array or dictionary. If you \
75 just want to add, remove or update individual values (or add something to \
76 the end), use one of the other settings sub-commands: append, replace, \
77 insert-before or insert-after.");
78 }
79
80 ~CommandObjectSettingsSet() override = default;
81
82 // Overrides base class's behavior where WantsCompletion =
83 // !WantsRawCommandString.
WantsCompletion()84 bool WantsCompletion() override { return true; }
85
GetOptions()86 Options *GetOptions() override { return &m_options; }
87
88 class CommandOptions : public Options {
89 public:
CommandOptions()90 CommandOptions() : Options(), m_global(false) {}
91
92 ~CommandOptions() override = default;
93
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)94 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
95 ExecutionContext *execution_context) override {
96 Status error;
97 const int short_option = m_getopt_table[option_idx].val;
98
99 switch (short_option) {
100 case 'f':
101 m_force = true;
102 break;
103 case 'g':
104 m_global = true;
105 break;
106 default:
107 llvm_unreachable("Unimplemented option");
108 }
109
110 return error;
111 }
112
OptionParsingStarting(ExecutionContext * execution_context)113 void OptionParsingStarting(ExecutionContext *execution_context) override {
114 m_global = false;
115 m_force = false;
116 }
117
GetDefinitions()118 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
119 return llvm::makeArrayRef(g_settings_set_options);
120 }
121
122 // Instance variables to hold the values for command options.
123 bool m_global;
124 bool m_force;
125 };
126
127 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)128 HandleArgumentCompletion(CompletionRequest &request,
129 OptionElementVector &opt_element_vector) override {
130
131 const size_t argc = request.GetParsedLine().GetArgumentCount();
132 const char *arg = nullptr;
133 size_t setting_var_idx;
134 for (setting_var_idx = 0; setting_var_idx < argc; ++setting_var_idx) {
135 arg = request.GetParsedLine().GetArgumentAtIndex(setting_var_idx);
136 if (arg && arg[0] != '-')
137 break; // We found our setting variable name index
138 }
139 if (request.GetCursorIndex() == setting_var_idx) {
140 // Attempting to complete setting variable name
141 CommandCompletions::InvokeCommonCompletionCallbacks(
142 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
143 request, nullptr);
144 return;
145 }
146 arg = request.GetParsedLine().GetArgumentAtIndex(request.GetCursorIndex());
147
148 if (!arg)
149 return;
150
151 // Complete option name
152 if (arg[0] != '-')
153 return;
154
155 // Complete setting value
156 const char *setting_var_name =
157 request.GetParsedLine().GetArgumentAtIndex(setting_var_idx);
158 Status error;
159 lldb::OptionValueSP value_sp(GetDebugger().GetPropertyValue(
160 &m_exe_ctx, setting_var_name, false, error));
161 if (!value_sp)
162 return;
163 value_sp->AutoComplete(m_interpreter, request);
164 }
165
166 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)167 bool DoExecute(llvm::StringRef command,
168 CommandReturnObject &result) override {
169 Args cmd_args(command);
170
171 // Process possible options.
172 if (!ParseOptions(cmd_args, result))
173 return false;
174
175 const size_t min_argc = m_options.m_force ? 1 : 2;
176 const size_t argc = cmd_args.GetArgumentCount();
177
178 if ((argc < min_argc) && (!m_options.m_global)) {
179 result.AppendError("'settings set' takes more arguments");
180 result.SetStatus(eReturnStatusFailed);
181 return false;
182 }
183
184 const char *var_name = cmd_args.GetArgumentAtIndex(0);
185 if ((var_name == nullptr) || (var_name[0] == '\0')) {
186 result.AppendError(
187 "'settings set' command requires a valid variable name");
188 result.SetStatus(eReturnStatusFailed);
189 return false;
190 }
191
192 // A missing value corresponds to clearing the setting when "force" is
193 // specified.
194 if (argc == 1 && m_options.m_force) {
195 Status error(GetDebugger().SetPropertyValue(
196 &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
197 if (error.Fail()) {
198 result.AppendError(error.AsCString());
199 result.SetStatus(eReturnStatusFailed);
200 return false;
201 }
202 return result.Succeeded();
203 }
204
205 // Split the raw command into var_name and value pair.
206 llvm::StringRef var_value(command);
207 var_value = var_value.split(var_name).second.ltrim();
208
209 Status error;
210 if (m_options.m_global)
211 error = GetDebugger().SetPropertyValue(nullptr, eVarSetOperationAssign,
212 var_name, var_value);
213
214 if (error.Success()) {
215 // FIXME this is the same issue as the one in commands script import
216 // we could be setting target.load-script-from-symbol-file which would
217 // cause Python scripts to be loaded, which could run LLDB commands (e.g.
218 // settings set target.process.python-os-plugin-path) and cause a crash
219 // if we did not clear the command's exe_ctx first
220 ExecutionContext exe_ctx(m_exe_ctx);
221 m_exe_ctx.Clear();
222 error = GetDebugger().SetPropertyValue(&exe_ctx, eVarSetOperationAssign,
223 var_name, var_value);
224 }
225
226 if (error.Fail()) {
227 result.AppendError(error.AsCString());
228 result.SetStatus(eReturnStatusFailed);
229 return false;
230 } else {
231 result.SetStatus(eReturnStatusSuccessFinishResult);
232 }
233
234 return result.Succeeded();
235 }
236
237 private:
238 CommandOptions m_options;
239 };
240
241 // CommandObjectSettingsShow -- Show current values
242
243 class CommandObjectSettingsShow : public CommandObjectParsed {
244 public:
CommandObjectSettingsShow(CommandInterpreter & interpreter)245 CommandObjectSettingsShow(CommandInterpreter &interpreter)
246 : CommandObjectParsed(interpreter, "settings show",
247 "Show matching debugger settings and their current "
248 "values. Defaults to showing all settings.",
249 nullptr) {
250 CommandArgumentEntry arg1;
251 CommandArgumentData var_name_arg;
252
253 // Define the first (and only) variant of this arg.
254 var_name_arg.arg_type = eArgTypeSettingVariableName;
255 var_name_arg.arg_repetition = eArgRepeatOptional;
256
257 // There is only one variant this argument could be; put it into the
258 // argument entry.
259 arg1.push_back(var_name_arg);
260
261 // Push the data for the first argument into the m_arguments vector.
262 m_arguments.push_back(arg1);
263 }
264
265 ~CommandObjectSettingsShow() override = default;
266
267 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)268 HandleArgumentCompletion(CompletionRequest &request,
269 OptionElementVector &opt_element_vector) override {
270 CommandCompletions::InvokeCommonCompletionCallbacks(
271 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
272 request, nullptr);
273 }
274
275 protected:
DoExecute(Args & args,CommandReturnObject & result)276 bool DoExecute(Args &args, CommandReturnObject &result) override {
277 result.SetStatus(eReturnStatusSuccessFinishResult);
278
279 if (!args.empty()) {
280 for (const auto &arg : args) {
281 Status error(GetDebugger().DumpPropertyValue(
282 &m_exe_ctx, result.GetOutputStream(), arg.ref(),
283 OptionValue::eDumpGroupValue));
284 if (error.Success()) {
285 result.GetOutputStream().EOL();
286 } else {
287 result.AppendError(error.AsCString());
288 result.SetStatus(eReturnStatusFailed);
289 }
290 }
291 } else {
292 GetDebugger().DumpAllPropertyValues(&m_exe_ctx, result.GetOutputStream(),
293 OptionValue::eDumpGroupValue);
294 }
295
296 return result.Succeeded();
297 }
298 };
299
300 // CommandObjectSettingsWrite -- Write settings to file
301 #define LLDB_OPTIONS_settings_write
302 #include "CommandOptions.inc"
303
304 class CommandObjectSettingsWrite : public CommandObjectParsed {
305 public:
CommandObjectSettingsWrite(CommandInterpreter & interpreter)306 CommandObjectSettingsWrite(CommandInterpreter &interpreter)
307 : CommandObjectParsed(
308 interpreter, "settings export",
309 "Write matching debugger settings and their "
310 "current values to a file that can be read in with "
311 "\"settings read\". Defaults to writing all settings.",
312 nullptr),
313 m_options() {
314 CommandArgumentEntry arg1;
315 CommandArgumentData var_name_arg;
316
317 // Define the first (and only) variant of this arg.
318 var_name_arg.arg_type = eArgTypeSettingVariableName;
319 var_name_arg.arg_repetition = eArgRepeatOptional;
320
321 // There is only one variant this argument could be; put it into the
322 // argument entry.
323 arg1.push_back(var_name_arg);
324
325 // Push the data for the first argument into the m_arguments vector.
326 m_arguments.push_back(arg1);
327 }
328
329 ~CommandObjectSettingsWrite() override = default;
330
GetOptions()331 Options *GetOptions() override { return &m_options; }
332
333 class CommandOptions : public Options {
334 public:
CommandOptions()335 CommandOptions() : Options() {}
336
337 ~CommandOptions() override = default;
338
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)339 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
340 ExecutionContext *execution_context) override {
341 Status error;
342 const int short_option = m_getopt_table[option_idx].val;
343
344 switch (short_option) {
345 case 'f':
346 m_filename.assign(std::string(option_arg));
347 break;
348 case 'a':
349 m_append = true;
350 break;
351 default:
352 llvm_unreachable("Unimplemented option");
353 }
354
355 return error;
356 }
357
OptionParsingStarting(ExecutionContext * execution_context)358 void OptionParsingStarting(ExecutionContext *execution_context) override {
359 m_filename.clear();
360 m_append = false;
361 }
362
GetDefinitions()363 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
364 return llvm::makeArrayRef(g_settings_write_options);
365 }
366
367 // Instance variables to hold the values for command options.
368 std::string m_filename;
369 bool m_append = false;
370 };
371
372 protected:
DoExecute(Args & args,CommandReturnObject & result)373 bool DoExecute(Args &args, CommandReturnObject &result) override {
374 FileSpec file_spec(m_options.m_filename);
375 FileSystem::Instance().Resolve(file_spec);
376 std::string path(file_spec.GetPath());
377 auto options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
378 if (m_options.m_append)
379 options |= File::eOpenOptionAppend;
380 else
381 options |= File::eOpenOptionTruncate;
382
383 StreamFile out_file(path.c_str(), options,
384 lldb::eFilePermissionsFileDefault);
385
386 if (!out_file.GetFile().IsValid()) {
387 result.AppendErrorWithFormat("%s: unable to write to file", path.c_str());
388 result.SetStatus(eReturnStatusFailed);
389 return false;
390 }
391
392 // Exporting should not be context sensitive.
393 ExecutionContext clean_ctx;
394
395 if (args.empty()) {
396 GetDebugger().DumpAllPropertyValues(&clean_ctx, out_file,
397 OptionValue::eDumpGroupExport);
398 return result.Succeeded();
399 }
400
401 for (const auto &arg : args) {
402 Status error(GetDebugger().DumpPropertyValue(
403 &clean_ctx, out_file, arg.ref(), OptionValue::eDumpGroupExport));
404 if (!error.Success()) {
405 result.AppendError(error.AsCString());
406 result.SetStatus(eReturnStatusFailed);
407 }
408 }
409
410 return result.Succeeded();
411 }
412
413 private:
414 CommandOptions m_options;
415 };
416
417 // CommandObjectSettingsRead -- Read settings from file
418 #define LLDB_OPTIONS_settings_read
419 #include "CommandOptions.inc"
420
421 class CommandObjectSettingsRead : public CommandObjectParsed {
422 public:
CommandObjectSettingsRead(CommandInterpreter & interpreter)423 CommandObjectSettingsRead(CommandInterpreter &interpreter)
424 : CommandObjectParsed(
425 interpreter, "settings read",
426 "Read settings previously saved to a file with \"settings write\".",
427 nullptr),
428 m_options() {}
429
430 ~CommandObjectSettingsRead() override = default;
431
GetOptions()432 Options *GetOptions() override { return &m_options; }
433
434 class CommandOptions : public Options {
435 public:
CommandOptions()436 CommandOptions() : Options() {}
437
438 ~CommandOptions() override = default;
439
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)440 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
441 ExecutionContext *execution_context) override {
442 Status error;
443 const int short_option = m_getopt_table[option_idx].val;
444
445 switch (short_option) {
446 case 'f':
447 m_filename.assign(std::string(option_arg));
448 break;
449 default:
450 llvm_unreachable("Unimplemented option");
451 }
452
453 return error;
454 }
455
OptionParsingStarting(ExecutionContext * execution_context)456 void OptionParsingStarting(ExecutionContext *execution_context) override {
457 m_filename.clear();
458 }
459
GetDefinitions()460 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
461 return llvm::makeArrayRef(g_settings_read_options);
462 }
463
464 // Instance variables to hold the values for command options.
465 std::string m_filename;
466 };
467
468 protected:
DoExecute(Args & command,CommandReturnObject & result)469 bool DoExecute(Args &command, CommandReturnObject &result) override {
470 FileSpec file(m_options.m_filename);
471 FileSystem::Instance().Resolve(file);
472 ExecutionContext clean_ctx;
473 CommandInterpreterRunOptions options;
474 options.SetAddToHistory(false);
475 options.SetEchoCommands(false);
476 options.SetPrintResults(true);
477 options.SetPrintErrors(true);
478 options.SetStopOnError(false);
479 m_interpreter.HandleCommandsFromFile(file, &clean_ctx, options, result);
480 return result.Succeeded();
481 }
482
483 private:
484 CommandOptions m_options;
485 };
486
487 // CommandObjectSettingsList -- List settable variables
488
489 class CommandObjectSettingsList : public CommandObjectParsed {
490 public:
CommandObjectSettingsList(CommandInterpreter & interpreter)491 CommandObjectSettingsList(CommandInterpreter &interpreter)
492 : CommandObjectParsed(interpreter, "settings list",
493 "List and describe matching debugger settings. "
494 "Defaults to all listing all settings.",
495 nullptr) {
496 CommandArgumentEntry arg;
497 CommandArgumentData var_name_arg;
498 CommandArgumentData prefix_name_arg;
499
500 // Define the first variant of this arg.
501 var_name_arg.arg_type = eArgTypeSettingVariableName;
502 var_name_arg.arg_repetition = eArgRepeatOptional;
503
504 // Define the second variant of this arg.
505 prefix_name_arg.arg_type = eArgTypeSettingPrefix;
506 prefix_name_arg.arg_repetition = eArgRepeatOptional;
507
508 arg.push_back(var_name_arg);
509 arg.push_back(prefix_name_arg);
510
511 // Push the data for the first argument into the m_arguments vector.
512 m_arguments.push_back(arg);
513 }
514
515 ~CommandObjectSettingsList() override = default;
516
517 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)518 HandleArgumentCompletion(CompletionRequest &request,
519 OptionElementVector &opt_element_vector) override {
520 CommandCompletions::InvokeCommonCompletionCallbacks(
521 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
522 request, nullptr);
523 }
524
525 protected:
DoExecute(Args & args,CommandReturnObject & result)526 bool DoExecute(Args &args, CommandReturnObject &result) override {
527 result.SetStatus(eReturnStatusSuccessFinishResult);
528
529 const bool will_modify = false;
530 const size_t argc = args.GetArgumentCount();
531 if (argc > 0) {
532 const bool dump_qualified_name = true;
533
534 for (const Args::ArgEntry &arg : args) {
535 const char *property_path = arg.c_str();
536
537 const Property *property =
538 GetDebugger().GetValueProperties()->GetPropertyAtPath(
539 &m_exe_ctx, will_modify, property_path);
540
541 if (property) {
542 property->DumpDescription(m_interpreter, result.GetOutputStream(), 0,
543 dump_qualified_name);
544 } else {
545 result.AppendErrorWithFormat("invalid property path '%s'",
546 property_path);
547 result.SetStatus(eReturnStatusFailed);
548 }
549 }
550 } else {
551 GetDebugger().DumpAllDescriptions(m_interpreter,
552 result.GetOutputStream());
553 }
554
555 return result.Succeeded();
556 }
557 };
558
559 // CommandObjectSettingsRemove
560
561 class CommandObjectSettingsRemove : public CommandObjectRaw {
562 public:
CommandObjectSettingsRemove(CommandInterpreter & interpreter)563 CommandObjectSettingsRemove(CommandInterpreter &interpreter)
564 : CommandObjectRaw(interpreter, "settings remove",
565 "Remove a value from a setting, specified by array "
566 "index or dictionary key.") {
567 CommandArgumentEntry arg1;
568 CommandArgumentEntry arg2;
569 CommandArgumentData var_name_arg;
570 CommandArgumentData index_arg;
571 CommandArgumentData key_arg;
572
573 // Define the first (and only) variant of this arg.
574 var_name_arg.arg_type = eArgTypeSettingVariableName;
575 var_name_arg.arg_repetition = eArgRepeatPlain;
576
577 // There is only one variant this argument could be; put it into the
578 // argument entry.
579 arg1.push_back(var_name_arg);
580
581 // Define the first variant of this arg.
582 index_arg.arg_type = eArgTypeSettingIndex;
583 index_arg.arg_repetition = eArgRepeatPlain;
584
585 // Define the second variant of this arg.
586 key_arg.arg_type = eArgTypeSettingKey;
587 key_arg.arg_repetition = eArgRepeatPlain;
588
589 // Push both variants into this arg
590 arg2.push_back(index_arg);
591 arg2.push_back(key_arg);
592
593 // Push the data for the first argument into the m_arguments vector.
594 m_arguments.push_back(arg1);
595 m_arguments.push_back(arg2);
596 }
597
598 ~CommandObjectSettingsRemove() override = default;
599
WantsCompletion()600 bool WantsCompletion() override { return true; }
601
602 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)603 HandleArgumentCompletion(CompletionRequest &request,
604 OptionElementVector &opt_element_vector) override {
605 if (request.GetCursorIndex() < 2)
606 CommandCompletions::InvokeCommonCompletionCallbacks(
607 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
608 request, nullptr);
609 }
610
611 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)612 bool DoExecute(llvm::StringRef command,
613 CommandReturnObject &result) override {
614 result.SetStatus(eReturnStatusSuccessFinishNoResult);
615
616 Args cmd_args(command);
617
618 // Process possible options.
619 if (!ParseOptions(cmd_args, result))
620 return false;
621
622 const size_t argc = cmd_args.GetArgumentCount();
623 if (argc == 0) {
624 result.AppendError("'settings remove' takes an array or dictionary item, "
625 "or an array followed by one or more indexes, or a "
626 "dictionary followed by one or more key names to "
627 "remove");
628 result.SetStatus(eReturnStatusFailed);
629 return false;
630 }
631
632 const char *var_name = cmd_args.GetArgumentAtIndex(0);
633 if ((var_name == nullptr) || (var_name[0] == '\0')) {
634 result.AppendError(
635 "'settings remove' command requires a valid variable name");
636 result.SetStatus(eReturnStatusFailed);
637 return false;
638 }
639
640 // Split the raw command into var_name and value pair.
641 llvm::StringRef var_value(command);
642 var_value = var_value.split(var_name).second.trim();
643
644 Status error(GetDebugger().SetPropertyValue(
645 &m_exe_ctx, eVarSetOperationRemove, var_name, var_value));
646 if (error.Fail()) {
647 result.AppendError(error.AsCString());
648 result.SetStatus(eReturnStatusFailed);
649 return false;
650 }
651
652 return result.Succeeded();
653 }
654 };
655
656 // CommandObjectSettingsReplace
657
658 class CommandObjectSettingsReplace : public CommandObjectRaw {
659 public:
CommandObjectSettingsReplace(CommandInterpreter & interpreter)660 CommandObjectSettingsReplace(CommandInterpreter &interpreter)
661 : CommandObjectRaw(interpreter, "settings replace",
662 "Replace the debugger setting value specified by "
663 "array index or dictionary key.") {
664 CommandArgumentEntry arg1;
665 CommandArgumentEntry arg2;
666 CommandArgumentEntry arg3;
667 CommandArgumentData var_name_arg;
668 CommandArgumentData index_arg;
669 CommandArgumentData key_arg;
670 CommandArgumentData value_arg;
671
672 // Define the first (and only) variant of this arg.
673 var_name_arg.arg_type = eArgTypeSettingVariableName;
674 var_name_arg.arg_repetition = eArgRepeatPlain;
675
676 // There is only one variant this argument could be; put it into the
677 // argument entry.
678 arg1.push_back(var_name_arg);
679
680 // Define the first (variant of this arg.
681 index_arg.arg_type = eArgTypeSettingIndex;
682 index_arg.arg_repetition = eArgRepeatPlain;
683
684 // Define the second (variant of this arg.
685 key_arg.arg_type = eArgTypeSettingKey;
686 key_arg.arg_repetition = eArgRepeatPlain;
687
688 // Put both variants into this arg
689 arg2.push_back(index_arg);
690 arg2.push_back(key_arg);
691
692 // Define the first (and only) variant of this arg.
693 value_arg.arg_type = eArgTypeValue;
694 value_arg.arg_repetition = eArgRepeatPlain;
695
696 // There is only one variant this argument could be; put it into the
697 // argument entry.
698 arg3.push_back(value_arg);
699
700 // Push the data for the first argument into the m_arguments vector.
701 m_arguments.push_back(arg1);
702 m_arguments.push_back(arg2);
703 m_arguments.push_back(arg3);
704 }
705
706 ~CommandObjectSettingsReplace() override = default;
707
708 // Overrides base class's behavior where WantsCompletion =
709 // !WantsRawCommandString.
WantsCompletion()710 bool WantsCompletion() override { return true; }
711
712 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)713 HandleArgumentCompletion(CompletionRequest &request,
714 OptionElementVector &opt_element_vector) override {
715 // Attempting to complete variable name
716 if (request.GetCursorIndex() < 2)
717 CommandCompletions::InvokeCommonCompletionCallbacks(
718 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
719 request, nullptr);
720 }
721
722 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)723 bool DoExecute(llvm::StringRef command,
724 CommandReturnObject &result) override {
725 result.SetStatus(eReturnStatusSuccessFinishNoResult);
726
727 Args cmd_args(command);
728 const char *var_name = cmd_args.GetArgumentAtIndex(0);
729 if ((var_name == nullptr) || (var_name[0] == '\0')) {
730 result.AppendError("'settings replace' command requires a valid variable "
731 "name; No value supplied");
732 result.SetStatus(eReturnStatusFailed);
733 return false;
734 }
735
736 // Split the raw command into var_name, index_value, and value triple.
737 llvm::StringRef var_value(command);
738 var_value = var_value.split(var_name).second.trim();
739
740 Status error(GetDebugger().SetPropertyValue(
741 &m_exe_ctx, eVarSetOperationReplace, var_name, var_value));
742 if (error.Fail()) {
743 result.AppendError(error.AsCString());
744 result.SetStatus(eReturnStatusFailed);
745 return false;
746 } else {
747 result.SetStatus(eReturnStatusSuccessFinishNoResult);
748 }
749
750 return result.Succeeded();
751 }
752 };
753
754 // CommandObjectSettingsInsertBefore
755
756 class CommandObjectSettingsInsertBefore : public CommandObjectRaw {
757 public:
CommandObjectSettingsInsertBefore(CommandInterpreter & interpreter)758 CommandObjectSettingsInsertBefore(CommandInterpreter &interpreter)
759 : CommandObjectRaw(interpreter, "settings insert-before",
760 "Insert one or more values into an debugger array "
761 "setting immediately before the specified element "
762 "index.") {
763 CommandArgumentEntry arg1;
764 CommandArgumentEntry arg2;
765 CommandArgumentEntry arg3;
766 CommandArgumentData var_name_arg;
767 CommandArgumentData index_arg;
768 CommandArgumentData value_arg;
769
770 // Define the first (and only) variant of this arg.
771 var_name_arg.arg_type = eArgTypeSettingVariableName;
772 var_name_arg.arg_repetition = eArgRepeatPlain;
773
774 // There is only one variant this argument could be; put it into the
775 // argument entry.
776 arg1.push_back(var_name_arg);
777
778 // Define the first (variant of this arg.
779 index_arg.arg_type = eArgTypeSettingIndex;
780 index_arg.arg_repetition = eArgRepeatPlain;
781
782 // There is only one variant this argument could be; put it into the
783 // argument entry.
784 arg2.push_back(index_arg);
785
786 // Define the first (and only) variant of this arg.
787 value_arg.arg_type = eArgTypeValue;
788 value_arg.arg_repetition = eArgRepeatPlain;
789
790 // There is only one variant this argument could be; put it into the
791 // argument entry.
792 arg3.push_back(value_arg);
793
794 // Push the data for the first argument into the m_arguments vector.
795 m_arguments.push_back(arg1);
796 m_arguments.push_back(arg2);
797 m_arguments.push_back(arg3);
798 }
799
800 ~CommandObjectSettingsInsertBefore() override = default;
801
802 // Overrides base class's behavior where WantsCompletion =
803 // !WantsRawCommandString.
WantsCompletion()804 bool WantsCompletion() override { return true; }
805
806 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)807 HandleArgumentCompletion(CompletionRequest &request,
808 OptionElementVector &opt_element_vector) override {
809 // Attempting to complete variable name
810 if (request.GetCursorIndex() < 2)
811 CommandCompletions::InvokeCommonCompletionCallbacks(
812 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
813 request, nullptr);
814 }
815
816 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)817 bool DoExecute(llvm::StringRef command,
818 CommandReturnObject &result) override {
819 result.SetStatus(eReturnStatusSuccessFinishNoResult);
820
821 Args cmd_args(command);
822 const size_t argc = cmd_args.GetArgumentCount();
823
824 if (argc < 3) {
825 result.AppendError("'settings insert-before' takes more arguments");
826 result.SetStatus(eReturnStatusFailed);
827 return false;
828 }
829
830 const char *var_name = cmd_args.GetArgumentAtIndex(0);
831 if ((var_name == nullptr) || (var_name[0] == '\0')) {
832 result.AppendError("'settings insert-before' command requires a valid "
833 "variable name; No value supplied");
834 result.SetStatus(eReturnStatusFailed);
835 return false;
836 }
837
838 // Split the raw command into var_name, index_value, and value triple.
839 llvm::StringRef var_value(command);
840 var_value = var_value.split(var_name).second.trim();
841
842 Status error(GetDebugger().SetPropertyValue(
843 &m_exe_ctx, eVarSetOperationInsertBefore, var_name, var_value));
844 if (error.Fail()) {
845 result.AppendError(error.AsCString());
846 result.SetStatus(eReturnStatusFailed);
847 return false;
848 }
849
850 return result.Succeeded();
851 }
852 };
853
854 // CommandObjectSettingInsertAfter
855
856 class CommandObjectSettingsInsertAfter : public CommandObjectRaw {
857 public:
CommandObjectSettingsInsertAfter(CommandInterpreter & interpreter)858 CommandObjectSettingsInsertAfter(CommandInterpreter &interpreter)
859 : CommandObjectRaw(interpreter, "settings insert-after",
860 "Insert one or more values into a debugger array "
861 "settings after the specified element index.") {
862 CommandArgumentEntry arg1;
863 CommandArgumentEntry arg2;
864 CommandArgumentEntry arg3;
865 CommandArgumentData var_name_arg;
866 CommandArgumentData index_arg;
867 CommandArgumentData value_arg;
868
869 // Define the first (and only) variant of this arg.
870 var_name_arg.arg_type = eArgTypeSettingVariableName;
871 var_name_arg.arg_repetition = eArgRepeatPlain;
872
873 // There is only one variant this argument could be; put it into the
874 // argument entry.
875 arg1.push_back(var_name_arg);
876
877 // Define the first (variant of this arg.
878 index_arg.arg_type = eArgTypeSettingIndex;
879 index_arg.arg_repetition = eArgRepeatPlain;
880
881 // There is only one variant this argument could be; put it into the
882 // argument entry.
883 arg2.push_back(index_arg);
884
885 // Define the first (and only) variant of this arg.
886 value_arg.arg_type = eArgTypeValue;
887 value_arg.arg_repetition = eArgRepeatPlain;
888
889 // There is only one variant this argument could be; put it into the
890 // argument entry.
891 arg3.push_back(value_arg);
892
893 // Push the data for the first argument into the m_arguments vector.
894 m_arguments.push_back(arg1);
895 m_arguments.push_back(arg2);
896 m_arguments.push_back(arg3);
897 }
898
899 ~CommandObjectSettingsInsertAfter() override = default;
900
901 // Overrides base class's behavior where WantsCompletion =
902 // !WantsRawCommandString.
WantsCompletion()903 bool WantsCompletion() override { return true; }
904
905 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)906 HandleArgumentCompletion(CompletionRequest &request,
907 OptionElementVector &opt_element_vector) override {
908 // Attempting to complete variable name
909 if (request.GetCursorIndex() < 2)
910 CommandCompletions::InvokeCommonCompletionCallbacks(
911 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
912 request, nullptr);
913 }
914
915 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)916 bool DoExecute(llvm::StringRef command,
917 CommandReturnObject &result) override {
918 result.SetStatus(eReturnStatusSuccessFinishNoResult);
919
920 Args cmd_args(command);
921 const size_t argc = cmd_args.GetArgumentCount();
922
923 if (argc < 3) {
924 result.AppendError("'settings insert-after' takes more arguments");
925 result.SetStatus(eReturnStatusFailed);
926 return false;
927 }
928
929 const char *var_name = cmd_args.GetArgumentAtIndex(0);
930 if ((var_name == nullptr) || (var_name[0] == '\0')) {
931 result.AppendError("'settings insert-after' command requires a valid "
932 "variable name; No value supplied");
933 result.SetStatus(eReturnStatusFailed);
934 return false;
935 }
936
937 // Split the raw command into var_name, index_value, and value triple.
938 llvm::StringRef var_value(command);
939 var_value = var_value.split(var_name).second.trim();
940
941 Status error(GetDebugger().SetPropertyValue(
942 &m_exe_ctx, eVarSetOperationInsertAfter, var_name, var_value));
943 if (error.Fail()) {
944 result.AppendError(error.AsCString());
945 result.SetStatus(eReturnStatusFailed);
946 return false;
947 }
948
949 return result.Succeeded();
950 }
951 };
952
953 // CommandObjectSettingsAppend
954
955 class CommandObjectSettingsAppend : public CommandObjectRaw {
956 public:
CommandObjectSettingsAppend(CommandInterpreter & interpreter)957 CommandObjectSettingsAppend(CommandInterpreter &interpreter)
958 : CommandObjectRaw(interpreter, "settings append",
959 "Append one or more values to a debugger array, "
960 "dictionary, or string setting.") {
961 CommandArgumentEntry arg1;
962 CommandArgumentEntry arg2;
963 CommandArgumentData var_name_arg;
964 CommandArgumentData value_arg;
965
966 // Define the first (and only) variant of this arg.
967 var_name_arg.arg_type = eArgTypeSettingVariableName;
968 var_name_arg.arg_repetition = eArgRepeatPlain;
969
970 // There is only one variant this argument could be; put it into the
971 // argument entry.
972 arg1.push_back(var_name_arg);
973
974 // Define the first (and only) variant of this arg.
975 value_arg.arg_type = eArgTypeValue;
976 value_arg.arg_repetition = eArgRepeatPlain;
977
978 // There is only one variant this argument could be; put it into the
979 // argument entry.
980 arg2.push_back(value_arg);
981
982 // Push the data for the first argument into the m_arguments vector.
983 m_arguments.push_back(arg1);
984 m_arguments.push_back(arg2);
985 }
986
987 ~CommandObjectSettingsAppend() override = default;
988
989 // Overrides base class's behavior where WantsCompletion =
990 // !WantsRawCommandString.
WantsCompletion()991 bool WantsCompletion() override { return true; }
992
993 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)994 HandleArgumentCompletion(CompletionRequest &request,
995 OptionElementVector &opt_element_vector) override {
996 // Attempting to complete variable name
997 if (request.GetCursorIndex() < 2)
998 CommandCompletions::InvokeCommonCompletionCallbacks(
999 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1000 request, nullptr);
1001 }
1002
1003 protected:
DoExecute(llvm::StringRef command,CommandReturnObject & result)1004 bool DoExecute(llvm::StringRef command,
1005 CommandReturnObject &result) override {
1006 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1007 Args cmd_args(command);
1008 const size_t argc = cmd_args.GetArgumentCount();
1009
1010 if (argc < 2) {
1011 result.AppendError("'settings append' takes more arguments");
1012 result.SetStatus(eReturnStatusFailed);
1013 return false;
1014 }
1015
1016 const char *var_name = cmd_args.GetArgumentAtIndex(0);
1017 if ((var_name == nullptr) || (var_name[0] == '\0')) {
1018 result.AppendError("'settings append' command requires a valid variable "
1019 "name; No value supplied");
1020 result.SetStatus(eReturnStatusFailed);
1021 return false;
1022 }
1023
1024 // Do not perform cmd_args.Shift() since StringRef is manipulating the raw
1025 // character string later on.
1026
1027 // Split the raw command into var_name and value pair.
1028 llvm::StringRef var_value(command);
1029 var_value = var_value.split(var_name).second.trim();
1030
1031 Status error(GetDebugger().SetPropertyValue(
1032 &m_exe_ctx, eVarSetOperationAppend, var_name, var_value));
1033 if (error.Fail()) {
1034 result.AppendError(error.AsCString());
1035 result.SetStatus(eReturnStatusFailed);
1036 return false;
1037 }
1038
1039 return result.Succeeded();
1040 }
1041 };
1042
1043 // CommandObjectSettingsClear
1044 #define LLDB_OPTIONS_settings_clear
1045 #include "CommandOptions.inc"
1046
1047 class CommandObjectSettingsClear : public CommandObjectParsed {
1048 public:
CommandObjectSettingsClear(CommandInterpreter & interpreter)1049 CommandObjectSettingsClear(CommandInterpreter &interpreter)
1050 : CommandObjectParsed(
1051 interpreter, "settings clear",
1052 "Clear a debugger setting array, dictionary, or string. "
1053 "If '-a' option is specified, it clears all settings.", nullptr) {
1054 CommandArgumentEntry arg;
1055 CommandArgumentData var_name_arg;
1056
1057 // Define the first (and only) variant of this arg.
1058 var_name_arg.arg_type = eArgTypeSettingVariableName;
1059 var_name_arg.arg_repetition = eArgRepeatPlain;
1060
1061 // There is only one variant this argument could be; put it into the
1062 // argument entry.
1063 arg.push_back(var_name_arg);
1064
1065 // Push the data for the first argument into the m_arguments vector.
1066 m_arguments.push_back(arg);
1067 }
1068
1069 ~CommandObjectSettingsClear() override = default;
1070
1071 void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1072 HandleArgumentCompletion(CompletionRequest &request,
1073 OptionElementVector &opt_element_vector) override {
1074 // Attempting to complete variable name
1075 if (request.GetCursorIndex() < 2)
1076 CommandCompletions::InvokeCommonCompletionCallbacks(
1077 GetCommandInterpreter(), CommandCompletions::eSettingsNameCompletion,
1078 request, nullptr);
1079 }
1080
GetOptions()1081 Options *GetOptions() override { return &m_options; }
1082
1083 class CommandOptions : public Options {
1084 public:
1085 CommandOptions() = default;
1086
1087 ~CommandOptions() override = default;
1088
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1089 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1090 ExecutionContext *execution_context) override {
1091 const int short_option = m_getopt_table[option_idx].val;
1092 switch (short_option) {
1093 case 'a':
1094 m_clear_all = true;
1095 break;
1096 default:
1097 llvm_unreachable("Unimplemented option");
1098 }
1099 return Status();
1100 }
1101
OptionParsingStarting(ExecutionContext * execution_context)1102 void OptionParsingStarting(ExecutionContext *execution_context) override {
1103 m_clear_all = false;
1104 }
1105
GetDefinitions()1106 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1107 return llvm::makeArrayRef(g_settings_clear_options);
1108 }
1109
1110 bool m_clear_all = false;
1111 };
1112
1113 protected:
DoExecute(Args & command,CommandReturnObject & result)1114 bool DoExecute(Args &command, CommandReturnObject &result) override {
1115 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1116 const size_t argc = command.GetArgumentCount();
1117
1118 if (m_options.m_clear_all) {
1119 if (argc != 0) {
1120 result.AppendError("'settings clear --all' doesn't take any arguments");
1121 result.SetStatus(eReturnStatusFailed);
1122 return false;
1123 }
1124 GetDebugger().GetValueProperties()->Clear();
1125 return result.Succeeded();
1126 }
1127
1128 if (argc != 1) {
1129 result.AppendError("'settings clear' takes exactly one argument");
1130 result.SetStatus(eReturnStatusFailed);
1131 return false;
1132 }
1133
1134 const char *var_name = command.GetArgumentAtIndex(0);
1135 if ((var_name == nullptr) || (var_name[0] == '\0')) {
1136 result.AppendError("'settings clear' command requires a valid variable "
1137 "name; No value supplied");
1138 result.SetStatus(eReturnStatusFailed);
1139 return false;
1140 }
1141
1142 Status error(GetDebugger().SetPropertyValue(
1143 &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef()));
1144 if (error.Fail()) {
1145 result.AppendError(error.AsCString());
1146 result.SetStatus(eReturnStatusFailed);
1147 return false;
1148 }
1149
1150 return result.Succeeded();
1151 }
1152
1153 private:
1154 CommandOptions m_options;
1155 };
1156
1157 // CommandObjectMultiwordSettings
1158
CommandObjectMultiwordSettings(CommandInterpreter & interpreter)1159 CommandObjectMultiwordSettings::CommandObjectMultiwordSettings(
1160 CommandInterpreter &interpreter)
1161 : CommandObjectMultiword(interpreter, "settings",
1162 "Commands for managing LLDB settings.",
1163 "settings <subcommand> [<command-options>]") {
1164 LoadSubCommand("set",
1165 CommandObjectSP(new CommandObjectSettingsSet(interpreter)));
1166 LoadSubCommand("show",
1167 CommandObjectSP(new CommandObjectSettingsShow(interpreter)));
1168 LoadSubCommand("list",
1169 CommandObjectSP(new CommandObjectSettingsList(interpreter)));
1170 LoadSubCommand("remove",
1171 CommandObjectSP(new CommandObjectSettingsRemove(interpreter)));
1172 LoadSubCommand("replace", CommandObjectSP(
1173 new CommandObjectSettingsReplace(interpreter)));
1174 LoadSubCommand(
1175 "insert-before",
1176 CommandObjectSP(new CommandObjectSettingsInsertBefore(interpreter)));
1177 LoadSubCommand(
1178 "insert-after",
1179 CommandObjectSP(new CommandObjectSettingsInsertAfter(interpreter)));
1180 LoadSubCommand("append",
1181 CommandObjectSP(new CommandObjectSettingsAppend(interpreter)));
1182 LoadSubCommand("clear",
1183 CommandObjectSP(new CommandObjectSettingsClear(interpreter)));
1184 LoadSubCommand("write",
1185 CommandObjectSP(new CommandObjectSettingsWrite(interpreter)));
1186 LoadSubCommand("read",
1187 CommandObjectSP(new CommandObjectSettingsRead(interpreter)));
1188 }
1189
1190 CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings() = default;
1191