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