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