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