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