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