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