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