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