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