1//===-- CommandObjectType.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 "CommandObjectType.h"
10
11#include "lldb/Core/Debugger.h"
12#include "lldb/Core/IOHandler.h"
13#include "lldb/DataFormatters/DataVisualization.h"
14#include "lldb/DataFormatters/FormatClasses.h"
15#include "lldb/Host/Config.h"
16#include "lldb/Host/OptionParser.h"
17#include "lldb/Interpreter/CommandInterpreter.h"
18#include "lldb/Interpreter/CommandObject.h"
19#include "lldb/Interpreter/CommandOptionArgumentTable.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Interpreter/OptionArgParser.h"
22#include "lldb/Interpreter/OptionGroupFormat.h"
23#include "lldb/Interpreter/OptionValueBoolean.h"
24#include "lldb/Interpreter/OptionValueLanguage.h"
25#include "lldb/Interpreter/OptionValueString.h"
26#include "lldb/Interpreter/Options.h"
27#include "lldb/Symbol/Symbol.h"
28#include "lldb/Target/Language.h"
29#include "lldb/Target/StackFrame.h"
30#include "lldb/Target/Target.h"
31#include "lldb/Target/Thread.h"
32#include "lldb/Utility/ConstString.h"
33#include "lldb/Utility/RegularExpression.h"
34#include "lldb/Utility/StringList.h"
35
36#include "llvm/ADT/STLExtras.h"
37
38#include <algorithm>
39#include <functional>
40#include <memory>
41
42using namespace lldb;
43using namespace lldb_private;
44
45class ScriptAddOptions {
46public:
47 TypeSummaryImpl::Flags m_flags;
48 StringList m_target_types;
49 FormatterMatchType m_match_type;
50 ConstString m_name;
51 std::string m_category;
52
53 ScriptAddOptions(const TypeSummaryImpl::Flags &flags,
54 FormatterMatchType match_type, ConstString name,
55 std::string catg)
56 : m_flags(flags), m_match_type(match_type), m_name(name),
57 m_category(catg) {}
58
59 typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
60};
61
62class SynthAddOptions {
63public:
64 bool m_skip_pointers;
65 bool m_skip_references;
66 bool m_cascade;
67 FormatterMatchType m_match_type;
68 StringList m_target_types;
69 std::string m_category;
70
71 SynthAddOptions(bool sptr, bool sref, bool casc,
72 FormatterMatchType match_type, std::string catg)
73 : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
74 m_match_type(match_type), m_category(catg) {}
75
76 typedef std::shared_ptr<SynthAddOptions> SharedPointer;
77};
78
79static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
80 CommandReturnObject &result) {
81 if (command.empty())
82 return false;
83
84 for (auto entry : llvm::enumerate(First: command.entries().drop_back())) {
85 if (entry.value().ref() != "unsigned")
86 continue;
87 auto next = command.entries()[entry.index() + 1].ref();
88 if (next == "int" || next == "short" || next == "char" || next == "long") {
89 result.AppendWarningWithFormat(
90 format: "unsigned %s being treated as two types. if you meant the combined "
91 "type "
92 "name use quotes, as in \"unsigned %s\"\n",
93 next.str().c_str(), next.str().c_str());
94 return true;
95 }
96 }
97 return false;
98}
99
100const char *FormatCategoryToString(FormatCategoryItem item, bool long_name) {
101 switch (item) {
102 case eFormatCategoryItemSummary:
103 return "summary";
104 case eFormatCategoryItemFilter:
105 return "filter";
106 case eFormatCategoryItemSynth:
107 if (long_name)
108 return "synthetic child provider";
109 return "synthetic";
110 case eFormatCategoryItemFormat:
111 return "format";
112 }
113 llvm_unreachable("Fully covered switch above!");
114}
115
116#define LLDB_OPTIONS_type_summary_add
117#include "CommandOptions.inc"
118
119class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
120 public IOHandlerDelegateMultiline {
121private:
122 class CommandOptions : public Options {
123 public:
124 CommandOptions(CommandInterpreter &interpreter) {}
125
126 ~CommandOptions() override = default;
127
128 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
129 ExecutionContext *execution_context) override;
130
131 void OptionParsingStarting(ExecutionContext *execution_context) override;
132
133 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
134 return llvm::ArrayRef(g_type_summary_add_options);
135 }
136
137 // Instance variables to hold the values for command options.
138
139 TypeSummaryImpl::Flags m_flags;
140 FormatterMatchType m_match_type = eFormatterMatchExact;
141 std::string m_format_string;
142 ConstString m_name;
143 std::string m_python_script;
144 std::string m_python_function;
145 bool m_is_add_script = false;
146 std::string m_category;
147 };
148
149 CommandOptions m_options;
150
151 Options *GetOptions() override { return &m_options; }
152
153 bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
154
155 bool Execute_StringSummary(Args &command, CommandReturnObject &result);
156
157public:
158 CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
159
160 ~CommandObjectTypeSummaryAdd() override = default;
161
162 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
163 static const char *g_summary_addreader_instructions =
164 "Enter your Python command(s). Type 'DONE' to end.\n"
165 "def function (valobj,internal_dict):\n"
166 " \"\"\"valobj: an SBValue which you want to provide a summary "
167 "for\n"
168 " internal_dict: an LLDB support object not to be used\"\"\"\n";
169
170 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
171 if (output_sp && interactive) {
172 output_sp->PutCString(cstr: g_summary_addreader_instructions);
173 output_sp->Flush();
174 }
175 }
176
177 void IOHandlerInputComplete(IOHandler &io_handler,
178 std::string &data) override {
179 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
180
181#if LLDB_ENABLE_PYTHON
182 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
183 if (interpreter) {
184 StringList lines;
185 lines.SplitIntoLines(lines: data);
186 if (lines.GetSize() > 0) {
187 ScriptAddOptions *options_ptr =
188 ((ScriptAddOptions *)io_handler.GetUserData());
189 if (options_ptr) {
190 ScriptAddOptions::SharedPointer options(
191 options_ptr); // this will ensure that we get rid of the pointer
192 // when going out of scope
193
194 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
195 if (interpreter) {
196 std::string funct_name_str;
197 if (interpreter->GenerateTypeScriptFunction(input&: lines,
198 output&: funct_name_str)) {
199 if (funct_name_str.empty()) {
200 error_sp->Printf(format: "unable to obtain a valid function name from "
201 "the script interpreter.\n");
202 error_sp->Flush();
203 } else {
204 // now I have a valid function name, let's add this as script
205 // for every type in the list
206
207 TypeSummaryImplSP script_format;
208 script_format = std::make_shared<ScriptSummaryFormat>(
209 args&: options->m_flags, args: funct_name_str.c_str(),
210 args: lines.CopyList(item_preamble: " ").c_str());
211
212 Status error;
213
214 for (const std::string &type_name : options->m_target_types) {
215 AddSummary(type_name: ConstString(type_name), entry: script_format,
216 match_type: options->m_match_type, category: options->m_category,
217 error: &error);
218 if (error.Fail()) {
219 error_sp->Printf(format: "error: %s", error.AsCString());
220 error_sp->Flush();
221 }
222 }
223
224 if (options->m_name) {
225 CommandObjectTypeSummaryAdd::AddNamedSummary(
226 summary_name: options->m_name, entry: script_format, error: &error);
227 if (error.Fail()) {
228 CommandObjectTypeSummaryAdd::AddNamedSummary(
229 summary_name: options->m_name, entry: script_format, error: &error);
230 if (error.Fail()) {
231 error_sp->Printf(format: "error: %s", error.AsCString());
232 error_sp->Flush();
233 }
234 } else {
235 error_sp->Printf(format: "error: %s", error.AsCString());
236 error_sp->Flush();
237 }
238 } else {
239 if (error.AsCString()) {
240 error_sp->Printf(format: "error: %s", error.AsCString());
241 error_sp->Flush();
242 }
243 }
244 }
245 } else {
246 error_sp->Printf(format: "error: unable to generate a function.\n");
247 error_sp->Flush();
248 }
249 } else {
250 error_sp->Printf(format: "error: no script interpreter.\n");
251 error_sp->Flush();
252 }
253 } else {
254 error_sp->Printf(format: "error: internal synchronization information "
255 "missing or invalid.\n");
256 error_sp->Flush();
257 }
258 } else {
259 error_sp->Printf(format: "error: empty function, didn't add python command.\n");
260 error_sp->Flush();
261 }
262 } else {
263 error_sp->Printf(
264 format: "error: script interpreter missing, didn't add python command.\n");
265 error_sp->Flush();
266 }
267#endif
268 io_handler.SetIsDone(true);
269 }
270
271 bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
272 FormatterMatchType match_type, std::string category,
273 Status *error = nullptr);
274
275 bool AddNamedSummary(ConstString summary_name, lldb::TypeSummaryImplSP entry,
276 Status *error = nullptr);
277
278protected:
279 void DoExecute(Args &command, CommandReturnObject &result) override;
280};
281
282static const char *g_synth_addreader_instructions =
283 "Enter your Python command(s). Type 'DONE' to end.\n"
284 "You must define a Python class with these methods:\n"
285 " def __init__(self, valobj, internal_dict):\n"
286 " def num_children(self):\n"
287 " def get_child_at_index(self, index):\n"
288 " def get_child_index(self, name):\n"
289 " def update(self):\n"
290 " '''Optional'''\n"
291 "class synthProvider:\n";
292
293#define LLDB_OPTIONS_type_synth_add
294#include "CommandOptions.inc"
295
296class CommandObjectTypeSynthAdd : public CommandObjectParsed,
297 public IOHandlerDelegateMultiline {
298private:
299 class CommandOptions : public Options {
300 public:
301 CommandOptions() = default;
302
303 ~CommandOptions() override = default;
304
305 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
306 ExecutionContext *execution_context) override {
307 Status error;
308 const int short_option = m_getopt_table[option_idx].val;
309 bool success;
310
311 switch (short_option) {
312 case 'C':
313 m_cascade = OptionArgParser::ToBoolean(s: option_arg, fail_value: true, success_ptr: &success);
314 if (!success)
315 error.SetErrorStringWithFormat("invalid value for cascade: %s",
316 option_arg.str().c_str());
317 break;
318 case 'P':
319 handwrite_python = true;
320 break;
321 case 'l':
322 m_class_name = std::string(option_arg);
323 is_class_based = true;
324 break;
325 case 'p':
326 m_skip_pointers = true;
327 break;
328 case 'r':
329 m_skip_references = true;
330 break;
331 case 'w':
332 m_category = std::string(option_arg);
333 break;
334 case 'x':
335 if (m_match_type == eFormatterMatchCallback)
336 error.SetErrorString(
337 "can't use --regex and --recognizer-function at the same time");
338 else
339 m_match_type = eFormatterMatchRegex;
340 break;
341 case '\x01':
342 if (m_match_type == eFormatterMatchRegex)
343 error.SetErrorString(
344 "can't use --regex and --recognizer-function at the same time");
345 else
346 m_match_type = eFormatterMatchCallback;
347 break;
348 default:
349 llvm_unreachable("Unimplemented option");
350 }
351
352 return error;
353 }
354
355 void OptionParsingStarting(ExecutionContext *execution_context) override {
356 m_cascade = true;
357 m_class_name = "";
358 m_skip_pointers = false;
359 m_skip_references = false;
360 m_category = "default";
361 is_class_based = false;
362 handwrite_python = false;
363 m_match_type = eFormatterMatchExact;
364 }
365
366 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
367 return llvm::ArrayRef(g_type_synth_add_options);
368 }
369
370 // Instance variables to hold the values for command options.
371
372 bool m_cascade;
373 bool m_skip_references;
374 bool m_skip_pointers;
375 std::string m_class_name;
376 bool m_input_python;
377 std::string m_category;
378 bool is_class_based;
379 bool handwrite_python;
380 FormatterMatchType m_match_type;
381 };
382
383 CommandOptions m_options;
384
385 Options *GetOptions() override { return &m_options; }
386
387 bool Execute_HandwritePython(Args &command, CommandReturnObject &result);
388
389 bool Execute_PythonClass(Args &command, CommandReturnObject &result);
390
391protected:
392 void DoExecute(Args &command, CommandReturnObject &result) override {
393 WarnOnPotentialUnquotedUnsignedType(command, result);
394
395 if (m_options.handwrite_python)
396 Execute_HandwritePython(command, result);
397 else if (m_options.is_class_based)
398 Execute_PythonClass(command, result);
399 else {
400 result.AppendError(in_string: "must either provide a children list, a Python class "
401 "name, or use -P and type a Python class "
402 "line-by-line");
403 }
404 }
405
406 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
407 StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
408 if (output_sp && interactive) {
409 output_sp->PutCString(cstr: g_synth_addreader_instructions);
410 output_sp->Flush();
411 }
412 }
413
414 void IOHandlerInputComplete(IOHandler &io_handler,
415 std::string &data) override {
416 StreamFileSP error_sp = io_handler.GetErrorStreamFileSP();
417
418#if LLDB_ENABLE_PYTHON
419 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
420 if (interpreter) {
421 StringList lines;
422 lines.SplitIntoLines(lines: data);
423 if (lines.GetSize() > 0) {
424 SynthAddOptions *options_ptr =
425 ((SynthAddOptions *)io_handler.GetUserData());
426 if (options_ptr) {
427 SynthAddOptions::SharedPointer options(
428 options_ptr); // this will ensure that we get rid of the pointer
429 // when going out of scope
430
431 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
432 if (interpreter) {
433 std::string class_name_str;
434 if (interpreter->GenerateTypeSynthClass(input&: lines, output&: class_name_str)) {
435 if (class_name_str.empty()) {
436 error_sp->Printf(
437 format: "error: unable to obtain a proper name for the class.\n");
438 error_sp->Flush();
439 } else {
440 // everything should be fine now, let's add the synth provider
441 // class
442
443 SyntheticChildrenSP synth_provider;
444 synth_provider = std::make_shared<ScriptedSyntheticChildren>(
445 SyntheticChildren::Flags()
446 .SetCascades(options->m_cascade)
447 .SetSkipPointers(options->m_skip_pointers)
448 .SetSkipReferences(options->m_skip_references),
449 class_name_str.c_str());
450
451 lldb::TypeCategoryImplSP category;
452 DataVisualization::Categories::GetCategory(
453 category: ConstString(options->m_category.c_str()), entry&: category);
454
455 Status error;
456
457 for (const std::string &type_name : options->m_target_types) {
458 if (!type_name.empty()) {
459 if (AddSynth(ConstString(type_name), synth_provider,
460 options->m_match_type, options->m_category,
461 &error)) {
462 error_sp->Printf("error: %s\n", error.AsCString());
463 error_sp->Flush();
464 break;
465 }
466 } else {
467 error_sp->Printf("error: invalid type name.\n");
468 error_sp->Flush();
469 break;
470 }
471 }
472 }
473 } else {
474 error_sp->Printf(format: "error: unable to generate a class.\n");
475 error_sp->Flush();
476 }
477 } else {
478 error_sp->Printf(format: "error: no script interpreter.\n");
479 error_sp->Flush();
480 }
481 } else {
482 error_sp->Printf(format: "error: internal synchronization data missing.\n");
483 error_sp->Flush();
484 }
485 } else {
486 error_sp->Printf(format: "error: empty function, didn't add python command.\n");
487 error_sp->Flush();
488 }
489 } else {
490 error_sp->Printf(
491 format: "error: script interpreter missing, didn't add python command.\n");
492 error_sp->Flush();
493 }
494
495#endif
496 io_handler.SetIsDone(true);
497 }
498
499public:
500 CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
501
502 ~CommandObjectTypeSynthAdd() override = default;
503
504 bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
505 FormatterMatchType match_type, std::string category_name,
506 Status *error);
507};
508
509// CommandObjectTypeFormatAdd
510
511#define LLDB_OPTIONS_type_format_add
512#include "CommandOptions.inc"
513
514class CommandObjectTypeFormatAdd : public CommandObjectParsed {
515private:
516 class CommandOptions : public OptionGroup {
517 public:
518 CommandOptions() = default;
519
520 ~CommandOptions() override = default;
521
522 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
523 return llvm::ArrayRef(g_type_format_add_options);
524 }
525
526 void OptionParsingStarting(ExecutionContext *execution_context) override {
527 m_cascade = true;
528 m_skip_pointers = false;
529 m_skip_references = false;
530 m_regex = false;
531 m_category.assign(s: "default");
532 m_custom_type_name.clear();
533 }
534
535 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
536 ExecutionContext *execution_context) override {
537 Status error;
538 const int short_option =
539 g_type_format_add_options[option_idx].short_option;
540 bool success;
541
542 switch (short_option) {
543 case 'C':
544 m_cascade = OptionArgParser::ToBoolean(s: option_value, fail_value: true, success_ptr: &success);
545 if (!success)
546 error.SetErrorStringWithFormat("invalid value for cascade: %s",
547 option_value.str().c_str());
548 break;
549 case 'p':
550 m_skip_pointers = true;
551 break;
552 case 'w':
553 m_category.assign(str: std::string(option_value));
554 break;
555 case 'r':
556 m_skip_references = true;
557 break;
558 case 'x':
559 m_regex = true;
560 break;
561 case 't':
562 m_custom_type_name.assign(str: std::string(option_value));
563 break;
564 default:
565 llvm_unreachable("Unimplemented option");
566 }
567
568 return error;
569 }
570
571 // Instance variables to hold the values for command options.
572
573 bool m_cascade;
574 bool m_skip_references;
575 bool m_skip_pointers;
576 bool m_regex;
577 std::string m_category;
578 std::string m_custom_type_name;
579 };
580
581 OptionGroupOptions m_option_group;
582 OptionGroupFormat m_format_options;
583 CommandOptions m_command_options;
584
585 Options *GetOptions() override { return &m_option_group; }
586
587public:
588 CommandObjectTypeFormatAdd(CommandInterpreter &interpreter)
589 : CommandObjectParsed(interpreter, "type format add",
590 "Add a new formatting style for a type.", nullptr),
591 m_format_options(eFormatInvalid) {
592 CommandArgumentEntry type_arg;
593 CommandArgumentData type_style_arg;
594
595 type_style_arg.arg_type = eArgTypeName;
596 type_style_arg.arg_repetition = eArgRepeatPlus;
597
598 type_arg.push_back(x: type_style_arg);
599
600 m_arguments.push_back(x: type_arg);
601
602 SetHelpLong(
603 R"(
604The following examples of 'type format add' refer to this code snippet for context:
605
606 typedef int Aint;
607 typedef float Afloat;
608 typedef Aint Bint;
609 typedef Afloat Bfloat;
610
611 Aint ix = 5;
612 Bint iy = 5;
613
614 Afloat fx = 3.14;
615 BFloat fy = 3.14;
616
617Adding default formatting:
618
619(lldb) type format add -f hex AInt
620(lldb) frame variable iy
621
622)"
623 " Produces hexadecimal display of iy, because no formatter is available for Bint and \
624the one for Aint is used instead."
625 R"(
626
627To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
628
629
630(lldb) type format add -f hex -C no AInt
631
632Similar reasoning applies to this:
633
634(lldb) type format add -f hex -C no float -p
635
636)"
637 " All float values and float references are now formatted as hexadecimal, but not \
638pointers to floats. Nor will it change the default display for Afloat and Bfloat objects.");
639
640 // Add the "--format" to all options groups
641 m_option_group.Append(group: &m_format_options,
642 src_mask: OptionGroupFormat::OPTION_GROUP_FORMAT,
643 LLDB_OPT_SET_1);
644 m_option_group.Append(group: &m_command_options);
645 m_option_group.Finalize();
646 }
647
648 ~CommandObjectTypeFormatAdd() override = default;
649
650protected:
651 void DoExecute(Args &command, CommandReturnObject &result) override {
652 const size_t argc = command.GetArgumentCount();
653
654 if (argc < 1) {
655 result.AppendErrorWithFormat(format: "%s takes one or more args.\n",
656 m_cmd_name.c_str());
657 return;
658 }
659
660 const Format format = m_format_options.GetFormat();
661 if (format == eFormatInvalid &&
662 m_command_options.m_custom_type_name.empty()) {
663 result.AppendErrorWithFormat(format: "%s needs a valid format.\n",
664 m_cmd_name.c_str());
665 return;
666 }
667
668 TypeFormatImplSP entry;
669
670 if (m_command_options.m_custom_type_name.empty())
671 entry = std::make_shared<TypeFormatImpl_Format>(
672 args: format, args&: TypeFormatImpl::Flags()
673 .SetCascades(m_command_options.m_cascade)
674 .SetSkipPointers(m_command_options.m_skip_pointers)
675 .SetSkipReferences(m_command_options.m_skip_references));
676 else
677 entry = std::make_shared<TypeFormatImpl_EnumType>(
678 args: ConstString(m_command_options.m_custom_type_name.c_str()),
679 args&: TypeFormatImpl::Flags()
680 .SetCascades(m_command_options.m_cascade)
681 .SetSkipPointers(m_command_options.m_skip_pointers)
682 .SetSkipReferences(m_command_options.m_skip_references));
683
684 // now I have a valid format, let's add it to every type
685
686 TypeCategoryImplSP category_sp;
687 DataVisualization::Categories::GetCategory(
688 category: ConstString(m_command_options.m_category), entry&: category_sp);
689 if (!category_sp)
690 return;
691
692 WarnOnPotentialUnquotedUnsignedType(command, result);
693
694 for (auto &arg_entry : command.entries()) {
695 if (arg_entry.ref().empty()) {
696 result.AppendError(in_string: "empty typenames not allowed");
697 return;
698 }
699
700 FormatterMatchType match_type = eFormatterMatchExact;
701 if (m_command_options.m_regex) {
702 match_type = eFormatterMatchRegex;
703 RegularExpression typeRX(arg_entry.ref());
704 if (!typeRX.IsValid()) {
705 result.AppendError(
706 in_string: "regex format error (maybe this is not really a regex?)");
707 return;
708 }
709 }
710 category_sp->AddTypeFormat(name: arg_entry.ref(), match_type, format_sp: entry);
711 }
712
713 result.SetStatus(eReturnStatusSuccessFinishNoResult);
714 }
715};
716
717#define LLDB_OPTIONS_type_formatter_delete
718#include "CommandOptions.inc"
719
720class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
721protected:
722 class CommandOptions : public Options {
723 public:
724 CommandOptions() = default;
725
726 ~CommandOptions() override = default;
727
728 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
729 ExecutionContext *execution_context) override {
730 Status error;
731 const int short_option = m_getopt_table[option_idx].val;
732
733 switch (short_option) {
734 case 'a':
735 m_delete_all = true;
736 break;
737 case 'w':
738 m_category = std::string(option_arg);
739 break;
740 case 'l':
741 m_language = Language::GetLanguageTypeFromString(string: option_arg);
742 break;
743 default:
744 llvm_unreachable("Unimplemented option");
745 }
746
747 return error;
748 }
749
750 void OptionParsingStarting(ExecutionContext *execution_context) override {
751 m_delete_all = false;
752 m_category = "default";
753 m_language = lldb::eLanguageTypeUnknown;
754 }
755
756 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
757 return llvm::ArrayRef(g_type_formatter_delete_options);
758 }
759
760 // Instance variables to hold the values for command options.
761
762 bool m_delete_all;
763 std::string m_category;
764 lldb::LanguageType m_language;
765 };
766
767 CommandOptions m_options;
768 FormatCategoryItem m_formatter_kind;
769
770 Options *GetOptions() override { return &m_options; }
771
772 static constexpr const char *g_short_help_template =
773 "Delete an existing %s for a type.";
774
775 static constexpr const char *g_long_help_template =
776 "Delete an existing %s for a type. Unless you specify a "
777 "specific category or all categories, only the "
778 "'default' category is searched. The names must be exactly as "
779 "shown in the 'type %s list' output";
780
781public:
782 CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter,
783 FormatCategoryItem formatter_kind)
784 : CommandObjectParsed(interpreter,
785 FormatCategoryToString(item: formatter_kind, long_name: false)),
786 m_formatter_kind(formatter_kind) {
787 CommandArgumentEntry type_arg;
788 CommandArgumentData type_style_arg;
789
790 type_style_arg.arg_type = eArgTypeName;
791 type_style_arg.arg_repetition = eArgRepeatPlain;
792
793 type_arg.push_back(x: type_style_arg);
794
795 m_arguments.push_back(x: type_arg);
796
797 const char *kind = FormatCategoryToString(item: formatter_kind, long_name: true);
798 const char *short_kind = FormatCategoryToString(item: formatter_kind, long_name: false);
799
800 StreamString s;
801 s.Printf(format: g_short_help_template, kind);
802 SetHelp(s.GetData());
803 s.Clear();
804 s.Printf(format: g_long_help_template, kind, short_kind);
805 SetHelpLong(s.GetData());
806 s.Clear();
807 s.Printf(format: "type %s delete", short_kind);
808 SetCommandName(s.GetData());
809 }
810
811 ~CommandObjectTypeFormatterDelete() override = default;
812
813 void
814 HandleArgumentCompletion(CompletionRequest &request,
815 OptionElementVector &opt_element_vector) override {
816 if (request.GetCursorIndex())
817 return;
818
819 DataVisualization::Categories::ForEach(
820 [this, &request](const lldb::TypeCategoryImplSP &category_sp) {
821 category_sp->AutoComplete(request, items: m_formatter_kind);
822 return true;
823 });
824 }
825
826protected:
827 virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
828
829 void DoExecute(Args &command, CommandReturnObject &result) override {
830 const size_t argc = command.GetArgumentCount();
831
832 if (argc != 1) {
833 result.AppendErrorWithFormat(format: "%s takes 1 arg.\n", m_cmd_name.c_str());
834 return;
835 }
836
837 const char *typeA = command.GetArgumentAtIndex(idx: 0);
838 ConstString typeCS(typeA);
839
840 if (!typeCS) {
841 result.AppendError(in_string: "empty typenames not allowed");
842 return;
843 }
844
845 if (m_options.m_delete_all) {
846 DataVisualization::Categories::ForEach(
847 [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool {
848 category_sp->Delete(name: typeCS, items: m_formatter_kind);
849 return true;
850 });
851 result.SetStatus(eReturnStatusSuccessFinishNoResult);
852 return;
853 }
854
855 bool delete_category = false;
856 bool extra_deletion = false;
857
858 if (m_options.m_language != lldb::eLanguageTypeUnknown) {
859 lldb::TypeCategoryImplSP category;
860 DataVisualization::Categories::GetCategory(language: m_options.m_language,
861 entry&: category);
862 if (category)
863 delete_category = category->Delete(name: typeCS, items: m_formatter_kind);
864 extra_deletion = FormatterSpecificDeletion(typeCS);
865 } else {
866 lldb::TypeCategoryImplSP category;
867 DataVisualization::Categories::GetCategory(
868 category: ConstString(m_options.m_category.c_str()), entry&: category);
869 if (category)
870 delete_category = category->Delete(name: typeCS, items: m_formatter_kind);
871 extra_deletion = FormatterSpecificDeletion(typeCS);
872 }
873
874 if (delete_category || extra_deletion) {
875 result.SetStatus(eReturnStatusSuccessFinishNoResult);
876 } else {
877 result.AppendErrorWithFormat(format: "no custom formatter for %s.\n", typeA);
878 }
879 }
880};
881
882#define LLDB_OPTIONS_type_formatter_clear
883#include "CommandOptions.inc"
884
885class CommandObjectTypeFormatterClear : public CommandObjectParsed {
886private:
887 class CommandOptions : public Options {
888 public:
889 CommandOptions() = default;
890
891 ~CommandOptions() override = default;
892
893 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
894 ExecutionContext *execution_context) override {
895 Status error;
896 const int short_option = m_getopt_table[option_idx].val;
897
898 switch (short_option) {
899 case 'a':
900 m_delete_all = true;
901 break;
902 default:
903 llvm_unreachable("Unimplemented option");
904 }
905
906 return error;
907 }
908
909 void OptionParsingStarting(ExecutionContext *execution_context) override {
910 m_delete_all = false;
911 }
912
913 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
914 return llvm::ArrayRef(g_type_formatter_clear_options);
915 }
916
917 // Instance variables to hold the values for command options.
918 bool m_delete_all;
919 };
920
921 CommandOptions m_options;
922 FormatCategoryItem m_formatter_kind;
923
924 Options *GetOptions() override { return &m_options; }
925
926public:
927 CommandObjectTypeFormatterClear(CommandInterpreter &interpreter,
928 FormatCategoryItem formatter_kind,
929 const char *name, const char *help)
930 : CommandObjectParsed(interpreter, name, help, nullptr),
931 m_formatter_kind(formatter_kind) {
932 CommandArgumentData category_arg{eArgTypeName, eArgRepeatOptional};
933 m_arguments.push_back(x: {category_arg});
934 }
935
936 ~CommandObjectTypeFormatterClear() override = default;
937
938protected:
939 virtual void FormatterSpecificDeletion() {}
940
941 void DoExecute(Args &command, CommandReturnObject &result) override {
942 if (m_options.m_delete_all) {
943 DataVisualization::Categories::ForEach(
944 callback: [this](const TypeCategoryImplSP &category_sp) -> bool {
945 category_sp->Clear(items: m_formatter_kind);
946 return true;
947 });
948 } else {
949 lldb::TypeCategoryImplSP category;
950 if (command.GetArgumentCount() > 0) {
951 const char *cat_name = command.GetArgumentAtIndex(idx: 0);
952 ConstString cat_nameCS(cat_name);
953 DataVisualization::Categories::GetCategory(category: cat_nameCS, entry&: category);
954 } else {
955 DataVisualization::Categories::GetCategory(category: ConstString(nullptr),
956 entry&: category);
957 }
958 category->Clear(items: m_formatter_kind);
959 }
960
961 FormatterSpecificDeletion();
962
963 result.SetStatus(eReturnStatusSuccessFinishResult);
964 }
965};
966
967// CommandObjectTypeFormatDelete
968
969class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete {
970public:
971 CommandObjectTypeFormatDelete(CommandInterpreter &interpreter)
972 : CommandObjectTypeFormatterDelete(
973 interpreter, eFormatCategoryItemFormat) {}
974
975 ~CommandObjectTypeFormatDelete() override = default;
976};
977
978// CommandObjectTypeFormatClear
979
980class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear {
981public:
982 CommandObjectTypeFormatClear(CommandInterpreter &interpreter)
983 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFormat,
984 "type format clear",
985 "Delete all existing format styles.") {}
986};
987
988#define LLDB_OPTIONS_type_formatter_list
989#include "CommandOptions.inc"
990
991template <typename FormatterType>
992class CommandObjectTypeFormatterList : public CommandObjectParsed {
993 typedef typename FormatterType::SharedPointer FormatterSharedPointer;
994
995 class CommandOptions : public Options {
996 public:
997 CommandOptions()
998 : Options(), m_category_regex("", ""),
999 m_category_language(lldb::eLanguageTypeUnknown,
1000 lldb::eLanguageTypeUnknown) {}
1001
1002 ~CommandOptions() override = default;
1003
1004 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1005 ExecutionContext *execution_context) override {
1006 Status error;
1007 const int short_option = m_getopt_table[option_idx].val;
1008 switch (short_option) {
1009 case 'w':
1010 m_category_regex.SetCurrentValue(option_arg);
1011 m_category_regex.SetOptionWasSet();
1012 break;
1013 case 'l':
1014 error = m_category_language.SetValueFromString(value: option_arg);
1015 if (error.Success())
1016 m_category_language.SetOptionWasSet();
1017 break;
1018 default:
1019 llvm_unreachable("Unimplemented option");
1020 }
1021
1022 return error;
1023 }
1024
1025 void OptionParsingStarting(ExecutionContext *execution_context) override {
1026 m_category_regex.Clear();
1027 m_category_language.Clear();
1028 }
1029
1030 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1031 return llvm::ArrayRef(g_type_formatter_list_options);
1032 }
1033
1034 // Instance variables to hold the values for command options.
1035
1036 OptionValueString m_category_regex;
1037 OptionValueLanguage m_category_language;
1038 };
1039
1040 CommandOptions m_options;
1041
1042 Options *GetOptions() override { return &m_options; }
1043
1044public:
1045 CommandObjectTypeFormatterList(CommandInterpreter &interpreter,
1046 const char *name, const char *help)
1047 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() {
1048 CommandArgumentEntry type_arg;
1049 CommandArgumentData type_style_arg;
1050
1051 type_style_arg.arg_type = eArgTypeName;
1052 type_style_arg.arg_repetition = eArgRepeatOptional;
1053
1054 type_arg.push_back(x: type_style_arg);
1055
1056 m_arguments.push_back(type_arg);
1057 }
1058
1059 ~CommandObjectTypeFormatterList() override = default;
1060
1061protected:
1062 virtual bool FormatterSpecificList(CommandReturnObject &result) {
1063 return false;
1064 }
1065
1066 static bool ShouldListItem(llvm::StringRef s, RegularExpression *regex) {
1067 // If we have a regex, it can match two kinds of results:
1068 // - An item created with that same regex string (exact string match), so
1069 // the user can list it using the same string it used at creation time.
1070 // - Items that match the regex.
1071 // No regex means list everything.
1072 return regex == nullptr || s == regex->GetText() || regex->Execute(string: s);
1073 }
1074
1075 void DoExecute(Args &command, CommandReturnObject &result) override {
1076 const size_t argc = command.GetArgumentCount();
1077
1078 std::unique_ptr<RegularExpression> category_regex;
1079 std::unique_ptr<RegularExpression> formatter_regex;
1080
1081 if (m_options.m_category_regex.OptionWasSet()) {
1082 category_regex = std::make_unique<RegularExpression>(
1083 m_options.m_category_regex.GetCurrentValueAsRef());
1084 if (!category_regex->IsValid()) {
1085 result.AppendErrorWithFormat(
1086 format: "syntax error in category regular expression '%s'",
1087 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str());
1088 return;
1089 }
1090 }
1091
1092 if (argc == 1) {
1093 const char *arg = command.GetArgumentAtIndex(idx: 0);
1094 formatter_regex = std::make_unique<RegularExpression>(arg);
1095 if (!formatter_regex->IsValid()) {
1096 result.AppendErrorWithFormat(format: "syntax error in regular expression '%s'",
1097 arg);
1098 return;
1099 }
1100 }
1101
1102 bool any_printed = false;
1103
1104 auto category_closure =
1105 [&result, &formatter_regex,
1106 &any_printed](const lldb::TypeCategoryImplSP &category) -> void {
1107 result.GetOutputStream().Printf(
1108 format: "-----------------------\nCategory: %s%s\n-----------------------\n",
1109 category->GetName(), category->IsEnabled() ? "" : " (disabled)");
1110
1111 TypeCategoryImpl::ForEachCallback<FormatterType> print_formatter =
1112 [&result, &formatter_regex,
1113 &any_printed](const TypeMatcher &type_matcher,
1114 const FormatterSharedPointer &format_sp) -> bool {
1115 if (ShouldListItem(s: type_matcher.GetMatchString().GetStringRef(),
1116 regex: formatter_regex.get())) {
1117 any_printed = true;
1118 result.GetOutputStream().Printf(
1119 format: "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1120 format_sp->GetDescription().c_str());
1121 }
1122 return true;
1123 };
1124 category->ForEach(print_formatter);
1125 };
1126
1127 if (m_options.m_category_language.OptionWasSet()) {
1128 lldb::TypeCategoryImplSP category_sp;
1129 DataVisualization::Categories::GetCategory(
1130 m_options.m_category_language.GetCurrentValue(), category_sp);
1131 if (category_sp)
1132 category_closure(category_sp);
1133 } else {
1134 DataVisualization::Categories::ForEach(
1135 callback: [&category_regex, &category_closure](
1136 const lldb::TypeCategoryImplSP &category) -> bool {
1137 if (ShouldListItem(s: category->GetName(), regex: category_regex.get())) {
1138 category_closure(category);
1139 }
1140 return true;
1141 });
1142
1143 any_printed = FormatterSpecificList(result) | any_printed;
1144 }
1145
1146 if (any_printed)
1147 result.SetStatus(eReturnStatusSuccessFinishResult);
1148 else {
1149 result.GetOutputStream().PutCString(cstr: "no matching results found.\n");
1150 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1151 }
1152 }
1153};
1154
1155// CommandObjectTypeFormatList
1156
1157class CommandObjectTypeFormatList
1158 : public CommandObjectTypeFormatterList<TypeFormatImpl> {
1159public:
1160 CommandObjectTypeFormatList(CommandInterpreter &interpreter)
1161 : CommandObjectTypeFormatterList(interpreter, "type format list",
1162 "Show a list of current formats.") {}
1163};
1164
1165Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
1166 uint32_t option_idx, llvm::StringRef option_arg,
1167 ExecutionContext *execution_context) {
1168 Status error;
1169 const int short_option = m_getopt_table[option_idx].val;
1170 bool success;
1171
1172 switch (short_option) {
1173 case 'C':
1174 m_flags.SetCascades(OptionArgParser::ToBoolean(s: option_arg, fail_value: true, success_ptr: &success));
1175 if (!success)
1176 error.SetErrorStringWithFormat("invalid value for cascade: %s",
1177 option_arg.str().c_str());
1178 break;
1179 case 'e':
1180 m_flags.SetDontShowChildren(false);
1181 break;
1182 case 'h':
1183 m_flags.SetHideEmptyAggregates(true);
1184 break;
1185 case 'v':
1186 m_flags.SetDontShowValue(true);
1187 break;
1188 case 'c':
1189 m_flags.SetShowMembersOneLiner(true);
1190 break;
1191 case 's':
1192 m_format_string = std::string(option_arg);
1193 break;
1194 case 'p':
1195 m_flags.SetSkipPointers(true);
1196 break;
1197 case 'r':
1198 m_flags.SetSkipReferences(true);
1199 break;
1200 case 'x':
1201 if (m_match_type == eFormatterMatchCallback)
1202 error.SetErrorString(
1203 "can't use --regex and --recognizer-function at the same time");
1204 else
1205 m_match_type = eFormatterMatchRegex;
1206 break;
1207 case '\x01':
1208 if (m_match_type == eFormatterMatchRegex)
1209 error.SetErrorString(
1210 "can't use --regex and --recognizer-function at the same time");
1211 else
1212 m_match_type = eFormatterMatchCallback;
1213 break;
1214 case 'n':
1215 m_name.SetString(option_arg);
1216 break;
1217 case 'o':
1218 m_python_script = std::string(option_arg);
1219 m_is_add_script = true;
1220 break;
1221 case 'F':
1222 m_python_function = std::string(option_arg);
1223 m_is_add_script = true;
1224 break;
1225 case 'P':
1226 m_is_add_script = true;
1227 break;
1228 case 'w':
1229 m_category = std::string(option_arg);
1230 break;
1231 case 'O':
1232 m_flags.SetHideItemNames(true);
1233 break;
1234 default:
1235 llvm_unreachable("Unimplemented option");
1236 }
1237
1238 return error;
1239}
1240
1241void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting(
1242 ExecutionContext *execution_context) {
1243 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
1244 m_flags.SetShowMembersOneLiner(false)
1245 .SetSkipPointers(false)
1246 .SetSkipReferences(false)
1247 .SetHideItemNames(false);
1248
1249 m_match_type = eFormatterMatchExact;
1250 m_name.Clear();
1251 m_python_script = "";
1252 m_python_function = "";
1253 m_format_string = "";
1254 m_is_add_script = false;
1255 m_category = "default";
1256}
1257
1258#if LLDB_ENABLE_PYTHON
1259
1260bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
1261 Args &command, CommandReturnObject &result) {
1262 const size_t argc = command.GetArgumentCount();
1263
1264 if (argc < 1 && !m_options.m_name) {
1265 result.AppendErrorWithFormat(format: "%s takes one or more args.\n",
1266 m_cmd_name.c_str());
1267 return false;
1268 }
1269
1270 TypeSummaryImplSP script_format;
1271
1272 if (!m_options.m_python_function
1273 .empty()) // we have a Python function ready to use
1274 {
1275 const char *funct_name = m_options.m_python_function.c_str();
1276 if (!funct_name || !funct_name[0]) {
1277 result.AppendError(in_string: "function name empty.\n");
1278 return false;
1279 }
1280
1281 std::string code =
1282 (" " + m_options.m_python_function + "(valobj,internal_dict)");
1283
1284 script_format = std::make_shared<ScriptSummaryFormat>(
1285 args&: m_options.m_flags, args&: funct_name, args: code.c_str());
1286
1287 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1288
1289 if (interpreter && !interpreter->CheckObjectExists(name: funct_name))
1290 result.AppendWarningWithFormat(
1291 format: "The provided function \"%s\" does not exist - "
1292 "please define it before attempting to use this summary.\n",
1293 funct_name);
1294 } else if (!m_options.m_python_script
1295 .empty()) // we have a quick 1-line script, just use it
1296 {
1297 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1298 if (!interpreter) {
1299 result.AppendError(in_string: "script interpreter missing - unable to generate "
1300 "function wrapper.\n");
1301 return false;
1302 }
1303 StringList funct_sl;
1304 funct_sl << m_options.m_python_script.c_str();
1305 std::string funct_name_str;
1306 if (!interpreter->GenerateTypeScriptFunction(input&: funct_sl, output&: funct_name_str)) {
1307 result.AppendError(in_string: "unable to generate function wrapper.\n");
1308 return false;
1309 }
1310 if (funct_name_str.empty()) {
1311 result.AppendError(
1312 in_string: "script interpreter failed to generate a valid function name.\n");
1313 return false;
1314 }
1315
1316 std::string code = " " + m_options.m_python_script;
1317
1318 script_format = std::make_shared<ScriptSummaryFormat>(
1319 args&: m_options.m_flags, args: funct_name_str.c_str(), args: code.c_str());
1320 } else {
1321 // Use an IOHandler to grab Python code from the user
1322 auto options = std::make_unique<ScriptAddOptions>(
1323 args&: m_options.m_flags, args&: m_options.m_match_type, args&: m_options.m_name,
1324 args&: m_options.m_category);
1325
1326 for (auto &entry : command.entries()) {
1327 if (entry.ref().empty()) {
1328 result.AppendError(in_string: "empty typenames not allowed");
1329 return false;
1330 }
1331
1332 options->m_target_types << std::string(entry.ref());
1333 }
1334
1335 m_interpreter.GetPythonCommandsFromIOHandler(
1336 prompt: " ", // Prompt
1337 delegate&: *this, // IOHandlerDelegate
1338 baton: options.release()); // Baton for the "io_handler" that will be passed
1339 // back into our IOHandlerDelegate functions
1340 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1341
1342 return result.Succeeded();
1343 }
1344
1345 // if I am here, script_format must point to something good, so I can add
1346 // that as a script summary to all interested parties
1347
1348 Status error;
1349
1350 for (auto &entry : command.entries()) {
1351 AddSummary(type_name: ConstString(entry.ref()), entry: script_format, match_type: m_options.m_match_type,
1352 category: m_options.m_category, error: &error);
1353 if (error.Fail()) {
1354 result.AppendError(in_string: error.AsCString());
1355 return false;
1356 }
1357 }
1358
1359 if (m_options.m_name) {
1360 AddNamedSummary(summary_name: m_options.m_name, entry: script_format, error: &error);
1361 if (error.Fail()) {
1362 result.AppendError(in_string: error.AsCString());
1363 result.AppendError(in_string: "added to types, but not given a name");
1364 return false;
1365 }
1366 }
1367
1368 return result.Succeeded();
1369}
1370
1371#endif
1372
1373bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
1374 Args &command, CommandReturnObject &result) {
1375 const size_t argc = command.GetArgumentCount();
1376
1377 if (argc < 1 && !m_options.m_name) {
1378 result.AppendErrorWithFormat(format: "%s takes one or more args.\n",
1379 m_cmd_name.c_str());
1380 return false;
1381 }
1382
1383 if (!m_options.m_flags.GetShowMembersOneLiner() &&
1384 m_options.m_format_string.empty()) {
1385 result.AppendError(in_string: "empty summary strings not allowed");
1386 return false;
1387 }
1388
1389 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner()
1390 ? ""
1391 : m_options.m_format_string.c_str());
1392
1393 // ${var%S} is an endless recursion, prevent it
1394 if (strcmp(s1: format_cstr, s2: "${var%S}") == 0) {
1395 result.AppendError(in_string: "recursive summary not allowed");
1396 return false;
1397 }
1398
1399 std::unique_ptr<StringSummaryFormat> string_format(
1400 new StringSummaryFormat(m_options.m_flags, format_cstr));
1401 if (!string_format) {
1402 result.AppendError(in_string: "summary creation failed");
1403 return false;
1404 }
1405 if (string_format->m_error.Fail()) {
1406 result.AppendErrorWithFormat(format: "syntax error: %s",
1407 string_format->m_error.AsCString(default_error_str: "<unknown>"));
1408 return false;
1409 }
1410 lldb::TypeSummaryImplSP entry(string_format.release());
1411
1412 // now I have a valid format, let's add it to every type
1413 Status error;
1414 for (auto &arg_entry : command.entries()) {
1415 if (arg_entry.ref().empty()) {
1416 result.AppendError(in_string: "empty typenames not allowed");
1417 return false;
1418 }
1419 ConstString typeCS(arg_entry.ref());
1420
1421 AddSummary(type_name: typeCS, entry, match_type: m_options.m_match_type, category: m_options.m_category,
1422 error: &error);
1423
1424 if (error.Fail()) {
1425 result.AppendError(in_string: error.AsCString());
1426 return false;
1427 }
1428 }
1429
1430 if (m_options.m_name) {
1431 AddNamedSummary(summary_name: m_options.m_name, entry, error: &error);
1432 if (error.Fail()) {
1433 result.AppendError(in_string: error.AsCString());
1434 result.AppendError(in_string: "added to types, but not given a name");
1435 return false;
1436 }
1437 }
1438
1439 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1440 return result.Succeeded();
1441}
1442
1443CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
1444 CommandInterpreter &interpreter)
1445 : CommandObjectParsed(interpreter, "type summary add",
1446 "Add a new summary style for a type.", nullptr),
1447 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
1448 CommandArgumentEntry type_arg;
1449 CommandArgumentData type_style_arg;
1450
1451 type_style_arg.arg_type = eArgTypeName;
1452 type_style_arg.arg_repetition = eArgRepeatPlus;
1453
1454 type_arg.push_back(x: type_style_arg);
1455
1456 m_arguments.push_back(x: type_arg);
1457
1458 SetHelpLong(
1459 R"(
1460The following examples of 'type summary add' refer to this code snippet for context:
1461
1462 struct JustADemo
1463 {
1464 int* ptr;
1465 float value;
1466 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
1467 };
1468 JustADemo demo_instance(42, 3.14);
1469
1470 typedef JustADemo NewDemo;
1471 NewDemo new_demo_instance(42, 3.14);
1472
1473(lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
1474
1475 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
1476
1477(lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
1478
1479 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
1480
1481)"
1482 "Alternatively, you could define formatting for all pointers to integers and \
1483rely on that when formatting JustADemo to obtain the same result:"
1484 R"(
1485
1486(lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
1487(lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
1488
1489)"
1490 "Type summaries are automatically applied to derived typedefs, so the examples \
1491above apply to both JustADemo and NewDemo. The cascade option can be used to \
1492suppress this behavior:"
1493 R"(
1494
1495(lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
1496
1497 The summary will now be used for values of JustADemo but not NewDemo.
1498
1499)"
1500 "By default summaries are shown for pointers and references to values of the \
1501specified type. To suppress formatting for pointers use the -p option, or apply \
1502the corresponding -r option to suppress formatting for references:"
1503 R"(
1504
1505(lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
1506
1507)"
1508 "One-line summaries including all fields in a type can be inferred without supplying an \
1509explicit summary string by passing the -c option:"
1510 R"(
1511
1512(lldb) type summary add -c JustADemo
1513(lldb) frame variable demo_instance
1514(ptr=<address>, value=3.14)
1515
1516)"
1517 "Type summaries normally suppress the nested display of individual fields. To \
1518supply a summary to supplement the default structure add the -e option:"
1519 R"(
1520
1521(lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
1522
1523)"
1524 "Now when displaying JustADemo values the int* is displayed, followed by the \
1525standard LLDB sequence of children, one per line:"
1526 R"(
1527
1528*ptr = 42 {
1529 ptr = <address>
1530 value = 3.14
1531}
1532
1533)"
1534 "You can also add summaries written in Python. These scripts use lldb public API to \
1535gather information from your variables and produce a meaningful summary. To start a \
1536multi-line script use the -P option. The function declaration will be displayed along with \
1537a comment describing the two arguments. End your script with the word 'DONE' on a line by \
1538itself:"
1539 R"(
1540
1541(lldb) type summary add JustADemo -P
1542def function (valobj,internal_dict):
1543"""valobj: an SBValue which you want to provide a summary for
1544internal_dict: an LLDB support object not to be used"""
1545 value = valobj.GetChildMemberWithName('value');
1546 return 'My value is ' + value.GetValue();
1547 DONE
1548
1549Alternatively, the -o option can be used when providing a simple one-line Python script:
1550
1551(lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
1552}
1553
1554void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
1555 CommandReturnObject &result) {
1556 WarnOnPotentialUnquotedUnsignedType(command, result);
1557
1558 if (m_options.m_is_add_script) {
1559#if LLDB_ENABLE_PYTHON
1560 Execute_ScriptSummary(command, result);
1561#else
1562 result.AppendError("python is disabled");
1563#endif
1564 return;
1565 }
1566
1567 Execute_StringSummary(command, result);
1568}
1569
1570static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
1571 llvm::StringRef type_name_ref(type_name.GetStringRef());
1572
1573 if (type_name_ref.ends_with(Suffix: "[]")) {
1574 std::string type_name_str(type_name.GetCString());
1575 type_name_str.resize(n: type_name_str.length() - 2);
1576 if (type_name_str.back() != ' ')
1577 type_name_str.append(s: " ?\\[[0-9]+\\]");
1578 else
1579 type_name_str.append(s: "\\[[0-9]+\\]");
1580 type_name.SetCString(type_name_str.c_str());
1581 return true;
1582 }
1583 return false;
1584}
1585
1586bool CommandObjectTypeSummaryAdd::AddNamedSummary(ConstString summary_name,
1587 TypeSummaryImplSP entry,
1588 Status *error) {
1589 // system named summaries do not exist (yet?)
1590 DataVisualization::NamedSummaryFormats::Add(type: summary_name, entry);
1591 return true;
1592}
1593
1594bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
1595 TypeSummaryImplSP entry,
1596 FormatterMatchType match_type,
1597 std::string category_name,
1598 Status *error) {
1599 lldb::TypeCategoryImplSP category;
1600 DataVisualization::Categories::GetCategory(category: ConstString(category_name.c_str()),
1601 entry&: category);
1602
1603 if (match_type == eFormatterMatchExact) {
1604 if (FixArrayTypeNameWithRegex(type_name))
1605 match_type = eFormatterMatchRegex;
1606 }
1607
1608 if (match_type == eFormatterMatchRegex) {
1609 match_type = eFormatterMatchRegex;
1610 RegularExpression typeRX(type_name.GetStringRef());
1611 if (!typeRX.IsValid()) {
1612 if (error)
1613 error->SetErrorString(
1614 "regex format error (maybe this is not really a regex?)");
1615 return false;
1616 }
1617 }
1618
1619 if (match_type == eFormatterMatchCallback) {
1620 const char *function_name = type_name.AsCString();
1621 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1622 if (interpreter && !interpreter->CheckObjectExists(name: function_name)) {
1623 error->SetErrorStringWithFormat(
1624 "The provided recognizer function \"%s\" does not exist - "
1625 "please define it before attempting to use this summary.\n",
1626 function_name);
1627 return false;
1628 }
1629 }
1630 category->AddTypeSummary(name: type_name.GetStringRef(), match_type, summary_sp: entry);
1631 return true;
1632}
1633
1634// CommandObjectTypeSummaryDelete
1635
1636class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete {
1637public:
1638 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter)
1639 : CommandObjectTypeFormatterDelete(
1640 interpreter, eFormatCategoryItemSummary) {}
1641
1642 ~CommandObjectTypeSummaryDelete() override = default;
1643
1644protected:
1645 bool FormatterSpecificDeletion(ConstString typeCS) override {
1646 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1647 return false;
1648 return DataVisualization::NamedSummaryFormats::Delete(type: typeCS);
1649 }
1650};
1651
1652class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear {
1653public:
1654 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter)
1655 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemSummary,
1656 "type summary clear",
1657 "Delete all existing summaries.") {}
1658
1659protected:
1660 void FormatterSpecificDeletion() override {
1661 DataVisualization::NamedSummaryFormats::Clear();
1662 }
1663};
1664
1665// CommandObjectTypeSummaryList
1666
1667class CommandObjectTypeSummaryList
1668 : public CommandObjectTypeFormatterList<TypeSummaryImpl> {
1669public:
1670 CommandObjectTypeSummaryList(CommandInterpreter &interpreter)
1671 : CommandObjectTypeFormatterList(interpreter, "type summary list",
1672 "Show a list of current summaries.") {}
1673
1674protected:
1675 bool FormatterSpecificList(CommandReturnObject &result) override {
1676 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
1677 result.GetOutputStream().Printf(format: "Named summaries:\n");
1678 DataVisualization::NamedSummaryFormats::ForEach(
1679 callback: [&result](const TypeMatcher &type_matcher,
1680 const TypeSummaryImplSP &summary_sp) -> bool {
1681 result.GetOutputStream().Printf(
1682 format: "%s: %s\n", type_matcher.GetMatchString().GetCString(),
1683 summary_sp->GetDescription().c_str());
1684 return true;
1685 });
1686 return true;
1687 }
1688 return false;
1689 }
1690};
1691
1692// CommandObjectTypeCategoryDefine
1693#define LLDB_OPTIONS_type_category_define
1694#include "CommandOptions.inc"
1695
1696class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
1697 class CommandOptions : public Options {
1698 public:
1699 CommandOptions()
1700 : m_define_enabled(false, false),
1701 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {}
1702
1703 ~CommandOptions() override = default;
1704
1705 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1706 ExecutionContext *execution_context) override {
1707 Status error;
1708 const int short_option = m_getopt_table[option_idx].val;
1709
1710 switch (short_option) {
1711 case 'e':
1712 m_define_enabled.SetValueFromString(value: llvm::StringRef("true"));
1713 break;
1714 case 'l':
1715 error = m_cate_language.SetValueFromString(value: option_arg);
1716 break;
1717 default:
1718 llvm_unreachable("Unimplemented option");
1719 }
1720
1721 return error;
1722 }
1723
1724 void OptionParsingStarting(ExecutionContext *execution_context) override {
1725 m_define_enabled.Clear();
1726 m_cate_language.Clear();
1727 }
1728
1729 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1730 return llvm::ArrayRef(g_type_category_define_options);
1731 }
1732
1733 // Instance variables to hold the values for command options.
1734
1735 OptionValueBoolean m_define_enabled;
1736 OptionValueLanguage m_cate_language;
1737 };
1738
1739 CommandOptions m_options;
1740
1741 Options *GetOptions() override { return &m_options; }
1742
1743public:
1744 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter)
1745 : CommandObjectParsed(interpreter, "type category define",
1746 "Define a new category as a source of formatters.",
1747 nullptr) {
1748 CommandArgumentEntry type_arg;
1749 CommandArgumentData type_style_arg;
1750
1751 type_style_arg.arg_type = eArgTypeName;
1752 type_style_arg.arg_repetition = eArgRepeatPlus;
1753
1754 type_arg.push_back(x: type_style_arg);
1755
1756 m_arguments.push_back(x: type_arg);
1757 }
1758
1759 ~CommandObjectTypeCategoryDefine() override = default;
1760
1761 void
1762 HandleArgumentCompletion(CompletionRequest &request,
1763 OptionElementVector &opt_element_vector) override {
1764 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1765 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eTypeCategoryNameCompletion, request,
1766 searcher: nullptr);
1767 }
1768
1769protected:
1770 void DoExecute(Args &command, CommandReturnObject &result) override {
1771 const size_t argc = command.GetArgumentCount();
1772
1773 if (argc < 1) {
1774 result.AppendErrorWithFormat(format: "%s takes 1 or more args.\n",
1775 m_cmd_name.c_str());
1776 return;
1777 }
1778
1779 for (auto &entry : command.entries()) {
1780 TypeCategoryImplSP category_sp;
1781 if (DataVisualization::Categories::GetCategory(category: ConstString(entry.ref()),
1782 entry&: category_sp) &&
1783 category_sp) {
1784 category_sp->AddLanguage(lang: m_options.m_cate_language.GetCurrentValue());
1785 if (m_options.m_define_enabled.GetCurrentValue())
1786 DataVisualization::Categories::Enable(category: category_sp,
1787 TypeCategoryMap::Default);
1788 }
1789 }
1790
1791 result.SetStatus(eReturnStatusSuccessFinishResult);
1792 }
1793};
1794
1795// CommandObjectTypeCategoryEnable
1796#define LLDB_OPTIONS_type_category_enable
1797#include "CommandOptions.inc"
1798
1799class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
1800 class CommandOptions : public Options {
1801 public:
1802 CommandOptions() = default;
1803
1804 ~CommandOptions() override = default;
1805
1806 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1807 ExecutionContext *execution_context) override {
1808 Status error;
1809 const int short_option = m_getopt_table[option_idx].val;
1810
1811 switch (short_option) {
1812 case 'l':
1813 if (!option_arg.empty()) {
1814 m_language = Language::GetLanguageTypeFromString(string: option_arg);
1815 if (m_language == lldb::eLanguageTypeUnknown)
1816 error.SetErrorStringWithFormat("unrecognized language '%s'",
1817 option_arg.str().c_str());
1818 }
1819 break;
1820 default:
1821 llvm_unreachable("Unimplemented option");
1822 }
1823
1824 return error;
1825 }
1826
1827 void OptionParsingStarting(ExecutionContext *execution_context) override {
1828 m_language = lldb::eLanguageTypeUnknown;
1829 }
1830
1831 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1832 return llvm::ArrayRef(g_type_category_enable_options);
1833 }
1834
1835 // Instance variables to hold the values for command options.
1836
1837 lldb::LanguageType m_language;
1838 };
1839
1840 CommandOptions m_options;
1841
1842 Options *GetOptions() override { return &m_options; }
1843
1844public:
1845 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter)
1846 : CommandObjectParsed(interpreter, "type category enable",
1847 "Enable a category as a source of formatters.",
1848 nullptr) {
1849 CommandArgumentEntry type_arg;
1850 CommandArgumentData type_style_arg;
1851
1852 type_style_arg.arg_type = eArgTypeName;
1853 type_style_arg.arg_repetition = eArgRepeatPlus;
1854
1855 type_arg.push_back(x: type_style_arg);
1856
1857 m_arguments.push_back(x: type_arg);
1858 }
1859
1860 ~CommandObjectTypeCategoryEnable() override = default;
1861
1862 void
1863 HandleArgumentCompletion(CompletionRequest &request,
1864 OptionElementVector &opt_element_vector) override {
1865 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1866 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eTypeCategoryNameCompletion, request,
1867 searcher: nullptr);
1868 }
1869
1870protected:
1871 void DoExecute(Args &command, CommandReturnObject &result) override {
1872 const size_t argc = command.GetArgumentCount();
1873
1874 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1875 result.AppendErrorWithFormat(format: "%s takes arguments and/or a language",
1876 m_cmd_name.c_str());
1877 return;
1878 }
1879
1880 if (argc == 1 && strcmp(s1: command.GetArgumentAtIndex(idx: 0), s2: "*") == 0) {
1881 DataVisualization::Categories::EnableStar();
1882 } else if (argc > 0) {
1883 for (int i = argc - 1; i >= 0; i--) {
1884 const char *typeA = command.GetArgumentAtIndex(idx: i);
1885 ConstString typeCS(typeA);
1886
1887 if (!typeCS) {
1888 result.AppendError(in_string: "empty category name not allowed");
1889 return;
1890 }
1891 DataVisualization::Categories::Enable(category: typeCS);
1892 lldb::TypeCategoryImplSP cate;
1893 if (DataVisualization::Categories::GetCategory(category: typeCS, entry&: cate) && cate) {
1894 if (cate->GetCount() == 0) {
1895 result.AppendWarning(in_string: "empty category enabled (typo?)");
1896 }
1897 }
1898 }
1899 }
1900
1901 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1902 DataVisualization::Categories::Enable(lang_type: m_options.m_language);
1903
1904 result.SetStatus(eReturnStatusSuccessFinishResult);
1905 }
1906};
1907
1908// CommandObjectTypeCategoryDelete
1909
1910class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
1911public:
1912 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter)
1913 : CommandObjectParsed(interpreter, "type category delete",
1914 "Delete a category and all associated formatters.",
1915 nullptr) {
1916 CommandArgumentEntry type_arg;
1917 CommandArgumentData type_style_arg;
1918
1919 type_style_arg.arg_type = eArgTypeName;
1920 type_style_arg.arg_repetition = eArgRepeatPlus;
1921
1922 type_arg.push_back(x: type_style_arg);
1923
1924 m_arguments.push_back(x: type_arg);
1925 }
1926
1927 ~CommandObjectTypeCategoryDelete() override = default;
1928
1929 void
1930 HandleArgumentCompletion(CompletionRequest &request,
1931 OptionElementVector &opt_element_vector) override {
1932 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
1933 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eTypeCategoryNameCompletion, request,
1934 searcher: nullptr);
1935 }
1936
1937protected:
1938 void DoExecute(Args &command, CommandReturnObject &result) override {
1939 const size_t argc = command.GetArgumentCount();
1940
1941 if (argc < 1) {
1942 result.AppendErrorWithFormat(format: "%s takes 1 or more arg.\n",
1943 m_cmd_name.c_str());
1944 return;
1945 }
1946
1947 bool success = true;
1948
1949 // the order is not relevant here
1950 for (int i = argc - 1; i >= 0; i--) {
1951 const char *typeA = command.GetArgumentAtIndex(idx: i);
1952 ConstString typeCS(typeA);
1953
1954 if (!typeCS) {
1955 result.AppendError(in_string: "empty category name not allowed");
1956 return;
1957 }
1958 if (!DataVisualization::Categories::Delete(category: typeCS))
1959 success = false; // keep deleting even if we hit an error
1960 }
1961 if (success) {
1962 result.SetStatus(eReturnStatusSuccessFinishResult);
1963 } else {
1964 result.AppendError(in_string: "cannot delete one or more categories\n");
1965 }
1966 }
1967};
1968
1969// CommandObjectTypeCategoryDisable
1970#define LLDB_OPTIONS_type_category_disable
1971#include "CommandOptions.inc"
1972
1973class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
1974 class CommandOptions : public Options {
1975 public:
1976 CommandOptions() = default;
1977
1978 ~CommandOptions() override = default;
1979
1980 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1981 ExecutionContext *execution_context) override {
1982 Status error;
1983 const int short_option = m_getopt_table[option_idx].val;
1984
1985 switch (short_option) {
1986 case 'l':
1987 if (!option_arg.empty()) {
1988 m_language = Language::GetLanguageTypeFromString(string: option_arg);
1989 if (m_language == lldb::eLanguageTypeUnknown)
1990 error.SetErrorStringWithFormat("unrecognized language '%s'",
1991 option_arg.str().c_str());
1992 }
1993 break;
1994 default:
1995 llvm_unreachable("Unimplemented option");
1996 }
1997
1998 return error;
1999 }
2000
2001 void OptionParsingStarting(ExecutionContext *execution_context) override {
2002 m_language = lldb::eLanguageTypeUnknown;
2003 }
2004
2005 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2006 return llvm::ArrayRef(g_type_category_disable_options);
2007 }
2008
2009 // Instance variables to hold the values for command options.
2010
2011 lldb::LanguageType m_language;
2012 };
2013
2014 CommandOptions m_options;
2015
2016 Options *GetOptions() override { return &m_options; }
2017
2018public:
2019 CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter)
2020 : CommandObjectParsed(interpreter, "type category disable",
2021 "Disable a category as a source of formatters.",
2022 nullptr) {
2023 CommandArgumentEntry type_arg;
2024 CommandArgumentData type_style_arg;
2025
2026 type_style_arg.arg_type = eArgTypeName;
2027 type_style_arg.arg_repetition = eArgRepeatPlus;
2028
2029 type_arg.push_back(x: type_style_arg);
2030
2031 m_arguments.push_back(x: type_arg);
2032 }
2033
2034 ~CommandObjectTypeCategoryDisable() override = default;
2035
2036 void
2037 HandleArgumentCompletion(CompletionRequest &request,
2038 OptionElementVector &opt_element_vector) override {
2039 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
2040 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eTypeCategoryNameCompletion, request,
2041 searcher: nullptr);
2042 }
2043
2044protected:
2045 void DoExecute(Args &command, CommandReturnObject &result) override {
2046 const size_t argc = command.GetArgumentCount();
2047
2048 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
2049 result.AppendErrorWithFormat(format: "%s takes arguments and/or a language",
2050 m_cmd_name.c_str());
2051 return;
2052 }
2053
2054 if (argc == 1 && strcmp(s1: command.GetArgumentAtIndex(idx: 0), s2: "*") == 0) {
2055 DataVisualization::Categories::DisableStar();
2056 } else if (argc > 0) {
2057 // the order is not relevant here
2058 for (int i = argc - 1; i >= 0; i--) {
2059 const char *typeA = command.GetArgumentAtIndex(idx: i);
2060 ConstString typeCS(typeA);
2061
2062 if (!typeCS) {
2063 result.AppendError(in_string: "empty category name not allowed");
2064 return;
2065 }
2066 DataVisualization::Categories::Disable(category: typeCS);
2067 }
2068 }
2069
2070 if (m_options.m_language != lldb::eLanguageTypeUnknown)
2071 DataVisualization::Categories::Disable(lang_type: m_options.m_language);
2072
2073 result.SetStatus(eReturnStatusSuccessFinishResult);
2074 }
2075};
2076
2077// CommandObjectTypeCategoryList
2078
2079class CommandObjectTypeCategoryList : public CommandObjectParsed {
2080public:
2081 CommandObjectTypeCategoryList(CommandInterpreter &interpreter)
2082 : CommandObjectParsed(interpreter, "type category list",
2083 "Provide a list of all existing categories.",
2084 nullptr) {
2085 CommandArgumentEntry type_arg;
2086 CommandArgumentData type_style_arg;
2087
2088 type_style_arg.arg_type = eArgTypeName;
2089 type_style_arg.arg_repetition = eArgRepeatOptional;
2090
2091 type_arg.push_back(x: type_style_arg);
2092
2093 m_arguments.push_back(x: type_arg);
2094 }
2095
2096 ~CommandObjectTypeCategoryList() override = default;
2097
2098 void
2099 HandleArgumentCompletion(CompletionRequest &request,
2100 OptionElementVector &opt_element_vector) override {
2101 if (request.GetCursorIndex())
2102 return;
2103 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
2104 interpreter&: GetCommandInterpreter(), completion_mask: lldb::eTypeCategoryNameCompletion, request,
2105 searcher: nullptr);
2106 }
2107
2108protected:
2109 void DoExecute(Args &command, CommandReturnObject &result) override {
2110 const size_t argc = command.GetArgumentCount();
2111
2112 std::unique_ptr<RegularExpression> regex;
2113
2114 if (argc == 1) {
2115 const char *arg = command.GetArgumentAtIndex(idx: 0);
2116 regex = std::make_unique<RegularExpression>(args&: arg);
2117 if (!regex->IsValid()) {
2118 result.AppendErrorWithFormat(
2119 format: "syntax error in category regular expression '%s'", arg);
2120 return;
2121 }
2122 } else if (argc != 0) {
2123 result.AppendErrorWithFormat(format: "%s takes 0 or one arg.\n",
2124 m_cmd_name.c_str());
2125 return;
2126 }
2127
2128 DataVisualization::Categories::ForEach(
2129 callback: [&regex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool {
2130 if (regex) {
2131 bool escape = true;
2132 if (regex->GetText() == category_sp->GetName()) {
2133 escape = false;
2134 } else if (regex->Execute(string: category_sp->GetName())) {
2135 escape = false;
2136 }
2137
2138 if (escape)
2139 return true;
2140 }
2141
2142 result.GetOutputStream().Printf(
2143 format: "Category: %s\n", category_sp->GetDescription().c_str());
2144
2145 return true;
2146 });
2147
2148 result.SetStatus(eReturnStatusSuccessFinishResult);
2149 }
2150};
2151
2152// CommandObjectTypeFilterList
2153
2154class CommandObjectTypeFilterList
2155 : public CommandObjectTypeFormatterList<TypeFilterImpl> {
2156public:
2157 CommandObjectTypeFilterList(CommandInterpreter &interpreter)
2158 : CommandObjectTypeFormatterList(interpreter, "type filter list",
2159 "Show a list of current filters.") {}
2160};
2161
2162// CommandObjectTypeSynthList
2163
2164class CommandObjectTypeSynthList
2165 : public CommandObjectTypeFormatterList<SyntheticChildren> {
2166public:
2167 CommandObjectTypeSynthList(CommandInterpreter &interpreter)
2168 : CommandObjectTypeFormatterList(
2169 interpreter, "type synthetic list",
2170 "Show a list of current synthetic providers.") {}
2171};
2172
2173// CommandObjectTypeFilterDelete
2174
2175class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
2176public:
2177 CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
2178 : CommandObjectTypeFormatterDelete(
2179 interpreter, eFormatCategoryItemFilter) {}
2180
2181 ~CommandObjectTypeFilterDelete() override = default;
2182};
2183
2184// CommandObjectTypeSynthDelete
2185
2186class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete {
2187public:
2188 CommandObjectTypeSynthDelete(CommandInterpreter &interpreter)
2189 : CommandObjectTypeFormatterDelete(
2190 interpreter, eFormatCategoryItemSynth) {}
2191
2192 ~CommandObjectTypeSynthDelete() override = default;
2193};
2194
2195
2196// CommandObjectTypeFilterClear
2197
2198class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear {
2199public:
2200 CommandObjectTypeFilterClear(CommandInterpreter &interpreter)
2201 : CommandObjectTypeFormatterClear(interpreter, eFormatCategoryItemFilter,
2202 "type filter clear",
2203 "Delete all existing filter.") {}
2204};
2205
2206// CommandObjectTypeSynthClear
2207
2208class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear {
2209public:
2210 CommandObjectTypeSynthClear(CommandInterpreter &interpreter)
2211 : CommandObjectTypeFormatterClear(
2212 interpreter, eFormatCategoryItemSynth, "type synthetic clear",
2213 "Delete all existing synthetic providers.") {}
2214};
2215
2216bool CommandObjectTypeSynthAdd::Execute_HandwritePython(
2217 Args &command, CommandReturnObject &result) {
2218 auto options = std::make_unique<SynthAddOptions>(
2219 args&: m_options.m_skip_pointers, args&: m_options.m_skip_references,
2220 args&: m_options.m_cascade, args&: m_options.m_match_type, args&: m_options.m_category);
2221
2222 for (auto &entry : command.entries()) {
2223 if (entry.ref().empty()) {
2224 result.AppendError(in_string: "empty typenames not allowed");
2225 return false;
2226 }
2227
2228 options->m_target_types << std::string(entry.ref());
2229 }
2230
2231 m_interpreter.GetPythonCommandsFromIOHandler(
2232 prompt: " ", // Prompt
2233 delegate&: *this, // IOHandlerDelegate
2234 baton: options.release()); // Baton for the "io_handler" that will be passed back
2235 // into our IOHandlerDelegate functions
2236 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2237 return result.Succeeded();
2238}
2239
2240bool CommandObjectTypeSynthAdd::Execute_PythonClass(
2241 Args &command, CommandReturnObject &result) {
2242 const size_t argc = command.GetArgumentCount();
2243
2244 if (argc < 1) {
2245 result.AppendErrorWithFormat(format: "%s takes one or more args.\n",
2246 m_cmd_name.c_str());
2247 return false;
2248 }
2249
2250 if (m_options.m_class_name.empty() && !m_options.m_input_python) {
2251 result.AppendErrorWithFormat(format: "%s needs either a Python class name or -P to "
2252 "directly input Python code.\n",
2253 m_cmd_name.c_str());
2254 return false;
2255 }
2256
2257 SyntheticChildrenSP entry;
2258
2259 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren(
2260 SyntheticChildren::Flags()
2261 .SetCascades(m_options.m_cascade)
2262 .SetSkipPointers(m_options.m_skip_pointers)
2263 .SetSkipReferences(m_options.m_skip_references),
2264 m_options.m_class_name.c_str());
2265
2266 entry.reset(p: impl);
2267
2268 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2269
2270 if (interpreter &&
2271 !interpreter->CheckObjectExists(name: impl->GetPythonClassName()))
2272 result.AppendWarning(in_string: "The provided class does not exist - please define it "
2273 "before attempting to use this synthetic provider");
2274
2275 // now I have a valid provider, let's add it to every type
2276
2277 lldb::TypeCategoryImplSP category;
2278 DataVisualization::Categories::GetCategory(
2279 category: ConstString(m_options.m_category.c_str()), entry&: category);
2280
2281 Status error;
2282
2283 for (auto &arg_entry : command.entries()) {
2284 if (arg_entry.ref().empty()) {
2285 result.AppendError(in_string: "empty typenames not allowed");
2286 return false;
2287 }
2288
2289 ConstString typeCS(arg_entry.ref());
2290 if (!AddSynth(type_name: typeCS, entry, match_type: m_options.m_match_type, category_name: m_options.m_category,
2291 error: &error)) {
2292 result.AppendError(in_string: error.AsCString());
2293 return false;
2294 }
2295 }
2296
2297 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2298 return result.Succeeded();
2299}
2300
2301CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd(
2302 CommandInterpreter &interpreter)
2303 : CommandObjectParsed(interpreter, "type synthetic add",
2304 "Add a new synthetic provider for a type.", nullptr),
2305 IOHandlerDelegateMultiline("DONE"), m_options() {
2306 CommandArgumentEntry type_arg;
2307 CommandArgumentData type_style_arg;
2308
2309 type_style_arg.arg_type = eArgTypeName;
2310 type_style_arg.arg_repetition = eArgRepeatPlus;
2311
2312 type_arg.push_back(x: type_style_arg);
2313
2314 m_arguments.push_back(x: type_arg);
2315}
2316
2317bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
2318 SyntheticChildrenSP entry,
2319 FormatterMatchType match_type,
2320 std::string category_name,
2321 Status *error) {
2322 lldb::TypeCategoryImplSP category;
2323 DataVisualization::Categories::GetCategory(category: ConstString(category_name.c_str()),
2324 entry&: category);
2325
2326 if (match_type == eFormatterMatchExact) {
2327 if (FixArrayTypeNameWithRegex(type_name))
2328 match_type = eFormatterMatchRegex;
2329 }
2330
2331 // Only check for conflicting filters in the same category if `type_name` is
2332 // an actual type name. Matching a regex string against registered regexes
2333 // doesn't work.
2334 if (match_type == eFormatterMatchExact) {
2335 // It's not generally possible to get a type object here. For example, this
2336 // command can be run before loading any binaries. Do just a best-effort
2337 // name-based lookup here to try to prevent conflicts.
2338 FormattersMatchCandidate candidate_type(type_name, nullptr, TypeImpl(),
2339 FormattersMatchCandidate::Flags());
2340 if (category->AnyMatches(candidate_type, items: eFormatCategoryItemFilter,
2341 only_enabled: false)) {
2342 if (error)
2343 error->SetErrorStringWithFormat("cannot add synthetic for type %s when "
2344 "filter is defined in same category!",
2345 type_name.AsCString());
2346 return false;
2347 }
2348 }
2349
2350 if (match_type == eFormatterMatchRegex) {
2351 RegularExpression typeRX(type_name.GetStringRef());
2352 if (!typeRX.IsValid()) {
2353 if (error)
2354 error->SetErrorString(
2355 "regex format error (maybe this is not really a regex?)");
2356 return false;
2357 }
2358 }
2359
2360 if (match_type == eFormatterMatchCallback) {
2361 const char *function_name = type_name.AsCString();
2362 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2363 if (interpreter && !interpreter->CheckObjectExists(name: function_name)) {
2364 error->SetErrorStringWithFormat(
2365 "The provided recognizer function \"%s\" does not exist - "
2366 "please define it before attempting to use this summary.\n",
2367 function_name);
2368 return false;
2369 }
2370 }
2371
2372 category->AddTypeSynthetic(name: type_name.GetStringRef(), match_type, synth_sp: entry);
2373 return true;
2374}
2375
2376#define LLDB_OPTIONS_type_filter_add
2377#include "CommandOptions.inc"
2378
2379class CommandObjectTypeFilterAdd : public CommandObjectParsed {
2380private:
2381 class CommandOptions : public Options {
2382 typedef std::vector<std::string> option_vector;
2383
2384 public:
2385 CommandOptions() = default;
2386
2387 ~CommandOptions() override = default;
2388
2389 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2390 ExecutionContext *execution_context) override {
2391 Status error;
2392 const int short_option = m_getopt_table[option_idx].val;
2393 bool success;
2394
2395 switch (short_option) {
2396 case 'C':
2397 m_cascade = OptionArgParser::ToBoolean(s: option_arg, fail_value: true, success_ptr: &success);
2398 if (!success)
2399 error.SetErrorStringWithFormat("invalid value for cascade: %s",
2400 option_arg.str().c_str());
2401 break;
2402 case 'c':
2403 m_expr_paths.push_back(x: std::string(option_arg));
2404 has_child_list = true;
2405 break;
2406 case 'p':
2407 m_skip_pointers = true;
2408 break;
2409 case 'r':
2410 m_skip_references = true;
2411 break;
2412 case 'w':
2413 m_category = std::string(option_arg);
2414 break;
2415 case 'x':
2416 m_regex = true;
2417 break;
2418 default:
2419 llvm_unreachable("Unimplemented option");
2420 }
2421
2422 return error;
2423 }
2424
2425 void OptionParsingStarting(ExecutionContext *execution_context) override {
2426 m_cascade = true;
2427 m_skip_pointers = false;
2428 m_skip_references = false;
2429 m_category = "default";
2430 m_expr_paths.clear();
2431 has_child_list = false;
2432 m_regex = false;
2433 }
2434
2435 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2436 return llvm::ArrayRef(g_type_filter_add_options);
2437 }
2438
2439 // Instance variables to hold the values for command options.
2440
2441 bool m_cascade;
2442 bool m_skip_references;
2443 bool m_skip_pointers;
2444 bool m_input_python;
2445 option_vector m_expr_paths;
2446 std::string m_category;
2447 bool has_child_list;
2448 bool m_regex;
2449
2450 typedef option_vector::iterator ExpressionPathsIterator;
2451 };
2452
2453 CommandOptions m_options;
2454
2455 Options *GetOptions() override { return &m_options; }
2456
2457 enum FilterFormatType { eRegularFilter, eRegexFilter };
2458
2459 bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
2460 FilterFormatType type, std::string category_name,
2461 Status *error) {
2462 lldb::TypeCategoryImplSP category;
2463 DataVisualization::Categories::GetCategory(
2464 category: ConstString(category_name.c_str()), entry&: category);
2465
2466 if (type == eRegularFilter) {
2467 if (FixArrayTypeNameWithRegex(type_name))
2468 type = eRegexFilter;
2469 }
2470
2471 // Only check for conflicting synthetic child providers in the same category
2472 // if `type_name` is an actual type name. Matching a regex string against
2473 // registered regexes doesn't work.
2474 if (type == eRegularFilter) {
2475 // It's not generally possible to get a type object here. For example,
2476 // this command can be run before loading any binaries. Do just a
2477 // best-effort name-based lookup here to try to prevent conflicts.
2478 FormattersMatchCandidate candidate_type(
2479 type_name, nullptr, TypeImpl(), FormattersMatchCandidate::Flags());
2480 lldb::SyntheticChildrenSP entry;
2481 if (category->AnyMatches(candidate_type, items: eFormatCategoryItemSynth,
2482 only_enabled: false)) {
2483 if (error)
2484 error->SetErrorStringWithFormat("cannot add filter for type %s when "
2485 "synthetic is defined in same "
2486 "category!",
2487 type_name.AsCString());
2488 return false;
2489 }
2490 }
2491
2492 FormatterMatchType match_type = eFormatterMatchExact;
2493 if (type == eRegexFilter) {
2494 match_type = eFormatterMatchRegex;
2495 RegularExpression typeRX(type_name.GetStringRef());
2496 if (!typeRX.IsValid()) {
2497 if (error)
2498 error->SetErrorString(
2499 "regex format error (maybe this is not really a regex?)");
2500 return false;
2501 }
2502 }
2503 category->AddTypeFilter(type_name.GetStringRef(), match_type, entry);
2504 return true;
2505 }
2506
2507public:
2508 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter)
2509 : CommandObjectParsed(interpreter, "type filter add",
2510 "Add a new filter for a type.", nullptr) {
2511 CommandArgumentEntry type_arg;
2512 CommandArgumentData type_style_arg;
2513
2514 type_style_arg.arg_type = eArgTypeName;
2515 type_style_arg.arg_repetition = eArgRepeatPlus;
2516
2517 type_arg.push_back(x: type_style_arg);
2518
2519 m_arguments.push_back(x: type_arg);
2520
2521 SetHelpLong(
2522 R"(
2523The following examples of 'type filter add' refer to this code snippet for context:
2524
2525 class Foo {
2526 int a;
2527 int b;
2528 int c;
2529 int d;
2530 int e;
2531 int f;
2532 int g;
2533 int h;
2534 int i;
2535 }
2536 Foo my_foo;
2537
2538Adding a simple filter:
2539
2540(lldb) type filter add --child a --child g Foo
2541(lldb) frame variable my_foo
2542
2543)"
2544 "Produces output where only a and g are displayed. Other children of my_foo \
2545(b, c, d, e, f, h and i) are available by asking for them explicitly:"
2546 R"(
2547
2548(lldb) frame variable my_foo.b my_foo.c my_foo.i
2549
2550)"
2551 "The formatting option --raw on frame variable bypasses the filter, showing \
2552all children of my_foo as if no filter was defined:"
2553 R"(
2554
2555(lldb) frame variable my_foo --raw)");
2556 }
2557
2558 ~CommandObjectTypeFilterAdd() override = default;
2559
2560protected:
2561 void DoExecute(Args &command, CommandReturnObject &result) override {
2562 const size_t argc = command.GetArgumentCount();
2563
2564 if (argc < 1) {
2565 result.AppendErrorWithFormat(format: "%s takes one or more args.\n",
2566 m_cmd_name.c_str());
2567 return;
2568 }
2569
2570 if (m_options.m_expr_paths.empty()) {
2571 result.AppendErrorWithFormat(format: "%s needs one or more children.\n",
2572 m_cmd_name.c_str());
2573 return;
2574 }
2575
2576 TypeFilterImplSP entry(new TypeFilterImpl(
2577 SyntheticChildren::Flags()
2578 .SetCascades(m_options.m_cascade)
2579 .SetSkipPointers(m_options.m_skip_pointers)
2580 .SetSkipReferences(m_options.m_skip_references)));
2581
2582 // go through the expression paths
2583 CommandOptions::ExpressionPathsIterator begin,
2584 end = m_options.m_expr_paths.end();
2585
2586 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
2587 entry->AddExpressionPath(*begin);
2588
2589 // now I have a valid provider, let's add it to every type
2590
2591 lldb::TypeCategoryImplSP category;
2592 DataVisualization::Categories::GetCategory(
2593 category: ConstString(m_options.m_category.c_str()), entry&: category);
2594
2595 Status error;
2596
2597 WarnOnPotentialUnquotedUnsignedType(command, result);
2598
2599 for (auto &arg_entry : command.entries()) {
2600 if (arg_entry.ref().empty()) {
2601 result.AppendError(in_string: "empty typenames not allowed");
2602 return;
2603 }
2604
2605 ConstString typeCS(arg_entry.ref());
2606 if (!AddFilter(type_name: typeCS, entry: entry,
2607 type: m_options.m_regex ? eRegexFilter : eRegularFilter,
2608 category_name: m_options.m_category, error: &error)) {
2609 result.AppendError(in_string: error.AsCString());
2610 return;
2611 }
2612 }
2613
2614 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2615 }
2616};
2617
2618// "type lookup"
2619#define LLDB_OPTIONS_type_lookup
2620#include "CommandOptions.inc"
2621
2622class CommandObjectTypeLookup : public CommandObjectRaw {
2623protected:
2624 // this function is allowed to do a more aggressive job at guessing languages
2625 // than the expression parser is comfortable with - so leave the original
2626 // call alone and add one that is specific to type lookup
2627 lldb::LanguageType GuessLanguage(StackFrame *frame) {
2628 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown;
2629
2630 if (!frame)
2631 return lang_type;
2632
2633 lang_type = frame->GuessLanguage();
2634 if (lang_type != lldb::eLanguageTypeUnknown)
2635 return lang_type;
2636
2637 Symbol *s = frame->GetSymbolContext(resolve_scope: eSymbolContextSymbol).symbol;
2638 if (s)
2639 lang_type = s->GetMangled().GuessLanguage();
2640
2641 return lang_type;
2642 }
2643
2644 class CommandOptions : public OptionGroup {
2645 public:
2646 CommandOptions() = default;
2647
2648 ~CommandOptions() override = default;
2649
2650 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2651 return llvm::ArrayRef(g_type_lookup_options);
2652 }
2653
2654 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2655 ExecutionContext *execution_context) override {
2656 Status error;
2657
2658 const int short_option = g_type_lookup_options[option_idx].short_option;
2659
2660 switch (short_option) {
2661 case 'h':
2662 m_show_help = true;
2663 break;
2664
2665 case 'l':
2666 m_language = Language::GetLanguageTypeFromString(string: option_value);
2667 break;
2668
2669 default:
2670 llvm_unreachable("Unimplemented option");
2671 }
2672
2673 return error;
2674 }
2675
2676 void OptionParsingStarting(ExecutionContext *execution_context) override {
2677 m_show_help = false;
2678 m_language = eLanguageTypeUnknown;
2679 }
2680
2681 // Options table: Required for subclasses of Options.
2682
2683 bool m_show_help = false;
2684 lldb::LanguageType m_language = eLanguageTypeUnknown;
2685 };
2686
2687 OptionGroupOptions m_option_group;
2688 CommandOptions m_command_options;
2689
2690public:
2691 CommandObjectTypeLookup(CommandInterpreter &interpreter)
2692 : CommandObjectRaw(interpreter, "type lookup",
2693 "Lookup types and declarations in the current target, "
2694 "following language-specific naming conventions.",
2695 "type lookup <type-specifier>",
2696 eCommandRequiresTarget) {
2697 m_option_group.Append(group: &m_command_options);
2698 m_option_group.Finalize();
2699 }
2700
2701 ~CommandObjectTypeLookup() override = default;
2702
2703 Options *GetOptions() override { return &m_option_group; }
2704
2705 llvm::StringRef GetHelpLong() override {
2706 if (!m_cmd_help_long.empty())
2707 return m_cmd_help_long;
2708
2709 StreamString stream;
2710 Language::ForEach(callback: [&](Language *lang) {
2711 if (const char *help = lang->GetLanguageSpecificTypeLookupHelp())
2712 stream.Printf(format: "%s\n", help);
2713 return true;
2714 });
2715
2716 m_cmd_help_long = std::string(stream.GetString());
2717 return m_cmd_help_long;
2718 }
2719
2720 void DoExecute(llvm::StringRef raw_command_line,
2721 CommandReturnObject &result) override {
2722 if (raw_command_line.empty()) {
2723 result.AppendError(
2724 in_string: "type lookup cannot be invoked without a type name as argument");
2725 return;
2726 }
2727
2728 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
2729 m_option_group.NotifyOptionParsingStarting(execution_context: &exe_ctx);
2730
2731 OptionsWithRaw args(raw_command_line);
2732 const char *name_of_type = args.GetRawPart().c_str();
2733
2734 if (args.HasArgs())
2735 if (!ParseOptionsAndNotify(args&: args.GetArgs(), result, group_options&: m_option_group,
2736 exe_ctx))
2737 return;
2738
2739 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();
2740
2741 bool any_found = false;
2742
2743 std::vector<Language *> languages;
2744
2745 bool is_global_search = false;
2746 LanguageType guessed_language = lldb::eLanguageTypeUnknown;
2747
2748 if ((is_global_search =
2749 (m_command_options.m_language == eLanguageTypeUnknown))) {
2750 Language::ForEach(callback: [&](Language *lang) {
2751 languages.push_back(x: lang);
2752 return true;
2753 });
2754 } else {
2755 languages.push_back(x: Language::FindPlugin(language: m_command_options.m_language));
2756 }
2757
2758 // This is not the most efficient way to do this, but we support very few
2759 // languages so the cost of the sort is going to be dwarfed by the actual
2760 // lookup anyway
2761 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
2762 guessed_language = GuessLanguage(frame);
2763 if (guessed_language != eLanguageTypeUnknown) {
2764 llvm::sort(
2765 Start: languages.begin(), End: languages.end(),
2766 Comp: [guessed_language](Language *lang1, Language *lang2) -> bool {
2767 if (!lang1 || !lang2)
2768 return false;
2769 LanguageType lt1 = lang1->GetLanguageType();
2770 LanguageType lt2 = lang2->GetLanguageType();
2771 if (lt1 == guessed_language)
2772 return true; // make the selected frame's language come first
2773 if (lt2 == guessed_language)
2774 return false; // make the selected frame's language come first
2775 return (lt1 < lt2); // normal comparison otherwise
2776 });
2777 }
2778 }
2779
2780 bool is_first_language = true;
2781
2782 for (Language *language : languages) {
2783 if (!language)
2784 continue;
2785
2786 if (auto scavenger = language->GetTypeScavenger()) {
2787 Language::TypeScavenger::ResultSet search_results;
2788 if (scavenger->Find(exe_scope: best_scope, key: name_of_type, results&: search_results) > 0) {
2789 for (const auto &search_result : search_results) {
2790 if (search_result && search_result->IsValid()) {
2791 any_found = true;
2792 search_result->DumpToStream(stream&: result.GetOutputStream(),
2793 print_help_if_available: this->m_command_options.m_show_help);
2794 }
2795 }
2796 }
2797 }
2798 // this is "type lookup SomeName" and we did find a match, so get out
2799 if (any_found && is_global_search)
2800 break;
2801 else if (is_first_language && is_global_search &&
2802 guessed_language != lldb::eLanguageTypeUnknown) {
2803 is_first_language = false;
2804 result.GetOutputStream().Printf(
2805 format: "no type was found in the current language %s matching '%s'; "
2806 "performing a global search across all languages\n",
2807 Language::GetNameForLanguageType(language: guessed_language), name_of_type);
2808 }
2809 }
2810
2811 if (!any_found)
2812 result.AppendMessageWithFormat(format: "no type was found matching '%s'\n",
2813 name_of_type);
2814
2815 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult
2816 : lldb::eReturnStatusSuccessFinishNoResult);
2817 }
2818};
2819
2820template <typename FormatterType>
2821class CommandObjectFormatterInfo : public CommandObjectRaw {
2822public:
2823 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)>
2824 DiscoveryFunction;
2825 CommandObjectFormatterInfo(CommandInterpreter &interpreter,
2826 const char *formatter_name,
2827 DiscoveryFunction discovery_func)
2828 : CommandObjectRaw(interpreter, "", "", "", eCommandRequiresFrame),
2829 m_formatter_name(formatter_name ? formatter_name : ""),
2830 m_discovery_function(discovery_func) {
2831 StreamString name;
2832 name.Printf(format: "type %s info", formatter_name);
2833 SetCommandName(name.GetString());
2834 StreamString help;
2835 help.Printf(format: "This command evaluates the provided expression and shows "
2836 "which %s is applied to the resulting value (if any).",
2837 formatter_name);
2838 SetHelp(help.GetString());
2839 StreamString syntax;
2840 syntax.Printf(format: "type %s info <expr>", formatter_name);
2841 SetSyntax(syntax.GetString());
2842 }
2843
2844 ~CommandObjectFormatterInfo() override = default;
2845
2846protected:
2847 void DoExecute(llvm::StringRef command,
2848 CommandReturnObject &result) override {
2849 TargetSP target_sp = GetDebugger().GetSelectedTarget();
2850 Thread *thread = GetDefaultThread();
2851 if (!thread) {
2852 result.AppendError(in_string: "no default thread");
2853 return;
2854 }
2855
2856 StackFrameSP frame_sp =
2857 thread->GetSelectedFrame(select_most_relevant: DoNoSelectMostRelevantFrame);
2858 ValueObjectSP result_valobj_sp;
2859 EvaluateExpressionOptions options;
2860 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(
2861 expression: command, exe_scope: frame_sp.get(), result_valobj_sp, options);
2862 if (expr_result == eExpressionCompleted && result_valobj_sp) {
2863 result_valobj_sp =
2864 result_valobj_sp->GetQualifiedRepresentationIfAvailable(
2865 dynValue: target_sp->GetPreferDynamicValue(),
2866 synthValue: target_sp->GetEnableSyntheticValue());
2867 typename FormatterType::SharedPointer formatter_sp =
2868 m_discovery_function(*result_valobj_sp);
2869 if (formatter_sp) {
2870 std::string description(formatter_sp->GetDescription());
2871 result.GetOutputStream()
2872 << m_formatter_name << " applied to ("
2873 << result_valobj_sp->GetDisplayTypeName().AsCString(value_if_empty: "<unknown>")
2874 << ") " << command << " is: " << description << "\n";
2875 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
2876 } else {
2877 result.GetOutputStream()
2878 << "no " << m_formatter_name << " applies to ("
2879 << result_valobj_sp->GetDisplayTypeName().AsCString(value_if_empty: "<unknown>")
2880 << ") " << command << "\n";
2881 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
2882 }
2883 } else {
2884 result.AppendError(in_string: "failed to evaluate expression");
2885 }
2886 }
2887
2888private:
2889 std::string m_formatter_name;
2890 DiscoveryFunction m_discovery_function;
2891};
2892
2893class CommandObjectTypeFormat : public CommandObjectMultiword {
2894public:
2895 CommandObjectTypeFormat(CommandInterpreter &interpreter)
2896 : CommandObjectMultiword(
2897 interpreter, "type format",
2898 "Commands for customizing value display formats.",
2899 "type format [<sub-command-options>] ") {
2900 LoadSubCommand(
2901 cmd_name: "add", command_obj: CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter)));
2902 LoadSubCommand(cmd_name: "clear", command_obj: CommandObjectSP(
2903 new CommandObjectTypeFormatClear(interpreter)));
2904 LoadSubCommand(cmd_name: "delete", command_obj: CommandObjectSP(new CommandObjectTypeFormatDelete(
2905 interpreter)));
2906 LoadSubCommand(
2907 cmd_name: "list", command_obj: CommandObjectSP(new CommandObjectTypeFormatList(interpreter)));
2908 LoadSubCommand(
2909 cmd_name: "info", command_obj: CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>(
2910 interpreter, "format",
2911 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer {
2912 return valobj.GetValueFormat();
2913 })));
2914 }
2915
2916 ~CommandObjectTypeFormat() override = default;
2917};
2918
2919class CommandObjectTypeSynth : public CommandObjectMultiword {
2920public:
2921 CommandObjectTypeSynth(CommandInterpreter &interpreter)
2922 : CommandObjectMultiword(
2923 interpreter, "type synthetic",
2924 "Commands for operating on synthetic type representations.",
2925 "type synthetic [<sub-command-options>] ") {
2926 LoadSubCommand(cmd_name: "add",
2927 command_obj: CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter)));
2928 LoadSubCommand(
2929 cmd_name: "clear", command_obj: CommandObjectSP(new CommandObjectTypeSynthClear(interpreter)));
2930 LoadSubCommand(cmd_name: "delete", command_obj: CommandObjectSP(new CommandObjectTypeSynthDelete(
2931 interpreter)));
2932 LoadSubCommand(
2933 cmd_name: "list", command_obj: CommandObjectSP(new CommandObjectTypeSynthList(interpreter)));
2934 LoadSubCommand(
2935 cmd_name: "info",
2936 command_obj: CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>(
2937 interpreter, "synthetic",
2938 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer {
2939 return valobj.GetSyntheticChildren();
2940 })));
2941 }
2942
2943 ~CommandObjectTypeSynth() override = default;
2944};
2945
2946class CommandObjectTypeFilter : public CommandObjectMultiword {
2947public:
2948 CommandObjectTypeFilter(CommandInterpreter &interpreter)
2949 : CommandObjectMultiword(interpreter, "type filter",
2950 "Commands for operating on type filters.",
2951 "type filter [<sub-command-options>] ") {
2952 LoadSubCommand(
2953 cmd_name: "add", command_obj: CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter)));
2954 LoadSubCommand(cmd_name: "clear", command_obj: CommandObjectSP(
2955 new CommandObjectTypeFilterClear(interpreter)));
2956 LoadSubCommand(cmd_name: "delete", command_obj: CommandObjectSP(new CommandObjectTypeFilterDelete(
2957 interpreter)));
2958 LoadSubCommand(
2959 cmd_name: "list", command_obj: CommandObjectSP(new CommandObjectTypeFilterList(interpreter)));
2960 }
2961
2962 ~CommandObjectTypeFilter() override = default;
2963};
2964
2965class CommandObjectTypeCategory : public CommandObjectMultiword {
2966public:
2967 CommandObjectTypeCategory(CommandInterpreter &interpreter)
2968 : CommandObjectMultiword(interpreter, "type category",
2969 "Commands for operating on type categories.",
2970 "type category [<sub-command-options>] ") {
2971 LoadSubCommand(
2972 cmd_name: "define",
2973 command_obj: CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter)));
2974 LoadSubCommand(
2975 cmd_name: "enable",
2976 command_obj: CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter)));
2977 LoadSubCommand(
2978 cmd_name: "disable",
2979 command_obj: CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter)));
2980 LoadSubCommand(
2981 cmd_name: "delete",
2982 command_obj: CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter)));
2983 LoadSubCommand(cmd_name: "list", command_obj: CommandObjectSP(
2984 new CommandObjectTypeCategoryList(interpreter)));
2985 }
2986
2987 ~CommandObjectTypeCategory() override = default;
2988};
2989
2990class CommandObjectTypeSummary : public CommandObjectMultiword {
2991public:
2992 CommandObjectTypeSummary(CommandInterpreter &interpreter)
2993 : CommandObjectMultiword(
2994 interpreter, "type summary",
2995 "Commands for editing variable summary display options.",
2996 "type summary [<sub-command-options>] ") {
2997 LoadSubCommand(
2998 cmd_name: "add", command_obj: CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter)));
2999 LoadSubCommand(cmd_name: "clear", command_obj: CommandObjectSP(new CommandObjectTypeSummaryClear(
3000 interpreter)));
3001 LoadSubCommand(cmd_name: "delete", command_obj: CommandObjectSP(new CommandObjectTypeSummaryDelete(
3002 interpreter)));
3003 LoadSubCommand(
3004 cmd_name: "list", command_obj: CommandObjectSP(new CommandObjectTypeSummaryList(interpreter)));
3005 LoadSubCommand(
3006 cmd_name: "info", command_obj: CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>(
3007 interpreter, "summary",
3008 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer {
3009 return valobj.GetSummaryFormat();
3010 })));
3011 }
3012
3013 ~CommandObjectTypeSummary() override = default;
3014};
3015
3016// CommandObjectType
3017
3018CommandObjectType::CommandObjectType(CommandInterpreter &interpreter)
3019 : CommandObjectMultiword(interpreter, "type",
3020 "Commands for operating on the type system.",
3021 "type [<sub-command-options>]") {
3022 LoadSubCommand(cmd_name: "category",
3023 command_obj: CommandObjectSP(new CommandObjectTypeCategory(interpreter)));
3024 LoadSubCommand(cmd_name: "filter",
3025 command_obj: CommandObjectSP(new CommandObjectTypeFilter(interpreter)));
3026 LoadSubCommand(cmd_name: "format",
3027 command_obj: CommandObjectSP(new CommandObjectTypeFormat(interpreter)));
3028 LoadSubCommand(cmd_name: "summary",
3029 command_obj: CommandObjectSP(new CommandObjectTypeSummary(interpreter)));
3030 LoadSubCommand(cmd_name: "synthetic",
3031 command_obj: CommandObjectSP(new CommandObjectTypeSynth(interpreter)));
3032 LoadSubCommand(cmd_name: "lookup",
3033 command_obj: CommandObjectSP(new CommandObjectTypeLookup(interpreter)));
3034}
3035
3036CommandObjectType::~CommandObjectType() = default;
3037

source code of lldb/source/Commands/CommandObjectType.cpp