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