1 //===-- CommandObjectType.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "CommandObjectType.h"
11 #include "lldb/Core/Debugger.h"
12 #include "lldb/Core/IOHandler.h"
13 #include "lldb/DataFormatters/DataVisualization.h"
14 #include "lldb/Host/OptionParser.h"
15 #include "lldb/Interpreter/CommandInterpreter.h"
16 #include "lldb/Interpreter/CommandObject.h"
17 #include "lldb/Interpreter/CommandReturnObject.h"
18 #include "lldb/Interpreter/OptionArgParser.h"
19 #include "lldb/Interpreter/OptionGroupFormat.h"
20 #include "lldb/Interpreter/OptionValueBoolean.h"
21 #include "lldb/Interpreter/OptionValueLanguage.h"
22 #include "lldb/Interpreter/OptionValueString.h"
23 #include "lldb/Interpreter/Options.h"
24 #include "lldb/Symbol/Symbol.h"
25 #include "lldb/Target/Language.h"
26 #include "lldb/Target/Process.h"
27 #include "lldb/Target/StackFrame.h"
28 #include "lldb/Target/Target.h"
29 #include "lldb/Target/Thread.h"
30 #include "lldb/Target/ThreadList.h"
31 #include "lldb/Utility/ConstString.h"
32 #include "lldb/Utility/RegularExpression.h"
33 #include "lldb/Utility/State.h"
34 #include "lldb/Utility/StringList.h"
36 #include "llvm/ADT/STLExtras.h"
44 using namespace lldb_private;
46 class ScriptAddOptions {
48 TypeSummaryImpl::Flags m_flags;
49 StringList m_target_types;
52 std::string m_category;
54 ScriptAddOptions(const TypeSummaryImpl::Flags &flags, bool regx,
55 ConstString name, std::string catg)
56 : m_flags(flags), m_regex(regx), m_name(name), m_category(catg) {}
58 typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
61 class SynthAddOptions {
64 bool m_skip_references;
67 StringList m_target_types;
68 std::string m_category;
70 SynthAddOptions(bool sptr, bool sref, bool casc, bool regx, std::string catg)
71 : m_skip_pointers(sptr), m_skip_references(sref), m_cascade(casc),
72 m_regex(regx), m_target_types(), m_category(catg) {}
74 typedef std::shared_ptr<SynthAddOptions> SharedPointer;
77 static bool WarnOnPotentialUnquotedUnsignedType(Args &command,
78 CommandReturnObject &result) {
82 for (auto entry : llvm::enumerate(command.entries().drop_back())) {
83 if (entry.value().ref != "unsigned")
85 auto next = command.entries()[entry.index() + 1].ref;
86 if (next == "int" || next == "short" || next == "char" || next == "long") {
87 result.AppendWarningWithFormat(
88 "unsigned %s being treated as two types. if you meant the combined "
90 "name use quotes, as in \"unsigned %s\"\n",
91 next.str().c_str(), next.str().c_str());
98 static constexpr OptionDefinition g_type_summary_add_options[] = {
99 #define LLDB_OPTIONS_type_summary_add
100 #include "CommandOptions.inc"
103 class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
104 public IOHandlerDelegateMultiline {
106 class CommandOptions : public Options {
108 CommandOptions(CommandInterpreter &interpreter) : Options() {}
110 ~CommandOptions() override = default;
112 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
113 ExecutionContext *execution_context) override;
115 void OptionParsingStarting(ExecutionContext *execution_context) override;
117 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
118 return llvm::makeArrayRef(g_type_summary_add_options);
121 // Instance variables to hold the values for command options.
123 TypeSummaryImpl::Flags m_flags;
125 std::string m_format_string;
127 std::string m_python_script;
128 std::string m_python_function;
129 bool m_is_add_script;
130 std::string m_category;
133 CommandOptions m_options;
135 Options *GetOptions() override { return &m_options; }
137 bool Execute_ScriptSummary(Args &command, CommandReturnObject &result);
139 bool Execute_StringSummary(Args &command, CommandReturnObject &result);
142 enum SummaryFormatType { eRegularSummary, eRegexSummary, eNamedSummary };
144 CommandObjectTypeSummaryAdd(CommandInterpreter &interpreter);
146 ~CommandObjectTypeSummaryAdd() override = default;
148 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
149 static const char *g_summary_addreader_instructions =
150 "Enter your Python command(s). Type 'DONE' to end.\n"
151 "def function (valobj,internal_dict):\n"
152 " \"\"\"valobj: an SBValue which you want to provide a summary "
154 " internal_dict: an LLDB support object not to be used\"\"\"\n";
156 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
157 if (output_sp && interactive) {
158 output_sp->PutCString(g_summary_addreader_instructions);
163 void IOHandlerInputComplete(IOHandler &io_handler,
164 std::string &data) override {
165 StreamFileSP error_sp = io_handler.GetErrorStreamFile();
167 #ifndef LLDB_DISABLE_PYTHON
168 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
171 lines.SplitIntoLines(data);
172 if (lines.GetSize() > 0) {
173 ScriptAddOptions *options_ptr =
174 ((ScriptAddOptions *)io_handler.GetUserData());
176 ScriptAddOptions::SharedPointer options(
177 options_ptr); // this will ensure that we get rid of the pointer
178 // when going out of scope
180 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
182 std::string funct_name_str;
183 if (interpreter->GenerateTypeScriptFunction(lines,
185 if (funct_name_str.empty()) {
186 error_sp->Printf("unable to obtain a valid function name from "
187 "the script interpreter.\n");
190 // now I have a valid function name, let's add this as script
191 // for every type in the list
193 TypeSummaryImplSP script_format;
194 script_format = std::make_shared<ScriptSummaryFormat>(
195 options->m_flags, funct_name_str.c_str(),
196 lines.CopyList(" ").c_str());
200 for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
201 const char *type_name =
202 options->m_target_types.GetStringAtIndex(i);
203 CommandObjectTypeSummaryAdd::AddSummary(
204 ConstString(type_name), script_format,
206 ? CommandObjectTypeSummaryAdd::eRegexSummary
207 : CommandObjectTypeSummaryAdd::eRegularSummary),
208 options->m_category, &error);
210 error_sp->Printf("error: %s", error.AsCString());
215 if (options->m_name) {
216 CommandObjectTypeSummaryAdd::AddSummary(
217 options->m_name, script_format,
218 CommandObjectTypeSummaryAdd::eNamedSummary,
219 options->m_category, &error);
221 CommandObjectTypeSummaryAdd::AddSummary(
222 options->m_name, script_format,
223 CommandObjectTypeSummaryAdd::eNamedSummary,
224 options->m_category, &error);
226 error_sp->Printf("error: %s", error.AsCString());
230 error_sp->Printf("error: %s", error.AsCString());
234 if (error.AsCString()) {
235 error_sp->Printf("error: %s", error.AsCString());
241 error_sp->Printf("error: unable to generate a function.\n");
245 error_sp->Printf("error: no script interpreter.\n");
249 error_sp->Printf("error: internal synchronization information "
250 "missing or invalid.\n");
254 error_sp->Printf("error: empty function, didn't add python command.\n");
259 "error: script interpreter missing, didn't add python command.\n");
262 #endif // LLDB_DISABLE_PYTHON
263 io_handler.SetIsDone(true);
266 static bool AddSummary(ConstString type_name, lldb::TypeSummaryImplSP entry,
267 SummaryFormatType type, std::string category,
268 Status *error = nullptr);
271 bool DoExecute(Args &command, CommandReturnObject &result) override;
274 static const char *g_synth_addreader_instructions =
275 "Enter your Python command(s). Type 'DONE' to end.\n"
276 "You must define a Python class with these methods:\n"
277 " def __init__(self, valobj, dict):\n"
278 " def num_children(self):\n"
279 " def get_child_at_index(self, index):\n"
280 " def get_child_index(self, name):\n"
281 " def update(self):\n"
283 "class synthProvider:\n";
285 static constexpr OptionDefinition g_type_synth_add_options[] = {
286 #define LLDB_OPTIONS_type_synth_add
287 #include "CommandOptions.inc"
290 class CommandObjectTypeSynthAdd : public CommandObjectParsed,
291 public IOHandlerDelegateMultiline {
293 class CommandOptions : public Options {
295 CommandOptions() : Options() {}
297 ~CommandOptions() override = default;
299 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
300 ExecutionContext *execution_context) override {
302 const int short_option = m_getopt_table[option_idx].val;
305 switch (short_option) {
307 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
309 error.SetErrorStringWithFormat("invalid value for cascade: %s",
310 option_arg.str().c_str());
313 handwrite_python = true;
316 m_class_name = std::string(option_arg);
317 is_class_based = true;
320 m_skip_pointers = true;
323 m_skip_references = true;
326 m_category = std::string(option_arg);
332 error.SetErrorStringWithFormat("unrecognized option '%c'",
340 void OptionParsingStarting(ExecutionContext *execution_context) override {
343 m_skip_pointers = false;
344 m_skip_references = false;
345 m_category = "default";
346 is_class_based = false;
347 handwrite_python = false;
351 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
352 return llvm::makeArrayRef(g_type_synth_add_options);
355 // Instance variables to hold the values for command options.
358 bool m_skip_references;
359 bool m_skip_pointers;
360 std::string m_class_name;
362 std::string m_category;
364 bool handwrite_python;
368 CommandOptions m_options;
370 Options *GetOptions() override { return &m_options; }
372 bool Execute_HandwritePython(Args &command, CommandReturnObject &result);
374 bool Execute_PythonClass(Args &command, CommandReturnObject &result);
377 bool DoExecute(Args &command, CommandReturnObject &result) override {
378 WarnOnPotentialUnquotedUnsignedType(command, result);
380 if (m_options.handwrite_python)
381 return Execute_HandwritePython(command, result);
382 else if (m_options.is_class_based)
383 return Execute_PythonClass(command, result);
385 result.AppendError("must either provide a children list, a Python class "
386 "name, or use -P and type a Python class "
388 result.SetStatus(eReturnStatusFailed);
393 void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
394 StreamFileSP output_sp(io_handler.GetOutputStreamFile());
395 if (output_sp && interactive) {
396 output_sp->PutCString(g_synth_addreader_instructions);
401 void IOHandlerInputComplete(IOHandler &io_handler,
402 std::string &data) override {
403 StreamFileSP error_sp = io_handler.GetErrorStreamFile();
405 #ifndef LLDB_DISABLE_PYTHON
406 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
409 lines.SplitIntoLines(data);
410 if (lines.GetSize() > 0) {
411 SynthAddOptions *options_ptr =
412 ((SynthAddOptions *)io_handler.GetUserData());
414 SynthAddOptions::SharedPointer options(
415 options_ptr); // this will ensure that we get rid of the pointer
416 // when going out of scope
418 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
420 std::string class_name_str;
421 if (interpreter->GenerateTypeSynthClass(lines, class_name_str)) {
422 if (class_name_str.empty()) {
424 "error: unable to obtain a proper name for the class.\n");
427 // everything should be fine now, let's add the synth provider
430 SyntheticChildrenSP synth_provider;
431 synth_provider = std::make_shared<ScriptedSyntheticChildren>(
432 SyntheticChildren::Flags()
433 .SetCascades(options->m_cascade)
434 .SetSkipPointers(options->m_skip_pointers)
435 .SetSkipReferences(options->m_skip_references),
436 class_name_str.c_str());
438 lldb::TypeCategoryImplSP category;
439 DataVisualization::Categories::GetCategory(
440 ConstString(options->m_category.c_str()), category);
444 for (size_t i = 0; i < options->m_target_types.GetSize(); i++) {
445 const char *type_name =
446 options->m_target_types.GetStringAtIndex(i);
447 ConstString const_type_name(type_name);
448 if (const_type_name) {
449 if (!CommandObjectTypeSynthAdd::AddSynth(
450 const_type_name, synth_provider,
452 ? CommandObjectTypeSynthAdd::eRegexSynth
453 : CommandObjectTypeSynthAdd::eRegularSynth,
454 options->m_category, &error)) {
455 error_sp->Printf("error: %s\n", error.AsCString());
460 error_sp->Printf("error: invalid type name.\n");
467 error_sp->Printf("error: unable to generate a class.\n");
471 error_sp->Printf("error: no script interpreter.\n");
475 error_sp->Printf("error: internal synchronization data missing.\n");
479 error_sp->Printf("error: empty function, didn't add python command.\n");
484 "error: script interpreter missing, didn't add python command.\n");
488 #endif // LLDB_DISABLE_PYTHON
489 io_handler.SetIsDone(true);
493 enum SynthFormatType { eRegularSynth, eRegexSynth };
495 CommandObjectTypeSynthAdd(CommandInterpreter &interpreter);
497 ~CommandObjectTypeSynthAdd() override = default;
499 static bool AddSynth(ConstString type_name, lldb::SyntheticChildrenSP entry,
500 SynthFormatType type, std::string category_name,
504 // CommandObjectTypeFormatAdd
506 static constexpr OptionDefinition g_type_format_add_options[] = {
507 #define LLDB_OPTIONS_type_format_add
508 #include "CommandOptions.inc"
511 class CommandObjectTypeFormatAdd : public CommandObjectParsed {
513 class CommandOptions : public OptionGroup {
515 CommandOptions() : OptionGroup() {}
517 ~CommandOptions() override = default;
519 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
520 return llvm::makeArrayRef(g_type_format_add_options);
523 void OptionParsingStarting(ExecutionContext *execution_context) override {
525 m_skip_pointers = false;
526 m_skip_references = false;
528 m_category.assign("default");
529 m_custom_type_name.clear();
532 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
533 ExecutionContext *execution_context) override {
535 const int short_option =
536 g_type_format_add_options[option_idx].short_option;
539 switch (short_option) {
541 m_cascade = OptionArgParser::ToBoolean(option_value, true, &success);
543 error.SetErrorStringWithFormat("invalid value for cascade: %s",
544 option_value.str().c_str());
547 m_skip_pointers = true;
550 m_category.assign(option_value);
553 m_skip_references = true;
559 m_custom_type_name.assign(option_value);
562 error.SetErrorStringWithFormat("unrecognized option '%c'",
570 // Instance variables to hold the values for command options.
573 bool m_skip_references;
574 bool m_skip_pointers;
576 std::string m_category;
577 std::string m_custom_type_name;
580 OptionGroupOptions m_option_group;
581 OptionGroupFormat m_format_options;
582 CommandOptions m_command_options;
584 Options *GetOptions() override { return &m_option_group; }
587 CommandObjectTypeFormatAdd(CommandInterpreter &interpreter)
588 : CommandObjectParsed(interpreter, "type format add",
589 "Add a new formatting style for a type.", nullptr),
590 m_option_group(), m_format_options(eFormatInvalid),
591 m_command_options() {
592 CommandArgumentEntry type_arg;
593 CommandArgumentData type_style_arg;
595 type_style_arg.arg_type = eArgTypeName;
596 type_style_arg.arg_repetition = eArgRepeatPlus;
598 type_arg.push_back(type_style_arg);
600 m_arguments.push_back(type_arg);
604 The following examples of 'type format add' refer to this code snippet for context:
607 typedef float Afloat;
609 typedef Afloat Bfloat;
617 Adding default formatting:
619 (lldb) type format add -f hex AInt
620 (lldb) frame variable iy
623 " Produces hexadecimal display of iy, because no formatter is available for Bint and \
624 the one for Aint is used instead."
627 To prevent this use the cascade option '-C no' to prevent evaluation of typedef chains:
630 (lldb) type format add -f hex -C no AInt
632 Similar reasoning applies to this:
634 (lldb) type format add -f hex -C no float -p
637 " All float values and float references are now formatted as hexadecimal, but not \
638 pointers to floats. Nor will it change the default display for Afloat and Bfloat objects.");
640 // Add the "--format" to all options groups
641 m_option_group.Append(&m_format_options,
642 OptionGroupFormat::OPTION_GROUP_FORMAT,
644 m_option_group.Append(&m_command_options);
645 m_option_group.Finalize();
648 ~CommandObjectTypeFormatAdd() override = default;
651 bool DoExecute(Args &command, CommandReturnObject &result) override {
652 const size_t argc = command.GetArgumentCount();
655 result.AppendErrorWithFormat("%s takes one or more args.\n",
657 result.SetStatus(eReturnStatusFailed);
661 const Format format = m_format_options.GetFormat();
662 if (format == eFormatInvalid &&
663 m_command_options.m_custom_type_name.empty()) {
664 result.AppendErrorWithFormat("%s needs a valid format.\n",
666 result.SetStatus(eReturnStatusFailed);
670 TypeFormatImplSP entry;
672 if (m_command_options.m_custom_type_name.empty())
673 entry = std::make_shared<TypeFormatImpl_Format>(
674 format, TypeFormatImpl::Flags()
675 .SetCascades(m_command_options.m_cascade)
676 .SetSkipPointers(m_command_options.m_skip_pointers)
677 .SetSkipReferences(m_command_options.m_skip_references));
679 entry = std::make_shared<TypeFormatImpl_EnumType>(
680 ConstString(m_command_options.m_custom_type_name.c_str()),
681 TypeFormatImpl::Flags()
682 .SetCascades(m_command_options.m_cascade)
683 .SetSkipPointers(m_command_options.m_skip_pointers)
684 .SetSkipReferences(m_command_options.m_skip_references));
686 // now I have a valid format, let's add it to every type
688 TypeCategoryImplSP category_sp;
689 DataVisualization::Categories::GetCategory(
690 ConstString(m_command_options.m_category), category_sp);
694 WarnOnPotentialUnquotedUnsignedType(command, result);
696 for (auto &arg_entry : command.entries()) {
697 if (arg_entry.ref.empty()) {
698 result.AppendError("empty typenames not allowed");
699 result.SetStatus(eReturnStatusFailed);
703 ConstString typeCS(arg_entry.ref);
704 if (m_command_options.m_regex) {
705 RegularExpressionSP typeRX(new RegularExpression());
706 if (!typeRX->Compile(arg_entry.ref)) {
708 "regex format error (maybe this is not really a regex?)");
709 result.SetStatus(eReturnStatusFailed);
712 category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS);
713 category_sp->GetRegexTypeFormatsContainer()->Add(typeRX, entry);
715 category_sp->GetTypeFormatsContainer()->Add(typeCS, entry);
718 result.SetStatus(eReturnStatusSuccessFinishNoResult);
719 return result.Succeeded();
723 static constexpr OptionDefinition g_type_formatter_delete_options[] = {
724 #define LLDB_OPTIONS_type_formatter_delete
725 #include "CommandOptions.inc"
728 class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
730 class CommandOptions : public Options {
732 CommandOptions() : Options() {}
734 ~CommandOptions() override = default;
736 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
737 ExecutionContext *execution_context) override {
739 const int short_option = m_getopt_table[option_idx].val;
741 switch (short_option) {
746 m_category = std::string(option_arg);
749 m_language = Language::GetLanguageTypeFromString(option_arg);
752 error.SetErrorStringWithFormat("unrecognized option '%c'",
760 void OptionParsingStarting(ExecutionContext *execution_context) override {
761 m_delete_all = false;
762 m_category = "default";
763 m_language = lldb::eLanguageTypeUnknown;
766 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
767 return llvm::makeArrayRef(g_type_formatter_delete_options);
770 // Instance variables to hold the values for command options.
773 std::string m_category;
774 lldb::LanguageType m_language;
777 CommandOptions m_options;
778 uint32_t m_formatter_kind_mask;
780 Options *GetOptions() override { return &m_options; }
783 CommandObjectTypeFormatterDelete(CommandInterpreter &interpreter,
784 uint32_t formatter_kind_mask,
785 const char *name, const char *help)
786 : CommandObjectParsed(interpreter, name, help, nullptr), m_options(),
787 m_formatter_kind_mask(formatter_kind_mask) {
788 CommandArgumentEntry type_arg;
789 CommandArgumentData type_style_arg;
791 type_style_arg.arg_type = eArgTypeName;
792 type_style_arg.arg_repetition = eArgRepeatPlain;
794 type_arg.push_back(type_style_arg);
796 m_arguments.push_back(type_arg);
799 ~CommandObjectTypeFormatterDelete() override = default;
802 virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
804 bool DoExecute(Args &command, CommandReturnObject &result) override {
805 const size_t argc = command.GetArgumentCount();
808 result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str());
809 result.SetStatus(eReturnStatusFailed);
813 const char *typeA = command.GetArgumentAtIndex(0);
814 ConstString typeCS(typeA);
817 result.AppendError("empty typenames not allowed");
818 result.SetStatus(eReturnStatusFailed);
822 if (m_options.m_delete_all) {
823 DataVisualization::Categories::ForEach(
824 [this, typeCS](const lldb::TypeCategoryImplSP &category_sp) -> bool {
825 category_sp->Delete(typeCS, m_formatter_kind_mask);
828 result.SetStatus(eReturnStatusSuccessFinishNoResult);
829 return result.Succeeded();
832 bool delete_category = false;
833 bool extra_deletion = false;
835 if (m_options.m_language != lldb::eLanguageTypeUnknown) {
836 lldb::TypeCategoryImplSP category;
837 DataVisualization::Categories::GetCategory(m_options.m_language,
840 delete_category = category->Delete(typeCS, m_formatter_kind_mask);
841 extra_deletion = FormatterSpecificDeletion(typeCS);
843 lldb::TypeCategoryImplSP category;
844 DataVisualization::Categories::GetCategory(
845 ConstString(m_options.m_category.c_str()), category);
847 delete_category = category->Delete(typeCS, m_formatter_kind_mask);
848 extra_deletion = FormatterSpecificDeletion(typeCS);
851 if (delete_category || extra_deletion) {
852 result.SetStatus(eReturnStatusSuccessFinishNoResult);
853 return result.Succeeded();
855 result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA);
856 result.SetStatus(eReturnStatusFailed);
862 static constexpr OptionDefinition g_type_formatter_clear_options[] = {
863 #define LLDB_OPTIONS_type_formatter_clear
864 #include "CommandOptions.inc"
867 class CommandObjectTypeFormatterClear : public CommandObjectParsed {
869 class CommandOptions : public Options {
871 CommandOptions() : Options() {}
873 ~CommandOptions() override = default;
875 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
876 ExecutionContext *execution_context) override {
878 const int short_option = m_getopt_table[option_idx].val;
880 switch (short_option) {
885 error.SetErrorStringWithFormat("unrecognized option '%c'",
893 void OptionParsingStarting(ExecutionContext *execution_context) override {
894 m_delete_all = false;
897 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
898 return llvm::makeArrayRef(g_type_formatter_clear_options);
901 // Instance variables to hold the values for command options.
905 CommandOptions m_options;
906 uint32_t m_formatter_kind_mask;
908 Options *GetOptions() override { return &m_options; }
911 CommandObjectTypeFormatterClear(CommandInterpreter &interpreter,
912 uint32_t formatter_kind_mask,
913 const char *name, const char *help)
914 : CommandObjectParsed(interpreter, name, help, nullptr), m_options(),
915 m_formatter_kind_mask(formatter_kind_mask) {}
917 ~CommandObjectTypeFormatterClear() override = default;
920 virtual void FormatterSpecificDeletion() {}
922 bool DoExecute(Args &command, CommandReturnObject &result) override {
923 if (m_options.m_delete_all) {
924 DataVisualization::Categories::ForEach(
925 [this](const TypeCategoryImplSP &category_sp) -> bool {
926 category_sp->Clear(m_formatter_kind_mask);
930 lldb::TypeCategoryImplSP category;
931 if (command.GetArgumentCount() > 0) {
932 const char *cat_name = command.GetArgumentAtIndex(0);
933 ConstString cat_nameCS(cat_name);
934 DataVisualization::Categories::GetCategory(cat_nameCS, category);
936 DataVisualization::Categories::GetCategory(ConstString(nullptr),
939 category->Clear(m_formatter_kind_mask);
942 FormatterSpecificDeletion();
944 result.SetStatus(eReturnStatusSuccessFinishResult);
945 return result.Succeeded();
949 // CommandObjectTypeFormatDelete
951 class CommandObjectTypeFormatDelete : public CommandObjectTypeFormatterDelete {
953 CommandObjectTypeFormatDelete(CommandInterpreter &interpreter)
954 : CommandObjectTypeFormatterDelete(
956 eFormatCategoryItemValue | eFormatCategoryItemRegexValue,
957 "type format delete",
958 "Delete an existing formatting style for a type.") {}
960 ~CommandObjectTypeFormatDelete() override = default;
963 // CommandObjectTypeFormatClear
965 class CommandObjectTypeFormatClear : public CommandObjectTypeFormatterClear {
967 CommandObjectTypeFormatClear(CommandInterpreter &interpreter)
968 : CommandObjectTypeFormatterClear(
970 eFormatCategoryItemValue | eFormatCategoryItemRegexValue,
971 "type format clear", "Delete all existing format styles.") {}
975 static constexpr OptionDefinition g_type_formatter_list_options[] = {
976 #define LLDB_OPTIONS_type_formatter_list
977 #include "CommandOptions.inc"
980 template <typename FormatterType>
981 class CommandObjectTypeFormatterList : public CommandObjectParsed {
982 typedef typename FormatterType::SharedPointer FormatterSharedPointer;
984 class CommandOptions : public Options {
987 : Options(), m_category_regex("", ""),
988 m_category_language(lldb::eLanguageTypeUnknown,
989 lldb::eLanguageTypeUnknown) {}
991 ~CommandOptions() override = default;
993 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
994 ExecutionContext *execution_context) override {
996 const int short_option = m_getopt_table[option_idx].val;
997 switch (short_option) {
999 m_category_regex.SetCurrentValue(option_arg);
1000 m_category_regex.SetOptionWasSet();
1003 error = m_category_language.SetValueFromString(option_arg);
1004 if (error.Success())
1005 m_category_language.SetOptionWasSet();
1008 error.SetErrorStringWithFormat("unrecognized option '%c'",
1016 void OptionParsingStarting(ExecutionContext *execution_context) override {
1017 m_category_regex.Clear();
1018 m_category_language.Clear();
1021 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1022 return llvm::makeArrayRef(g_type_formatter_list_options);
1025 // Instance variables to hold the values for command options.
1027 OptionValueString m_category_regex;
1028 OptionValueLanguage m_category_language;
1031 CommandOptions m_options;
1033 Options *GetOptions() override { return &m_options; }
1036 CommandObjectTypeFormatterList(CommandInterpreter &interpreter,
1037 const char *name, const char *help)
1038 : CommandObjectParsed(interpreter, name, help, nullptr), m_options() {
1039 CommandArgumentEntry type_arg;
1040 CommandArgumentData type_style_arg;
1042 type_style_arg.arg_type = eArgTypeName;
1043 type_style_arg.arg_repetition = eArgRepeatOptional;
1045 type_arg.push_back(type_style_arg);
1047 m_arguments.push_back(type_arg);
1050 ~CommandObjectTypeFormatterList() override = default;
1053 virtual bool FormatterSpecificList(CommandReturnObject &result) {
1057 bool DoExecute(Args &command, CommandReturnObject &result) override {
1058 const size_t argc = command.GetArgumentCount();
1060 std::unique_ptr<RegularExpression> category_regex;
1061 std::unique_ptr<RegularExpression> formatter_regex;
1063 if (m_options.m_category_regex.OptionWasSet()) {
1064 category_regex.reset(new RegularExpression());
1065 if (!category_regex->Compile(
1066 m_options.m_category_regex.GetCurrentValueAsRef())) {
1067 result.AppendErrorWithFormat(
1068 "syntax error in category regular expression '%s'",
1069 m_options.m_category_regex.GetCurrentValueAsRef().str().c_str());
1070 result.SetStatus(eReturnStatusFailed);
1076 const char *arg = command.GetArgumentAtIndex(0);
1077 formatter_regex.reset(new RegularExpression());
1078 if (!formatter_regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) {
1079 result.AppendErrorWithFormat("syntax error in regular expression '%s'",
1081 result.SetStatus(eReturnStatusFailed);
1086 bool any_printed = false;
1088 auto category_closure = [&result, &formatter_regex, &any_printed](
1089 const lldb::TypeCategoryImplSP &category) -> void {
1090 result.GetOutputStream().Printf(
1091 "-----------------------\nCategory: %s%s\n-----------------------\n",
1092 category->GetName(), category->IsEnabled() ? "" : " (disabled)");
1094 TypeCategoryImpl::ForEachCallbacks<FormatterType> foreach;
1096 .SetExact([&result, &formatter_regex, &any_printed](
1098 const FormatterSharedPointer &format_sp) -> bool {
1099 if (formatter_regex) {
1101 if (name.GetStringRef() == formatter_regex->GetText()) {
1103 } else if (formatter_regex->Execute(name.GetStringRef())) {
1112 result.GetOutputStream().Printf("%s: %s\n", name.AsCString(),
1113 format_sp->GetDescription().c_str());
1118 .SetWithRegex([&result, &formatter_regex, &any_printed](
1119 RegularExpressionSP regex_sp,
1120 const FormatterSharedPointer &format_sp) -> bool {
1121 if (formatter_regex) {
1123 if (regex_sp->GetText() == formatter_regex->GetText()) {
1125 } else if (formatter_regex->Execute(regex_sp->GetText())) {
1134 result.GetOutputStream().Printf("%s: %s\n",
1135 regex_sp->GetText().str().c_str(),
1136 format_sp->GetDescription().c_str());
1140 category->ForEach(foreach);
1143 if (m_options.m_category_language.OptionWasSet()) {
1144 lldb::TypeCategoryImplSP category_sp;
1145 DataVisualization::Categories::GetCategory(
1146 m_options.m_category_language.GetCurrentValue(), category_sp);
1148 category_closure(category_sp);
1150 DataVisualization::Categories::ForEach(
1151 [&category_regex, &category_closure](
1152 const lldb::TypeCategoryImplSP &category) -> bool {
1153 if (category_regex) {
1155 if (category->GetName() == category_regex->GetText()) {
1157 } else if (category_regex->Execute(
1158 llvm::StringRef::withNullAsEmpty(
1159 category->GetName()))) {
1167 category_closure(category);
1172 any_printed = FormatterSpecificList(result) | any_printed;
1176 result.SetStatus(eReturnStatusSuccessFinishResult);
1178 result.GetOutputStream().PutCString("no matching results found.\n");
1179 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1181 return result.Succeeded();
1185 // CommandObjectTypeFormatList
1187 class CommandObjectTypeFormatList
1188 : public CommandObjectTypeFormatterList<TypeFormatImpl> {
1190 CommandObjectTypeFormatList(CommandInterpreter &interpreter)
1191 : CommandObjectTypeFormatterList(interpreter, "type format list",
1192 "Show a list of current formats.") {}
1195 #ifndef LLDB_DISABLE_PYTHON
1197 // CommandObjectTypeSummaryAdd
1199 #endif // LLDB_DISABLE_PYTHON
1201 Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue(
1202 uint32_t option_idx, llvm::StringRef option_arg,
1203 ExecutionContext *execution_context) {
1205 const int short_option = m_getopt_table[option_idx].val;
1208 switch (short_option) {
1210 m_flags.SetCascades(OptionArgParser::ToBoolean(option_arg, true, &success));
1212 error.SetErrorStringWithFormat("invalid value for cascade: %s",
1213 option_arg.str().c_str());
1216 m_flags.SetDontShowChildren(false);
1219 m_flags.SetHideEmptyAggregates(true);
1222 m_flags.SetDontShowValue(true);
1225 m_flags.SetShowMembersOneLiner(true);
1228 m_format_string = std::string(option_arg);
1231 m_flags.SetSkipPointers(true);
1234 m_flags.SetSkipReferences(true);
1240 m_name.SetString(option_arg);
1243 m_python_script = option_arg;
1244 m_is_add_script = true;
1247 m_python_function = option_arg;
1248 m_is_add_script = true;
1251 m_is_add_script = true;
1254 m_category = std::string(option_arg);
1257 m_flags.SetHideItemNames(true);
1260 error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
1267 void CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting(
1268 ExecutionContext *execution_context) {
1269 m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
1270 m_flags.SetShowMembersOneLiner(false)
1271 .SetSkipPointers(false)
1272 .SetSkipReferences(false)
1273 .SetHideItemNames(false);
1277 m_python_script = "";
1278 m_python_function = "";
1279 m_format_string = "";
1280 m_is_add_script = false;
1281 m_category = "default";
1284 #ifndef LLDB_DISABLE_PYTHON
1286 bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary(
1287 Args &command, CommandReturnObject &result) {
1288 const size_t argc = command.GetArgumentCount();
1290 if (argc < 1 && !m_options.m_name) {
1291 result.AppendErrorWithFormat("%s takes one or more args.\n",
1292 m_cmd_name.c_str());
1293 result.SetStatus(eReturnStatusFailed);
1297 TypeSummaryImplSP script_format;
1299 if (!m_options.m_python_function
1300 .empty()) // we have a Python function ready to use
1302 const char *funct_name = m_options.m_python_function.c_str();
1303 if (!funct_name || !funct_name[0]) {
1304 result.AppendError("function name empty.\n");
1305 result.SetStatus(eReturnStatusFailed);
1310 (" " + m_options.m_python_function + "(valobj,internal_dict)");
1312 script_format = std::make_shared<ScriptSummaryFormat>(
1313 m_options.m_flags, funct_name, code.c_str());
1315 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1317 if (interpreter && !interpreter->CheckObjectExists(funct_name))
1318 result.AppendWarningWithFormat(
1319 "The provided function \"%s\" does not exist - "
1320 "please define it before attempting to use this summary.\n",
1322 } else if (!m_options.m_python_script
1323 .empty()) // we have a quick 1-line script, just use it
1325 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
1327 result.AppendError("script interpreter missing - unable to generate "
1328 "function wrapper.\n");
1329 result.SetStatus(eReturnStatusFailed);
1332 StringList funct_sl;
1333 funct_sl << m_options.m_python_script.c_str();
1334 std::string funct_name_str;
1335 if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) {
1336 result.AppendError("unable to generate function wrapper.\n");
1337 result.SetStatus(eReturnStatusFailed);
1340 if (funct_name_str.empty()) {
1342 "script interpreter failed to generate a valid function name.\n");
1343 result.SetStatus(eReturnStatusFailed);
1347 std::string code = " " + m_options.m_python_script;
1349 script_format = std::make_shared<ScriptSummaryFormat>(
1350 m_options.m_flags, funct_name_str.c_str(), code.c_str());
1352 // Use an IOHandler to grab Python code from the user
1353 ScriptAddOptions *options =
1354 new ScriptAddOptions(m_options.m_flags, m_options.m_regex,
1355 m_options.m_name, m_options.m_category);
1357 for (auto &entry : command.entries()) {
1358 if (entry.ref.empty()) {
1359 result.AppendError("empty typenames not allowed");
1360 result.SetStatus(eReturnStatusFailed);
1364 options->m_target_types << entry.ref;
1367 m_interpreter.GetPythonCommandsFromIOHandler(
1369 *this, // IOHandlerDelegate
1370 true, // Run IOHandler in async mode
1371 options); // Baton for the "io_handler" that will be passed back into
1372 // our IOHandlerDelegate functions
1373 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1375 return result.Succeeded();
1378 // if I am here, script_format must point to something good, so I can add
1379 // that as a script summary to all interested parties
1383 for (auto &entry : command.entries()) {
1384 CommandObjectTypeSummaryAdd::AddSummary(
1385 ConstString(entry.ref), script_format,
1386 (m_options.m_regex ? eRegexSummary : eRegularSummary),
1387 m_options.m_category, &error);
1389 result.AppendError(error.AsCString());
1390 result.SetStatus(eReturnStatusFailed);
1395 if (m_options.m_name) {
1396 AddSummary(m_options.m_name, script_format, eNamedSummary,
1397 m_options.m_category, &error);
1399 result.AppendError(error.AsCString());
1400 result.AppendError("added to types, but not given a name");
1401 result.SetStatus(eReturnStatusFailed);
1406 return result.Succeeded();
1409 #endif // LLDB_DISABLE_PYTHON
1411 bool CommandObjectTypeSummaryAdd::Execute_StringSummary(
1412 Args &command, CommandReturnObject &result) {
1413 const size_t argc = command.GetArgumentCount();
1415 if (argc < 1 && !m_options.m_name) {
1416 result.AppendErrorWithFormat("%s takes one or more args.\n",
1417 m_cmd_name.c_str());
1418 result.SetStatus(eReturnStatusFailed);
1422 if (!m_options.m_flags.GetShowMembersOneLiner() &&
1423 m_options.m_format_string.empty()) {
1424 result.AppendError("empty summary strings not allowed");
1425 result.SetStatus(eReturnStatusFailed);
1429 const char *format_cstr = (m_options.m_flags.GetShowMembersOneLiner()
1431 : m_options.m_format_string.c_str());
1433 // ${var%S} is an endless recursion, prevent it
1434 if (strcmp(format_cstr, "${var%S}") == 0) {
1435 result.AppendError("recursive summary not allowed");
1436 result.SetStatus(eReturnStatusFailed);
1440 std::unique_ptr<StringSummaryFormat> string_format(
1441 new StringSummaryFormat(m_options.m_flags, format_cstr));
1442 if (!string_format) {
1443 result.AppendError("summary creation failed");
1444 result.SetStatus(eReturnStatusFailed);
1447 if (string_format->m_error.Fail()) {
1448 result.AppendErrorWithFormat("syntax error: %s",
1449 string_format->m_error.AsCString("<unknown>"));
1450 result.SetStatus(eReturnStatusFailed);
1453 lldb::TypeSummaryImplSP entry(string_format.release());
1455 // now I have a valid format, let's add it to every type
1457 for (auto &arg_entry : command.entries()) {
1458 if (arg_entry.ref.empty()) {
1459 result.AppendError("empty typenames not allowed");
1460 result.SetStatus(eReturnStatusFailed);
1463 ConstString typeCS(arg_entry.ref);
1465 AddSummary(typeCS, entry,
1466 (m_options.m_regex ? eRegexSummary : eRegularSummary),
1467 m_options.m_category, &error);
1470 result.AppendError(error.AsCString());
1471 result.SetStatus(eReturnStatusFailed);
1476 if (m_options.m_name) {
1477 AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category,
1480 result.AppendError(error.AsCString());
1481 result.AppendError("added to types, but not given a name");
1482 result.SetStatus(eReturnStatusFailed);
1487 result.SetStatus(eReturnStatusSuccessFinishNoResult);
1488 return result.Succeeded();
1491 CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd(
1492 CommandInterpreter &interpreter)
1493 : CommandObjectParsed(interpreter, "type summary add",
1494 "Add a new summary style for a type.", nullptr),
1495 IOHandlerDelegateMultiline("DONE"), m_options(interpreter) {
1496 CommandArgumentEntry type_arg;
1497 CommandArgumentData type_style_arg;
1499 type_style_arg.arg_type = eArgTypeName;
1500 type_style_arg.arg_repetition = eArgRepeatPlus;
1502 type_arg.push_back(type_style_arg);
1504 m_arguments.push_back(type_arg);
1508 The following examples of 'type summary add' refer to this code snippet for context:
1514 JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}
1516 JustADemo demo_instance(42, 3.14);
1518 typedef JustADemo NewDemo;
1519 NewDemo new_demo_instance(42, 3.14);
1521 (lldb) type summary add --summary-string "the answer is ${*var.ptr}" JustADemo
1523 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42"
1525 (lldb) type summary add --summary-string "the answer is ${*var.ptr}, and the question is ${var.value}" JustADemo
1527 Subsequently displaying demo_instance with 'frame variable' or 'expression' will display "the answer is 42 and the question is 3.14"
1530 "Alternatively, you could define formatting for all pointers to integers and \
1531 rely on that when formatting JustADemo to obtain the same result:"
1534 (lldb) type summary add --summary-string "${var%V} -> ${*var}" "int *"
1535 (lldb) type summary add --summary-string "the answer is ${var.ptr}, and the question is ${var.value}" JustADemo
1538 "Type summaries are automatically applied to derived typedefs, so the examples \
1539 above apply to both JustADemo and NewDemo. The cascade option can be used to \
1540 suppress this behavior:"
1543 (lldb) type summary add --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo -C no
1545 The summary will now be used for values of JustADemo but not NewDemo.
1548 "By default summaries are shown for pointers and references to values of the \
1549 specified type. To suppress formatting for pointers use the -p option, or apply \
1550 the corresponding -r option to suppress formatting for references:"
1553 (lldb) type summary add -p -r --summary-string "${var.ptr}, ${var.value},{${var.byte}}" JustADemo
1556 "One-line summaries including all fields in a type can be inferred without supplying an \
1557 explicit summary string by passing the -c option:"
1560 (lldb) type summary add -c JustADemo
1561 (lldb) frame variable demo_instance
1562 (ptr=<address>, value=3.14)
1565 "Type summaries normally suppress the nested display of individual fields. To \
1566 supply a summary to supplement the default structure add the -e option:"
1569 (lldb) type summary add -e --summary-string "*ptr = ${*var.ptr}" JustADemo
1572 "Now when displaying JustADemo values the int* is displayed, followed by the \
1573 standard LLDB sequence of children, one per line:"
1582 "You can also add summaries written in Python. These scripts use lldb public API to \
1583 gather information from your variables and produce a meaningful summary. To start a \
1584 multi-line script use the -P option. The function declaration will be displayed along with \
1585 a comment describing the two arguments. End your script with the word 'DONE' on a line by \
1589 (lldb) type summary add JustADemo -P
1590 def function (valobj,internal_dict):
1591 """valobj: an SBValue which you want to provide a summary for
1592 internal_dict: an LLDB support object not to be used"""
1593 value = valobj.GetChildMemberWithName('value');
1594 return 'My value is ' + value.GetValue();
1597 Alternatively, the -o option can be used when providing a simple one-line Python script:
1599 (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
1602 bool CommandObjectTypeSummaryAdd::DoExecute(Args &command,
1603 CommandReturnObject &result) {
1604 WarnOnPotentialUnquotedUnsignedType(command, result);
1606 if (m_options.m_is_add_script) {
1607 #ifndef LLDB_DISABLE_PYTHON
1608 return Execute_ScriptSummary(command, result);
1610 result.AppendError("python is disabled");
1611 result.SetStatus(eReturnStatusFailed);
1613 #endif // LLDB_DISABLE_PYTHON
1616 return Execute_StringSummary(command, result);
1619 static bool FixArrayTypeNameWithRegex(ConstString &type_name) {
1620 llvm::StringRef type_name_ref(type_name.GetStringRef());
1622 if (type_name_ref.endswith("[]")) {
1623 std::string type_name_str(type_name.GetCString());
1624 type_name_str.resize(type_name_str.length() - 2);
1625 if (type_name_str.back() != ' ')
1626 type_name_str.append(" \\[[0-9]+\\]");
1628 type_name_str.append("\\[[0-9]+\\]");
1629 type_name.SetCString(type_name_str.c_str());
1635 bool CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
1636 TypeSummaryImplSP entry,
1637 SummaryFormatType type,
1638 std::string category_name,
1640 lldb::TypeCategoryImplSP category;
1641 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
1644 if (type == eRegularSummary) {
1645 if (FixArrayTypeNameWithRegex(type_name))
1646 type = eRegexSummary;
1649 if (type == eRegexSummary) {
1650 RegularExpressionSP typeRX(new RegularExpression());
1651 if (!typeRX->Compile(type_name.GetStringRef())) {
1653 error->SetErrorString(
1654 "regex format error (maybe this is not really a regex?)");
1658 category->GetRegexTypeSummariesContainer()->Delete(type_name);
1659 category->GetRegexTypeSummariesContainer()->Add(typeRX, entry);
1662 } else if (type == eNamedSummary) {
1663 // system named summaries do not exist (yet?)
1664 DataVisualization::NamedSummaryFormats::Add(type_name, entry);
1667 category->GetTypeSummariesContainer()->Add(type_name, entry);
1672 // CommandObjectTypeSummaryDelete
1674 class CommandObjectTypeSummaryDelete : public CommandObjectTypeFormatterDelete {
1676 CommandObjectTypeSummaryDelete(CommandInterpreter &interpreter)
1677 : CommandObjectTypeFormatterDelete(
1679 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary,
1680 "type summary delete", "Delete an existing summary for a type.") {}
1682 ~CommandObjectTypeSummaryDelete() override = default;
1685 bool FormatterSpecificDeletion(ConstString typeCS) override {
1686 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1688 return DataVisualization::NamedSummaryFormats::Delete(typeCS);
1692 class CommandObjectTypeSummaryClear : public CommandObjectTypeFormatterClear {
1694 CommandObjectTypeSummaryClear(CommandInterpreter &interpreter)
1695 : CommandObjectTypeFormatterClear(
1697 eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary,
1698 "type summary clear", "Delete all existing summaries.") {}
1701 void FormatterSpecificDeletion() override {
1702 DataVisualization::NamedSummaryFormats::Clear();
1706 // CommandObjectTypeSummaryList
1708 class CommandObjectTypeSummaryList
1709 : public CommandObjectTypeFormatterList<TypeSummaryImpl> {
1711 CommandObjectTypeSummaryList(CommandInterpreter &interpreter)
1712 : CommandObjectTypeFormatterList(interpreter, "type summary list",
1713 "Show a list of current summaries.") {}
1716 bool FormatterSpecificList(CommandReturnObject &result) override {
1717 if (DataVisualization::NamedSummaryFormats::GetCount() > 0) {
1718 result.GetOutputStream().Printf("Named summaries:\n");
1719 DataVisualization::NamedSummaryFormats::ForEach(
1720 [&result](ConstString name,
1721 const TypeSummaryImplSP &summary_sp) -> bool {
1722 result.GetOutputStream().Printf(
1723 "%s: %s\n", name.AsCString(),
1724 summary_sp->GetDescription().c_str());
1733 // CommandObjectTypeCategoryDefine
1735 static constexpr OptionDefinition g_type_category_define_options[] = {
1736 #define LLDB_OPTIONS_type_category_define
1737 #include "CommandOptions.inc"
1740 class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
1741 class CommandOptions : public Options {
1744 : Options(), m_define_enabled(false, false),
1745 m_cate_language(eLanguageTypeUnknown, eLanguageTypeUnknown) {}
1747 ~CommandOptions() override = default;
1749 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1750 ExecutionContext *execution_context) override {
1752 const int short_option = m_getopt_table[option_idx].val;
1754 switch (short_option) {
1756 m_define_enabled.SetValueFromString(llvm::StringRef("true"));
1759 error = m_cate_language.SetValueFromString(option_arg);
1762 error.SetErrorStringWithFormat("unrecognized option '%c'",
1770 void OptionParsingStarting(ExecutionContext *execution_context) override {
1771 m_define_enabled.Clear();
1772 m_cate_language.Clear();
1775 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1776 return llvm::makeArrayRef(g_type_category_define_options);
1779 // Instance variables to hold the values for command options.
1781 OptionValueBoolean m_define_enabled;
1782 OptionValueLanguage m_cate_language;
1785 CommandOptions m_options;
1787 Options *GetOptions() override { return &m_options; }
1790 CommandObjectTypeCategoryDefine(CommandInterpreter &interpreter)
1791 : CommandObjectParsed(interpreter, "type category define",
1792 "Define a new category as a source of formatters.",
1795 CommandArgumentEntry type_arg;
1796 CommandArgumentData type_style_arg;
1798 type_style_arg.arg_type = eArgTypeName;
1799 type_style_arg.arg_repetition = eArgRepeatPlus;
1801 type_arg.push_back(type_style_arg);
1803 m_arguments.push_back(type_arg);
1806 ~CommandObjectTypeCategoryDefine() override = default;
1809 bool DoExecute(Args &command, CommandReturnObject &result) override {
1810 const size_t argc = command.GetArgumentCount();
1813 result.AppendErrorWithFormat("%s takes 1 or more args.\n",
1814 m_cmd_name.c_str());
1815 result.SetStatus(eReturnStatusFailed);
1819 for (auto &entry : command.entries()) {
1820 TypeCategoryImplSP category_sp;
1821 if (DataVisualization::Categories::GetCategory(ConstString(entry.ref),
1824 category_sp->AddLanguage(m_options.m_cate_language.GetCurrentValue());
1825 if (m_options.m_define_enabled.GetCurrentValue())
1826 DataVisualization::Categories::Enable(category_sp,
1827 TypeCategoryMap::Default);
1831 result.SetStatus(eReturnStatusSuccessFinishResult);
1832 return result.Succeeded();
1836 // CommandObjectTypeCategoryEnable
1838 static constexpr OptionDefinition g_type_category_enable_options[] = {
1839 #define LLDB_OPTIONS_type_category_enable
1840 #include "CommandOptions.inc"
1843 class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
1844 class CommandOptions : public Options {
1846 CommandOptions() : Options() {}
1848 ~CommandOptions() override = default;
1850 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1851 ExecutionContext *execution_context) override {
1853 const int short_option = m_getopt_table[option_idx].val;
1855 switch (short_option) {
1857 if (!option_arg.empty()) {
1858 m_language = Language::GetLanguageTypeFromString(option_arg);
1859 if (m_language == lldb::eLanguageTypeUnknown)
1860 error.SetErrorStringWithFormat("unrecognized language '%s'",
1861 option_arg.str().c_str());
1865 error.SetErrorStringWithFormat("unrecognized option '%c'",
1873 void OptionParsingStarting(ExecutionContext *execution_context) override {
1874 m_language = lldb::eLanguageTypeUnknown;
1877 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1878 return llvm::makeArrayRef(g_type_category_enable_options);
1881 // Instance variables to hold the values for command options.
1883 lldb::LanguageType m_language;
1886 CommandOptions m_options;
1888 Options *GetOptions() override { return &m_options; }
1891 CommandObjectTypeCategoryEnable(CommandInterpreter &interpreter)
1892 : CommandObjectParsed(interpreter, "type category enable",
1893 "Enable a category as a source of formatters.",
1896 CommandArgumentEntry type_arg;
1897 CommandArgumentData type_style_arg;
1899 type_style_arg.arg_type = eArgTypeName;
1900 type_style_arg.arg_repetition = eArgRepeatPlus;
1902 type_arg.push_back(type_style_arg);
1904 m_arguments.push_back(type_arg);
1907 ~CommandObjectTypeCategoryEnable() override = default;
1910 bool DoExecute(Args &command, CommandReturnObject &result) override {
1911 const size_t argc = command.GetArgumentCount();
1913 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
1914 result.AppendErrorWithFormat("%s takes arguments and/or a language",
1915 m_cmd_name.c_str());
1916 result.SetStatus(eReturnStatusFailed);
1920 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
1921 DataVisualization::Categories::EnableStar();
1922 } else if (argc > 0) {
1923 for (int i = argc - 1; i >= 0; i--) {
1924 const char *typeA = command.GetArgumentAtIndex(i);
1925 ConstString typeCS(typeA);
1928 result.AppendError("empty category name not allowed");
1929 result.SetStatus(eReturnStatusFailed);
1932 DataVisualization::Categories::Enable(typeCS);
1933 lldb::TypeCategoryImplSP cate;
1934 if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate) {
1935 if (cate->GetCount() == 0) {
1936 result.AppendWarning("empty category enabled (typo?)");
1942 if (m_options.m_language != lldb::eLanguageTypeUnknown)
1943 DataVisualization::Categories::Enable(m_options.m_language);
1945 result.SetStatus(eReturnStatusSuccessFinishResult);
1946 return result.Succeeded();
1950 // CommandObjectTypeCategoryDelete
1952 class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
1954 CommandObjectTypeCategoryDelete(CommandInterpreter &interpreter)
1955 : CommandObjectParsed(interpreter, "type category delete",
1956 "Delete a category and all associated formatters.",
1958 CommandArgumentEntry type_arg;
1959 CommandArgumentData type_style_arg;
1961 type_style_arg.arg_type = eArgTypeName;
1962 type_style_arg.arg_repetition = eArgRepeatPlus;
1964 type_arg.push_back(type_style_arg);
1966 m_arguments.push_back(type_arg);
1969 ~CommandObjectTypeCategoryDelete() override = default;
1972 bool DoExecute(Args &command, CommandReturnObject &result) override {
1973 const size_t argc = command.GetArgumentCount();
1976 result.AppendErrorWithFormat("%s takes 1 or more arg.\n",
1977 m_cmd_name.c_str());
1978 result.SetStatus(eReturnStatusFailed);
1982 bool success = true;
1984 // the order is not relevant here
1985 for (int i = argc - 1; i >= 0; i--) {
1986 const char *typeA = command.GetArgumentAtIndex(i);
1987 ConstString typeCS(typeA);
1990 result.AppendError("empty category name not allowed");
1991 result.SetStatus(eReturnStatusFailed);
1994 if (!DataVisualization::Categories::Delete(typeCS))
1995 success = false; // keep deleting even if we hit an error
1998 result.SetStatus(eReturnStatusSuccessFinishResult);
1999 return result.Succeeded();
2001 result.AppendError("cannot delete one or more categories\n");
2002 result.SetStatus(eReturnStatusFailed);
2008 // CommandObjectTypeCategoryDisable
2010 OptionDefinition constexpr g_type_category_disable_options[] = {
2011 #define LLDB_OPTIONS_type_category_disable
2012 #include "CommandOptions.inc"
2015 class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
2016 class CommandOptions : public Options {
2018 CommandOptions() : Options() {}
2020 ~CommandOptions() override = default;
2022 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2023 ExecutionContext *execution_context) override {
2025 const int short_option = m_getopt_table[option_idx].val;
2027 switch (short_option) {
2029 if (!option_arg.empty()) {
2030 m_language = Language::GetLanguageTypeFromString(option_arg);
2031 if (m_language == lldb::eLanguageTypeUnknown)
2032 error.SetErrorStringWithFormat("unrecognized language '%s'",
2033 option_arg.str().c_str());
2037 error.SetErrorStringWithFormat("unrecognized option '%c'",
2045 void OptionParsingStarting(ExecutionContext *execution_context) override {
2046 m_language = lldb::eLanguageTypeUnknown;
2049 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2050 return llvm::makeArrayRef(g_type_category_disable_options);
2053 // Instance variables to hold the values for command options.
2055 lldb::LanguageType m_language;
2058 CommandOptions m_options;
2060 Options *GetOptions() override { return &m_options; }
2063 CommandObjectTypeCategoryDisable(CommandInterpreter &interpreter)
2064 : CommandObjectParsed(interpreter, "type category disable",
2065 "Disable a category as a source of formatters.",
2068 CommandArgumentEntry type_arg;
2069 CommandArgumentData type_style_arg;
2071 type_style_arg.arg_type = eArgTypeName;
2072 type_style_arg.arg_repetition = eArgRepeatPlus;
2074 type_arg.push_back(type_style_arg);
2076 m_arguments.push_back(type_arg);
2079 ~CommandObjectTypeCategoryDisable() override = default;
2082 bool DoExecute(Args &command, CommandReturnObject &result) override {
2083 const size_t argc = command.GetArgumentCount();
2085 if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
2086 result.AppendErrorWithFormat("%s takes arguments and/or a language",
2087 m_cmd_name.c_str());
2088 result.SetStatus(eReturnStatusFailed);
2092 if (argc == 1 && strcmp(command.GetArgumentAtIndex(0), "*") == 0) {
2093 DataVisualization::Categories::DisableStar();
2094 } else if (argc > 0) {
2095 // the order is not relevant here
2096 for (int i = argc - 1; i >= 0; i--) {
2097 const char *typeA = command.GetArgumentAtIndex(i);
2098 ConstString typeCS(typeA);
2101 result.AppendError("empty category name not allowed");
2102 result.SetStatus(eReturnStatusFailed);
2105 DataVisualization::Categories::Disable(typeCS);
2109 if (m_options.m_language != lldb::eLanguageTypeUnknown)
2110 DataVisualization::Categories::Disable(m_options.m_language);
2112 result.SetStatus(eReturnStatusSuccessFinishResult);
2113 return result.Succeeded();
2117 // CommandObjectTypeCategoryList
2119 class CommandObjectTypeCategoryList : public CommandObjectParsed {
2121 CommandObjectTypeCategoryList(CommandInterpreter &interpreter)
2122 : CommandObjectParsed(interpreter, "type category list",
2123 "Provide a list of all existing categories.",
2125 CommandArgumentEntry type_arg;
2126 CommandArgumentData type_style_arg;
2128 type_style_arg.arg_type = eArgTypeName;
2129 type_style_arg.arg_repetition = eArgRepeatOptional;
2131 type_arg.push_back(type_style_arg);
2133 m_arguments.push_back(type_arg);
2136 ~CommandObjectTypeCategoryList() override = default;
2139 bool DoExecute(Args &command, CommandReturnObject &result) override {
2140 const size_t argc = command.GetArgumentCount();
2142 std::unique_ptr<RegularExpression> regex;
2145 regex.reset(new RegularExpression());
2146 const char *arg = command.GetArgumentAtIndex(0);
2147 if (!regex->Compile(llvm::StringRef::withNullAsEmpty(arg))) {
2148 result.AppendErrorWithFormat(
2149 "syntax error in category regular expression '%s'", arg);
2150 result.SetStatus(eReturnStatusFailed);
2153 } else if (argc != 0) {
2154 result.AppendErrorWithFormat("%s takes 0 or one arg.\n",
2155 m_cmd_name.c_str());
2156 result.SetStatus(eReturnStatusFailed);
2160 DataVisualization::Categories::ForEach(
2161 [®ex, &result](const lldb::TypeCategoryImplSP &category_sp) -> bool {
2164 if (regex->GetText() == category_sp->GetName()) {
2166 } else if (regex->Execute(llvm::StringRef::withNullAsEmpty(
2167 category_sp->GetName()))) {
2175 result.GetOutputStream().Printf(
2176 "Category: %s\n", category_sp->GetDescription().c_str());
2181 result.SetStatus(eReturnStatusSuccessFinishResult);
2182 return result.Succeeded();
2186 // CommandObjectTypeFilterList
2188 class CommandObjectTypeFilterList
2189 : public CommandObjectTypeFormatterList<TypeFilterImpl> {
2191 CommandObjectTypeFilterList(CommandInterpreter &interpreter)
2192 : CommandObjectTypeFormatterList(interpreter, "type filter list",
2193 "Show a list of current filters.") {}
2196 #ifndef LLDB_DISABLE_PYTHON
2198 // CommandObjectTypeSynthList
2200 class CommandObjectTypeSynthList
2201 : public CommandObjectTypeFormatterList<SyntheticChildren> {
2203 CommandObjectTypeSynthList(CommandInterpreter &interpreter)
2204 : CommandObjectTypeFormatterList(
2205 interpreter, "type synthetic list",
2206 "Show a list of current synthetic providers.") {}
2209 #endif // LLDB_DISABLE_PYTHON
2211 // CommandObjectTypeFilterDelete
2213 class CommandObjectTypeFilterDelete : public CommandObjectTypeFormatterDelete {
2215 CommandObjectTypeFilterDelete(CommandInterpreter &interpreter)
2216 : CommandObjectTypeFormatterDelete(
2218 eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
2219 "type filter delete", "Delete an existing filter for a type.") {}
2221 ~CommandObjectTypeFilterDelete() override = default;
2224 #ifndef LLDB_DISABLE_PYTHON
2226 // CommandObjectTypeSynthDelete
2228 class CommandObjectTypeSynthDelete : public CommandObjectTypeFormatterDelete {
2230 CommandObjectTypeSynthDelete(CommandInterpreter &interpreter)
2231 : CommandObjectTypeFormatterDelete(
2233 eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
2234 "type synthetic delete",
2235 "Delete an existing synthetic provider for a type.") {}
2237 ~CommandObjectTypeSynthDelete() override = default;
2240 #endif // LLDB_DISABLE_PYTHON
2242 // CommandObjectTypeFilterClear
2244 class CommandObjectTypeFilterClear : public CommandObjectTypeFormatterClear {
2246 CommandObjectTypeFilterClear(CommandInterpreter &interpreter)
2247 : CommandObjectTypeFormatterClear(
2249 eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
2250 "type filter clear", "Delete all existing filter.") {}
2253 #ifndef LLDB_DISABLE_PYTHON
2254 // CommandObjectTypeSynthClear
2256 class CommandObjectTypeSynthClear : public CommandObjectTypeFormatterClear {
2258 CommandObjectTypeSynthClear(CommandInterpreter &interpreter)
2259 : CommandObjectTypeFormatterClear(
2261 eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
2262 "type synthetic clear",
2263 "Delete all existing synthetic providers.") {}
2266 bool CommandObjectTypeSynthAdd::Execute_HandwritePython(
2267 Args &command, CommandReturnObject &result) {
2268 SynthAddOptions *options = new SynthAddOptions(
2269 m_options.m_skip_pointers, m_options.m_skip_references,
2270 m_options.m_cascade, m_options.m_regex, m_options.m_category);
2272 for (auto &entry : command.entries()) {
2273 if (entry.ref.empty()) {
2274 result.AppendError("empty typenames not allowed");
2275 result.SetStatus(eReturnStatusFailed);
2279 options->m_target_types << entry.ref;
2282 m_interpreter.GetPythonCommandsFromIOHandler(
2284 *this, // IOHandlerDelegate
2285 true, // Run IOHandler in async mode
2286 options); // Baton for the "io_handler" that will be passed back into our
2287 // IOHandlerDelegate functions
2288 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2289 return result.Succeeded();
2292 bool CommandObjectTypeSynthAdd::Execute_PythonClass(
2293 Args &command, CommandReturnObject &result) {
2294 const size_t argc = command.GetArgumentCount();
2297 result.AppendErrorWithFormat("%s takes one or more args.\n",
2298 m_cmd_name.c_str());
2299 result.SetStatus(eReturnStatusFailed);
2303 if (m_options.m_class_name.empty() && !m_options.m_input_python) {
2304 result.AppendErrorWithFormat("%s needs either a Python class name or -P to "
2305 "directly input Python code.\n",
2306 m_cmd_name.c_str());
2307 result.SetStatus(eReturnStatusFailed);
2311 SyntheticChildrenSP entry;
2313 ScriptedSyntheticChildren *impl = new ScriptedSyntheticChildren(
2314 SyntheticChildren::Flags()
2315 .SetCascades(m_options.m_cascade)
2316 .SetSkipPointers(m_options.m_skip_pointers)
2317 .SetSkipReferences(m_options.m_skip_references),
2318 m_options.m_class_name.c_str());
2322 ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter();
2325 !interpreter->CheckObjectExists(impl->GetPythonClassName()))
2326 result.AppendWarning("The provided class does not exist - please define it "
2327 "before attempting to use this synthetic provider");
2329 // now I have a valid provider, let's add it to every type
2331 lldb::TypeCategoryImplSP category;
2332 DataVisualization::Categories::GetCategory(
2333 ConstString(m_options.m_category.c_str()), category);
2337 for (auto &arg_entry : command.entries()) {
2338 if (arg_entry.ref.empty()) {
2339 result.AppendError("empty typenames not allowed");
2340 result.SetStatus(eReturnStatusFailed);
2344 ConstString typeCS(arg_entry.ref);
2345 if (!AddSynth(typeCS, entry,
2346 m_options.m_regex ? eRegexSynth : eRegularSynth,
2347 m_options.m_category, &error)) {
2348 result.AppendError(error.AsCString());
2349 result.SetStatus(eReturnStatusFailed);
2354 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2355 return result.Succeeded();
2358 CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd(
2359 CommandInterpreter &interpreter)
2360 : CommandObjectParsed(interpreter, "type synthetic add",
2361 "Add a new synthetic provider for a type.", nullptr),
2362 IOHandlerDelegateMultiline("DONE"), m_options() {
2363 CommandArgumentEntry type_arg;
2364 CommandArgumentData type_style_arg;
2366 type_style_arg.arg_type = eArgTypeName;
2367 type_style_arg.arg_repetition = eArgRepeatPlus;
2369 type_arg.push_back(type_style_arg);
2371 m_arguments.push_back(type_arg);
2374 bool CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
2375 SyntheticChildrenSP entry,
2376 SynthFormatType type,
2377 std::string category_name,
2379 lldb::TypeCategoryImplSP category;
2380 DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()),
2383 if (type == eRegularSynth) {
2384 if (FixArrayTypeNameWithRegex(type_name))
2388 if (category->AnyMatches(type_name, eFormatCategoryItemFilter |
2389 eFormatCategoryItemRegexFilter,
2392 error->SetErrorStringWithFormat("cannot add synthetic for type %s when "
2393 "filter is defined in same category!",
2394 type_name.AsCString());
2398 if (type == eRegexSynth) {
2399 RegularExpressionSP typeRX(new RegularExpression());
2400 if (!typeRX->Compile(type_name.GetStringRef())) {
2402 error->SetErrorString(
2403 "regex format error (maybe this is not really a regex?)");
2407 category->GetRegexTypeSyntheticsContainer()->Delete(type_name);
2408 category->GetRegexTypeSyntheticsContainer()->Add(typeRX, entry);
2412 category->GetTypeSyntheticsContainer()->Add(type_name, entry);
2417 #endif // LLDB_DISABLE_PYTHON
2419 static constexpr OptionDefinition g_type_filter_add_options[] = {
2420 #define LLDB_OPTIONS_type_filter_add
2421 #include "CommandOptions.inc"
2424 class CommandObjectTypeFilterAdd : public CommandObjectParsed {
2426 class CommandOptions : public Options {
2427 typedef std::vector<std::string> option_vector;
2430 CommandOptions() : Options() {}
2432 ~CommandOptions() override = default;
2434 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2435 ExecutionContext *execution_context) override {
2437 const int short_option = m_getopt_table[option_idx].val;
2440 switch (short_option) {
2442 m_cascade = OptionArgParser::ToBoolean(option_arg, true, &success);
2444 error.SetErrorStringWithFormat("invalid value for cascade: %s",
2445 option_arg.str().c_str());
2448 m_expr_paths.push_back(option_arg);
2449 has_child_list = true;
2452 m_skip_pointers = true;
2455 m_skip_references = true;
2458 m_category = std::string(option_arg);
2464 error.SetErrorStringWithFormat("unrecognized option '%c'",
2472 void OptionParsingStarting(ExecutionContext *execution_context) override {
2474 m_skip_pointers = false;
2475 m_skip_references = false;
2476 m_category = "default";
2477 m_expr_paths.clear();
2478 has_child_list = false;
2482 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2483 return llvm::makeArrayRef(g_type_filter_add_options);
2486 // Instance variables to hold the values for command options.
2489 bool m_skip_references;
2490 bool m_skip_pointers;
2491 bool m_input_python;
2492 option_vector m_expr_paths;
2493 std::string m_category;
2494 bool has_child_list;
2497 typedef option_vector::iterator ExpressionPathsIterator;
2500 CommandOptions m_options;
2502 Options *GetOptions() override { return &m_options; }
2504 enum FilterFormatType { eRegularFilter, eRegexFilter };
2506 bool AddFilter(ConstString type_name, TypeFilterImplSP entry,
2507 FilterFormatType type, std::string category_name,
2509 lldb::TypeCategoryImplSP category;
2510 DataVisualization::Categories::GetCategory(
2511 ConstString(category_name.c_str()), category);
2513 if (type == eRegularFilter) {
2514 if (FixArrayTypeNameWithRegex(type_name))
2515 type = eRegexFilter;
2518 if (category->AnyMatches(type_name, eFormatCategoryItemSynth |
2519 eFormatCategoryItemRegexSynth,
2522 error->SetErrorStringWithFormat("cannot add filter for type %s when "
2523 "synthetic is defined in same "
2525 type_name.AsCString());
2529 if (type == eRegexFilter) {
2530 RegularExpressionSP typeRX(new RegularExpression());
2531 if (!typeRX->Compile(type_name.GetStringRef())) {
2533 error->SetErrorString(
2534 "regex format error (maybe this is not really a regex?)");
2538 category->GetRegexTypeFiltersContainer()->Delete(type_name);
2539 category->GetRegexTypeFiltersContainer()->Add(typeRX, entry);
2543 category->GetTypeFiltersContainer()->Add(type_name, entry);
2549 CommandObjectTypeFilterAdd(CommandInterpreter &interpreter)
2550 : CommandObjectParsed(interpreter, "type filter add",
2551 "Add a new filter for a type.", nullptr),
2553 CommandArgumentEntry type_arg;
2554 CommandArgumentData type_style_arg;
2556 type_style_arg.arg_type = eArgTypeName;
2557 type_style_arg.arg_repetition = eArgRepeatPlus;
2559 type_arg.push_back(type_style_arg);
2561 m_arguments.push_back(type_arg);
2565 The following examples of 'type filter add' refer to this code snippet for context:
2580 Adding a simple filter:
2582 (lldb) type filter add --child a --child g Foo
2583 (lldb) frame variable my_foo
2586 "Produces output where only a and g are displayed. Other children of my_foo \
2587 (b, c, d, e, f, h and i) are available by asking for them explicitly:"
2590 (lldb) frame variable my_foo.b my_foo.c my_foo.i
2593 "The formatting option --raw on frame variable bypasses the filter, showing \
2594 all children of my_foo as if no filter was defined:"
2597 (lldb) frame variable my_foo --raw)");
2600 ~CommandObjectTypeFilterAdd() override = default;
2603 bool DoExecute(Args &command, CommandReturnObject &result) override {
2604 const size_t argc = command.GetArgumentCount();
2607 result.AppendErrorWithFormat("%s takes one or more args.\n",
2608 m_cmd_name.c_str());
2609 result.SetStatus(eReturnStatusFailed);
2613 if (m_options.m_expr_paths.empty()) {
2614 result.AppendErrorWithFormat("%s needs one or more children.\n",
2615 m_cmd_name.c_str());
2616 result.SetStatus(eReturnStatusFailed);
2620 TypeFilterImplSP entry(new TypeFilterImpl(
2621 SyntheticChildren::Flags()
2622 .SetCascades(m_options.m_cascade)
2623 .SetSkipPointers(m_options.m_skip_pointers)
2624 .SetSkipReferences(m_options.m_skip_references)));
2626 // go through the expression paths
2627 CommandOptions::ExpressionPathsIterator begin,
2628 end = m_options.m_expr_paths.end();
2630 for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
2631 entry->AddExpressionPath(*begin);
2633 // now I have a valid provider, let's add it to every type
2635 lldb::TypeCategoryImplSP category;
2636 DataVisualization::Categories::GetCategory(
2637 ConstString(m_options.m_category.c_str()), category);
2641 WarnOnPotentialUnquotedUnsignedType(command, result);
2643 for (auto &arg_entry : command.entries()) {
2644 if (arg_entry.ref.empty()) {
2645 result.AppendError("empty typenames not allowed");
2646 result.SetStatus(eReturnStatusFailed);
2650 ConstString typeCS(arg_entry.ref);
2651 if (!AddFilter(typeCS, entry,
2652 m_options.m_regex ? eRegexFilter : eRegularFilter,
2653 m_options.m_category, &error)) {
2654 result.AppendError(error.AsCString());
2655 result.SetStatus(eReturnStatusFailed);
2660 result.SetStatus(eReturnStatusSuccessFinishNoResult);
2661 return result.Succeeded();
2666 static constexpr OptionDefinition g_type_lookup_options[] = {
2667 #define LLDB_OPTIONS_type_lookup
2668 #include "CommandOptions.inc"
2671 class CommandObjectTypeLookup : public CommandObjectRaw {
2673 // this function is allowed to do a more aggressive job at guessing languages
2674 // than the expression parser is comfortable with - so leave the original
2675 // call alone and add one that is specific to type lookup
2676 lldb::LanguageType GuessLanguage(StackFrame *frame) {
2677 lldb::LanguageType lang_type = lldb::eLanguageTypeUnknown;
2682 lang_type = frame->GuessLanguage();
2683 if (lang_type != lldb::eLanguageTypeUnknown)
2686 Symbol *s = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
2688 lang_type = s->GetMangled().GuessLanguage();
2693 class CommandOptions : public OptionGroup {
2696 : OptionGroup(), m_show_help(false), m_language(eLanguageTypeUnknown) {}
2698 ~CommandOptions() override = default;
2700 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2701 return llvm::makeArrayRef(g_type_lookup_options);
2704 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value,
2705 ExecutionContext *execution_context) override {
2708 const int short_option = g_type_lookup_options[option_idx].short_option;
2710 switch (short_option) {
2716 m_language = Language::GetLanguageTypeFromString(option_value);
2720 error.SetErrorStringWithFormat("invalid short option character '%c'",
2728 void OptionParsingStarting(ExecutionContext *execution_context) override {
2729 m_show_help = false;
2730 m_language = eLanguageTypeUnknown;
2733 // Options table: Required for subclasses of Options.
2736 lldb::LanguageType m_language;
2739 OptionGroupOptions m_option_group;
2740 CommandOptions m_command_options;
2743 CommandObjectTypeLookup(CommandInterpreter &interpreter)
2744 : CommandObjectRaw(interpreter, "type lookup",
2745 "Lookup types and declarations in the current target, "
2746 "following language-specific naming conventions.",
2747 "type lookup <type-specifier>",
2748 eCommandRequiresTarget),
2749 m_option_group(), m_command_options() {
2750 m_option_group.Append(&m_command_options);
2751 m_option_group.Finalize();
2754 ~CommandObjectTypeLookup() override = default;
2756 Options *GetOptions() override { return &m_option_group; }
2758 llvm::StringRef GetHelpLong() override {
2759 if (!m_cmd_help_long.empty())
2760 return m_cmd_help_long;
2762 StreamString stream;
2763 Language::ForEach([&](Language *lang) {
2764 if (const char *help = lang->GetLanguageSpecificTypeLookupHelp())
2765 stream.Printf("%s\n", help);
2769 m_cmd_help_long = stream.GetString();
2770 return m_cmd_help_long;
2773 bool DoExecute(llvm::StringRef raw_command_line,
2774 CommandReturnObject &result) override {
2775 if (raw_command_line.empty()) {
2777 "type lookup cannot be invoked without a type name as argument");
2781 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
2782 m_option_group.NotifyOptionParsingStarting(&exe_ctx);
2784 OptionsWithRaw args(raw_command_line);
2785 const char *name_of_type = args.GetRawPart().c_str();
2788 if (!ParseOptionsAndNotify(args.GetArgs(), result, m_option_group,
2792 ExecutionContextScope *best_scope = exe_ctx.GetBestExecutionContextScope();
2794 bool any_found = false;
2796 std::vector<Language *> languages;
2798 bool is_global_search = false;
2799 LanguageType guessed_language = lldb::eLanguageTypeUnknown;
2801 if ((is_global_search =
2802 (m_command_options.m_language == eLanguageTypeUnknown))) {
2803 Language::ForEach([&](Language *lang) {
2804 languages.push_back(lang);
2808 languages.push_back(Language::FindPlugin(m_command_options.m_language));
2811 // This is not the most efficient way to do this, but we support very few
2812 // languages so the cost of the sort is going to be dwarfed by the actual
2814 if (StackFrame *frame = m_exe_ctx.GetFramePtr()) {
2815 guessed_language = GuessLanguage(frame);
2816 if (guessed_language != eLanguageTypeUnknown) {
2818 languages.begin(), languages.end(),
2819 [guessed_language](Language *lang1, Language *lang2) -> bool {
2820 if (!lang1 || !lang2)
2822 LanguageType lt1 = lang1->GetLanguageType();
2823 LanguageType lt2 = lang2->GetLanguageType();
2824 if (lt1 == guessed_language)
2825 return true; // make the selected frame's language come first
2826 if (lt2 == guessed_language)
2827 return false; // make the selected frame's language come first
2828 return (lt1 < lt2); // normal comparison otherwise
2833 bool is_first_language = true;
2835 for (Language *language : languages) {
2839 if (auto scavenger = language->GetTypeScavenger()) {
2840 Language::TypeScavenger::ResultSet search_results;
2841 if (scavenger->Find(best_scope, name_of_type, search_results) > 0) {
2842 for (const auto &search_result : search_results) {
2843 if (search_result && search_result->IsValid()) {
2845 search_result->DumpToStream(result.GetOutputStream(),
2846 this->m_command_options.m_show_help);
2851 // this is "type lookup SomeName" and we did find a match, so get out
2852 if (any_found && is_global_search)
2854 else if (is_first_language && is_global_search &&
2855 guessed_language != lldb::eLanguageTypeUnknown) {
2856 is_first_language = false;
2857 result.GetOutputStream().Printf(
2858 "no type was found in the current language %s matching '%s'; "
2859 "performing a global search across all languages\n",
2860 Language::GetNameForLanguageType(guessed_language), name_of_type);
2865 result.AppendMessageWithFormat("no type was found matching '%s'\n",
2868 result.SetStatus(any_found ? lldb::eReturnStatusSuccessFinishResult
2869 : lldb::eReturnStatusSuccessFinishNoResult);
2874 template <typename FormatterType>
2875 class CommandObjectFormatterInfo : public CommandObjectRaw {
2877 typedef std::function<typename FormatterType::SharedPointer(ValueObject &)>
2879 CommandObjectFormatterInfo(CommandInterpreter &interpreter,
2880 const char *formatter_name,
2881 DiscoveryFunction discovery_func)
2882 : CommandObjectRaw(interpreter, "", "", "",
2883 eCommandRequiresFrame),
2884 m_formatter_name(formatter_name ? formatter_name : ""),
2885 m_discovery_function(discovery_func) {
2887 name.Printf("type %s info", formatter_name);
2888 SetCommandName(name.GetString());
2890 help.Printf("This command evaluates the provided expression and shows "
2891 "which %s is applied to the resulting value (if any).",
2893 SetHelp(help.GetString());
2894 StreamString syntax;
2895 syntax.Printf("type %s info <expr>", formatter_name);
2896 SetSyntax(syntax.GetString());
2899 ~CommandObjectFormatterInfo() override = default;
2902 bool DoExecute(llvm::StringRef command,
2903 CommandReturnObject &result) override {
2904 TargetSP target_sp = GetDebugger().GetSelectedTarget();
2905 Thread *thread = GetDefaultThread();
2907 result.AppendError("no default thread");
2908 result.SetStatus(lldb::eReturnStatusFailed);
2912 StackFrameSP frame_sp = thread->GetSelectedFrame();
2913 ValueObjectSP result_valobj_sp;
2914 EvaluateExpressionOptions options;
2915 lldb::ExpressionResults expr_result = target_sp->EvaluateExpression(
2916 command, frame_sp.get(), result_valobj_sp, options);
2917 if (expr_result == eExpressionCompleted && result_valobj_sp) {
2919 result_valobj_sp->GetQualifiedRepresentationIfAvailable(
2920 target_sp->GetPreferDynamicValue(),
2921 target_sp->GetEnableSyntheticValue());
2922 typename FormatterType::SharedPointer formatter_sp =
2923 m_discovery_function(*result_valobj_sp);
2925 std::string description(formatter_sp->GetDescription());
2926 result.GetOutputStream()
2927 << m_formatter_name << " applied to ("
2928 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2929 << ") " << command << " is: " << description << "\n";
2930 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
2932 result.GetOutputStream()
2933 << "no " << m_formatter_name << " applies to ("
2934 << result_valobj_sp->GetDisplayTypeName().AsCString("<unknown>")
2935 << ") " << command << "\n";
2936 result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
2940 result.AppendError("failed to evaluate expression");
2941 result.SetStatus(lldb::eReturnStatusFailed);
2947 std::string m_formatter_name;
2948 DiscoveryFunction m_discovery_function;
2951 class CommandObjectTypeFormat : public CommandObjectMultiword {
2953 CommandObjectTypeFormat(CommandInterpreter &interpreter)
2954 : CommandObjectMultiword(
2955 interpreter, "type format",
2956 "Commands for customizing value display formats.",
2957 "type format [<sub-command-options>] ") {
2959 "add", CommandObjectSP(new CommandObjectTypeFormatAdd(interpreter)));
2960 LoadSubCommand("clear", CommandObjectSP(
2961 new CommandObjectTypeFormatClear(interpreter)));
2962 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFormatDelete(
2965 "list", CommandObjectSP(new CommandObjectTypeFormatList(interpreter)));
2967 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeFormatImpl>(
2968 interpreter, "format",
2969 [](ValueObject &valobj) -> TypeFormatImpl::SharedPointer {
2970 return valobj.GetValueFormat();
2974 ~CommandObjectTypeFormat() override = default;
2977 #ifndef LLDB_DISABLE_PYTHON
2979 class CommandObjectTypeSynth : public CommandObjectMultiword {
2981 CommandObjectTypeSynth(CommandInterpreter &interpreter)
2982 : CommandObjectMultiword(
2983 interpreter, "type synthetic",
2984 "Commands for operating on synthetic type representations.",
2985 "type synthetic [<sub-command-options>] ") {
2986 LoadSubCommand("add",
2987 CommandObjectSP(new CommandObjectTypeSynthAdd(interpreter)));
2989 "clear", CommandObjectSP(new CommandObjectTypeSynthClear(interpreter)));
2990 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSynthDelete(
2993 "list", CommandObjectSP(new CommandObjectTypeSynthList(interpreter)));
2996 CommandObjectSP(new CommandObjectFormatterInfo<SyntheticChildren>(
2997 interpreter, "synthetic",
2998 [](ValueObject &valobj) -> SyntheticChildren::SharedPointer {
2999 return valobj.GetSyntheticChildren();
3003 ~CommandObjectTypeSynth() override = default;
3006 #endif // LLDB_DISABLE_PYTHON
3008 class CommandObjectTypeFilter : public CommandObjectMultiword {
3010 CommandObjectTypeFilter(CommandInterpreter &interpreter)
3011 : CommandObjectMultiword(interpreter, "type filter",
3012 "Commands for operating on type filters.",
3013 "type synthetic [<sub-command-options>] ") {
3015 "add", CommandObjectSP(new CommandObjectTypeFilterAdd(interpreter)));
3016 LoadSubCommand("clear", CommandObjectSP(
3017 new CommandObjectTypeFilterClear(interpreter)));
3018 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeFilterDelete(
3021 "list", CommandObjectSP(new CommandObjectTypeFilterList(interpreter)));
3024 ~CommandObjectTypeFilter() override = default;
3027 class CommandObjectTypeCategory : public CommandObjectMultiword {
3029 CommandObjectTypeCategory(CommandInterpreter &interpreter)
3030 : CommandObjectMultiword(interpreter, "type category",
3031 "Commands for operating on type categories.",
3032 "type category [<sub-command-options>] ") {
3035 CommandObjectSP(new CommandObjectTypeCategoryDefine(interpreter)));
3038 CommandObjectSP(new CommandObjectTypeCategoryEnable(interpreter)));
3041 CommandObjectSP(new CommandObjectTypeCategoryDisable(interpreter)));
3044 CommandObjectSP(new CommandObjectTypeCategoryDelete(interpreter)));
3045 LoadSubCommand("list", CommandObjectSP(
3046 new CommandObjectTypeCategoryList(interpreter)));
3049 ~CommandObjectTypeCategory() override = default;
3052 class CommandObjectTypeSummary : public CommandObjectMultiword {
3054 CommandObjectTypeSummary(CommandInterpreter &interpreter)
3055 : CommandObjectMultiword(
3056 interpreter, "type summary",
3057 "Commands for editing variable summary display options.",
3058 "type summary [<sub-command-options>] ") {
3060 "add", CommandObjectSP(new CommandObjectTypeSummaryAdd(interpreter)));
3061 LoadSubCommand("clear", CommandObjectSP(new CommandObjectTypeSummaryClear(
3063 LoadSubCommand("delete", CommandObjectSP(new CommandObjectTypeSummaryDelete(
3066 "list", CommandObjectSP(new CommandObjectTypeSummaryList(interpreter)));
3068 "info", CommandObjectSP(new CommandObjectFormatterInfo<TypeSummaryImpl>(
3069 interpreter, "summary",
3070 [](ValueObject &valobj) -> TypeSummaryImpl::SharedPointer {
3071 return valobj.GetSummaryFormat();
3075 ~CommandObjectTypeSummary() override = default;
3078 // CommandObjectType
3080 CommandObjectType::CommandObjectType(CommandInterpreter &interpreter)
3081 : CommandObjectMultiword(interpreter, "type",
3082 "Commands for operating on the type system.",
3083 "type [<sub-command-options>]") {
3084 LoadSubCommand("category",
3085 CommandObjectSP(new CommandObjectTypeCategory(interpreter)));
3086 LoadSubCommand("filter",
3087 CommandObjectSP(new CommandObjectTypeFilter(interpreter)));
3088 LoadSubCommand("format",
3089 CommandObjectSP(new CommandObjectTypeFormat(interpreter)));
3090 LoadSubCommand("summary",
3091 CommandObjectSP(new CommandObjectTypeSummary(interpreter)));
3092 #ifndef LLDB_DISABLE_PYTHON
3093 LoadSubCommand("synthetic",
3094 CommandObjectSP(new CommandObjectTypeSynth(interpreter)));
3095 #endif // LLDB_DISABLE_PYTHON
3096 LoadSubCommand("lookup",
3097 CommandObjectSP(new CommandObjectTypeLookup(interpreter)));
3100 CommandObjectType::~CommandObjectType() = default;