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