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: |
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. |
84 | bool WantsCompletion() override { return true; } |
85 | |
86 | Options *GetOptions() override { return &m_options; } |
87 | |
88 | class CommandOptions : public Options { |
89 | public: |
90 | CommandOptions() = default; |
91 | |
92 | ~CommandOptions() override = default; |
93 | |
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 | |
116 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
117 | m_global = false; |
118 | m_force = false; |
119 | m_exists = false; |
120 | } |
121 | |
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 |
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(idx: 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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
148 | searcher: nullptr); |
149 | return; |
150 | } |
151 | arg = request.GetParsedLine().GetArgumentAtIndex(idx: 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(idx: setting_var_idx); |
163 | Status error; |
164 | lldb::OptionValueSP value_sp( |
165 | GetDebugger().GetPropertyValue(exe_ctx: &m_exe_ctx, property_path: setting_var_name, error)); |
166 | if (!value_sp) |
167 | return; |
168 | value_sp->AutoComplete(interpreter&: m_interpreter, request); |
169 | } |
170 | |
171 | protected: |
172 | void DoExecute(llvm::StringRef command, |
173 | CommandReturnObject &result) override { |
174 | Args cmd_args(command); |
175 | |
176 | // Process possible options. |
177 | if (!ParseOptions(args&: 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(in_string: "'settings set' takes more arguments" ); |
185 | return; |
186 | } |
187 | |
188 | const char *var_name = cmd_args.GetArgumentAtIndex(idx: 0); |
189 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
190 | result.AppendError( |
191 | in_string: "'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 | exe_ctx: &m_exe_ctx, op: eVarSetOperationClear, property_path: var_name, value: llvm::StringRef())); |
200 | if (error.Fail()) { |
201 | result.AppendError(in_string: 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(exe_ctx: nullptr, op: eVarSetOperationAssign, |
213 | property_path: var_name, value: 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: &exe_ctx, op: eVarSetOperationAssign, |
224 | property_path: var_name, value: var_value); |
225 | } |
226 | |
227 | if (error.Fail() && !m_options.m_exists) { |
228 | result.AppendError(in_string: 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: |
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(arg_type: eArgTypeSettingVariableName, repetition_type: eArgRepeatOptional); |
249 | } |
250 | |
251 | ~CommandObjectSettingsShow() override = default; |
252 | |
253 | protected: |
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 | exe_ctx: &m_exe_ctx, strm&: result.GetOutputStream(), property_path: arg.ref(), |
261 | dump_mask: OptionValue::eDumpGroupValue)); |
262 | if (error.Success()) { |
263 | result.GetOutputStream().EOL(); |
264 | } else { |
265 | result.AppendError(in_string: error.AsCString()); |
266 | } |
267 | } |
268 | } else { |
269 | GetDebugger().DumpAllPropertyValues(exe_ctx: &m_exe_ctx, strm&: result.GetOutputStream(), |
270 | dump_mask: 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: |
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(arg_type: eArgTypeSettingVariableName, repetition_type: eArgRepeatOptional); |
289 | } |
290 | |
291 | ~CommandObjectSettingsWrite() override = default; |
292 | |
293 | Options *GetOptions() override { return &m_options; } |
294 | |
295 | class CommandOptions : public Options { |
296 | public: |
297 | CommandOptions() = default; |
298 | |
299 | ~CommandOptions() override = default; |
300 | |
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(str: 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 | |
320 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
321 | m_filename.clear(); |
322 | m_append = false; |
323 | } |
324 | |
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: |
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(format: "%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(exe_ctx: &clean_ctx, strm&: out_file, |
358 | dump_mask: 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: |
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 | |
389 | Options *GetOptions() override { return &m_options; } |
390 | |
391 | class CommandOptions : public Options { |
392 | public: |
393 | CommandOptions() = default; |
394 | |
395 | ~CommandOptions() override = default; |
396 | |
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(str: std::string(option_arg)); |
405 | break; |
406 | default: |
407 | llvm_unreachable("Unimplemented option" ); |
408 | } |
409 | |
410 | return error; |
411 | } |
412 | |
413 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
414 | m_filename.clear(); |
415 | } |
416 | |
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: |
426 | void DoExecute(Args &command, CommandReturnObject &result) override { |
427 | FileSpec file(m_options.m_filename); |
428 | FileSystem::Instance().Resolve(file_spec&: 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: |
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(x: var_name_arg); |
464 | arg.push_back(x: prefix_name_arg); |
465 | |
466 | // Push the data for the first argument into the m_arguments vector. |
467 | m_arguments.push_back(x: arg); |
468 | } |
469 | |
470 | ~CommandObjectSettingsList() override = default; |
471 | |
472 | void |
473 | HandleArgumentCompletion(CompletionRequest &request, |
474 | OptionElementVector &opt_element_vector) override { |
475 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
476 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
477 | searcher: nullptr); |
478 | } |
479 | |
480 | protected: |
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 | exe_ctx: &m_exe_ctx, property_path); |
494 | |
495 | if (property) { |
496 | property->DumpDescription(interpreter&: m_interpreter, strm&: result.GetOutputStream(), output_width: 0, |
497 | display_qualified_name: dump_qualified_name); |
498 | } else { |
499 | result.AppendErrorWithFormat(format: "invalid property path '%s'" , |
500 | property_path); |
501 | } |
502 | } |
503 | } else { |
504 | GetDebugger().DumpAllDescriptions(interpreter&: m_interpreter, |
505 | strm&: result.GetOutputStream()); |
506 | } |
507 | } |
508 | }; |
509 | |
510 | // CommandObjectSettingsRemove |
511 | |
512 | class CommandObjectSettingsRemove : public CommandObjectRaw { |
513 | public: |
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(x: 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(x: index_arg); |
542 | arg2.push_back(x: key_arg); |
543 | |
544 | // Push the data for the first argument into the m_arguments vector. |
545 | m_arguments.push_back(x: arg1); |
546 | m_arguments.push_back(x: arg2); |
547 | } |
548 | |
549 | ~CommandObjectSettingsRemove() override = default; |
550 | |
551 | bool WantsCompletion() override { return true; } |
552 | |
553 | void |
554 | HandleArgumentCompletion(CompletionRequest &request, |
555 | OptionElementVector &opt_element_vector) override { |
556 | if (request.GetCursorIndex() < 2) |
557 | lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks( |
558 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
559 | searcher: nullptr); |
560 | } |
561 | |
562 | protected: |
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(args&: cmd_args, result)) |
571 | return; |
572 | |
573 | const size_t argc = cmd_args.GetArgumentCount(); |
574 | if (argc == 0) { |
575 | result.AppendError(in_string: "'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(idx: 0); |
583 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
584 | result.AppendError( |
585 | in_string: "'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(Separator: var_name).second.trim(); |
592 | |
593 | Status error(GetDebugger().SetPropertyValue( |
594 | exe_ctx: &m_exe_ctx, op: eVarSetOperationRemove, property_path: var_name, value: var_value)); |
595 | if (error.Fail()) { |
596 | result.AppendError(in_string: error.AsCString()); |
597 | } |
598 | } |
599 | }; |
600 | |
601 | // CommandObjectSettingsReplace |
602 | |
603 | class CommandObjectSettingsReplace : public CommandObjectRaw { |
604 | public: |
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(x: 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(x: index_arg); |
635 | arg2.push_back(x: 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(x: value_arg); |
644 | |
645 | // Push the data for the first argument into the m_arguments vector. |
646 | m_arguments.push_back(x: arg1); |
647 | m_arguments.push_back(x: arg2); |
648 | m_arguments.push_back(x: arg3); |
649 | } |
650 | |
651 | ~CommandObjectSettingsReplace() override = default; |
652 | |
653 | // Overrides base class's behavior where WantsCompletion = |
654 | // !WantsRawCommandString. |
655 | bool WantsCompletion() override { return true; } |
656 | |
657 | void |
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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
664 | searcher: nullptr); |
665 | } |
666 | |
667 | protected: |
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(idx: 0); |
674 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
675 | result.AppendError(in_string: "'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(Separator: var_name).second.trim(); |
683 | |
684 | Status error(GetDebugger().SetPropertyValue( |
685 | exe_ctx: &m_exe_ctx, op: eVarSetOperationReplace, property_path: var_name, value: var_value)); |
686 | if (error.Fail()) { |
687 | result.AppendError(in_string: error.AsCString()); |
688 | } else { |
689 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
690 | } |
691 | } |
692 | }; |
693 | |
694 | // CommandObjectSettingsInsertBefore |
695 | |
696 | class CommandObjectSettingsInsertBefore : public CommandObjectRaw { |
697 | public: |
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(x: 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(x: 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(x: value_arg); |
733 | |
734 | // Push the data for the first argument into the m_arguments vector. |
735 | m_arguments.push_back(x: arg1); |
736 | m_arguments.push_back(x: arg2); |
737 | m_arguments.push_back(x: arg3); |
738 | } |
739 | |
740 | ~CommandObjectSettingsInsertBefore() override = default; |
741 | |
742 | // Overrides base class's behavior where WantsCompletion = |
743 | // !WantsRawCommandString. |
744 | bool WantsCompletion() override { return true; } |
745 | |
746 | void |
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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
753 | searcher: nullptr); |
754 | } |
755 | |
756 | protected: |
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(in_string: "'settings insert-before' takes more arguments" ); |
766 | return; |
767 | } |
768 | |
769 | const char *var_name = cmd_args.GetArgumentAtIndex(idx: 0); |
770 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
771 | result.AppendError(in_string: "'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(Separator: var_name).second.trim(); |
779 | |
780 | Status error(GetDebugger().SetPropertyValue( |
781 | exe_ctx: &m_exe_ctx, op: eVarSetOperationInsertBefore, property_path: var_name, value: var_value)); |
782 | if (error.Fail()) { |
783 | result.AppendError(in_string: error.AsCString()); |
784 | } |
785 | } |
786 | }; |
787 | |
788 | // CommandObjectSettingInsertAfter |
789 | |
790 | class CommandObjectSettingsInsertAfter : public CommandObjectRaw { |
791 | public: |
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(x: 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(x: 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(x: value_arg); |
826 | |
827 | // Push the data for the first argument into the m_arguments vector. |
828 | m_arguments.push_back(x: arg1); |
829 | m_arguments.push_back(x: arg2); |
830 | m_arguments.push_back(x: arg3); |
831 | } |
832 | |
833 | ~CommandObjectSettingsInsertAfter() override = default; |
834 | |
835 | // Overrides base class's behavior where WantsCompletion = |
836 | // !WantsRawCommandString. |
837 | bool WantsCompletion() override { return true; } |
838 | |
839 | void |
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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
846 | searcher: nullptr); |
847 | } |
848 | |
849 | protected: |
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(in_string: "'settings insert-after' takes more arguments" ); |
859 | return; |
860 | } |
861 | |
862 | const char *var_name = cmd_args.GetArgumentAtIndex(idx: 0); |
863 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
864 | result.AppendError(in_string: "'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(Separator: var_name).second.trim(); |
872 | |
873 | Status error(GetDebugger().SetPropertyValue( |
874 | exe_ctx: &m_exe_ctx, op: eVarSetOperationInsertAfter, property_path: var_name, value: var_value)); |
875 | if (error.Fail()) { |
876 | result.AppendError(in_string: error.AsCString()); |
877 | } |
878 | } |
879 | }; |
880 | |
881 | // CommandObjectSettingsAppend |
882 | |
883 | class CommandObjectSettingsAppend : public CommandObjectRaw { |
884 | public: |
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(x: 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(x: value_arg); |
909 | |
910 | // Push the data for the first argument into the m_arguments vector. |
911 | m_arguments.push_back(x: arg1); |
912 | m_arguments.push_back(x: arg2); |
913 | } |
914 | |
915 | ~CommandObjectSettingsAppend() override = default; |
916 | |
917 | // Overrides base class's behavior where WantsCompletion = |
918 | // !WantsRawCommandString. |
919 | bool WantsCompletion() override { return true; } |
920 | |
921 | void |
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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
928 | searcher: nullptr); |
929 | } |
930 | |
931 | protected: |
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(in_string: "'settings append' takes more arguments" ); |
940 | return; |
941 | } |
942 | |
943 | const char *var_name = cmd_args.GetArgumentAtIndex(idx: 0); |
944 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
945 | result.AppendError(in_string: "'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(Separator: var_name).second.trim(); |
956 | |
957 | Status error(GetDebugger().SetPropertyValue( |
958 | exe_ctx: &m_exe_ctx, op: eVarSetOperationAppend, property_path: var_name, value: var_value)); |
959 | if (error.Fail()) { |
960 | result.AppendError(in_string: 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: |
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(arg_type: eArgTypeSettingVariableName); |
977 | } |
978 | |
979 | ~CommandObjectSettingsClear() override = default; |
980 | |
981 | void |
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 | interpreter&: GetCommandInterpreter(), completion_mask: lldb::eSettingsNameCompletion, request, |
988 | searcher: nullptr); |
989 | } |
990 | |
991 | Options *GetOptions() override { return &m_options; } |
992 | |
993 | class CommandOptions : public Options { |
994 | public: |
995 | CommandOptions() = default; |
996 | |
997 | ~CommandOptions() override = default; |
998 | |
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 | |
1012 | void OptionParsingStarting(ExecutionContext *execution_context) override { |
1013 | m_clear_all = false; |
1014 | } |
1015 | |
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: |
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(in_string: "'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(in_string: "'settings clear' takes exactly one argument" ); |
1039 | return; |
1040 | } |
1041 | |
1042 | const char *var_name = command.GetArgumentAtIndex(idx: 0); |
1043 | if ((var_name == nullptr) || (var_name[0] == '\0')) { |
1044 | result.AppendError(in_string: "'settings clear' command requires a valid variable " |
1045 | "name; No value supplied" ); |
1046 | return; |
1047 | } |
1048 | |
1049 | Status error(GetDebugger().SetPropertyValue( |
1050 | exe_ctx: &m_exe_ctx, op: eVarSetOperationClear, property_path: var_name, value: llvm::StringRef())); |
1051 | if (error.Fail()) { |
1052 | result.AppendError(in_string: error.AsCString()); |
1053 | } |
1054 | } |
1055 | |
1056 | private: |
1057 | CommandOptions m_options; |
1058 | }; |
1059 | |
1060 | // CommandObjectMultiwordSettings |
1061 | |
1062 | CommandObjectMultiwordSettings::CommandObjectMultiwordSettings( |
1063 | CommandInterpreter &interpreter) |
1064 | : CommandObjectMultiword(interpreter, "settings" , |
1065 | "Commands for managing LLDB settings." , |
1066 | "settings <subcommand> [<command-options>]" ) { |
1067 | LoadSubCommand(cmd_name: "set" , |
1068 | command_obj: CommandObjectSP(new CommandObjectSettingsSet(interpreter))); |
1069 | LoadSubCommand(cmd_name: "show" , |
1070 | command_obj: CommandObjectSP(new CommandObjectSettingsShow(interpreter))); |
1071 | LoadSubCommand(cmd_name: "list" , |
1072 | command_obj: CommandObjectSP(new CommandObjectSettingsList(interpreter))); |
1073 | LoadSubCommand(cmd_name: "remove" , |
1074 | command_obj: CommandObjectSP(new CommandObjectSettingsRemove(interpreter))); |
1075 | LoadSubCommand(cmd_name: "replace" , command_obj: CommandObjectSP( |
1076 | new CommandObjectSettingsReplace(interpreter))); |
1077 | LoadSubCommand( |
1078 | cmd_name: "insert-before" , |
1079 | command_obj: CommandObjectSP(new CommandObjectSettingsInsertBefore(interpreter))); |
1080 | LoadSubCommand( |
1081 | cmd_name: "insert-after" , |
1082 | command_obj: CommandObjectSP(new CommandObjectSettingsInsertAfter(interpreter))); |
1083 | LoadSubCommand(cmd_name: "append" , |
1084 | command_obj: CommandObjectSP(new CommandObjectSettingsAppend(interpreter))); |
1085 | LoadSubCommand(cmd_name: "clear" , |
1086 | command_obj: CommandObjectSP(new CommandObjectSettingsClear(interpreter))); |
1087 | LoadSubCommand(cmd_name: "write" , |
1088 | command_obj: CommandObjectSP(new CommandObjectSettingsWrite(interpreter))); |
1089 | LoadSubCommand(cmd_name: "read" , |
1090 | command_obj: CommandObjectSP(new CommandObjectSettingsRead(interpreter))); |
1091 | } |
1092 | |
1093 | CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings() = default; |
1094 | |